Overview
Custom device models allow you to extend NMIS monitoring for:
Unsupported device vendors
Proprietary MIBs
Custom monitoring requirements
Override default model behavior
Model Directory Structure
nmis9/
├── models-default/ # Opmantek-provided models (do not modify)
│ ├── Model-*.nmis
│ ├── Common-*.nmis
│ └── Graph-*.nmis
└── models-custom/ # Your custom models (safe from upgrades)
├── Model-MyDevice.nmis
├── Common-MyFeature.nmis
└── Graph-MyGraph.nmis
Important: Always create custom models in models-custom/ directory. Files in models-default/ are overwritten during NMIS upgrades.
Model Precedence
NMIS loads models in this order (later files override earlier ones):
models-default/ - Base models from Opmantek
models-custom/ - Your custom models (highest precedence)
To override a default model, copy it to models-custom/ and modify.
The model_tool.pl script helps discover SNMP capabilities of devices:
Location
/usr/local/nmis9/admin/model_tool.pl
Basic Usage
# Discover what a device supports
./model_tool.pl node=devicename debug= true
# Check model syntax
./model_tool.pl check= true
# Generate discovery report
./model_tool.pl node=devicename file=/tmp/discovery.txt
# Create a new model automatically
./model_tool.pl node=devicename model=MyNewModel
# Exclude specific common models
./model_tool.pl node=devicename model=MyDevice common_exclude="(cbqos|netflow)"
Discovery Output
From model_tool.pl:1342-1377:
usage: ./model_tool.pl node=<nodename> [model=name for new model]
[file=/path/to/file_for_details.txt]
[debug=true|false]
Params:
node: NMIS nodename
check: (true|false), check the models structure and for errors
model: Name of new model and the result file to be generated
common_exclude: A regular expression for the Common models
to exclude in the auto generated model
file: Where to save the results to, TAB delimited CSV
errors: Display models errors found or not
schema: Check the models structure against the schema
make_schema: Make the model schema file
Discovery Process
From model_tool.pl:369-501:
Load node configuration - Gets SNMP credentials
Test SNMP connectivity - Verifies device is reachable
Walk MIB trees - Tests each OID from models
Report findings - Shows supported/unsupported MIBs
Generate model - Creates basic model structure
Creating a New Model
Step 1: Discover Device Capabilities
# First, add the device to NMIS with Default model
# Then run discovery
./model_tool.pl node=mydevice model=MyCustomDevice debug= true
This generates:
models-custom/Model-MyCustomDevice.nmis
Console output showing supported MIBs
Common models to include
Step 2: Basic Model Template
# models-custom/Model-MyCustomDevice.nmis
%hash = (
'system' => {
'nodeModel' => 'MyCustomDevice' ,
'nodeVendor' => 'VendorName' ,
'nodetype' => 'router' , # or switch, firewall, server, generic
'sys' => {
'standard' => {
'snmp' => {
'sysLocation' => {
'oid' => 'sysLocation' ,
'title' => 'Location'
},
'sysDescr' => {
'oid' => 'sysDescr' ,
'title' => 'Description'
},
'sysObjectID' => {
'oid' => 'sysObjectID'
},
'sysContact' => {
'oid' => 'sysContact' ,
'title' => 'Contact'
},
'sysName' => {
'oid' => 'sysName' ,
'title' => 'System Name'
},
'sysUpTime' => {
'oid' => 'sysUpTime' ,
'title' => 'Uptime'
}
}
}
}
},
'interface' => {
'sys' => {
'standard' => {
'indexed' => 'true' ,
'snmp' => {
'ifDescr' => {
'oid' => 'ifDescr' ,
'title' => 'Description'
},
'ifSpeed' => {
'oid' => 'ifSpeed' ,
'title' => 'Speed'
},
'ifAdminStatus' => {
'oid' => 'ifAdminStatus' ,
'title' => 'Admin Status'
},
'ifOperStatus' => {
'oid' => 'ifOperStatus' ,
'title' => 'Oper Status'
}
}
}
},
'rrd' => {
'interface' => {
'indexed' => 'true' ,
'graphtype' => 'bits,abits,maxbits,util,autil' ,
'snmp' => {
'ifInOctets' => {
'oid' => 'ifInOctets' ,
'option' => 'counter,0:U'
},
'ifOutOctets' => {
'oid' => 'ifOutOctets' ,
'option' => 'counter,0:U'
}
}
}
}
},
'systemHealth' => {
'sections' => 'entityMib,temperature,fanStatus' ,
},
'-common-' => {
'class' => {
'entityMib' => {
'common-model' => 'entityMib'
}
}
}
);
Step 3: Add Custom SNMP Collection
Add device-specific monitoring:
'systemHealth' => {
'sections' => 'myCustomMetric' ,
'sys' => {
'myCustomMetric' => {
'indexed' => 'true' ,
'index_oid' => '1.3.6.1.4.1.9999.1.2.1.1' ,
'index_regex' => '\.(\d+)$' ,
'headers' => 'index,metricName,metricValue' ,
'snmp' => {
'metricName' => {
'oid' => '1.3.6.1.4.1.9999.1.2.1.2' ,
'title' => 'Metric Name'
},
'metricValue' => {
'oid' => '1.3.6.1.4.1.9999.1.2.1.3' ,
'title' => 'Value'
}
}
}
},
'rrd' => {
'myCustomMetric' => {
'indexed' => 'true' ,
'graphtype' => 'myCustomGraph' ,
'snmp' => {
'metricValue' => {
'oid' => '1.3.6.1.4.1.9999.1.2.1.3' ,
'option' => 'gauge,0:U'
}
}
}
}
}
Step 4: Device Identification
Add autodiscovery to models-custom/Model.nmis:
# Get the Enterprise ID from sysObjectID
# Example: 1.3.6.1.4.1.9999 (9999 is Enterprise ID)
'9999' => { # Your vendor's Enterprise ID
'order' => {
'10' => {
'MyCustomDevice' => 'my vendor.*device model'
}
}
}
The regex matches against the device’s sysDescr.
Model Inheritance and Overrides
Including Common Models
'-common-' => {
'class' => {
'database' => {
'common-model' => 'database'
},
'entityMib' => {
'common-model' => 'entityMib'
},
'lldp' => {
'common-model' => 'lldp'
}
}
}
Overriding Default Behavior
Copy the default model to models-custom/ and modify:
cp models-default/Model-CiscoRouter.nmis models-custom/Model-CiscoRouter.nmis
Then edit models-custom/Model-CiscoRouter.nmis to add/change sections.
Creating Common Models
Reusable monitoring components:
# models-custom/Common-MyFeature.nmis
%hash = (
'systemHealth' => {
'sys' => {
'myFeature' => {
'indexed' => 'myFeatureIndex' ,
'headers' => 'featureName,featureStatus' ,
'snmp' => {
'featureName' => {
'oid' => '1.3.6.1.4.1.9999.2.1.1.2' ,
'title' => 'Feature Name'
},
'featureStatus' => {
'oid' => '1.3.6.1.4.1.9999.2.1.1.3' ,
'title' => 'Status' ,
'replace' => {
'1' => 'enabled' ,
'2' => 'disabled'
}
}
}
}
}
}
);
Include in other models:
'-common-' => {
'class' => {
'MyFeature' => {
'common-model' => 'MyFeature'
}
}
}
Advanced Features
Value Calculations
Transform SNMP values:
'memoryUsed' => {
'oid' => 'memoryTotal' ,
'calculate' => 'CVAR1=memoryFree; return $r - $CVAR1;'
}
Control Statements
Conditionally collect data:
'env-temp' => {
'control' => 'CVAR=tempType;$CVAR =~ /celsius/' ,
'snmp' => {
'currentTemp' => {
'oid' => 'entSensorValue'
}
}
}
Value Replacement
Map numeric values to strings:
'interfaceStatus' => {
'oid' => 'ifOperStatus' ,
'replace' => {
'1' => 'up' ,
'2' => 'down' ,
'3' => 'testing' ,
'4' => 'unknown' ,
'5' => 'dormant' ,
'6' => 'notPresent' ,
'7' => 'lowerLayerDown'
}
}
Alert Thresholds
'alerts' => {
'myCustomMetric' => {
'highValue' => {
'type' => 'threshold-rising' ,
'threshold' => {
'Warning' => '80' ,
'Minor' => '85' ,
'Major' => '90' ,
'Critical' => '95' ,
'Fatal' => '100'
},
'element' => 'metricName' ,
'event' => 'High Metric Value' ,
'level' => 'Major' ,
'unit' => '%' ,
'value' => 'CVAR1=metricValue;int($CVAR1)'
}
}
}
Model Testing
Syntax Check
./model_tool.pl check= true errors= true
Test SNMP Collection
# Update the device to use your model
# Then run a manual collect
/usr/local/nmis9/bin/nmis-cli act=collect node=mydevice debug= true
Check RRD Creation
ls -la /usr/local/nmis9/var/nmis/mydevice/health/
ls -la /usr/local/nmis9/var/nmis/mydevice/interface/
Verify in GUI
Navigate to node view
Check System Health sections
Verify graphs are generated
Check for alerts
Common Model Structure
Complete Model Structure Reference
%hash = (
# Device identification and basic info
'system' => {
'nodeModel' => 'ModelName' ,
'nodeVendor' => 'VendorName' ,
'nodetype' => 'router|switch|firewall|server|generic' ,
'sys' => {
'standard' => {
'snmp' => {
# System MIB-II variables
}
}
}
},
# Interface statistics
'interface' => {
'sys' => {
'standard' => {
'indexed' => 'true' ,
'snmp' => {
# Interface MIB variables (ifTable, ifXTable)
}
}
},
'rrd' => {
'interface' => {
'indexed' => 'true' ,
'graphtype' => 'bits,abits,maxbits,util,autil' ,
'snmp' => {
# Time-series interface metrics
}
}
}
},
# Device health metrics
'systemHealth' => {
'sections' => 'section1,section2,section3' ,
'sys' => {
'mySection' => {
'indexed' => 'indexOID' ,
'index_oid' => '1.3.6.1.x.x.x' ,
'index_regex' => ' \\ .( \\ d+)$' ,
'headers' => 'col1,col2,col3' ,
'snmp' => {
# Display values in GUI
}
}
},
'rrd' => {
'mySection' => {
'indexed' => 'true' ,
'graphtype' => 'myGraph' ,
'threshold' => 'myThreshold' ,
'control' => 'CVAR=var;$CVAR > 0' ,
'snmp' => {
# Store values in RRD
}
}
}
},
# Alert definitions
'alerts' => {
'mySection' => {
'myAlert' => {
'type' => 'test|threshold-rising|threshold-falling' ,
'threshold' => {
'Warning' => 'value' ,
'Minor' => 'value' ,
'Major' => 'value' ,
'Critical' => 'value' ,
'Fatal' => 'value'
},
'element' => 'columnName' ,
'event' => 'Event Description' ,
'level' => 'Major' ,
'test' => 'CVAR1=var;$CVAR1 > 10' ,
'value' => 'CVAR1=var;int($CVAR1)' ,
'unit' => 'units'
}
}
},
# RRD database definitions
'database' => {
'type' => {
'mySection' => '/nodes/$node/health/mySection-$index.rrd'
}
},
# Graph headings
'heading' => {
'graphtype' => {
'myGraph' => 'My Graph Title'
}
},
# Include common models
'-common-' => {
'class' => {
'CommonModel' => {
'common-model' => 'CommonModel'
}
}
}
);
SNMP Data Types
Counter Types
# Counter32 - 32-bit counter (wraps at 2^32)
'ifInOctets' => {
'oid' => 'ifInOctets' ,
'option' => 'counter,0:U'
}
# Counter64 - 64-bit counter
'ifHCInOctets' => {
'oid' => 'ifHCInOctets' ,
'option' => 'counter,0:U'
}
Gauge Types
# Gauge32 - Instantaneous value
'cpuLoad' => {
'oid' => 'cpuLoad' ,
'option' => 'gauge,0:100'
}
RRD Options
counter,min:max - Counter that increments (calculates rate)
gauge,min:max - Instantaneous value
derive,min:max - Rate of change
nosave - Don’t store in RRD (display only)
0:U - Min 0, max unlimited
0:100 - Range 0-100
Enterprise ID Registration
If monitoring a new vendor:
Find Enterprise ID from sysObjectID:
1.3.6.1.4.1.9999.x.x.x
^^^^ Enterprise ID
Look up vendor at: https://www.iana.org/assignments/enterprise-numbers/
Add to conf/Enterprise.nmis:
'9999' => {
'Enterprise' => 'Vendor Name' ,
'OID' => '9999'
}
Troubleshooting
Model Not Loading
# Check syntax errors
./model_tool.pl check= true
# Verify model file permissions
ls -la models-custom/Model-MyDevice.nmis
# Check NMIS logs
tail -f /usr/local/nmis9/logs/nmis.log
SNMP Collection Failing
# Test SNMP manually
snmpwalk -v2c -c public devicename 1.3.6.1.4.1.9999
# Check OID resolution
grep "1.3.6.1.4.1.9999" /usr/local/nmis9/mibs/nmis_mibs.oid
# Run collection with debug
/usr/local/nmis9/bin/nmis-cli act=collect node=mydevice debug= 9
No Graphs Displayed
Verify graphtype exists in models-default/Graph-*.nmis
Check RRD file was created
Ensure data type (counter/gauge) is correct
Wait for 2+ collection cycles
Best Practices
Start with model_tool.pl - Discover supported MIBs first
Use Common models - Reuse existing monitoring definitions
Document your models - Add comments explaining custom sections
Test incrementally - Add one section at a time
Version control - Keep custom models in git
Follow naming conventions - Model-Vendor-Model.nmis
Set proper thresholds - Tune alert levels for your environment
Use control statements - Avoid collecting invalid data
Next Steps