MIMIC gNMI Protocol Module Guide

  1. Table of Contents

  2. Overview

    The MIMIC gNMI Simulator is an optional facility that simulates the OpenConfig gNMI specification as detailed in this page . The GNMI service defines a gRPC-based protocol for retrieval and modification of device configuration, and the control and generation of telemetry streams from a managed device to a data collection system.

    This management protocol is found on Cisco Nexus switches, Arista EOS, Juniper JUNOS and others.

    For this proof-of-concept the gNMI Simulator is a standalone server application.

    MIMIC gNMI Simulator currently has the following limitations:

    • only Linux is supported

    • only JSON encoding is supported, since it is mandatory, but not Protobuf

    • only dial-in telemetry is supported, not dial-out

    Compatibility with various clients and applications is documented in the section below.

  3. Installation

    Install the GNMI Simulator package with the Update Wizard in the MIMICview graphical user interface.

    Once the gNMI server is started with a configured data model, it will be able to respond to requests from clients.

  4. Server Configuration

    The gNMI server accepts following command line arguments.

    -h,--help			Show this help message
    -u,--username USERNAME		Define connection username
    -p,--password PASSWORD		Define connection password
    -f,--force-insecure		No TLS connection, no password authentication
    -k,--priv-key KEY_PATH		Path to server PEM private key
    -c,--cert-chain CERT_PATH	Path to server PEM certificate chain
    -s,--sim SIM_NAME		Name of the simulation to load
    -a,--server-addr ADDR		IP Address to bind to for gNMI server, default 0.0.0.0
    -t,--server-port PORT		Port to listen on for gNMI requests, default 50051
    -A,--agent AGENT_NUM		MIMIC agent to associate with
    -M,--mimic-host HOST		MIMIC ip-address or hostname, default 127.0.0.1
    -T,--mimic-port PORT		MIMIC management port, default 9797
    

    -s/--sim and -A/--agent are required arguments.

    To start the server, change current directory to mimic-shared-area/bin and execute the following command.

    ./gnmi-start -f -s simulation-name -A agent-number
    

    e.g.

    ./gnmi-start -f -s veos -A 1
    

    This will start the gNMI server, load the veos simulation from scripts/gnmi/veos directory and associate it with agent 1 for MIMIC instance running on localhost.

  5. Simulation Configuration
  6. gNMI responses to be returned by the simulated server are specified by the gNMI simulation located in the scripts/gnmi/ directory in the MIMIC directory hierarchy. Each simulation is contained in a subdirectory under this location.

    Each simulation is comprised of three JSON formatted ASCII text files.

    • datatree.json - simulation data used for responding to RPCs

    • schema.json - schema/model information derived from YANG models

    • devconfig.json - simulation configuration

    Any TCL scripts referred in the simulation configuration file also need to be in this same directory.

    Overview

    The configuration information is encoded as JSON.

    The information under the subtrees identified by xpath /get and /subscribe affects the behavior of the simulator and should not be altered.

    The information under the subtree identified by xpath /capabilities is used to respond to the capabilities RPC.

    The information under the subtree identified by xpath /rules is used to customize the responses for get and subscribe RPCs.

    The get and subscribe RPCs take one or more paths as arguments to retrieve information. Failure to resolve the specified path will result in gNMI error.

    Format

    The /rules subtree is collection of JSON objects, each object containing zero or more simulation rules arranged as JSON array.

    • /rules/startup - rules to be executed sequentially at server startup

    • /rules/animate - rules to be executed according to the specified schedule

    • /rules/get - rules to customize responses of get RPC

    • /rules/subscribe - rules to customize responses of subscribe RPC

    • /rules/shutdown - rules to be executed sequentially at server shutdown

    In each of the rules (see example below), xpath and script are necessary fields. Rules for get and subscribe RPC are triggered when the value of xpath field is matched with the path specified in the RPC.

    Here is an example of devconfig.json.

    {
    	"rules": {
    		"startup": [
    			{
    				"description": "set system-priority to 500",
    				"name": "Startup Script 1",
    				"xpath": "/lacp/config/system-priority",
    				"script": "startup1.tcl"
    			},
    			{
    				"description": "get interfaces from agent",
    				"name": "Startup Script 2",
    				"xpath": "/interfaces",
    				"script": "init-interfaces.tcl"
    			}
    		],
    		"animate": [
    			{
    				"description": "double value of system-priority every 10 second",
    				"name": "Animate Script 1",
    				"every": 10000,
    				"xpath": "/lacp/config/system-priority",
    				"script": "animate1.tcl"
    			},
    			{
    				"description": "toggle value of enable twice every min i.e. every 500 msec",
    				"name": "Animate Script 2",
    				"rate": 2,
    				"timeunit": "min",
    				"xpath": "/lldp/config/enabled",
    				"script": "animate2.tcl"
    			}
    		],
    		"get": [
    			{
    				"description": "get hostname (.iso.org.dod.internet.mgmt.mib-2.system.sysName) of asociated mimic agent",
    				"name": "GET Script for /system/state/hostname",
    				"xpath": "/system/state/hostname",
    				"script": "get-hostname.tcl"
    			},
    			{
    				"description": "get updated interface counters from associated mimic agent",
    				"name": "GET Script for /interfaces/interface/state/counters",
    				"xpath": "/interfaces/interface/state/counters",
    				"script": "get-interface-counters.tcl"
    			}
    		],
    		"sub": [
    			{
    				"description": "get updated interface counters from associated mimic agent",
    				"name": "GET Script for /interfaces/interface/state/counters",
    				"xpath": "/interfaces/interface/state/counters",
    				"script": "get-interface-counters.tcl"
    			}
    		]
    	}
    }
    

    Global Tcl Variables

    Any Tcl procedure invoked will have a predefined set of global variables passed to it which identify the current environment.

    • gMimicHost

      This variable holds the MIMIC hostname/IP.

    • gMimicPort

      This variable holds the MIMIC management port.

    • gMimicAgent

      This variable holds the MIMIC Agent number associated with the simulation instance.

    • gCurrentRule

      This variable holds stringified JSON copy of the rule as specified in the device config JSON. The value is parsed as a DOM object and made available as a tcl global variable _rule_dom.

    • gCurrentDataset

      This variable holds the stringified JSON copy of subtree extracted from the simulation datatree. The extraction criteria is the xpath specified in the rule. The value is parsed as a DOM object and made available as a Tcl global variable _dataset_in.

  7. Creating a new Simulation
  8. MIMIC gNMI Simulator ships with few samples of simulated gNMI devices as part of its library of simulations.

    The general process of creating a gNMI simulation involves

    • recording communication with a real device over gNMI using a client tool such as gNMIC
    • analyzing recorded contents and collecting a list of YANG models supported by the device
    • processing the recording into to a data-tree
    • processing the YANG model into device schema
    • creating a device configuration file
    • using the data-tree, device schema and configuration with the gNMI simulator to simulate the devices

    The 'capabilities' RPC is handled seperately using information provided in the device configuration file. Here is a snippet from the file.

    "capabilities": {
        "models": [
          [
            "openconfig-if-ip",
            "OpenConfig working group",
            "2.3.0"
          ],
          [
            "arista-rpol-deviations",
            "Arista Networks, Inc.",
            ""
          ],
    ...
    ]
    }
    

    Contact Gambit Support team for any queries/guidance about the above process.

  9. gNMI Simulation samples
  10. The gNMI Simulator package includes two samples of the gNMI Devices.

    The purpose of the simulation samples provided is to

    • demonstrate the ability of gNMI Server to handle 'get' and 'subscribe' requests
    • configurability of gNMI server behavior
    • ability to associate gNMI simulator with MIMIC SNMP Agent to -- map device model with SNMP MIB -- fetch values from MIB variables to convert static recording into dynamically simulation

    NOTE: No claim is made that sample simulations provided are a true and complete representation of the actual devices.

    Here are some details about the sample gNMI simulations.

    1. CISCO NXOS - Nexus 9000v Switch

      • values in responses are static i.e. as recorded during recording phase

    2. Arista EOS - vEOS Router

      • demonstrates the process of converting a static simulation into dynamic simulation
      • associates with an MIMIC SNMP agent to fetch MIB values and map them to device model
      • review device configuration file "rules" section
        • action script "init-interfaces.tcl" initializes the number of interfaces
        • action script "get-interface-counters.tcl" maps a subset of interface table values SNMP MIB

  11. Compatibility
    1. GNMIC

      The open-source gnmic command returns this when run against a GNMI simulation of the first agent of the default lab:

      % gnmic -u admin -p admin --insecure -a 45.10.11.1:6030 get --path "/lacp/config/system-priority"
      [
        {
          "timestamp": 1639752772122189783,
          "time": "2021-12-17T09:52:52.122189783-05:00",
          "updates": [
            {
              "Path": "lacp/config/system-priority",
              "values": {
                "lacp/config/system-priority": 1010
              }
            }
          ]
        }
      ]
      
      % gnmic -u admin -p admin --insecure -a 45.10.11.1:6030 get --path "/lacp/config/system-priority"
      [
        {
          "timestamp": 1639752778301540826,
          "time": "2021-12-17T09:52:58.301540826-05:00",
          "updates": [
            {
              "Path": "lacp/config/system-priority",
              "values": {
                "lacp/config/system-priority": 1120
              }
            }
          ]
        }
      ]
      

      Notice the changing system-priority value.

      The subscribe command returns a sequence of values:

      % gnmic -u admin -p admin --insecure -a 45.10.11.1:6030 sub --path "/lacp/config/system-priority"
      --stream-mode sample --sample-interval 2s
      
      {
        "source": "45.10.11.1:6030",
        "subscription-name": "default-1639753280",
        "timestamp": 1639753280844912601,
        "time": "2021-12-17T10:01:20.844912601-05:00",
        "updates": [
          {
            "Path": "lacp/config/system-priority",
            "values": {
              "lacp/config/system-priority": 5620
            }
          }
        ]
      }
      {
        "source": "45.10.11.1:6030",
        "subscription-name": "default-1639753280",
        "timestamp": 1639753282846568862,
        "time": "2021-12-17T10:01:22.846568862-05:00",
        "updates": [
          {
            "Path": "lacp/config/system-priority",
            "values": {
              "lacp/config/system-priority": 5720
            }
          }
        ]
      }
      {
        "source": "45.10.11.1:6030",
        "subscription-name": "default-1639753280",
        "timestamp": 1639753284847797280,
        "time": "2021-12-17T10:01:24.84779728-05:00",
        "updates": [
          {
            "Path": "lacp/config/system-priority",
            "values": {
              "lacp/config/system-priority": 5720
            }
          }
        ]
      }
      {
        "source": "45.10.11.1:6030",
        "subscription-name": "default-1639753280",
        "timestamp": 1639753286849044976,
        "time": "2021-12-17T10:01:26.849044976-05:00",
        "updates": [
          {
            "Path": "lacp/config/system-priority",
            "values": {
              "lacp/config/system-priority": 5720
            }
          }
        ]
      }
      {
        "source": "45.10.11.1:6030",
        "subscription-name": "default-1639753280",
        "timestamp": 1639753288850428558,
        "time": "2021-12-17T10:01:28.850428558-05:00",
        "updates": [
          {
            "Path": "lacp/config/system-priority",
            "values": {
              "lacp/config/system-priority": 5720
            }
          }
        ]
      }
      {
        "source": "45.10.11.1:6030",
        "subscription-name": "default-1639753280",
        "timestamp": 1639753290851603731,
        "time": "2021-12-17T10:01:30.851603731-05:00",
        "updates": [
          {
            "Path": "lacp/config/system-priority",
            "values": {
              "lacp/config/system-priority": 5720
            }
          }
        ]
      }
      {
        "source": "45.10.11.1:6030",
        "subscription-name": "default-1639753280",
        "timestamp": 1639753292852920489,
        "time": "2021-12-17T10:01:32.852920489-05:00",
        "updates": [
          {
            "Path": "lacp/config/system-priority",
            "values": {
              "lacp/config/system-priority": 5820
            }
          }
        ]
      }
      {
        "source": "45.10.11.1:6030",
        "subscription-name": "default-1639753280",
        "timestamp": 1639753294854281347,
        "time": "2021-12-17T10:01:34.854281347-05:00",
        "updates": [
          {
            "Path": "lacp/config/system-priority",
            "values": {
              "lacp/config/system-priority": 5820
            }
          }
        ]
      }
      ^C
      received signal 'interrupt'. terminating...
      
      

      Notice the value increments by 100 every 10 seconds, as configured in the simulation. Of course you can customize it to your requirements.

      Of course, entire sub-trees can be retrieved, eg. try

      % gnmic -u admin -p admin --insecure -a 45.10.11.1:6030 get --path "/interfaces/interface/state/counters"
      [
        {
          "timestamp": 1639762215561673945,
          "time": "2021-12-17T12:30:15.561673945-05:00",
          "updates": [
            {
              "Path": "interfaces/interface[name=MgmtEth0/RSP0/CPU0/0]/state/counters"
      ,
              "values": {
                "interfaces/interface/state/counters": {
                  "openconfig-interfaces:in-broadcast-pkts": "0",
                  "openconfig-interfaces:in-discards": "112011",
                  "openconfig-interfaces:in-errors": "112010",
                  "openconfig-interfaces:in-multicast-pkts": "0",
                  "openconfig-interfaces:in-octets": "112011",
                  "openconfig-interfaces:in-unicast-pkts": "17279708",
                  "openconfig-interfaces:out-broadcast-pkts": "1167",
                  "openconfig-interfaces:out-discards": "112011",
                  "openconfig-interfaces:out-errors": "112011",
                  "openconfig-interfaces:out-multicast-pkts": "58457",
                  "openconfig-interfaces:out-octets": "14949037",
                  "openconfig-interfaces:out-unicast-pkts": "17266784"
                }
              }
            },
            {
              "Path": "interfaces/interface[name=MgmtEth0/RSP0/CPU0/1]/state/counters"
      ,
              "values": {
                "interfaces/interface/state/counters": {
                  "openconfig-interfaces:in-broadcast-pkts": "0",
                  "openconfig-interfaces:in-discards": "0",
                  "openconfig-interfaces:in-errors": "0",
                  "openconfig-interfaces:in-multicast-pkts": "0",
                  "openconfig-interfaces:in-octets": "0",
                  "openconfig-interfaces:in-unicast-pkts": "0",
                  "openconfig-interfaces:out-broadcast-pkts": "1167",
                  "openconfig-interfaces:out-discards": "0",
                  "openconfig-interfaces:out-errors": "0",
                  "openconfig-interfaces:out-multicast-pkts": "58457",
                  "openconfig-interfaces:out-octets": "0",
                  "openconfig-interfaces:out-unicast-pkts": "0"
                }
              }
            },
      

      and 1500 more lines.

      The following simple pipeline keeps updating a single statistical value:

      % gnmic -u admin -p admin --insecure -a 45.10.11.1:6030 sub --path "/interfaces/interface/state/counters"
      --stream-mode sample --sample-interval 2s | awk -f single-interface.awk
      "2021-12-17T12:27:11.709145386-05:00", "interfaces/interface[name=GigabitEthernet101/0/0/38]/state/counters/out-octets", "69241402"
      "2021-12-17T12:27:14.80406031-05:00", "interfaces/interface[name=GigabitEthernet101/0/0/38]/state/counters/out-octets", "69293628"
      "2021-12-17T12:27:16.888229365-05:00", "interfaces/interface[name=GigabitEthernet101/0/0/38]/state/counters/out-octets", "69329061"
      "2021-12-17T12:27:18.986085317-05:00", "interfaces/interface[name=GigabitEthernet101/0/0/38]/state/counters/out-octets", "69363823"
      "2021-12-17T12:27:21.073823536-05:00", "interfaces/interface[name=GigabitEthernet101/0/0/38]/state/counters/out-octets", "69399256"
      "2021-12-17T12:27:23.161293852-05:00", "interfaces/interface[name=GigabitEthernet101/0/0/38]/state/counters/out-octets", "69434185"
      ^C
      
      % cat single-interface.awk
      /"time":/ {time=$2}
      /name=GigabitEthernet101\/0\/0\/38\]\/state\/counters\/out-octets/ {doprint=1; interface=$2}
      /interfaces\/interface\/state\/counters\/out-octets/ {if (doprint) { print time, interface,$2 }; doprint=0}
      
      

    2. Telegraf/InfluxDB

      The Telegraf collector has a plugin to collect gNMI telemetry. We followed their documentation to produce this 2-minute Youtube video of Telegraf collecting interface statistics via gNMI and graphing with Grafana through the InfluxDB dashboard.