In RFC 2579 section 2, a RowPointer is defined as:
RowPointer ::= TEXTUAL-CONVENTION
STATUS current
DESCRIPTION
"Represents a pointer to a conceptual row. The value is the
name of the instance of the first accessible columnar object
in the conceptual row.
For example, ifIndex.3 would point to the 3rd row in the
ifTable (note that if ifIndex were not-accessible, then
ifDescr.3 would be used instead)."
SYNTAX OBJECT IDENTIFIER
The RFC gives a good example for a row pointer with a single index (I assume the full OID for ifIndex.3 is .1.3.6.1.2.1.2.2.1.1.3 (.1.3.6.1.2.1.2.2.1.1 for ifIndex, the index of the ifTable, and the .3 for the value of the index)). So it having the format:
OID-to-table-entry.OID-of-index.value-of-index
I was wondering how a multiple index RowPointer would work then as there would be multiple OID's, one to each index. I can think of the following two formats
OID-to-table-entry.OID-of-index-1.value-of-index-1.OID-of-index-2.value-of-index-2...
and
OID-to-table-entry.OID-of-index-1.value-of-index-1.value-of-index-2...
where the second omits any additional OID to reference the other indices
I also know that for an OID to an object in a row that is not an index, the OID is of the format:
OID-to-table-entry.OID-of-non-index-object.value-of-index1.value-of-index-2...
However, this OID points to a particular object in a row, not the entire row (as a RowPointer should do) (which is why I am confused as a RowPointer shouldn't have the OID to a particular object in the row like the example given in the RFC has)
I can't seem to find any examples online or details in the RFC about multiple index row pointers. Any clarification would be appreciated.
I'll admit, I'm confused about what exactly you are asking, and I think it's because you are using the word "index" wrong. I'll start by explaining SNMP tables, what exactly an INDEX
is, and how a RowPointer
works, and hopefully some part of that will answer your question.
The first thing to understand is that an OID like ifIndex
(1.3.6.1.2.1.2.2.1.1), refers to an OBJECT-TYPE
, as defined in some MIB definition file. You can't directly query the value of ifIndex
, instead you have to query the value of some instance of ifIndex
.
There are some variables that can only have a single instance per engine. A common example is sysDescr
, which gives a textual description of the system. To refer to the concrete instance of this variable, you add the .0
sub-identifier to the OID. A response PDU should never provide a value forsysDescr
, only for sysDescr.0
. For more on this, see RFC 1157, section 3.2.6.3.
Variables that may have multiple instances per engine are organized into tables. Like any table, SNMP tables contain rows and columns. Most often, the rows are referred to as "entries". The SYNTAX
clause of the *Entry
OBJECT-TYPE
gives the name of a SEQUENCE
of OBJECT-TYPES
, each of which defines a column in the table. The numbering of the columns is actually determined by the OBJECT-TYPE
definition for each column, though there's probably a requirement somewhere that says that the OID numbers have to match the ordering in the *Entry
SEQUENCE
.
If all that jargon was confusing, here's the definition of ifTable
:
ifTable OBJECT-TYPE
SYNTAX SEQUENCE OF IfEntry
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
"A list of interface entries. The number of entries is
given by the value of ifNumber."
::= { interfaces 2 }
ifEntry OBJECT-TYPE
SYNTAX IfEntry
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
"An entry containing management information applicable to a
particular interface."
INDEX { ifIndex }
::= { ifTable 1 }
IfEntry ::=
SEQUENCE {
ifIndex InterfaceIndex,
ifDescr DisplayString,
ifType IANAifType,
ifMtu Integer32,
ifSpeed Gauge32,
ifPhysAddress PhysAddress,
ifAdminStatus INTEGER,
ifOperStatus INTEGER,
ifLastChange TimeTicks,
ifInOctets Counter32,
ifInUcastPkts Counter32,
ifInNUcastPkts Counter32, -- deprecated
ifInDiscards Counter32,
ifInErrors Counter32,
ifInUnknownProtos Counter32,
ifOutOctets Counter32,
ifOutUcastPkts Counter32,
ifOutNUcastPkts Counter32, -- deprecated
ifOutDiscards Counter32,
ifOutErrors Counter32,
ifOutQLen Gauge32, -- deprecated
ifSpecific OBJECT IDENTIFIER -- deprecated
}
ifIndex OBJECT-TYPE
SYNTAX InterfaceIndex
MAX-ACCESS read-only
STATUS current
DESCRIPTION
"A unique value, greater than zero, for each interface. It
is recommended that values are assigned contiguously
starting from 1. The value for each interface sub-layer
must remain constant at least from one re-initialization of
the entity's network management system to the next re-
initialization."
::= { ifEntry 1 }
ifDescr OBJECT-TYPE
SYNTAX DisplayString (SIZE (0..255))
MAX-ACCESS read-only
STATUS current
DESCRIPTION
"A textual string containing information about the
interface. This string should include the name of the
manufacturer, the product name and the version of the
interface hardware/software."
::= { ifEntry 2 }
You can see that ifTable
is a SEQUENCE OF IfEntry
. Each entry (row) is accessible through ifEntry
, which is an IfEntry
whose OID is ifTable.1
. Then, you can see that ifIndex
is defined as { ifEntry 1 }
, meaning its OID is ifEntry.1
, and similarly, ifDescr
is ifEntry.2
. This may be what you meant by "index" in your question, but it's important to understand that it's the column index, which I would prefer to call the "column number", because the term "index" usually refers to the "instance identifier", or the portion of the OID that identifies a concrete instance of an object. Remember that it's not valid for a response PDU to provide a value for ifIndex
, because that's the OID of the OBJECT-TYPE
, not of any single instance.
So, to finally get to the point, the INDEX
clause of the *Entry
OBJECT-TYPE
definition tells you which columns are used to uniquely identify a row. This is perfectly analagous to the PRIMARY KEY
in an SQL database table. In most cases, such as the ifTable
, the INDEX
simply uses a single INTEGER
. You can see from the MIB excerpt above, that ifEntry
uses ifIndex
as the INDEX
, meaning that ifIndex.3
, ifDescr.3
, and ifType.3
refer to three columns in the same row. The .3
would generally be called the "index".
It is absolutely possible for a row to have a composite INDEX
, just as a database table can have a composite PRIMARY KEY
. One example is IP-MIB::ipAddressEntry
:
ipAddressEntry OBJECT-TYPE
SYNTAX IpAddressEntry
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
"An address mapping for a particular interface."
INDEX { ipAddressAddrType, ipAddressAddr }
::= { ipAddressTable 1 }
IpAddressEntry ::= SEQUENCE {
ipAddressAddrType InetAddressType,
ipAddressAddr InetAddress,
ipAddressIfIndex InterfaceIndex,
ipAddressType INTEGER,
ipAddressPrefix RowPointer,
ipAddressOrigin IpAddressOriginTC,
ipAddressStatus IpAddressStatusTC,
ipAddressCreated TimeStamp,
ipAddressLastChanged TimeStamp,
ipAddressRowStatus RowStatus,
ipAddressStorageType StorageType
}
Note that the INDEX
contains two column names. The first is an INTEGER
, indicating the IP address type (ipv4 or ipv6), and the second is an OCTET STRING
containing the address itself. Both ipAddressAddrType
and ipAddressAddr
are marked as not-accessible
, meaning that it's not valid to query/return those columns directly. Their values can only be determined by querying the value of another column in the table.
Having explained all this, hopefully the definition of a RowPointer
will make more sense. Copying from the text in your question:
The value is the name of the instance of the first accessible columnar object in the conceptual row.
The example given refers to ifIndex.3
. This is because ifIndex
is the first OBJECT-TYPE
in IfEntry
, and it's MAX-ACCESS
is read-only
. The value of any other column in that row can be determined by extracting the .3
index, and tacking it onto to the OID of the desired column.
For a row of ipAddressTable
, the RowPointer
might be something like ipAddressIfIndex.1.4.192.168.0.1
. Unlike in IfEntry
, the first two OBJECT-TYPE
s in IpAddressEntry
are marked not-accessible
, so the "first accessible columnar object" is ifAddressIfIndex
. The index contains an ipAddressAddrType
of .1
(ipv4), and an ipAddressAddr
of .4.192.168.0.1
, which encodes the IP address "192.168.0.1" (the .4
indicates the length -- that's a different discussion). Together these two fields constitute the index of the row. To query, say, ipAddressCreated
for the same row, you would use ipAddressCreated.1.4.192.168.0.1
.