MIMIC Compiler Guide

  1. Table of Contents
  2. Overview
  3. The MIMIC Compiler is used for two purposes:

    • To import new MIBs into MIMIC. This allows MIMIC to recognize new device types. MIMIC supplies more than 1000 pre-compiled standard and enterprise MIBs for devices from the leading network companies. If the MIB for the device that you are trying to simulate is not included, you can import it into MIMIC by compiling the MIB source file with the Compiler;

    • To compile simulations. Simulations are created by amending the MIB file with the SIMULATE clause.

  4. Compiler Reference
  5. Importing a MIB

    Before compiling a new MIB, you need to import the source file into the MIMIC area.

    1. In MIMICView, use MIB->Import... to invoke the Import MIB dialog. The source file is the file containing the definition of the MIB in ASN.1 syntax following the standard SNMP Structure of Management Information (SMI) specification. All MIB source files known to MIMIC are in the mibs/ subdirectory.

    2. Type the absolute path of the MIB source file that you want to import in the MIB File field, or use the File Browser dialog with the Browse... button. The MIB source file can be in any directory on your system.

    3. To import a standard MIB, leave the enterprise name in the Enterprise field blank. To import an enterprise-specific MIB, type an enterprise name in the Enterprise field. For simplicity, use a single-word, lower-case, name.

    4. If you want to save it as a different name in MIMIC, type the new name in the Save As field.

    5. Pressing the OK button copies the file into the appropriate place in the MIMIC area. From then on the MIB source file is accessible by MIMIC.

    Compiling a MIB

    1. Use MIB->Compile... to pop up the Compile MIB dialog.

    2. Type the enterprise name of the MIB in the Enterprise field and the MIB file name in the MIB File field, or browse with the Browse... button.

    3. Click Cancel to dismiss the dialog, or click OK to begin the compilation in a separate log window.

    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

    Editing a MIB

    In case the MIB compilation has errors, you can edit the MIB file.

    1. Use MIB->Edit... A File Browser dialog is automatically opened.

    2. Select the path to the MIB file.

    3. Click OK to open the built-in MIMIC File Editor. (You can invoke the editor of your choice if you set the MIMIC_EDITOR environment variable prior to starting MIMICView.)

    Creating a Custom Simulation

    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.

    1. Create a subdirectory under the sim/ directory in the MIMIC area. Give the simulation a simple name, such as the ones that are already there.

    2. Create a simulation file for each MIB you intend to simulate in that subdirectory. The simulation file contains the simulation expression for each MIB object.

    As detailed below there can be two formats for the simulation file.

    • SMI with added SIMULATE statements. This consists of the original MIB file with a SIMULATE clause for each MIB object. This is useful when you start with the original MIB file and just edit it to add SIMULATE expressions, but it can become rather lengthy.

    • minimal format. This format deletes the unnecessary clauses for each object definition (SYNTAX, ACCESS, STATUS, DESCRIPTION). Look at the existing simulations for conventions to follow. You can even copy over the files of existing simulations as a starting point. Its simplified syntax is:

      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:

      1. cut the relevant lines from the original MIB files, eg.
        grep OBJECT-TYPE original-MIB-file > simulation-file
      2. edit the simulation-file to add the header line, and add a SIMULATE clause for each object.

    Compiling a Simulation

    To compile a simulation:

    1. Use Simulation->Compile... to invoke the Compile MIB Extensions dialog.

    2. Type the simulation name in the Simulation field.

    3. Type the MIB extensions file name in the MIB Extensions File field, or browse for it by clicking Browse....

    4. Click Cancel to dismiss this dialog.

    5. Press OK to begin the compilation in a separate log window.

    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

    Editing a Simulation

    In case the simulation compilation has errors, you can edit the simulation file.

    1. Use Simulation->Edit.... A File Browser dialog is automatically opened.

    2. Select the path to the simulation file.

    3. Click OK to open the built-in MIMIC File Editor. (You can invoke the editor of your choice if you set the MIMIC_EDITOR environment variable prior to starting MIMICView.)

    Creating a Scenario

    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.

    • The format of the .tab files is a list of instances, one per line.

    • The format of the .var files is

      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

  6. MIMIC Simulation Language Reference
  7. High-level Syntax

    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}
    ...

    Types

    Each expression in the MIMIC language returns a value with one of the types in the SNMP Structure of Management Information (SMI) specification:

    • INTEGER
    • OCTET-STRING
    • OBJECT-ID
    • Counter
    • Gauge
    • IpAddress

    Constants

    Constant expressions return the same value at any point in the simulation.

    Decimal, hexadecimal, octal, binary INTEGER constants

    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

    Enumerated INTEGER Constants

    You can use enumerated symbol names just as in the SMI.

    Examples:
    ethernet-csmacd

    Octet Strings

    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

    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

    IpAddress

    IP addresses need to be specified in dot notation or as 4 hexadecimal bytes.

    Examples:
    192.9.200.71
    \x C0 09 C8 47

    Arithmetic Functions

    MIMIC supports the basic complement of integer arithmetic functions:

    • Addition +
    • Subtraction -
    • Multiplication *
    • Division /
    • Mod %

    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:

    • INTEGER counter32(number)
      Converts the number to a 32-bit value.

    • INTEGER counter64(number)
      Converts the number to a 64-bit value.

    • STRING string_cast(number)
      Converts the number to a string value.

    Nested Expressions

    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.

    System Functions

    This is a set of typed functions that return system-related information:

    • INTEGER agent_no()
      Returns the agent instance identifier.

    • INTEGER agent_addr()
      Returns the agent instance IP address.

    • INTEGER sysuptime()
      Returns an INTEGER containing the time in ticks (100ths of seconds) since the agent booted. This time will be maintained on a per agent instance basis.

    • INTEGER random(integer low, integer high)
      Returns a random value between (and including) low and high.

    Conditional Operator

    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.

    Value Space Access

    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

    • OCTET-STRING lookup (const char* variable_name)

    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

    • boolean exists (const char* variable_name)

    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

    • OCTET-STRING set (const char* variable_name, const char* value)

    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.

    Variable Store Access

    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.

    • integer global_store_exists (const char* variable_name)
    • OCTET-STRING global_store_get (const char* variable_name)
    • OCTET-STRING global_store_set (const char* variable_name, const char* value, integer persist)
    • integer agent_store_exists (const char* variable_name)
    • OCTET-STRING agent_store_get (const char* variable_name)
    • OCTET-STRING agent_store_set (const char* variable_name, const char* value, integer persist)

    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") }

    Counter Statistics

    The following group of functions allows flow-based simulation of MIB objects of type Counter:

    • Counter uniform(integer rate)
      Returns the current value of a uniformly distributed random variable with the specified average rate per second.

    • Counter uniform_per_tu(integer rate, integer timeunit)
      Returns the current value of a uniformly distributed random variable with the specified average rate per given timeunit in seconds. This is to simulate counters with low rates. When timeunit is 1, this function is the same as uniform().

    • Counter constant(integer rate)
      Returns the current value of a constant variable with the specified average rate per second.

    • Counter constant_per_tu(integer rate, integer timeunit)
      Returns the current value of a constant variable with the specified average rate per given timeunit in seconds. This is to simulate counters with low rates. When timeunit is 1, this function is the same as constant().

    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")) }

    MIB Tables

    This group of operations is related to MIB tables and the INDEX clause.

    • table.range (minindex, maxindex, stepindex)
      Used in the table object with INDEX clause, it defines this table as a static table with a range of index values as specified by the minindex, maxindex and stepindex arguments. This function is used to define tables with a "mostly" contiguous range of indices. The minindex argument specifies the first index in the table, the maxindex argument the last index, and the stepindex the "distance" between each consecutive index.

    • table.static
      Used in the table object with INDEX clause, it defines this table as a static table with indices specified in an index file. This function is used to define tables with non-contiguous indices.
      The index file lives in the scenario directory with the same name as the INDEX object, with .tab appended.
      You can add and remove entries to this type of table at run time.

    • OBJECT-ID table.index (int i)
      Returns the OID containing the i-th index component of the index OID. This is useful for simulating the objects which are contained in the INDEX clause of a table. The compiler will make this function the default for all objects which are specified in a INDEX clause. Also, this function can be used for special casing in value simulations.

    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 }

    For example, if the ifEntry.tab file contains
    5
    10
    11

    then only interfaces 5, 10 and 11 will be simulated.

    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") }

    Information about current Object

    If you want to get information about the currently accessed MIB object, you use the operations

    • OCTET-STRING oid()
      Returns the OID of the currently accessed MIB object without the instance.

    • OCTET-STRING object()
      Returns the name of the currently accessed MIB object.

    • OCTET-STRING instance()
      Returns the instance of the currently accessed MIB object.

    Relationships Between Objects

    This operation implements relationships between MIB object instances.

    • value (const char* object)
      Returns the value of the specified object with the same index as the object that is being simulated. This can currently only be used with objects in the same table.

    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 }

    Trap Generation

    This operation simulates trap PDU generation.

    • void trap_periodic (rate, time_unit, cutoff_time)

      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.