\documentclass{ictlab}
\errorcontextlines=99

\RCS $Revision: 1.17 $

\usepackage{verbatim,key,alltt,subfigure}
\usepackage[hang,bf,nooneline]{caption2}
\ifx\pdftexversion\undefined \else
  \usepackage[pdfpagemode=None,pdfauthor={Nick Urbanik}]{hyperref}
\fi

\newcommand*{\labTitle}{SNMP Agent, the Set Operation, Traps and
  Notifications}%
\providecommand*{\SNMP}{\acro{SNMP}\xspace}
\providecommand*{\MIB}{\acro{MIB}\xspace}
\providecommand*{\ID}{\acro{ID}\xspace}
\providecommand*{\OID}{\acro{OID}\xspace}
\providecommand*{\FAQ}{\acro{FAQ}\xspace}
\providecommand*{\EGP}{\acro{EGP}\xspace}
\providecommand*{\RPM}{\acro{RPM}\xspace}
\providecommand*{\VACM}{\acro{VACM}\xspace}

\renewcommand{\floatpagefraction}{0.75} % default is .5, to increase
% density.
\renewcommand*{\bottomfraction}{0.6} % default is 0.3
\renewcommand*{\topfraction}{0.85} % default is 0.7
\renewcommand*{\textfraction}{0.1} % default is 0.2


\begin{document}

