Annotation of 43BSDReno/contrib/isode-beta/doc/snmp/snmp.tex, revision 1.1

1.1     ! root        1: % -*- LaTeX -*-
        !             2: 
        !             3: \input lcustom
        !             4: 
        !             5: \documentstyle[12pt,sfwmac]{article}
        !             6: 
        !             7: \begin{document}
        !             8: 
        !             9: \begin{center}\Large\bf
        !            10: 4BSD/ISODE SNMP Roadmap\\[0.25in]
        !            11: \normalsize\bf Marshall T. Rose\\ Performance Systems International, Inc.%
        !            12: \footnote{This work was partially supported by the U.S.~Defense Advanced
        !            13: Research Projects Agency and the Rome Air Development Center of the U.S.~Air
        !            14: Force Systems Command under contract number F30602--88--C-0016.
        !            15: The content of the information contained herein does not necessarily reflect
        !            16: the position or the policy of the U.S.~Government,
        !            17: and no official endorsement should be inferred.}
        !            18: \end{center}
        !            19: 
        !            20: \section*     {Introduction}
        !            21: You might consider it strange that the ISODE,
        !            22: the openly available implementation of the upper-layers of OSI,
        !            23: includes an implementation of the SNMP.
        !            24: Inasmuch as the continued survival of the Internet hinges on all nodes
        !            25: becoming network manageable,
        !            26: this package was developed using the ISODE and is being freely
        !            27: distributed with releases of Berkeley \unix/.
        !            28: 
        !            29: It must be stressed that this package is not a complete network management
        !            30: system.
        !            31: In particular,
        !            32: whilst \pgm{snmpd} provides a minimal agent functionality,
        !            33: there are no Network Operation Center (NOC) tools~---~\pgm{snmpi} is a
        !            34: debugging aid only.
        !            35: 
        !            36: The purpose of this {\em Roadmap\/} is simply to point out where you can find
        !            37: the various components in the 4BSD/ISODE SNMP package.
        !            38: 
        !            39: \section*     {SNMP Agent}
        !            40: The SNMP agent (the \pgm{snmpd} program) along with the simple initiator
        !            41: (the \pgm{snmpi} program) are in the directory \file{snmp/}.
        !            42: The \file{READ-ME} file in the top-level directory describes how to generate
        !            43: and install these.
        !            44: 
        !            45: \subsection*   {Streamlined Installation}
        !            46: The standard installation directions assume that you wish to install the base
        !            47: ISODE system in addition to the 4BSD/ISODE SNMP package.
        !            48: However,
        !            49: you might wish to install only SNMP software.
        !            50: If this is the case,
        !            51: then follow these steps and ignore the \file{READ-ME} file.
        !            52: \begin{enumerate}
        !            53: \item  Configure the ISODE by selecting the appropriate configuration files
        !            54: in the \file{config/} directory.
        !            55: For example,
        !            56: \begin{quote}\small\begin{verbatim}
        !            57: % cp config/sunos3.h h/config.h
        !            58: % cp config/sunos3.make config/CONFIG.make
        !            59: % cp config/*.local support/
        !            60: \end{verbatim}\end{quote}
        !            61: is all that's required to configure the ISODE on a Sun workstation running
        !            62: SunOS~3.5.
        !            63: 
        !            64: You might wish to consult the {\bf CONFIGURATION\/} section of the
        !            65: \file{READ-ME} file for information on other target platforms.
        !            66: 
        !            67: \item  Generate both the base ISODE system and the SNMP software:
        !            68: \begin{quote}\small\begin{verbatim}
        !            69: % ./make all all-snmp
        !            70: \end{verbatim}\end{quote}
        !            71: 
        !            72: \item  Make sure the ISODE installation directories are created:
        !            73: \begin{quote}\begin{tabular}{|l|l|l|}
        !            74: \hline
        !            75: \multicolumn{1}{|c|}{\bf name}&
        !            76:                \multicolumn{1}{c|}{\bf usually}&
        !            77:                                        \multicolumn{1}{c|}{\bf containing}\\
        !            78: \hline
        !            79: \verb"BINDIR"& \file{/usr/local/bin/}& user programs\\
        !            80: \verb"SBINDIR"&        \file{/usr/etc/}&       administrator programs\\
        !            81: \verb"ETCDIR"& \file{/usr/etc/}&       administrator files\\
        !            82: \verb"INCDIR"& \file{/usr/include/}&   {\em C\/} include files\\
        !            83: \verb"LOGDIR"& \file{/usr/spool/isode/}&
        !            84:                                        log files\\
        !            85: \hline
        !            86: \end{tabular}\end{quote}
        !            87: 
        !            88: \item  Check the \file{/etc/services} file and make sure that these three
        !            89:        lines are present:
        !            90: \begin{quote}\small\begin{verbatim}
        !            91: snmp       161/udp
        !            92: snmp-trap  162/udp
        !            93: smux       199/tcp
        !            94: \end{verbatim}\end{quote}
        !            95: If you are running Sun Yellow Pages,
        !            96: then you will need to modify this file on the YP master and run a command to
        !            97: export the changes to the other YP hosts.
        !            98: 
        !            99: \item  Add these lines to the \file{/etc/rc.local} file:
        !           100: \begin{quote}\small\begin{verbatim}
        !           101: if [ -f $(SBINDIR)snmpd ]; then
        !           102:     $(SBINDIR)snmpd & (echo -n ' snmp') > /dev/console
        !           103: fi
        !           104: if [ -f $(SBINDIR)smux.unixd -a -f $(SBINDIR)snmpd ]; then
        !           105:     $(SBINDIR)smux.unixd &
        !           106:         (echo -n ' smux-unix') > /dev/console
        !           107: fi
        !           108: \end{verbatim}\end{quote}
        !           109: 
        !           110: \item  If you wish to have an SNMP trap sink on your system,
        !           111:        also add these lines to the \file{/etc/rc.local} file:
        !           112: \begin{quote}\small\begin{verbatim}
        !           113: if [ -f $(SBINDIR)snmpt ]; then
        !           114:     $(SBINDIR)snmpt & (echo -n ' snmp-trap') > /dev/console
        !           115: fi
        !           116: \end{verbatim}\end{quote}
        !           117: Usually the trap sink is started before the agent,
        !           118: so if the agent sends any traps initially,
        !           119: then can be audited.
        !           120: 
        !           121: \item  Install a partial ISODE system, as the super-user:
        !           122: \begin{quote}\small\begin{verbatim}
        !           123: # ./make inst-partial
        !           124: \end{verbatim}\end{quote}
        !           125: 
        !           126: \item  Install the 4BSD/ISODE SNMP software:
        !           127: \begin{quote}\small\begin{verbatim}
        !           128: # ./make inst-snmp
        !           129: \end{verbatim}\end{quote}
        !           130: 
        !           131: \item  Configure the SNMP agent by editing the file \file{snmpd.rc} in the
        !           132: \verb"$ETCDIR" directory:
        !           133:     \begin{itemize}
        !           134:     \item      Fill-in the value for \verb"sysContact" and \verb"sysLocation".
        !           135: 
        !           136:     \item      If your site has a management station that listens for traps,
        !           137:                fill-in the information for the trap sink, e.g.,
        !           138: \begin{quote}\small    \begin{verbatim}
        !           139: trap    traps   a.b.c.d
        !           140: \end{verbatim}\end{quote}
        !           141:        where \verb"traps" is the community that traps should be logged under
        !           142:        and \verb"a.b.c.d" is the IP address of the host where a trap sink is
        !           143:        listening on UDP port~162.
        !           144: 
        !           145:     \item      For each of your network interfaces
        !           146:                (as reported by the
        !           147: \begin{quote}\small\begin{verbatim}
        !           148: netstat -i
        !           149: \end{verbatim}\end{quote}
        !           150:                command)
        !           151:                make sure that it is defined in the configuration file with
        !           152:                the appropriate type and speed.
        !           153:                For the vast majority of BSD-derived systems,
        !           154:                the definitions already appear.
        !           155:     \end{itemize}
        !           156: 
        !           157: \item  Finally, start the SNMP agent and SMUX \unix/ daemon.
        !           158: The command from \pgm{CShell} is:
        !           159: \begin{quote}\small\begin{verbatim}
        !           160: # $(SBINDIR)snmpd >& /dev/null
        !           161: # $(SBINDIR)smux.unixd >& /dev/null
        !           162: \end{verbatim}\end{quote}
        !           163: which starts the daemons and directs them to automatically detach.
        !           164: If you are going to run a sink for SNMP traps,
        !           165: then you will need to start that daemon as well:
        !           166: \begin{quote}\small\begin{verbatim}
        !           167: # $(SBINDIR)snmpt >& /dev/null
        !           168: \end{verbatim}\end{quote}
        !           169: \end{enumerate}
        !           170: The agent logs activity to the file \file{snmpd.log} in the ISODE
        !           171: \verb"LOGDIR" directory.
        !           172: 
        !           173: By default,
        !           174: the trap sink will audit all traps to the file \file{snmp.traps} in the
        !           175: ISODE \verb"LOGDIR" directory.
        !           176: The \verb"audit" command in \pgm{snmpi} can be used to examine the file.
        !           177: 
        !           178: \section*     {Exporting MIB Modules}
        !           179: You might wish to modify your existing daemons to export MIB modules for
        !           180: access via the SNMP agent.
        !           181: The SMUX protocol is used for this.
        !           182: The SMUX protocol is defined in the file \file{doc/rfcs/smux.txt}.
        !           183: You should read this document once just to familiarize yourself with the
        !           184: general concepts of SNMP multiplexing.
        !           185: 
        !           186: However,
        !           187: when you instrument your agent to export the MIB,
        !           188: you use the SMUX Applications Programming Interface (SMUX API) which is
        !           189: defined in the file \file{doc/rfcs/smux-api.txt}.
        !           190: This API is fully implemented in the 4BSD/ISODE SNMP software.
        !           191: 
        !           192: The SMUX \unix/ daemon is an example of a program which uses the software.
        !           193: The source for this daemon is in the \file{snmp/} directory.
        !           194: At present,
        !           195: this daemon exports information on the system's mbufs.
        !           196: In the future,
        !           197: it is conceivable that it may make generalized process information available.
        !           198: 
        !           199: \subsection*   {One day}
        !           200: $\ldots$ it would be nice to have MIBs defined to allow management
        !           201: applications to be written which have equivalent functionality to:
        !           202: \begin{quote}\begin{tabular}{l}
        !           203: mailq/mailstats\\
        !           204: lpq\\
        !           205: finger/rwho\\
        !           206: iostat/pstat/vmstat\\
        !           207: named (DNS)\\
        !           208: nntpd (NTP)\\
        !           209: bgpd (BGP)\\
        !           210: nfsstat/rpcinfo
        !           211: \end{tabular}\end{quote}
        !           212: 
        !           213: \section*     {SNMP and gawk}
        !           214: If you are interested in prototyping network management applications,
        !           215: then you might find it interesting to run a version of GNU \pgm{awk}
        !           216: (the \pgm{gawk} program) which is SNMP capable.
        !           217: 
        !           218: The directory \file{snmp/gawk-2.11 contains} the modifications to the GNU
        !           219: \pgm{awk} 2.11~beta release necessary to achieve this.
        !           220: Follow the instructions in the \file{READ-ME-FIRST} file in this directory to
        !           221: install this modified \pgm{gawk}.
        !           222: 
        !           223: \subsection*   {Accessing SNMP variables}
        !           224: The current implementation assumes a read-only view of an SNMP MIB.
        !           225: This means that MIB objects must occur only as {\em rvalues\/} in expressions.
        !           226: 
        !           227: \subsubsection*        {Non-tabular variables}
        !           228: To access an object which does not occur inside a table,
        !           229: simply use the name of that object, e.g.,
        !           230: \begin{quote}\small\begin{verbatim}
        !           231: % gawk 'BEGIN { print sysDescr; }'
        !           232: \end{verbatim}\end{quote}
        !           233: Instead,
        !           234: if you want to supply a special instance identifier,
        !           235: then reference the variable as an array.
        !           236: Hence,
        !           237: an equivalent command is:
        !           238: \begin{quote}\small\begin{verbatim}
        !           239: % gawk 'BEGIN { print sysDescr[0]; }'
        !           240: \end{verbatim}\end{quote}
        !           241: This is less intuitive,
        !           242: but it's your choice.
        !           243: 
        !           244: Of course,
        !           245: you may not be able to retrieve a variable.
        !           246: For example, \verb"sysDescr[1]", according to the MIB,
        !           247: doesn't make much sense.
        !           248: There is a special built-in variable,
        !           249: \verb"DIAGNOSTIC" which returns a textual description of any problem which
        !           250: occurred with the last SNMP operation,
        !           251: hence:
        !           252: \begin{quote}\small\begin{verbatim}
        !           253: % gawk 'BEGIN { print "sysDescr: ", sysDescr, DIAGNOSTIC; }'
        !           254: \end{verbatim}\end{quote}
        !           255: prints either the system description of the agent you are talking to,
        !           256: or a diagnostic,
        !           257: depending on what happened with the SNMP interaction.
        !           258: 
        !           259: \subsubsection*        {Tabular Variables}
        !           260: To retrieve the value of an object occurring in a table,
        !           261: there are also two methods.
        !           262: 
        !           263: First,
        !           264: you can simply put the instance identifier inside an array reference,
        !           265: e.g.,
        !           266: \begin{quote}\small\begin{verbatim}
        !           267: ifDescr[1]
        !           268: \end{verbatim}\end{quote}
        !           269: which is equivalent to an SNMP get operation on the variable
        !           270: \begin{quote}\small\begin{verbatim}
        !           271: ifDescr.1
        !           272: \end{verbatim}\end{quote}
        !           273: or
        !           274: \begin{quote}\small\begin{verbatim}
        !           275: ipRouteNextHop["10.0.0.0"]
        !           276: \end{verbatim}\end{quote}
        !           277: which is equivalent to an SNMP get operation on the variable
        !           278: \begin{quote}\small\begin{verbatim}
        !           279: ipRouteNextHop.10.0.0.0
        !           280: \end{verbatim}\end{quote}
        !           281: This is called the ``subscript notation''.
        !           282: 
        !           283: Note that care should be taken to make sure that the subscript doesn't look
        !           284: like a floating-point number to \pgm{gawk}.
        !           285: These are all the same, valid, references:
        !           286: \begin{quote}\small\begin{verbatim}
        !           287: ipRouteNextHop[10,0,0,0]
        !           288: ipRouteNextHop["10.0.0.0"]
        !           289: \end{verbatim}\end{quote}
        !           290: In contrast,
        !           291: this is a bogus reference:
        !           292: \begin{quote}\small\begin{verbatim}
        !           293: ipRouteNextHop[10.0.0.0]
        !           294: \end{verbatim}\end{quote}
        !           295: 
        !           296: Second,
        !           297: you can traverse the table (referred to as ``walking the tree'').
        !           298: This is done with the \verb"for-in" construct, e.g.,
        !           299: \begin{quote}\small\begin{verbatim}
        !           300: for (i in ipRouteDest) {
        !           301:     printf "route to %s from %s\n",
        !           302:         ipRouteDest, ipRouteNextHop;
        !           303: }
        !           304: \end{verbatim}\end{quote}
        !           305: which says to traverse the table containing the object \verb"ipRouteDest".
        !           306: The for-loop body will be executed once for each row of the table;
        !           307: for each iteration,
        !           308: the control variable will be assigned the value of the instance-identifier for
        !           309: that row ({\bf not\/} the value of the column in that row).
        !           310: This allows you to reference other parts of the MIB using the same
        !           311: instance-identifier, e.g.,
        !           312: \begin{quote}\small\begin{verbatim}
        !           313: for (i in ipRouteDest) {
        !           314:     printf "ipRoutingTable[%s]: to %s from %s\n",
        !           315:         i, ipRouteDest, ipRouteNextHop;
        !           316: }
        !           317: \end{verbatim}\end{quote}
        !           318: 
        !           319: The \verb"for-in" construct retrieves a row of a table using a single powerful
        !           320: SNMP get-next operator.
        !           321: If a particular column is unsupported by the agent,
        !           322: then referencing the corresponding variable will return the empty string.
        !           323: Note that within the for-loop body,
        !           324: repeated references to a column of a table will not result in additional SNMP
        !           325: operations.
        !           326: If, for some reason, you want to force a refresh of the variable's value,
        !           327: use the subscript notation, e.g.,
        !           328: \begin{quote}\small\begin{verbatim}
        !           329: for (i in ipRouteDest) {
        !           330:     printf "route to %s from %s\n",
        !           331:         ipRouteDest, ipRouteNextHop[i];
        !           332: }
        !           333: \end{verbatim}\end{quote}
        !           334: which causes each iteration to use the powerful SNMP get-next operation
        !           335: to bind values to each column in the \verb"ipRoutingTable",
        !           336: and the corresponding instance-identifier is assigned to \verb"i".
        !           337: Then,
        !           338: when the \verb"printf" statement is executed,
        !           339: a separate SNMP get operation will be used to supply a (possibly) new value
        !           340: for \verb"ipRouteNextHop".
        !           341: Usually,
        !           342: you use the subscript notation when you want to look at a variable in another
        !           343: table, e.g.,
        !           344: \begin{quote}\small\begin{verbatim}
        !           345: for (i in ipRouteDest) {
        !           346:     printf "route to %s from %s on %s (interface #%d)\n",
        !           347:         ipRouteDest, ipRouteNextHop,;
        !           348:         ifDescr[ipRouteIfIndex], ipRouteIfIndex;
        !           349: }
        !           350: \end{verbatim}\end{quote}
        !           351: which causes each iteration to perform the powerful SNMP get-next operation
        !           352: being to bind values to each column in the \verb"ipRoutingTable",
        !           353: and the corresponding instance-identifier is assigned to \verb"i".
        !           354: Then,
        !           355: when the \verb"printf" statement is executed,
        !           356: a separate SNMP get operation will be used to supply the corresponding value
        !           357: of \verb"ifDescr".
        !           358: 
        !           359: Of course,
        !           360: there's always the question of dealing with agents which may not support the
        !           361: table or when an error occurs.
        !           362: Usually, the following code fragment is sufficient:
        !           363: \begin{quote}\small\begin{verbatim}
        !           364: didone = 0;
        !           365: for (i in tabularVariable) {
        !           366:     didone = 1;
        !           367: 
        !           368: #   handle one row of the table here...
        !           369: }
        !           370: if (didone == 0) {
        !           371:     if (DIAGNOSTIC) {
        !           372: #       handle table error here...
        !           373:     }
        !           374:     else {
        !           375: #       handle empty table here...
        !           376:     }
        !           377: }
        !           378: else
        !           379:     if (DIAGNOSTIC) {
        !           380: #       handle partial table here...
        !           381:     }
        !           382: \end{verbatim}\end{quote}
        !           383: Finding an empty or partial table is often unimportant,
        !           384: so the boilerplate usually is:
        !           385: \begin{quote}\small\begin{verbatim}
        !           386: didone = 0;
        !           387: for (i in tabularVariable) {
        !           388:     didone = 1;
        !           389: 
        !           390: #   handle one row of the table here...
        !           391: }
        !           392: if (!didone && DIAGNOSTIC)
        !           393:     printf "table: %s\n", DIAGNOSTIC;
        !           394: \end{verbatim}\end{quote}
        !           395: 
        !           396: \subsubsection*        {Non-tabular variables (revisited)}
        !           397: If you are accessing a lot of non-tabular variables sharing a common parent
        !           398: (e.g., within the \verb"system" group),
        !           399: you can use the \verb"for-in" construct to walk this degenerate tree,
        !           400: e.g.,
        !           401: \begin{quote}\small\begin{verbatim}
        !           402: for (i in sysDescr) {
        !           403: #   this for-loop is executed at most once...
        !           404: }
        !           405: \end{verbatim}\end{quote}
        !           406: will cause all the non-tabular variables having the same immediate parent as
        !           407: \verb"sysDescr" to be retrieved in a single SNMP operation,
        !           408: and the corresponding instance-identifier (i.e., \verb"0") is assigned to
        !           409: \verb"i".
        !           410: 
        !           411: This syntax is used only for optimization of network traffic.
        !           412: 
        !           413: \subsubsection*        {Illegal References}
        !           414: If you do not use the subscript notation,
        !           415: then it is illegal to reference a tabular variable outside of a \verb"for-in"
        !           416: loop.
        !           417: This causes a fatal error in a \pgm{gawk} script.
        !           418: 
        !           419: Further,
        !           420: it is illegal to use an SNMP variable as an ``lvalue''.
        !           421: 
        !           422: Finally,
        !           423: non-leaf variables,
        !           424: (e.g., \verb"ifTable") are not recognized by the \pgm{gawk} front-end as being
        !           425: accessible via the SNMP.
        !           426: These are treated as ordinary \pgm{gawk} variables without any SNMP semantics.
        !           427: 
        !           428: \subsection*   {Data typing}
        !           429: The \pgm{gawk} program has two kinds of data types: numbers and strings.
        !           430: When mapping MIB objects to these data types,
        !           431: the following conventions are used: 
        !           432: \[\begin{tabular}{|r|l|l|l|}
        !           433: \hline
        !           434: \multicolumn{1}{|c|}{\bf Syntax}&
        !           435:                \multicolumn{1}{c|}{\bf Type}&
        !           436:                        \multicolumn{1}{c|}{\bf Format}\\
        !           437: \hline
        !           438: INTEGER&               number&         \\
        !           439: OCTET STRING&          string&         \verb|"%02x: ... : %02x"|\\
        !           440: DisplayString&         string&         \\
        !           441: OBJECT IDENTIFIER&     string&         \verb|"%u. ... .%u"|\\
        !           442: NULL&                  string&         \verb|"NULL"|\\
        !           443: IpAddress&             string&         \verb|"a.b.c.d"|\\
        !           444: NetworkAddress&                string&         \verb|"a.b.c.d"|\\
        !           445: Counter&               number&         \\
        !           446: Gauge&                 number&         \\
        !           447: TimeTicks&             number&         \\
        !           448: ClnpAddress&           string&         \verb|"%02x: ... : %02x"|\\
        !           449: \hline
        !           450: \end{tabular}\]
        !           451: 
        !           452: \subsection*   {Modifications to gawk}
        !           453: The functional changes to \pgm{gawk} are quite straight-forward:
        !           454: 
        !           455: \subsubsection*        {Switches}
        !           456: The \switch"s" turns on SNMP debugging to level 1,
        !           457: whilst the \switch"S" turns on SNMP debugging to level 2.
        !           458: 
        !           459: At level~1 debugging and above,
        !           460: exceptional events are reported to the diagnostic output.
        !           461: At level~2 debugging and above,
        !           462: SNMP PDUs are logged to the standard output.
        !           463: For any debugging activity to occur,
        !           464: the \file{snmp.c} module in \pgm{gawk} must be compiled with \verb"-DDEBUG".
        !           465: 
        !           466: \subsubsection*        {Variables}
        !           467: There are a few built-in, read-write variables added:
        !           468: \begin{small}
        !           469: \[\begin{tabular}{|r|l|l|l|}
        !           470: \hline
        !           471: \multicolumn{1}{|c|}{\bf Variable}&
        !           472:                \multicolumn{1}{|c|}{\bf Type}&
        !           473:                        \multicolumn{1}{|c|}{\bf Value of}&
        !           474:                                        \multicolumn{1}{|c|}{\bf Default}\\
        !           475: \hline
        !           476: \smaller AGENT&                string& SNMP agent name or address&     localhost\\
        !           477: \smaller COMMUNITY&    string& SNMP community name&            public\\
        !           478: \smaller DIAGNOSTIC&   string& last thing to go wrong&         \\
        !           479: \smaller ERROR&                number& last SNMP error status&         \\
        !           480: \smaller RETRIES&      number& times to retry SNMP operation&  3\\
        !           481: \smaller TIMEOUT&      number& seconds between retries&        10\\
        !           482: \hline
        !           483: \end{tabular}\]\normalsize
        !           484: The \verb"DIAGNOSTIC" and \verb"ERROR" variables are set after each SNMP
        !           485: operation.
        !           486: If no error occurs,
        !           487: then \verb"DIAGNOSTIC" variable is set to the empty string,
        !           488: and \verb"ERROR" varaible is set to \verb"0".
        !           489: \end{small}
        !           490: 
        !           491: \subsubsection*        {Functions}
        !           492: There are a few built-in functions added:
        !           493: \begin{itemize}
        !           494: \item  The \verb"bitwise_and(i,j)" function returns the bit-wise AND of the
        !           495:        two unsigned long quantities, \verb"i" and \verb"j".
        !           496: 
        !           497: \item  The \verb"bitwise_or(i,j)" function returns the bit-wise OR of the
        !           498:        two unsigned long quantities, \verb"i" and \verb"j".
        !           499: \end{itemize}
        !           500: 
        !           501: \subsection*   {An Example}
        !           502: After installing the SNMP-capable \pgm{gawk},
        !           503: the \file{READ-ME-FIRST} file describes how to install \pgm{s-netstat},
        !           504: a program which provides the functionality of \pgm{netstat} using the SNMP
        !           505: rather than reading \file{/dev/kmem}.
        !           506: This script and associated \pgm{gawk} scripts is an excellent example of how
        !           507: the new \pgm{gawk} can be used to prototype new management applications.
        !           508: 
        !           509: \end{document}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.