Network Management Week 2
Fall 2009; LT-412, Wed 4:15-6:45 pm
Assignment 1 is below.
SNMP
snmpwalk/get
history
ASN.1
table format
interfaces table
at, ip tables
assignment
ASN.1
get, get-next
net-snmp agent configuration
Network planning
BER
Read: Mauro & Schmidt, pp 19-39, 43-44
If everyone is at work, using SNMP to let you know of a network
failure is likely to be only a few minutes ahead of the telephone.
However, in the evenings things can be different. Things are even more
different if you're monitoring a server that your customers use, like
your web-server database or credit-card-verification server. With these
kinds of network entities, the next chance at notification after SNMP
might be the week's sales summary, which is a very bad place to discover a network outage.
Brief intro to SNMP
Last week we looked at the naming hierarchy
(which the OSI people use to name "everything", not just SNMP-related
objects). The top of the mib2 subtree was OID 1.3.6.1.2.1.
1 iso
3 standard
6 dod
1 internet
2 mgmt 4: private
1 mib-2
I didn't notice this last week, but there was in fact no answer for sysServices, mib2.1.7.
Here are some of the next mib-2 levels; we will use "mib2" to represent "1.3.6.1.2.1"; thus mib2.5 denotes "1.3.6.1.2.1.5"
mib2.1 system
mib2.2 interfaces
mib2.3 arp
mib2.4 ip
mib2.5 icmp
mib2.6 tcp
mib2.7 udp
mib2.8 egp (obsolete)
mib2.9 unimplemented [?]
mib2.10 unimplemented [?]
mib2.11 snmp server
mib2.25 host resources
There are more.
Be sure you understand that a MIB is an assignment to each of a set of
OIDs a specific attribute name and type. (MIBs also define tabular data
forms.) The OIDs name the general attributes, not a specific instance.
In that sense, OIDs are like Java class definitions, not class
instances.
Questions:
- given an OID, how do we find a MIB file that defines it?
- given a piece of hardware, how do we find a MIB that defines its SNMP responses?
The first case corresponds to our seeing 1.3.6.1.2.1.1.9 in the output of the system snmp walk; we did not, however, know how to interpret the responses.
The second case is probably more common: you have a new switch, and need to find out what kinds of SNMP data it submits in the private (1.3.6.1.4.1) subtree.
If we run a MIB browser such as iReasoning, we can see the OIDs.
Sometimes googling for the OID will turn something up. Sometimes
searching the mib files for, say, the string "system 9" to figure out
the OIDs of form system.9, will find what we want.
First look at SNMP tables
All leaf nodes of the SNMP tree are atomic data values. However, tables
(lists of records) can be constructed by using the OID sequences to
index the data. The indexing is slightly nonstandard, though.
Recall the system group, {mib-2 1}. It is a "group" in the sense that system is a prefix to the OIDs of the group:
sysDescr ::= {system 1}
sysObjectID ::= {system 2}
sysUpTime ::= {system 3}
etc. The group is thus simply a collection of values. In this case, the are all scalars
(except for system.9!); as such, their full OID must have .0 appended.
That is, to get sysDescr, you have to fetch {system 1 0}, or
1.3.6.1.2.1.1.1.0. Doing a GET of 1.3.6.1.2.1.1.1 returns "no such name
error".
A table can be a member of a group in the same way as a scalar. A table is a collection of rows; each row consists of columns, or fields, and one (or more) of the fields serves as the table index, or key. We'll consider the interfaces table ifTable, part of the interfaces group. We have:
interfaces ::= {mib-2 2}
ifNumber ::= {interfaces 1} ;; a scalar value, retrieved with 1.3.6.1.2.1.2.1.0
ifTable ::= {interfaces 2}
By convention, SNMP then defines a table entry by adding another 1:
ifEntry ::= {ifTable 1}
An ifEntry is a list of fields (the columns), numbered starting at 1. Here are a few of the fields:
ifIndex ::= {ifEntry 1}
ifDescr ::= {ifEntry 2}
ifType ::= {ifEntry 3}
ifPhysAddr ::= {ifEntry 6}
ifInOctets ::= {ifEntry 10}
ifOutOctets::= {ifEntry 16}
Actual data is then indexed with OID {ifEntry col row}. (Note that the
numbering order {... row col} would be more conventional.) That is, the
address of the 4th interface is ifPhysAddr.4, or ifEntry.6.4. These
OIDs serve as the keys for retrieving any particular row and column of
the table. The key for a given row is, of course, the row number.
Here's a representation of all the OIDs involved in a table. Note that only leaf OIDs are actually stored; these are interior nodes.
1.3.6.1.2.1.2 interfaces
1.3.6.1.2.1.2.1 ifNumber
1.3.6.1.2.1.2.2 ifTable
1.3.6.1.2.1.2.2.1 ifEntry
1.3.6.1.2.1.2.2.1.1 ifIndex, our first column name
1.3.6.1.2.1.2.2.1.2 ifDesc, our second column name
1.3.6.1.2.1.2.2.1.3 ifType, our third column name
The actual leaf data is stored under OID columnName.ifNumber. That is,
the ifDesc for interface 4 would be at ifDesc.4, or
1.3.6.1.2.1.2.2.1.2.4.
There are no trailing .0's (as is required for scalar values).
Note that this indexing strategy means that, as we traverse the tree, we get all of
column 1, then all of column 2, then all of column 3, etc. The
second-to-last field of the OID is in effect the column number and the
last field is the row number, so values are named prefix.col.row. This
is sometimes called column-major indexing.
On host ulam3 (10.38.2.42) there are several interfaces, and two significant ones (eth0 and eth1).
Columns in principle can be numbered nonconsecutively, though such
examples are rare. Rows, however, are fairly often "numbered
"nonconsecutively. In fact, the actual rule is to take the column that
represents the table index (or key in the database sense of the word "key"), and replace "row" with the OID of the index column's value.
For the interface table, the index is required to be an integer between
1 and ifNumber, inclusive. But if the index were an IP address, we
might retrieve a value for column 7 of the row indexed by ip address
147.126.65.47 with OID tableEntry.7.147.126.65.47. Similarly, if a
table had two columns that served as index (key), we would access
column 7 with tableEntry.7.row1val.row2val, where row1val and row2val
were the index values for the row in question.
Note that we can also use the snmpwalk method (details later) to traverse the subtree and thus retrieve the entire table, without using key/index values as such.
Note that adding an extra slot in the OID for the tableEntry is
slightly wasteful; it does, however, help to make the grammar a bit
clearer. However, it would be feasible to define ifEntry to be
ifTable, and not {ifTable 1}, at the expense of making it
slightly harder to connect retrieved OIDs with named MIB entries.
Fundamental SNMP-v1 messges:
-
SET
- GET
- GET-NEXT
- response to above
- TRAP
atomic data values only! Note use of GET-NEXT to retrieve these.
Issues:
data presentation (eg byte order, but much more)
NAMING for all those possible attributes!
ASN.1/BER data representation: defer
data can be subdivided into fields, though it is not for SNMP.
Demos using iReasoning tool and snmpwalk
Some things work only if the OID string is terminated by a period; some things require it not be terminated by a period.
snmpwalk -v 1 -c public ulam2 .1.3.6.1.2.1.1
snmpwalk -v 1 -c public ulam2 1.3.6.1.4.1
End of MIB
snmpwalk -v 1 -c public ulam2 1.3.6.1.4.1.42
gads of data
You can put .1.3.6.1.4.1.42 into upper-right box of iReason tool [at least for ulam2]
snmpget ?? OIDs for atomic values must end in .0. Also, there are some
peculiarities as to whether the list should end with a dot.
Other ways of polling devices: ssh can be used, to run commands on remote machines, but there are limitations:
- lack of "universal" account
- lack of "limited" account
- doesn't work for most hubs/switches/non-hosts
History of SNMP
SGMP: Simple Gateway Monitoring Protocol:
started 1987; conflict with OSI approach
CMIP: Basic OSI strategy; too complex and large at the time it was defined for practical implementation.
1988: IAB decided to pursue both SGMP and CMOT: CMIP Over TCP/IP
This failed within a year: CMOT was dropped and SGMP had evolved into SNMPv1.
(Note that the IAB typically standardizes things a year or so after the thing has been rolled out. In fact, in order to become a standard, two independent implementations must exist.)
1990: SNMP v1 and SMI v1 had both been standardized. See RFC 1155.
1991: the SNMP mib-2 group was published, consisting of system, interfaces, etc.
1993: RFC 1442, SNMP v2 SMI (first version, obsoleted by RFC 1902 in
1996); first SNMPv2 proposal. There is extensive controversy on how
best to improve the security of SNMPv1.
1996: SNMPv2, Experimental (RFC 1901, Jan 1996); SNMPv2 standardization
for the so-called "community-based version", now known as SNMPv2c, is
complete. This version ignores all attempts at improving security,
postponing that until a future consensus.
1999: SMI version 2. Note that version 2 and mib 2 have nothing in common.
2002: RFCs 3411-3418 are published, defining SNMPv3. It becomes a
standard a couple years later. Security support is now thoroughly built
in.
To
enable community-based security for SNMPv1 (or SNMPv2c), you have to
"manually" (that is, outside of SNMP) configure the agent with the
community string, and then configure the manager to contain that
<agent,community> pair. SNMPv3 likewise requires some initial
"manual" configuration of the agent with a suitable key, and then
provide the manager with suitable credentials so that it can prove to
the agent that it has (or knows) the key. So, in that sense, SNMPv3 is
similar to its predecessors. In the details, however, SNMPv3
configuration is decidedly more complex.
ASN.1
See http://luca.ntop.org/Teaching/Appunti/asn1.html.
SNMP uses Abstract Syntax Notation 1 (ASN.1) to define syntax;
encoding into UDP packets is then done using the Basic Encoding Rules
(BER). Right now it sufficies to note the following:
- BER data is tagged with its type.
- ASN.1 and BER supports compound data types. However, SNMP does not use these; all data is atomic. (However, SNMP does support tables, which corresponds roughly to record formats and which can be pressed into service to represent, say, arrays.)
- SNMP
uses the ASN.1 type constructors SEQUENCE (to define lists)
and SEQUENCE OF (to define records). A table is a SEQUENCE of records;
each record is a SEQUENCE OF a specific list of fields. (ASN.1 also has
SET and SET OF constructors, but SNMP does not use these directly.)
- ASN.1 also supports CHOICE types, but these are used in SNMP only for very high-level definitions, eg
SimpleSyntax ::=
CHOICE {
number
INTEGER,
string
OCTET STRING,
object
OBJECT IDENTIFIER,
empty
NULL
}
- SNMP
does not use all the available basic ASN.1/BER data types. In fact,
only INTEGER, OCTET STRING, OBJECT IDENTIFIER, and NULL are allowed.
However, some subtypes of INTEGER are created; these are called defined types.
- The BER encoding is such that the actual size in bytes of the data can be difficult to predict.
Some defined types from RFC 1155:
- IpAddress: (a 4-byte OCTET STRING in network byte order)
- Counter: (a non-negative INTEGER which increases monotonically to 2^32-1 until it wraps around)
- Gauge: a nonnegative
integer which "latches at a maximum value". This generally means that
if it ever hits the maximum, it sticks there and will not decrease.
Thus, if it hits the maximum, you will know.
- TimeTicks: an INTEGER representing time measured in 10ms (0.01 sec) units.
- Opaque: an arbitrary byte string, encoded as an OCTET STRING.
ASN.1 has more built-in data types. Every type is either
Universal, Application-specific, Private, or Context-specific. Some of
the universal types are BITSTRING, UTCTime, and PrintableString.
Some ASN.1:
Some definitions of high-level OID prefixes:
internet OBJECT IDENTIFIER ::= { iso org(3) dod(6) 1 }
directory OBJECT IDENTIFIER ::= { internet 1 }
mgmt OBJECT IDENTIFIER ::= { internet 2 }
experimental OBJECT IDENTIFIER ::= { internet 3 }
private OBJECT IDENTIFIER ::= { internet 4 }
For defining records (eg ifEntry, or other table rows):
SEQUENCE { <type1>, ..., <typeN> }
Tables are lists of records, defined with
SEQUENCE OF <entry>
The OBJECT-TYPE macro is ubiquitous in MIB files. It provides a uniform
way to specify the value's type (the SYNTAX) field, and also the ACESS
and STATUS fields. The notation closes with "::= <OIDvalue>".
OBJECT-TYPE MACRO ::=
BEGIN
TYPE NOTATION ::= "SYNTAX" type (TYPE ObjectSyntax)
"ACCESS" Access
"STATUS" Status
VALUE NOTATION ::= value (VALUE ObjectName)
Access ::= "read-only"
| "read-write"
| "write-only"
| "not-accessible"
Status ::= "mandatory"
| "optional"
| "obsolete"
END
Here are five examples of OBJECT-TYPE in use to define the (now-deprecated) at table (for ARP data). The OID for the at
group is 1.3.6.1.2.1.3. It defines atTable as at.1 (that is,
1.3.6.1.2.1.3.1), and atEntry as atTable.1, and the three columns as
atEntry.1, atEntry.2, and atEntry.3.
1. atIndex OBJECT-TYPE
SYNTAX INTEGER
ACCESS read-write
STATUS mandatory
::= { atEntry 1 }
2. atPhysAddress OBJECT-TYPE
SYNTAX OCTET STRING
ACCESS read-write
STATUS mandatory
::= { atEntry 2 }
3. atNetAddress OBJECT-TYPE
SYNTAX NetworkAddress
ACCESS read-write
STATUS mandatory
::= { atEntry 3 }
4. atEntry OBJECT-TYPE
SYNTAX AtEntry
ACCESS read-write
STATUS mandatory
::= { atTable 1 }
5. atTable OBJECT-TYPE
SYNTAX SEQUENCE OF AtEntry
ACCESS read-write
STATUS mandatory
::= { at 1 }
The first three entries define columns ("fields") of atEntry. The
fourth defines atEntry as having OID atTable.1, and with syntax the
CAPITALIZED AtEntry. The fifth defines atTable as having OID at.1, and
with syntax SEQUENCE OF AtEntry.
Finally there is
AtEntry ::= SEQUENCE {
atIndex
INTEGER,
atPhysAddress
OCTET STRING,
atNetAddress
NetworkAddress
}
Every table has a row specification like this, with name capitalized by convention. Note that the OBJECT-TYPE is not used here. We could splice AtEntry into the fourth and fifth OBJECT-TYPE entries above, but it's simpler not to.
Interface Table
Go through details of ifTable, ifEntry, IfEntry, and all the columns (fields). This amounts to table syntax.
Then discuss the semantics, or meaning, of all the fields.
Special attention: ifInOctets and ifOutOctets.
Note that not all fields are updated immediately in real time, and some
fields are notorious for being permanently wrong. ifSpeed, for example,
is often set to 0 when the speed is variable, and is sometimes set to
some incorrect constant valuein order to convince higher-level routing
software to assign a specific "preference" to the link connected to
that interface.
Assignment 1
Write a script (in whatever scripting language you
wish; I'd use unix shell scripting if you don't have an established
favorite) to get ifInOctets and ifOutOctets from ulam2.cs.luc.edu every
15 minutes,
for a day.
Due: Sept 18 (week 4)
Here are some notes on shell scripting.
Every hour, at a certain number of minutes past the hour, ulam2
transfers a large chunk of data across its "loopback" (lo) interface.
Find the amount, and in which quarter-hour it occurs.
1.3.6.1.2.1: mib2
mib2.1: system
mib2.2: interfaces
system.2. iftable
iftable.1: ifentry
ifinoctets: ifentry.10 = 1.3.6.1.2.1.2.2.1.10
ifoutoctets: ifentry.16
individual ifinoctet values for specific interfaces (2 on ulam2):
ifinoctents.1 (loopback), ifinoctets.2 (ethernet)
Run this on random.cs.luc.edu or infinity.cs.luc.edu, probably.
use snmpget or snmpwalk.
To run something every 15 minutes:
crontab:
Run "crontab -e" to open up an editor (probably nano), and create the
following entry for your script:
(This runs it when the minutes part of the clock is 0, 15, 30, or 45)
0,15,30,45 * * * * $HOME/bin/myscriptname >> myfile.out 2>&1
There must be no spaces in the "0,15,30,45", followed by exactly four asterisks that are
separated by spaces. These represent the five crontab time fields: the
minutes, hours, day-of-month, day-of-week, and year. Asterisk means
that the script is run every hour of every day of every year, at the minutes specified (0,15,30,45).
Alternative: create a script file, keep it running for 24 hours
(either from a home computer through a terminal session on random or infinity
that's just quietly sitting there or using the "nohup" command)
I can be flexible if you run it less than 24 hours; it's fine, for
example, if you leave it running overnight, while your laptop is at
home and you have a terminal window open to random|infinity.
Suppose the script file is foo.sh:
while true
do
script >> myfile.out
sleep 900
# 900 seconds = 15 minutes
done
nohup foo.sh >/dev/null 2>&1
snmpget & snmpwalk are installed in standard places on {random,infinity}.
Continued overview of networks:
Ethernet
Failures/config issues: unique addresses, b'cast traffic, ethernet "meltdown",
total bandwidth consumption, hub v switch
runt packets, late collisions, bad CRC, collisions, too-big-packets, bad jitter
Hubs: 5.1
setup: rs-232 port, telnet, web-based, snmp
Note: hubs do NOT automatically get IP address!!
Switches, 5.2:
what is the difference between a switch and a hub?
setup: similar
additional item: <dest,port> tables
static entries??
security options
port speed (though some hubs have partial support for this)
monitor: one port replicates another
all statistics are per-port!
redundant links and the switch-to-switch spanning-tree protocol
ATM
virtual circuit maintenance
vc performance
ATM-ARP: given an IP addr, what VC is or needs to be set up to get you there?
Token Ring
Token maintenance protocols
ring disconnects
IP
Addressing
Routing tables: <dest,next_hop>, where dest represents a network address.
ARP, ARP storms
ICMP responses
fragmentation/reassembly timers
packet loss rates
IP support:
DHCP
DNS
SNMPv1 formats
-
SET
- GET
- GET-NEXT
- GET-RESPONSE
- TRAP
A GET request contains a list of OIDs being requested,
OID1, OID2, ... OID_N
The corresponding response is then a list of N <OID,VALUE> pairs. Such a list is called a VarBind list.
Often the request list is also called a varbind list, with the values
NULL. Very often, the list has length 1, that is, only a single OID
value is requested.
Note that the set of all OIDs, including proper prefixes, form a tree. SNMP tree traversal is generally depth-first, also known as lexicographic order. From any node on the tree, there is a well-defined next node, and a well-defined next leaf node.
Both the next node and the next leaf node for an interior node are
always below it (ie their OIDs represent proper extensions of the
original OID). The next and next-leaf nodes of a leaf node involve some
backtracking back up the tree, to the next "right branch", and then
taking that.
Here are a few hypothetical OIDs; leaf nodes are in bold.
1.5.1
1.5.1.0
1.5.2
1.5.2.0
1.5.3
1.5.3.1
1.5.3.1.1
1.5.3.1.1.7
1.5.3.1.1.9
1.5.3.1.2
1.5.3.1.2.28
From 1.5.2, the next and next-leaf nodes are both 1.5.2.0. From 1.5.3, the next node is 1.5.3.1; the next leaf is 1.5.3.1.1.7.
A GET-NEXT request contains, like a GET request, a list of OIDs. The agent then, for each OID in the list, finds the next leaf node properly following the received OID, and returns that <OIDleaf, VALUE> pair. Note that OIDleaf will always be different from the OID included in the request (and further on in the tree traversal).
Note that, if we're in an SNMP table, not on the last row, then the next-leaf node in the tree sense is the same column but down one row, in the table sense. If we were on the last row, then the tree next-leaf is the table's top of the next column.
Consider GET-NEXT in the system group. A GET-NEXT of system.1 will return sysDescr.0, ie system.1.0, while a GET-NEXT of system.1.0 will return sysObjectID.0, or system.2.0. If there is no next OID, a special end-of-MIB value is returned.
GET-NEXT is at the heart of snmpwalk: we ask for OIDs in sequence,
until we get to an OID "above" (in the tree) our starting value. We get
each leaf node below our starting value, in turn.
Normal practice is for GET-NEXT requests to request one OID at a
time, though for tables it is possible to request several. In that
case, each OID supplied has its "next" OIDleaf returned.
For SNMP tables, GET-NEXT will traverse down each column of the table, and then move on to subsequent columns.