\tableofcontents
% \Large
\section{Background}
Before you do this exercise, you will need a Linux installation on
your hard disk.  To see how to do this, refer to the document
\url{http://nicku.org/snm/lab/install-linux/install-linux.pdf}.
You will then need to configure \texttt{sudo} as described in
\url{http://nicku.org/ossi/lab/sudo/sudo.pdf}.

You then need to configure your \SNMP agent to allow
\texttt{set-request} and \texttt{get-request} operations as described
below.  For this exercise, you will set a simple \emph{community
  string} for read and another for read-write operations.  The agent
is called \texttt{snmpd}.  The configuration for the agent is in the
file \texttt{/etc\allowbreak/snmp\allowbreak/snmpd.conf}.

\subsection{Traps and Inform Requests}
\label{sec:traps-and-notifications}
\begin{figure}[htb]
  \centering%
  \mbox{%
    \subfigure[Traps]%
    {\label{sbf:trap}\includegraphics[height=0.2\linewidth]{trap}}%
    \qquad%
    \subfigure[Notification]%
    {\label{sbf:inform}\includegraphics[height=0.2\linewidth]{inform}}
  }%
  \caption{Traps get no response, while an \SNMP{}v2 inform requires a
    response.  The agent may resend the inform-request after a timeout
    period during which it gets no response.}
  \label{fig:traps-and-notifications}
\end{figure}

All versions of \SNMP support a mechanism called a \emph{trap} or
\emph{inform request}.  A \emph{trap} or \emph{inform request} is like
an interrupt from the agent to the manager.  There is no response to a
trap, as seen in figure~\vref{sbf:trap}, whereas inform requests have
responses, as shown in figure~\ref{sbf:inform}.  A
trap usually indicates something is wrong, allowing the manager
software to take actions such as flag the problem with a red symbol,
and perhaps send email and perhaps a short message to the management
team.

The Net-\SNMP tools provide the \texttt{snmptrap} command to send
traps and notifications, and the \texttt{snmptrapd} program to receive
them.


\subsection{SNMPv1 traps}
\label{sec:snmpv1-traps}

Traps in \SNMP version 1 come with seven ``generic traps'' as shown in
table~\vref{tab:generic-traps}.

\begin{table}[htb]
  \begin{tabularx}{\linewidth}[t]{@{}>{\ttfamily}lX@{}}
    \toprule%
    \textnormal{\textbf{Generic trap name}}& \\[-0.5ex]
      \textnormal{\textbf{and number}} & \textbf{Definition}\\
    \midrule%
    coldStart(0) & Shows the agent has been restarted.\\
    warmStart(1) & Indicates that the agent has reinitialised itself.
    None of the management variables have been reset.\\
    linkDown(2) & Sent when an interface on the device has gone down.
    The first variable binding indicates which interface went down.\\
    linkUp(3) & Sent when an interface on the device comes back up.
    The first variable binding indicates which interface came up.\\
    authenticationFailure(4) & Indicates someone used the wrong
    community string to access your agent.  Useful to detect if
    someone is attacking your device using \SNMP.\\
    egpNeighborLoss(5) & Indicates that an \emph{Exterior Gateway
      Protocol} (\EGP) neighbour has gone down.\\
    enterpriseSpecific(6) & Indicates that the trap is enterprise
    specific.  Devices from vendors often come with their own \SNMP
    traps under the vendor's branch under the private-enterprise node
    of the \MIB tree.  To process this, the \NMS needs to decode the
    trap number from the \SNMP message.

    You can implement your own traps.  See the example below, where a
    trap \MIB module defines a trap.\\
    \bottomrule
  \end{tabularx}
  \caption{Generic traps in \SNMP version 1.}
  \label{tab:generic-traps}
\end{table}
You can define your own \MIB for your own specific traps.  See the
exercises in section~\vref{sec:traps-exercises}.


\subsection{Using \texttt{snmptrap} to send traps}
\label{sec:snmptrap}

The syntax of the program \texttt{snmptrap} for sending \SNMP{}\,v1 traps is:

\begin{alltt}
$ \textbf{snmptrap -v 1 -c \meta{community-string} \meta{hostname} \meta{enterprise-oid} \meta{agent} \bs
\meta{generic-trap} \meta{specific-trap} \meta{uptime} \textmd{[}\meta{OID} \meta{type} \meta{value}\textmd{]}\ldots}
\end{alltt}%$

\begin{table}[htb]
  \begin{tabularx}{\linewidth}{@{}lX@{}}
    \toprule%
    \textbf{Argument} & \textbf{Meaning}\\
    \midrule%
    \meta{hostname} & the hostname of the manager to which you are
    sending the trap.\\
    \meta{enterprise-oid} & the \OID under which a number of different
    enterprise traps may be defined.  In the example below, this is
    \texttt{TRAP-TEST-MIB::demotraps}.\\
    \meta{agent} & the hostname or \IP address of the agent.  If you
    leave this as \texttt{""}, then it will be set to the address of
    the current machine.  This may seem pointless, but it is important
    when you use a
    proxy.\\
    \meta{generic-trap} & the number from
    table~\vref{tab:generic-traps},
    which is in the range 0\ldots6. \\
    \meta{specific-trap} & the number of the trap defined under the
    \MIB object \meta{enterprise-oid}.  In the example below, this is
    17,
    corresponding to \texttt{TRAP-TEST-MIB::demo-trap}. \\
    \meta{uptime} & normally an empty string; that means use the local
    value of \texttt{sysUpTime} on this agent.\\
    \meta{OID} & there may be one or more variable values sent with
    the trap to indicate what is happening.  You provide them in a
    group of \meta{OID} \meta{type} \meta{value}\\
    \meta{type} & The data type of the value sent.  Usually \texttt{i}
    for integer, or \texttt{s} for string.  \texttt{man snmptrap} for
    all the types.\\
    \meta{value} & the value of the variable that is sent in the trap.\\
    \bottomrule
  \end{tabularx}
  \caption{The required arguments for an \SNMP{}v1 trap with the
    format: \texttt{snmptrap -v 1 -c \meta{community-string}
      \meta{hostname} \meta{enterprise-oid} \meta{agent} 
      \meta{generic-trap} \meta{specific-trap} \meta{uptime}
      {[{\meta{OID} \meta{type} \meta{value}}]}\ldots}}
  \label{tab:snmpv1-arguments}
\end{table}

\subsection{SNMPv2c Notifications}
\label{sec:snmpv2c-notifications}

In \SNMP{}v2c and v3, the agent sends \emph{notifications}.
Notification is a macro which sends either a trap or an inform
request.  An inform request is like a trap with an acknowledgment.  A
trap is simpler; it has no generic numbers, specific numbers or
enterprise \OID{}s.  As with \SNMP{}v1 traps, you will use \texttt{''}
to indicate the current system uptime.

The syntax for generating an \SNMP{}v2 notification is
\begin{alltt}
$ \textbf{snmptrap -v 2c -c \meta{community-string} \meta{hostname} \meta{uptime} \meta{trapOID} \bs
\textmd{[}\meta{OID} \meta{type} \meta{value}\textmd{]}\ldots}
\end{alltt}%$

The meaning of each argument is the same as for \SNMP{}v1 traps,
except for the \meta{trapOID}, which is the \OID of a complete \MIB
object which must be defined for the notification.

\section{Procedure}

\subsection{Installing and Configuring the Agent}
\label{sec:Configuring the Agent}

I took the \texttt{net-snmp} source \RPM software package from Fedora
Core 1 and compiled it on Red Hat 9.  I did this because it provides
better support for Perl \SNMP programming.  We will install the
resulting binary software packages from an \NFS directory on our server.

\begin{enumerate}
\item Change to the network directory:
\begin{alltt}
$ \textbf{cd /home/nfs/snmp}    
\end{alltt}%$

\item Now install the software packages:
\begin{alltt}
$ \textbf{sudo rpm -Uhv net-snmp-*5.0.9-2.i386.rpm}
\end{alltt}%$
\begin{explanation}
  Note the asterisk `\texttt{*}'.  I suggest press the \key{Tab} key
  to complete the file name, then add the asterisk afterwards, to
  reduce typing mistakes.
\end{explanation}
%% \item Verify that the agent is installed:
%% \begin{alltt}
%% $ \textbf{rpm -qa | grep net-snmp}
%% net-snmp-devel-5.0.6-17
%% net-snmp-5.0.6-17
%% net-snmp-utils-5.0.6-17
%% \end{alltt}%$
%%   \begin{explanation}
%%     See the note further down about the \RPM package manager.  Here we
%%     are listing all the software packages installed on the system, and
%%     just looking for those with the string ``\texttt{net-snmp}'' in
%%     the name.
%%   \end{explanation}

%%   If not, then install it like this:
%%   \begin{enumerate}

%%   \item Use \texttt{yum}:
%% \begin{alltt}
%% $ \textbf{sudo yum install net-snmp\bs*}
%% \end{alltt}%$
%% %%   \item mount the network drive from
%% %%     \texttt{ictlab\allowbreak.tyict\allowbreak.vtc\allowbreak.edu\allowbreak.hk:\allowbreak/var\allowbreak/ftp\allowbreak/pub}
%% %%     on some convenient directory:
%% %% \begin{alltt}
%% %% $ \textbf{sudo mkdir /mnt/nfs}
%% %% $ \textbf{sudo mount nicku.org:/var/ftp/pub /mnt/nfs}
%% %% \end{alltt}


%% \item OR if \texttt{yum} is not set up properly on your machine,
%%   install them manually:
%%   \begin{enumerate}
%%   \item Change to directory containing the software:
%% \begin{alltt}
%% $ \textbf{cd /home/nfs/rh-9.0-updated/RedHat/RPMS}
%% \end{alltt}%$
  
%% \item \dots and install the software.
%%   \begin{enumerate}
%%   \item If no packages are installed, then do this:
%% \begin{alltt}
%% $ \textbf{sudo rpm -Uhv net-snmp-*.rpm}
%% \end{alltt}%$
%% \item Otherwise install only the ones that are missing.
%% \end{enumerate}
%% \end{enumerate}
%% \end{enumerate}

\item Edit the configuration for the \SNMP agent:
\begin{alltt}
$ \textbf{xhost +localhost}
$ \textbf{sudo -v}
$ \textbf{sudo emacs /etc/snmp/snmpd.conf &}
\end{alltt}%$
  \begin{explanation}
    The first line allows users other than your own account (such as
    the user root) to display graphical objects on your local X server.
    
    The second line starts a new five-minute password free period for
    \texttt{sudo}.  If the five-minute period has expired, then the
    editor cannot start in the background; \texttt{sudo} will wait for
    you to bring it to the foreground by typing \texttt{fg}, so that
    you can enter your password.  Typing \texttt{sudo -v} simply
    avoids this inconvenience.
  \end{explanation}
%% \item Comment out the section on \texttt{Access Control} by selecting
%%   it with your mouse, and then press
%%   \key{Alt-x}\allowbreak\,\texttt{comment-region}, or go through and
%%   comment each line out by hand.  Note that
%%   \key{Alt-x}\allowbreak\,\texttt{comment-region} will work if you are
%%   logged into your \LDAP account, where you have my nice
%%   \texttt{.emacs} macro file.
%%   \begin{explanation}
%%     Note that this is a large section of the configuration file: there
%%     are about five lines in mine that start with options
%%     \texttt{com2sec}, \texttt{group}, \texttt{view} and
%%     \texttt{access}.  These need to be commented out, since they
%%     impose too tight an access control for our exercises here.
%%   \end{explanation}
% ####
% # First, map the community name "public" into a "security name"

% #       sec.name  source          community
% # com2sec notConfigUser  default       public

% # ####
% # # Second, map the security name into a group name:

% # #       groupName      securityModel securityName
% # group   notConfigGroup v1           notConfigUser
% # group   notConfigGroup v2c           notConfigUser

% # ####
% # # Third, create a view for us to let the group have rights to:

% # #       name           incl/excl     subtree         mask(optional)
% # view    systemview     included      system

% # ####
% # # Finally, grant the group read-only access to the systemview view.

% # #       group          context sec.model sec.level prefix read   write  notif
% # access  notConfigGroup ""      any       noauth    exact  systemview none none

\item Configure two community strings in the \texttt{snmpd.conf}
  file, as in the following patch.\label{ste:community-strings}  Note
  that we are using \VACM commands here; we could just use
  \texttt{rocommunity} and \texttt{rwcommunity} instead (see
  \texttt{man snmpd.conf}), but we are
  learning about \VACM.
{\footnotesize
\begin{verbatim}
--- snmpd.conf~ 2003-11-28 16:25:40.000000000 +0800
+++ snmpd.conf  2003-12-01 11:47:49.000000000 +0800
@@ -39,13 +39,16 @@
 
 #       sec.name  source          community
 com2sec notConfigUser  default       public
+com2sec RWUser         default       private
 
 ####
 # Second, map the security name into a group name:
 
 #       groupName      securityModel securityName
-group   notConfigGroup v1           notConfigUser
+group   notConfigGroup v1            notConfigUser
 group   notConfigGroup v2c           notConfigUser
+group   RWGroup        v1            RWUser
+group   RWGroup        v2c           RWUser
 
 ####
 # Third, create a view for us to let the group have rights to:
@@ -54,12 +57,15 @@
 #       name           incl/excl     subtree         mask(optional)
 view    systemview    included   .1.3.6.1.2.1.1
 view    systemview    included   .1.3.6.1.2.1.25.1.1
+view    all           included   .1
 
 ####
 # Finally, grant the group read-only access to the systemview view.
 
 #       group          context sec.model sec.level prefix read   write  notif
-access  notConfigGroup ""      any       noauth    exact  systemview none none
+#access  notConfigGroup ""      any       noauth    exact  systemview none none
+access  notConfigGroup ""      any       noauth    exact  all none none
+access  RWGroup        ""      any       noauth    exact  all all all
 
 # -----------------------------------------------------------------------------
 
\end{verbatim}%
}
  \begin{explanation}
    You can see all the options that the agent can understand in its
    configuration file \texttt{snmpd.conf} by typing
    \texttt{snmpd~-H}, and of course, from the man page: \texttt{man
      snmpd.conf}.
    
    Another good source of information about the Net-\SNMP tools is
    the Net-\SNMP \FAQ:
    \url{http://net-snmp.sourceforge.net/FAQ.html}, and also the
    Net-\SNMP tutorials:
    \url{http://net-snmp.sourceforge.net/tutorial/}.

    Note that ``in real life,'' these passwords are
    sensitive, and should be selected as you would any other password.
  \end{explanation}

\item Start the agent:
\begin{alltt}
$ \textbf{sudo /sbin/service snmpd start}
\end{alltt}%$

\item Enable the agent to always start when the computer boots:
\begin{alltt}
$ \textbf{sudo /sbin/chkconfig snmpd on}
$ \textbf{/sbin/chkconfig snmpd --list}
\end{alltt}
  \begin{explanation}
    The first command ensures that the next time a computer boots on
    your hard disk, it will start the agent \texttt{snmpd} whenever it
    moves into runlevels 3, 4 or 5.

    The second command lists which runlevels \texttt{snmpd} will start
    at, to confirm to yourself that the previous command worked.

    Note: you may wish to add the directories \texttt{/sbin} and
    \texttt{/usr/sbin} to your \texttt{PATH} in your login script,
    $\sim$\texttt{/.bash\_profile}.  The line you would want to add
    is:
\begin{verbatim}
export PATH=$PATH:/sbin:/usr/sbin
\end{verbatim}%$
  \end{explanation}

\item Note that any time you change the configuration for the agent
  (by editing \texttt{/etc\allowbreak/snmp\allowbreak/snmpd.conf}),
  you will need to restart the agent to get it to read the new
  configuration with:
\begin{alltt}
$ \textbf{sudo /sbin/service snmpd restart}
\end{alltt}%$
\end{enumerate}


\subsection{The MIB Files}
\label{sec:The MIB Files}

\begin{enumerate}
\item Identify the list of \MIB files installed on your computer:
\begin{alltt}
$ \textbf{rpm -ql net-snmp | grep mibs}
\end{alltt}%$
  \begin{explanation}
    The \acro{RPM} package manager manages software packages on your
    computer.  It maintains a database of all the software packages
    installed, all the files within each package, and checksums on
    each file, as well as plenty of other information that you can
    query.  For more about this, read the chapter on \RPM in the Red
    Hat Reference Guide (download from the Red Hat web site---it's a
    really well-written manual, worth reading).

    The command \texttt{rpm -ql net-snmp} is a \textbf{q}uery to
    \textbf{l}ist the files in the \texttt{net-snmp} package.  We are
    just \texttt{grep}ping here for the \MIB files.
  \end{explanation}
\item Examine the file \texttt{SNMPv2-MIB.txt}.
  \begin{explanation}
  \item This is one of the \MIB files on your computer.  They are text
    files, written using Abstract Syntax Notation One (\ASN.1).  The
    \MIB files are like the schema for a database: they determine what
    type of data each \MIB variable can carry, and provide a name and
    \OID for each \MIB variable (managed object).  They also show the
    exact location of each \MIB variable in the \MIB tree.
  \end{explanation}
  
\item Identify some \MIB objects that have a \texttt{MAX-ACCESS} of
  \texttt{read-write}.  These are variables that you can change with a
  \texttt{set-request} \SNMP operation.
  \begin{explanation}
    Note that the manual page for the agent configuration file,
    \texttt{snmpd.conf}, shows that if
    \texttt{/etc\allowbreak/snmp\allowbreak/snmpd.conf} has a value
    for \texttt{syslocation}, \texttt{syscontact} or \texttt{sysname},
    then the \MIB variables \texttt{sysLocation}, \texttt{sysContact}
    and \texttt{sysName} respectively will become read only, so only
    try to set these \MIB variables if you comment out the
    corresponding value in
    \texttt{/etc\allowbreak/snmp\allowbreak/snmpd.conf}.
  \end{explanation}
\end{enumerate}

\subsection{Setting Managed Objects}
\label{sec:Setting Managed Objects}

\begin{enumerate}
\item Identify some managed objects that you can set.

\item Read their original values with \texttt{snmpgetnext}.

\item Change their value with \texttt{snmpset}.
  \begin{explanation}
    You can refer to the man page for \texttt{snmpset}.  There is also
    a simple tutorial on \texttt{snmpset} at
    \url{http://net-snmp.sourceforge.net/tutorial-5/commands/snmpset.html}.
  \end{explanation}

\item You can use \texttt{snmpset} like this:
\begin{alltt}
$ \textbf{snmpset -v 2c -c \meta{rw community string} \meta{hostname} \bs
\meta{OID} \meta{type} \meta{value} \textmd{[}\meta{OID} \meta{type} \meta{value}\textmd{]}\ldots}
\end{alltt}%$
  \begin{explanation}
    Just in case you are wondering what the value of \meta{rw
    community string} might be, you set it in your agent back in
    step~\vref{ste:community-strings}.  The value of \meta{type} is
    shown on the \texttt{snmpset} manual page.  It is a single letter,
    such as \texttt{s} for string, or \texttt{i} for integer.
  \end{explanation}

\item Verify that the value has or has not changed.  Note that the
  \texttt{SYNTAX} determines that type of data that you may put into
  that managed object.  The syntax values are what we have discussed
  in the lectures.
\end{enumerate}


\subsection{Sending Traps}
\label{sec:Traps}

Now read the Net-SNMP tutorial on traps at
\url{http://net-snmp.sourceforge.net/tutorial-5/commands/snmptrap.html}.
Using this as a guide, working with a partner if possible, send your
partner a trap using \texttt{snmptrap}, and also receive a trap from
your partner using \texttt{snmptrapd}.  If you have no partner
available, then you can send and receive the trap on the same machine.


\subsubsection{Exercises with Traps and Notifications}
\label{sec:traps-exercises}

We begin by installing two \MIB files, one for an enterprise \OID for
an \SNMP{}v1 trap, and another for a notification \MIB object for an
\SNMP{}v2c notification.  We install the \MIB files as described in
the Net-\SNMP \FAQ at
\url{http://net-snmp.sourceforge.net/FAQ.html#How_do_I_add_a_MIB_}.
\begin{enumerate}
\item Download the two \MIB files from the subject web site, at
  \url{http://nicku.org/snm/lab/snmp-set-trap/TRAP-TEST-MIB.txt}
  and
  \url{http://nicku.org/snm/lab/snmp-set-trap/NOTIFICATION-TEST-MIB.txt}.
  These are from the Net-\SNMP Trap tutorial.

  Here is the file \texttt{TRAP-TEST-MIB.txt}
\begin{verbatim}
TRAP-TEST-MIB DEFINITIONS ::= BEGIN
        IMPORTS ucdExperimental FROM Net-SNMP-MIB; 

demotraps OBJECT IDENTIFIER ::= { ucdExperimental 990 }

demo-trap TRAP-TYPE
        STATUS current
        ENTERPRISE demotraps
        VARIABLES { sysLocation }
        DESCRIPTION "This is just a demo"
        ::= 17
END 
\end{verbatim}
  And here is \texttt{NOTIFICATION-TEST-MIB.txt}
\begin{verbatim}
NOTIFICATION-TEST-MIB DEFINITIONS ::= BEGIN
        IMPORTS ucdavis FROM Net-SNMP-MIB;

demonotifs OBJECT IDENTIFIER ::= { ucdavis 991 }

demo-notif NOTIFICATION-TYPE
        STATUS current
        OBJECTS { sysLocation } 
        DESCRIPTION "Just a test notification"
        ::= { demonotifs 17 }

END 
\end{verbatim}

\item Create a directory in your home directory to put these \MIB
  files':
\begin{alltt}
$ \textbf{mkdir -p \(\sim\)/.snmp/mibs}
\end{alltt}%$
Notice the dot in the directory name.

\item Copy the two \MIB files into this directory:
\begin{alltt}
$ \textbf{cp NOTIFICATION-TEST-MIB.txt TRAP-TEST-MIB \(\sim\)/.snmp/mibs}
\end{alltt}%$

\item Now start the \texttt{snmptrapd} service:
\begin{alltt}
$ \textbf{sudo /sbin/service snmptrapd start}
\end{alltt}%$
  and optionally set the service to always start on boot:
\begin{alltt}
$ \textbf{sudo chkconfig snmptrapd on}
\end{alltt}%$
  \ldots then verify that it is on:
\begin{alltt}
$ \textbf{sudo chkconfig snmptrapd --list}
\end{alltt}%$

\item Open another terminal window to watch the main log:
\begin{alltt}
$ \textbf{sudo tail -f /var/log/messages}
\end{alltt}%$

\item Now send some traps while watching the log window.  This first
  example is an \SNMP{}v1 trap.
\begin{alltt}
$ \textbf{snmptrap -c public localhost TRAP-TEST-MIB::demotraps \bs
    '' 6 17 '' SNMPv2-MIB::sysLocation.0 s "Just here"}
\end{alltt}%$
  \begin{explanation}
    See section~\vref{sec:snmptrap} for a more detailed explanation of
    what is happening here.
  \end{explanation}

\item This other example from the tutorial is an \SNMP{}v2c
  notification.
\begin{alltt}
$ \textbf{snmptrap -v 2c -c public localhost '' \bs
    NOTIFICATION-TEST-MIB::demo-notif \bs
    SNMPv2-MIB::sysLocation.0 s "just here"}
\end{alltt}%$
\end{enumerate}
\begin{explanation}
  See section~\vref{sec:snmpv2c-notifications} for an explanation of
  the parameters.

  For the \SNMP version 1 example, we are using the enterprise
  specific trap (see table~\vref{tab:generic-traps}).  The \MIB file
  \texttt{TRAP-TEST-MIB.txt} defines a trap (\texttt{demo-trap}) with
  numeric \OID of \texttt{.1.3.6.1.4.1.2021.13.990.0.17}.  Go ahead:
  try this after installing the two \MIB files:
\begin{alltt}
$ \textbf{snmptranslate -On TRAP-TEST-MIB::demo-trap}
.1.3.6.1.4.1.2021.13.990.0.17
$ \textbf{snmptranslate -On NOTIFICATION-TEST-MIB::demo-notif}
.1.3.6.1.4.1.2021.991.17
\end{alltt}%$
\end{explanation}
\end{document}
