On Sat, 2005-02-19 at 10:17, Ben Rockwood wrote: > I've long been frustrated by the poor documentation available for > Net-SNMP so I wrote my own manual a while back.... > I hope it can be useful.
Thank you for that. I've had a look through it, and there's a lot of good stuff there. However, I also detected a few areas where either you seem to have misunderstood certain aspects of SNMP slightly, or else you've phrased things in such a way that an inexperienced reader could very easily come away with the wrong impression. I've therefore taken the liberty of putting together a series of comments and suggested amendments, which I'm attaching. Please don't be alarmed by the length of this list! It's more an indication of my pedantic nature, rather than a comment on the quality of your document :-) (It also includes various minor typos and grammatical corrections - none of which affect the basic quality of the content, but I thought I might as well point them out so you could get them fixed). I hope you find this useful. Dave
1.1 General Overview p2, para 2: "The agent populates these values" This description makes it sound as if the agent holds an internal database of key-value pairs, and simply looks things up in this. That's one possible approach but is not universally true, and the agent may well retrieve data dynamically from somewhere else. p2 typos: para 2, line 6: "agent's" para 2, line 14: "performed" p3, para 1: "... disk usage numbers or port status information" It might be possible to recognise host names or disk mount points from the raw SNMP values. I defy you to interpret disk usage figures or network ports without a knowledge of the MIB objects that they represent! p3, para 2: "SNMP can be used in 2 ways" There are actually three ways: polling, traps and configuration (SETs) Polling can be done using either GET or GETNEXT requests. "..contact another SNMP agent when..." Strictly speaking, traps aren't normally sent to an SNMP agent. These tend to be "notification generators" rather than "notification receivers". It's possible for an agent to receive traps as well, but it's relatively unusual. This is repeated in the next paragraph as well. p3, para 4: "Even an OpenSource NMS is now available" There's actually been an OpenSource NMS (tkined) available for almost ten years. It may not have the same polished appearance as OpenNMS or some of the commercial offerings, but it predates most of these by quite some time. p3 typos: para 1, line 2: "you're" para 1, line 5: "OIDs" para 2, line 2: "..that *sends* an SNMP.." para 2, line 2/3: "..looking *for* some value.." 1.2 Three Flavors of SNMP p4, para 2: "SNMPv2 ... had no message definition" This is somewhat misleading. SNMPv2 *did* define request structures (PDUs in SNMP terminology) - with Trap2/Inform being additions to SNMPv1. It was only the administrative stuff that was missing. Your discussion of types isn't quite right either. Counter32, Gauge32 and UInteger32 weren't really new - just renamed and more clearly described. And BIT STRING is not part of SMIv1 or SMIv2 (though it is part of ASN.1). You're probably thinking of BITS, which *was* added to SMIv2. It's not particularly clear what you mean by "enhancements to OID tables", though I presume you mean the GETBULK request. SET support wasn't really altered - SNMPv2 just added better error reporting. A more significant difference (that you don't seem to mention) would be the use of exceptions in GET (and GETNEXT) requests - this allows "partial" results to be returned. p4, para 3: "ASN.1 BER" These are actually two separate standards - BER is used to encode ASN.1, but they're not the same thing. SMIv2 and ASN.1 are probably more closely linked, although you refer to them separately later in this paragraph. p4 typos: para 4, line 1: "However" (capital H) 1.3 What we won't discuss p4, para 1: The other thing that isn't covered at all in this document is the handling of MIB tables. I can understand why you might omit covering this, but it's definitely important to mention it here. Some of your discussion of instance subidentifiers later is a bit confusing, and could be made clearer if you state that you'll only be working with scalar objects. (However you want to phrase that). p4, para 2: "that's referring to applications..." What is? You actually mean asynchronous applications, but it's not immediately clear from the text. I'd also question whether GUIs are an example of the asynchronous (SNMP) interface - they're more an example of something that would need to *use* this approach. Threads and Forks aren't the same as the asynchronous interface either - they're almost alternatives to it. p4 typos: para 2, line 2: "that's" 2.1 OIDs p5, para 1: I've been working with SNMP for ten years now, and I can't recall ever coming across the term "relevant" used in this way. Where have you found it used? p5, para 3: There are plenty of OIDs that don't fall under the 'private' subtree (and hence don't start .1.3.6.1.4) - all "standard" MIB objects, for instance. But everything that comes in this tree will *always* be under the "enterprises(1)" subtree. The leading dot to indicate a fully-qualified OID is actually a Net-SNMP convention, and it's perfectly valid to refer to "iso.org...." without this leading dot. (And strictly speaking, the leading dot form probably isn't actually legal!) p5, para 5: Similarly, the "relative" form is also a Net-SNMP convention, and isn't quite as simple as you make out. It's primarily rooted at .iso(1).org(3).dod(6).mgmt(2).mib-2(1), and the .iso(1).org(3).dod(6).private(4) form is more of an add-on. p6, para 2: On the other hand, the "MIB::key" syntax *is* standard. Or rather, the syntax "MIB.key" is - the :: form is not strictly valid, but is widely accepted Your description of "multiple instances" and "instance value" is not particularly clear. In particular, it's probably worth mentioning that .0 is used for all scalar objects (where there is only one instance) p6 typos: para 1, line 2: drop the leading '.' 2.2 MIBs p6, example: You'd probably do better to import the standard symbols from SNMPv2-SMI and SNMPv2-TC (i.e. define MIBs in SMIv2) wherever possible. p6 typos: para 1, line 3: "you're" para 2, line 1: "Let's" para 4, line 3/4: drop the leading dots p7, para 4: You describe building up the OID of 'upsBasicOutputStatus' by walking back through the ancestors of this definitions. But none of these ancestral definitions are listed, so it's not actually particularly clear what's happening. The last line talks about .0 indicating the first instance of the key. It would be more accurate to say that it indicates the *only* instance of this key (assuming it's not part of a p8 typos: para 2, line 1: "what's" para 2, line 7/8: "you're" (both times) 2.3 OID Data Types p8: I'm not sure how true it is to say that Octet String is typically limited to 255 characters- at least not without mentioning some of the standard Textual Conventions that define this. It doesn't make much sense to refer to Bit String (or BITS) as an "unsigned" datatype, given that it's a string, rather than numeric. The format used for representing maximum values is different for TimeTicks when compared with the other types. Opaque *is* still used, though not much (and its use is discouraged). It's how we support floating point values, for example. p9, para 1: The meaning of "otherwise disregard it" is unclear. I presume you mean instructing the tools not to display the type string, but that's not really the same thing. 2.4 MIB-II All of the MIB groups that you refer to in this section have been superceded by equivalent or updated SMIv2 MIBs - which is why the Net-SNMP tools report them using the more modern versions. Also, none of this information lies under .1.3.6.1.4 (contrary to what you say on p5) p10, para 1: It's misleading to say that all this data is required. Each block is required for agents that support that particular MIB (and that particular protocol), but this is something of a tautology. It's perfectly valid for a UDP-only box not to support the TCP group, for example. And the Address Translation group is officially deprecated now. 2.5 Adding MIBs p10, para 1: Referring to ${PREFIX} is strictly accurate, but a little unhelpful for beginners. It would probably be more useful to talk about /usr/local/share/snmp/mibs (as you do in your later examples, and on p13). Renaming MIBs to follow a particular naming convention is purely for the convenience of the administrator - the Net-SNMP tools don't care. They'll use whatever MIB files they find, regardless of name or suffix. p10, para 5: I'm somewhat surprised that '-m ./filename.txt' works. The -m flag is primarily intended to take a list of MIB module names (i.e. "MY_MIB") rather than filenames. But if it works, then OK. p10 typos: para 1, line 4: "MIB's" para 5, line 5: "Net-SNMP mibs/ directory" (see use in para 3) 3 The Net-SNMP CLI p11 typos: para 1, line 3: "you're" and "that's" line 4: "home in", not "hone in" 3.1 Probing a device p11 typos: para 1, line 2: "what's" line 7: needs a comma after "reported" line 1: "what's" p12, para 2: "all OIDs will start from that root [enterprises]" This is not correct - see above. p12, second example The MIB name (PowerNet-MIB) doesn't match the MIB file that you've requested to be loaded (APC-POWERNET.txt). While this is perfectly valid, it's somewhat confusing - particularly since you earlier suggested using the same name for both. p12, last paragraph Walking the agent is certainly useful, but only reports what devices, etc that it knows about at that particular time. If the system or agent configuration changes later, then this might well add new MIB objects that weren't present before. But the saved walk won't know about them. p12 typos: para 2, line 1: "you're" line 3: "what's" para 3, line 1: "Let's" para 6, line 4: "*I* returned" ?? line 1: "what's" 3.2 Polling Individual OIDs p13, para 1: "return [the value to] STDOUT in any form that you wish" This is perhaps a little optimistic! 'snmpget' and friends offer a range of possible output formats, but it's not infinitely flexible! p13, para 4: "we might start probing the wrong OID" Revisions to MIB files are not allowed to change the behaviour of a given OID, or change the OID associated with a given name. So it doesn't matter whether you have the MIB file or not - the data for a given OID/name will be consistent. p13 typos: para 1, line 2: Missing "to" before "STDOUT" example, line 2: Suggest you omit the leading '>' (both here and elsewhere) para 3, line 1: "its" (of it) not "it's" (it is) numeric OID 3.3 Net-SNMP CLI Tool Options p13, para 1: "the community name of the target agent" This is not relevant for SNMPv3 queries, for which there are different "mandatory" options. (And these options, the community string and even the SNMP version can be specified in the $HOME/.snmp/snmp.conf file) p13, para 4: The Net-SNMP library (and hence the tools) don't care about the suffix used for MIB files. They'll work with MY-MIB.txt, MY-MIB.mib, MY-MIB.suffix or even just MY-MIB - it shouldn't make any difference whatsoever. But there *is* a distinction between the name of the file (including suffix) and the name of the MIB (the token before DEFINITIONS). So when anything refers to the MIB without the suffix, it's usually referring to the name of the MIB *module*, and is nothing to do with filename at all. p14 typos: second example, last line: "*has* an Input..." (and again in the output that follows) 4.1 Simply Polling with PERL The name of the language is conventionally written as Perl, not PERL p15, example: If you're requesting a MIB to be loaded using -m, then you don't need to specify individual objects using the syntax MIB::name. Conversely, if you're specify objects using MIB::name, then you don't need the -m option. p15 typos: para 1, line 3: "GETs" (for consistency) para 2, line 1: "Let's" p16 typos: para 2, line 1: "pretty *or* efficient" 4.2 The Net-SNMP Perl Module p16, para 1: Several of the SNMP-related module in CPAN are completely unrelated to the Net-SNMP project, and it's not appropriate for us to describe them as deprecated. It's *only* the "SNMP" module itself that is ours (and *is* deprecated). p16, para 2: The other thing that is important is to use the version of the Perl module that matches the SNMP C library. If these aren't the same, then things may not work correctly. p16, para 3: Perl applications don't typically use "SNMP::getnext()" in that form. They're more likely to use "$session->getnext()" or "$session->get()", calling methods of a particular SNMP::Session variable. p17 typos: para 1, line 1: "its" p18, para 1: Loading "ALL" MIBs relies on the Power-MIB being installed into the appropriate MIB directory (as in fact the earlier examples in this chapter do). This contrasts with the approach used in Chapter 3, where the MIB file was in the current directory. It might be worth mentioning this explicitly - perhaps at the start of the chapter. p18 typos: para 3, line 1: "previous version [singular]" example, line 2: "Serial No" doesn't line up with IP (and you haven't removed the actual serial number, as you do elsewhere) 5 Trap Handlers p19 typos: para 1, line 4: "that's" 5.1 Trap Daemon Configuration p20, para 1: It might be worth mentioning that snmptrapd.conf entries should always use the SMIv2-style NOTIFICATION-TYPE OIDs (or equivalent) - even if the traps actually arrive as SNMPv1 traps. p20 typos: para 1, line 1: "all 4 lines uncommented line" doesn't make sense! para 1, line 4: "it is *wise*, and "trap's" 5.2 Simple Trap Handler p20, para 1: Perl, not PERL p20, para 2: This could be mis-read as implying that the snmptrapd.conf arguments will be passed via STDIN (rather than as command-line options). p20, para 3: VARBIND and VarList are not quite the same thing - a VarList is made up of one or more VarBinds. p21, example: This output shows very clearly that traps are *always* passed to the traphandler script in SNMPv2 trap format, even if they actually arrived as an SNMPv1 trap. This is probably worth mentioning somewhere. 5.3 Starting the Trap Daemon p21, example: Your code for starting the trap daemon includes an option (-n) that you haven't mentioned at all, and which affects the behaviour that you did mention earlier (passing the hostname to the script). Either mention the option here, or drop it from the example. I'd also suggest reducing the amount of indentation, so that the trapd start line doesn't race off to the edge of the page. 6 Net-SNMP C API p23, para 1: Perl, not PERL p23, para 2: This talks about "several aspects" and "these aspects" (both plural), but the only new aspect that you actually mention is "namely PDUs" (a single aspect). Either list some other new aspects, or make everything singular. [Yes, I know - I'm being incredibly picky! But both my parents are arts graduates, so I was indoctrinated at a very early age and this sort of inconsistency grates something horrible! :-) ] 6.1 SNMP Internals p23, bullet 4: PDU stands for *Protocol* Data Unit (and again on p24, para 3) bullet 8: Free the *response* PDU The request PDU is freed automatically (as long as the request succeeds) p24, para 2: The system MIBs are actually loaded when the library is initialised, rather than when the session is created. (Although the session creation may well be the call that triggers this, depending on what else happened before). "[using] a MIB that isn't installed" is a bit unclear. I think you mean installing a MIB in order to use it, though I'm not sure how removing a MIB enters into things. p24, para 3: A PDU isn't actually just a fancy name for a packet. There *is* a difference between an SNMP request PDU, and an SNMP message (i.e. the packet as commonly understood). The message comprises the version and admin information, together with the PDU itself. So the PDU proper doesn't actually include the version or community string. The discussion of how many PDUs are needed is a bit misleading. The fundamental point is that a single PDU can only handle one *type* of request at a time. So if you have a single OID that you need to both read from and write to, then this will inherently involve two separate requests (although you could re-use the same data structure for the second request). If you need to read two or more OIDs, or write to two or more OIDs, these just involve a single type of request, so all the OIDs can be packed into the one PDU request. (Or they could be sent individually, which is then exactly the same situation as the read/write example). You don't actually need to "read the OID from the MIB" before adding it to the PDU. What 'read_objid()' does is convert from the textual name into the numeric OID (using the MIB). If you know what the numeric form of the OID is, you can add it directly to the PDU without needing to look at the MIB at all. p25, structure It would be sensible to use the current Net-SNMP naming conventions, rather than the old UCD-SNMP style. So the name of the PDU structure would actually be "netsnmp_pdu" (and the capitalisation of "snmp_PDU" just before is wrong anyway). p25, para 4: The 'reqid' value is provided automatically - the programmer doesn't need to bother filling this in. p25 typos: para 4, line 4: "you're" para 5, line 5: "a break capture" ? p25/26, example: The indentation and spacing of the Ethereal header doesn't match that on the previous page (which looked somewhat clearer). p26, para 1: If you're only showing two OIDs, why mention that you originally sent eight? Why not lie and say you sent two all along? No-one will know! p26, para 2: This paragraph is not at all clear - is this structure's use of a list meant to be obvious or not? ('Cos that's all it is - a linked list of varbinds) p26, structure: You can safely omit the last five fields - they're internal stuff. The only important fields are the name/type/value triplet (including lengths), and the 'next' pointer for the linked list. p27 typos: para 1, line 1: "it's" para 2, line 3: "that's" para 3, line 1: "let's" [Sorry to be so picky - but I'm very conscious of the proper (and improper) use of the apostrophe. I don't know whether you've come across Lynn Truss' book "Eats, Shoots & Leaves", but that's the sort of person I am :-) ] 6.3 Simple Example p27 typos: para 1, line 4: "and *receives* the response" p28, example code: Indentation is wrong on lines 1-2 (usage error handling), lines 6-9 (configuring the session settings), lines 15/17 (adding varbinds) and 20 (printing the results) p28, output This uses a new approach for hiding the serial number (cf p16) p29, para 3: While strictly speakeing, it is perfectly correct that the PDU type is defined as a "macro", in practise it's really just a named constant. It might be simpler to refer to it as such. Once again, 'read_objid()' simply converts from a MIB object name to the numeric form - it's not really reading the OID from the MIB. It's probably not true to say that this is typically wrapped in a loop. Many SNMP application may well work with specific MIB objects, in which case they would simply list them in order (exactly as here). Always assuming that they didn't hardwire the numeric OIDs in the first place. Wrapping "read_objid()/snmp_add_null_var()" within a loop is only necessary for applications that work with arbitrary OIDs supplied by the user (such as 'snmpget' and friends) p29, para 6: The PDU used for the request will be freed automatically if the request succeeds. It's only the response PDU that needs to be freed by the programmer. Of course, if sending the request fails, there won't be a response PDU to free, but the request PDU will contain information about the failure, and this PDU *will* need to be freed. p29 typos: para 1, line 3: "of *the* agent...." 6.4 Closing Thoughts p29 typos: para 1, line 7: "vendor's" [Trust Shield to end off with yet another missing apostrophe!!]