The MIMIC Compiler is used for two purposes:
Before compiling a new MIB, you need to import the source file into the MIMIC area.
Here is a sample log. If the last line says "done", the compile was successful, otherwise it did not complete and you need to fix the shown errors.
INFO 06/18.14:41:40 - mimiccom 2.2 #1 (sparc) of Mon Jun 15 18:16:02 EDT 1998
INFO 06/18.14:41:40 - Evaluation license, expires 7/18/1998
INFO 06/18.14:41:40 - loading mib : RFC1213-MIB
INFO 06/18.14:41:48 - done
In case the MIB compilation has errors, you can edit the MIB file.
The easiest way to create a simulation is to use the MIMIC Recorder to record an existing device. If you cannot record a device (e.g., if you don't have one available, or it is under development), then you can create a basic simulation with mib2walk. But, if you want to simulate a device with capabilities beyond the basic simulation that the Recorder outputs, you need to customize it manually as follows.
As detailed below there can be two formats for the simulation file.
mib-name SIMULATION ::=
list-of-object-simulations
where list-of-object-simulations is one or more object simulations of the form
object-name OBJECT-TYPE
SIMULATE simulation-expression
Alternatively, you can create a minimal simulation file from the original MIB file as follows:
To compile a simulation:
Here is a sample log. If the last line says "done", then it was successful, otherwise the compile did not complete and you need to fix the shown errors.
INFO 06/18.14:41:40 - mimiccom 2.2 #1 (sparc) of Mon Jun 15 18:16:02 EDT 1998
INFO 06/18.14:41:40 - Evaluation license, expires 7/18/1998
INFO 06/18.14:41:40 - parsing MIB Extension
INFO 06/18.14:41:40 - loading mib : RFC1213-MIB
INFO 06/18.14:41:48 - done
In case the simulation compilation has errors, you can edit the simulation file.
Once you have created a simulation, you need to create a scenario for it. The scenario defines the MIB object instances and values. A simulation can have multiple scenarios.
The internal data files for a scenario for a particular simulation are in a directory in the data/sim/ subdirectory, under each MIB with the name of the scenario. This directory contains files for each table and MIB object to be simulated.
instance variable value
This determines the value for the specified variable for the specified instance. For example, if you were to edit ifInOctets.var as follows, you would basically be setting the rate of instances 1 and 2 to 10 and 50 (respectively):
1 r 10
2 r 50
The MIMIC MIB extension language is a declarative language based on the C programming language. It specifies a simulation expression to be executed when a particular instance of a MIB object is accessed.
NOTE: The main thing to remember is that MIMIC does not execute simulation expressions unless there is an access to the MIB object.
A simulation takes on the form of a SIMULATE clause for each object in the MIB of the syntax:
SIMULATE {expression}
where expression is an expression in the MIMIC language. A value returned by MIMIC in response to a request for a MIB object instance is effectively a function of the form
value-returned = function (expression, time)
The simulation expression can be embedded into (a copy of) an existing MIB file. Each object definition is augmented with a SIMULATE clause. In this case, the file would contain something like
sysUpTime OBJECT-TYPE
SYNTAX TimeTicks
ACCESS read-only
STATUS mandatory
SIMULATE {expression}
DESCRIPTION
...
Alternatively, a separate file can be created containing just simulation expressions, such as:
sysUpTime OBJECT-TYPE
SIMULATE {expression}
...
Each expression in the MIMIC language returns a value with one of the types in the SNMP Structure of Management Information (SMI) specification:
INTEGER constants can be specified in base 10, 16 and 8.
Syntax:
[1-9][0-9]* for decimal constants
0[0-7] for octal constants
0x[0-9a-fA-F]+ for hexadecimal constants
Examples:
1500
0700
0x700
Octets strings can be defined both in ASCII (enclosed in double quotes), and binary (hex) format.
Examples:
"this is a string"
"\x08 00 2b 12 34 56"
Object identifiers can be specified in dot notation, or by any part of the sequence of sub-identifier names.
Examples:
1.3.1.6.1.2.1
system.sysDescr
enterprises.886
IP addresses need to be specified in dot notation or as 4 hexadecimal bytes.
Examples:
192.9.200.71
\x C0 09 C8 47
MIMIC supports the basic complement of integer arithmetic functions:
MIMIC will do type propagation based on the return value of the SIMULATE expression. For example, if the SIMULATE is done for a Counter64 MIB object, then 64-bit arithmetic is performed automatically, else 32-bit arithmetic is performed.
These functions do explicit typecasts:
Order or evaluation is left-to-right, but nested expressions should be parenthesized, to avoid misunderstandings in operator precedence. Expressions can be concatenated with the ; operator, like the , operator in the C programming language.
This is a set of typed functions that return system-related information:
The conditional operator will allow decisions to be made in your simulation. Its syntax is just like in C: conditional-expression ? true-expression : false-expression The conditional expression is evaluated, and either of the true-expression or false-expression is executed depending on whether the conditional expression evaluates to true or false at this particular time.
Examples:
ifStatus OBJECT-TYPE
SIMULATE { sysuptime () > 8640000 ? down : up }
This simulation expression makes an interface be up for one day, after which it will appear down.
These operation allows indexed access of configurable data in the MIMIC Value Space. It allows run-time configuration of simulations for individual agent instances. The lookup function returns the OCTET-STRING for a given variable for the specified object instance. The signature is
Examples:
This simulation expression returns a system description value directly from
the Value Space:
sysDescr OBJECT-TYPE
SIMULATE { lookup ("v") }
The problem with the above is that a variable does not need to be set in the Value Space. Since it is adaptive, a default value will be returned, but if the lookup function is part of an expression, it will fail. For this reason, you can check the existance of the variable with the exists function, which returns 1 if it exists, 0 otherwise. Those return values can be used in the conditional operator. The signature is
Examples:
This simulation expression returns a default value if not set.
sysDescr OBJECT-TYPE
SIMULATE { exists ("v") ? "not set" : lookup ("v") }
The set function allows modification of value space variables. It sets the specified variable to the specified value, and returns it. The signature is
Examples:
This simulation expression auto-increments a Gauge MIB object
tcpCurrEstab in the range between min and max:
tcpCurrEstab OBJECT-TYPE
SIMULATE { (exists ("_retval") == "0") ? set ( "_retval", lookup ("min")) : ((set ("_retval", (lookup ("_retval") + 1)) > lookup ("max")) ? set ("_retval", lookup ("min")) : lookup ("_retval")) }
If _retval is not set, then it is initialized with min. Else, _retval is incremented, and if larger than max, rolls back to min.
These operations allow access to the global and per-agent Variable Store. This effectively allows even cloned agents (which share Value Space) to individualize values through the per-agent variable store.
Examples:
This simulation expression returns a system description value directly from
the agent store variable "sysDescr":
sysDescr OBJECT-TYPE
SIMULATE { agent_store_get ("sysDescr") }
The problem is that a store variable may not exist, causing the simulation to result in error. This expression checks for existance first, and returns the value from the agent store, else from the value space as in the default simulation.
sysDescr OBJECT-TYPE
SIMULATE { (agent_store_exists ("sysDescr") == 1 ) ? agent_store_get ("sysDescr") : lookup ("v") }
The following group of functions allows flow-based simulation of MIB objects of type Counter:
Examples:
This simulation expression sets the rate of incoming packets to 100 per minute
as a random variable with uniform distribution:
ifInUcastPkts OBJECT-TYPE
SIMULATE { uniform_per_tu (100, 60) }
or more flexibly, to allow run-time configuration of both parameters via
variables r (for rate) and tu (for timeunit):
SIMULATE { uniform_per_tu (lookup ("r"), lookup ("tu")) }
This group of operations is related to MIB tables and the INDEX clause.
Examples:
The following simulation expression creates an interfaces table from 1 to 9, with odd indices.
ifEntry OBJECT-TYPE
SIMULATE { table.range (1, 10, 2) }
The following simulation expression creates an interfaces table that is configured at run-time from an index file. The index file lives in the scenario directory, and has the name ifEntry.tab.
ifEntry OBJECT-TYPE
SIMULATE { table.static }
This simulation expression returns a run-time configurable interface type for all interfaces but the second one, for which it returns the constant ethernet-csmacd.
ifType OBJECT-TYPE
SIMULATE { table.index(1) == 2 ? ethernet-csmacd : lookup ("v") }
If you want to get information about the currently accessed MIB object, you use the operations
This operation implements relationships between MIB object instances.
Examples:
This simulation expression makes the error rate 10 % of the incoming packets:
ifInErrors OBJECT-TYPE
SIMULATE { (value ("ifInUcastPkts") * 10) / 100 }
or, more efficiently:
ifInErrors OBJECT-TYPE
SIMULATE { value ("ifInUcastPkts") / 10 }
or, more flexibly, to allow run-time configuration of the error rate:
SIMULATE { (value ("ifInUcastPkts") * lookup ("error-rate")) / 100 }
This operation simulates trap PDU generation.
This operation causes periodic trap PDUs to be generated for a specific trap. rate and time_unit defined the frequency of the generated traps. The cutoff_time argument specifies a time (in seconds) relative to now at which trap generation is stopped. This allows a precise number of traps to be generated for a precise amount of time. The default simulation expression for traps is
SIMULATE {trap_periodic (lookup "r", lookup "tu", lookup "c")}
which causes the arguments to be looked up in the value space.
MIB variable values to be sent with the generated traps can be stored in the value space and are used by all trap generation functions.
Examples:
For the linkDown or linkUp traps, if you set the
variable ifIndex to a value, that value will be sent with
any of these generated traps.