This directory contains a SNMPv1/v2 protocol stack that was written to support a Tcl based programming interface. It was implemented by Sven Schmidt (vschmidt@ibr.cs.tu-bs.de) during his master thesis at the Technical University of Braunschweig, GERMANY. Some ideas for the Tcl interface were inspired by previous work done by P.H. Kamp. The current version depends on the C interface of the event scheduler found in Tcl7.5. Although we use this SNMP package mainly with scotty, you can also use this SNMP extension in wish since it is dynamic loadable. Below is a short description of the syntax of the new SNMP Tcl commands. The SNMPv1/v2 interface is implemented with two new Tcl commands. The first command deals with the Management Information Base (MIB) and is called mib. Its syntax is: mib name ?-exact? mib oid ?-exact? mib syntax ?-exact? mib description ?-exact? mib successor ?-exact? mib access ?-exact? mib macro ?-exact? mib module ?-exact? mib file ?-exact? mib tc ?-excat? The name, oid and syntax options retrieve the considered field of the OBJECT-TYPE macro. The description can be retrieved using the description command. The successor option returns all know direct successors of a node and may be used by MIB browser programs. The return values are implicitely defined by the argument. If you query for successors providing an object identifier, you will get a list of object identifiers as a result list. If you query by name, you will get the names. Note, name are not unique and object identifier are faster. So use object identifier internally and convert them to `nice' names when you print them out. The -exact switch request exact matches only, that is a lookup as `mib -exact syntax sysDescr' is legal while `mib -exact syntax sysDescr.0' will fail. The exact switch has no meaning for the successor lookup since they are always done using exact lookups. The snmp command is used to create SNMP session handles. All operations are later done using session handles. snmp session snmp info The snmp session command creates a new session handle and the snmp info command returns a list of all handles currently available. An existing handle can be configured later. We assume that $s contains the name of a valid snmp handle: $s configure [] Called without any options, this command returns a keyed list of all currently configured options. Options may be specified in one of the following forms: SNMPv1 (RFC 1157): -address -port -community -timeout -retries -version SNMPv1 SNMPv2C (RFC 1901-1908): -address -port -community -timeout -retries -version SNMPv2C SNMPv2USEC (RFC 1909-1910): -user -password -context -timeout -retries -version SNMPv2USEC SNMP operations are invoked by using one of the following commands: $s get [] $s getnext [] $s set [] $s getbulk nr max [] The SNMP operation will be done synchronously if no callback is defined. The command will return the result of the SNMP operation or an error. Asynchronous operations happen if you define a callback function. The callback will be called when a response is received or if the protocol engine did not receive an answer after some retries. The varbind will always contain the object identifier in the first element of the varbind list. Use an explicit mib name lookup to convert it to something more readable. The script can contain format strings that can be used to access parameters in the callback. An example: $s get "sysDescr.0 sysUpTime.0" { puts "Answer from %S (%R): %V" } The format escapes are: %V default varbind rendering (a list containing name, syntax and value for each varbind) %R the request id %S the session id %E error status %I error index %A the network address of the agent %P the port number of the agent There is another small goodie which makes walks easier. The walk subcommand just does a walk over a subtree and evaluates body foreach object in the subtree, which can be found in the variable var. $s walk There is currently no asynchronous version of this one. SNMP Traps are also supported. The syntax is quite simple: $s bind "" trap The callback may contain the usual escapes described above. SNMPv1 traps look like SNMPv2 traps as described in RFC 1452. The first element in the varbind is the sysUpTime of the agent sending the trap and the second element is the snmpTrapOID. See 1452 how enterprise specific traps are coded as an object identifier. To send traps to another manager, you can use the trap session command: $s trap trapOid Note: You have to make sure that the session handle is configured to send traps to the correct port. The default port used when creating session handles is the SNMP port 161. You have to switch it to something useful in most cases, e.g. $s configure -port 162 The latest feature allows scotty to run as an SNMP agent. To initialize scotty as an agent, you have to create a session and turn this session into an agent: $s configure -agent "" -port 1701 The example above will create a listening socket on port 1701 and answer SNMP request that are valid regarding the session handle $s (that is setting the community string on $s to foobar will only allow messages which also use the foobar community). The agent supports some buildin variables: The MIB-2 system group and the SNMP statistics group. You can define you own MIB variables by writing down some ASN.1 MIB definitions and loading them via the 'mib load' command. Now you can create instances using the following command: $s instance [] This command create an instance with the object identifier instance-oid and links it to the Tcl variable . You can use instance bindings to bind Tcl procedures to variables, which gives an easy way to implement agents that translate between management applications and real world hard- and software. The agents directory contains some example agent code. Below are some examples to see how to program with this Tcl SNMP interface: 1. Simple SNMPv1 operations: set s [snmp session -address 134.169.34.3] $s get sysDescr.0 $s getnext [mib successor system] $s destroy 2. A set operation using a private community: set txt "greetings from [exec hostname]" set s [snmp session -address 134.169.34.3 -community private] $s set [list [list sysName.0 "OCTET STRING" $txt] ] $s destroy 3. An authenticated SNMPv2USEC session on port 1701 for user james: set s [snmp session -port 1701 -user james -password enterprise] $s get "sysDescr.0 sysUpTime.0" $s destroy 4. A simple table walk. set s [snmp session -address 134.169.34.3] puts "Index ifInOctets ifOutOctets Description" $s walk x "ifIndex ifInOctets ifOutOctets ifDescr" { set Index [lindex [lindex $x 0] 2] set ifInOctets [lindex [lindex $x 1] 2] set ifOutOctets [lindex [lindex $x 2] 2] set ifDescr [lindex [lindex $x 3] 2] puts [format "%3u %12u %12u %s" \ $Index $ifInOctets $ifOutOctets $ifDescr] } $s destroy 5. A simple trap handler (SNMP version 1). proc traphandler {ip list} { set msg "SNMP trap from $ip:" foreach vb $list { append msg " [mib name [lindex $vb 0]]=\"[lindex $vb 2]\"" } puts stderr $msg } set s [snmp session -port 162] $s bind "" trap {traphandler %A "%V"} 6. Sending some well known traps. set s [snmp session -port 162] $s trap coldStart "" $s trap warmStart "" 7. A simple agent with a counter SNMP variable (abusing sysLocation): set s [snmp session -port 8161 -agent ""] # Create a counter binding for the sysLocation variable: $s bind sysLocation.0 get { incr sysLocation } # Send a set request to yourself to initialize the sysLocation # counter. $s set {{sysLocation.0 1}} {puts "%E %V"} # you can even send asynchronous requests to yourself :-) $s get sysLocation.0 {puts "%V"} # and you can add more bindings to the MIB tree $s bind system get "puts {GET request on session %S from %A}" $s get sysLocation.0 {puts "%V"} # and you can do special things when variables are set $s bind sysContact.0 set { set sysContact [string toupper "%v"] # a break makes sure that no other (default) bindings are invoked break } $s set {{sysContact.0 foobar}} {puts "%E %V"} 8. Another agent with a save Tcl interpreter using check/commit/rollback bindings. This needs some more work to simplify things a lot more. set i [interp create -safe] $i alias puts puts stderr set a [snmp session -agent $i -port 1701] $a bind "" begin {puts ""} $a bind sysContact set { puts {set %o.[%i] = %v} } $a bind sysContact get { puts {get %o.[%i]} } $a bind sysContact check {puts {check %o.[%i] = %v} } $a bind sysContact commit { puts {commit %o.[%i] = %v} } $a bind sysContact rollback { puts {rollback %o.[%i] = %v} } set m [snmp session -port 1701] $m set {{sysContact.0 "Bert Nase"}} {puts "%E@%I %V"} $m get sysContact.0 {puts "%E@%I %V"} $m set {{sysContact.0 ga} {sysDescr.0 no}} {puts "%E@%I %V"} $m get sysContact.0 {puts "%E@%I %V"} $m set {{sysContact.0 ga} {sysContact.0 gu} {sysDescr.0 no}} {puts "%E@%I %V"} $m get sysContact.0 {puts "%E@%I %V"}