MIBGen 1.0 Developer User Guide
MIBGen 1.0 creates extensible, safe-Rust SNMP agents from SMIv1 and SMIv2 MIB definitions. This guide is for software developers who understand basic SNMP concepts such as OIDs, scalar instances, tables, GET, GET-NEXT, GET-BULK, SET, communities, and SNMPv3 security, but who have not used the MIBGen runtime or generated project structure before.
The guide covers the desktop application on macOS, Linux, and Windows. It does not cover the command-line generator.
Contents
- What MIBGen generates
- Install MIBGen
- Requirements
- The six-step workflow
- Tutorial: create an agent
- Beginner end-to-end tutorial
- Understand the generated project
- Implement generated scalars
- Implement a generated table
- Build and run the agent
- Test the agent with SNMP
- Add another target
- Synchronize a revised MIB
- Provider development rules
- MIB syntax and Rust values
- Agent configuration reference
- Troubleshooting
- Production release checklist
- Glossary
What MIBGen generates
A MIB describes the management schema:
- Numeric OIDs and symbolic names.
- Scalar and table structure.
- Table indexes and
AUGMENTSrelationships. - Value syntax, enumerations, ranges, sizes, and display hints.
- Readability and writability declared by the MIB.
A MIB does not explain how to obtain application data. MIBGen therefore separates generated schema code from engineer-written data collection:
MIB files
│
▼
MIBGen schema and typed Rust models
│
├── generated validation, OID/index encoding, and publication
│
└── engineer-owned collectors and application integration
│
▼
Running SNMP agent
MIBGen produces a project that compiles and runs before collectors are implemented. Unfinished
tables are registered with no rows. Unfinished scalars without a usable MIB default are registered
without a .0 instance.
For SNMPv2c and SNMPv3:
- An exact GET for a claimed but absent instance returns
noSuchInstance. - GET-NEXT and GET-BULK skip absent instances.
- An object not claimed by any provider returns
noSuchObject.
SNMPv1 uses its protocol-level noSuchName behavior.
Supported selections
MIBGen can generate:
- A complete conceptual table, including its index model and accessible columns.
- An OID group or subtree containing accessible scalars and tables.
- An SMIv2
OBJECT-GROUP, limited to the objects in itsOBJECTSclause. - Multiple independent targets from one or more entry MIB files.
MIBGen rejects individual scalar selections, notifications, compliance statements, ambiguous symbols, unresolved imports, overlapping selections, and unsupported index syntax.
Built-in providers
The Rust agent already implements common standard MIB objects, including:
- MIB-II system and interfaces.
- MIB-II address translation, IP, TCP, and UDP.
- IF-MIB
ifXTable. - IP-MIB
ipAddressTable. - Host Resources system, storage, device, partition, filesystem, running-software, performance, and installed-software objects.
- SNMPv3 USM user management.
- VACM security-to-group and access tables.
When a selected target is fully built in, MIBGen records and enables the runtime feature but does not create a duplicate provider skeleton. A mixed subtree produces code only for the custom remainder. Built-in provider reuse prevents two providers from claiming the same OIDs.
Install MIBGen
MIBGen is distributed for 64-bit Windows and Linux as well as Apple silicon and Intel macOS. Every installer includes the safe-Rust agent developer kit, built-in providers, offline documentation, and the target-specific binary SNMP SDK library. Rust itself is not bundled.
Before installing, compare the package with the accompanying SHA256SUMS file:
# macOS
shasum -a 256 -c SHA256SUMS
# Linux
sha256sum -c SHA256SUMS
# Windows PowerShell
(Get-FileHash .\MIBGen-1.0.0-x64-setup.exe -Algorithm SHA256).Hash
The Windows and Linux packages in this release are unsigned. Obtain them from a trusted source and verify their checksum before accepting a Windows SmartScreen warning or marking an AppImage executable.
Linux x86-64
For Ubuntu 20.04 or a newer Debian-family system, install the DEB:
sudo apt install ./mibgen_1.0.0_amd64.deb
The program is installed in /usr/bin, and its agent developer kit is installed under
/usr/lib/mibgen/agent-kit. Remove it with:
sudo apt remove mibgen
For another compatible desktop distribution, use the AppImage:
chmod +x MIBGen-1.0.0-x86_64.AppImage
./MIBGen-1.0.0-x86_64.AppImage
The portable tar archive may be extracted anywhere. Keep agent-kit beside the MIBGen
executable:
tar -xzf MIBGen-1.0.0-x86_64-linux.tar.gz
./MIBGen-1.0.0-x86_64-linux/MIBGen
Windows x86-64
Run MIBGen-1.0.0-x64-setup.exe. The default installation is for the current user, does not
require administrator access, and creates Start Menu and uninstall entries. Windows SmartScreen
may display an unrecognized-app warning because this milestone is unsigned. Verify the checksum
before selecting More info and Run anyway.
Alternatively, extract MIBGen-1.0.0-x86_64-windows.zip and run MIBGen.exe. Do not move the
executable away from its adjacent agent-kit directory. Remove the installed version through
Windows Installed apps, or delete the portable directory.
macOS
Open MIBGen-1.0.0-universal-apple-darwin.dmg and drag MIBGen.app to Applications. This unsigned
milestone may require Control-clicking the application and selecting Open the first time.
Delete the application to uninstall it.
Requirements
Install:
- Rust 1.85 or newer.
- Cargo from the same Rust toolchain.
- The
rustfmtcomponent. - MIBGen and a compatible iReasoning Rust agent developer kit.
MIBGen is available on macOS, Linux, and Windows. An installed distribution may include a platform-compatible developer kit and binary SNMP SDK library; MIBGen selects it automatically when present. Otherwise, select a compatible developer-kit directory or use the repository Rust workspace. MIBGen automatically discovers and validates the Rust tools and runtime at startup.
All imports needed by an entry MIB must be available in the same directory as that entry file. Different entry MIBs may use different directories. Identical shared modules are deduplicated; different files declaring the same module name are rejected as a version conflict.
For development, use a loopback address and a non-privileged UDP port. Generated projects default
to 127.0.0.1:1161.
The six-step workflow
MIBGen displays all six steps. A control remains disabled until its prerequisites are satisfied.
Step 1: Choose Project
MIBGen starts in New Project mode.
- Select Open Project… to open an existing
MIBGenProject.mibgendocument. - An opened project restores MIB paths, targets, output directory, runtime, configuration path, and generated-project state.
- Select Change… while an existing project is open to switch project context.
- Switching to New Project clears only the GUI's working state. It does not delete the previous project from disk.
Project switching is disabled while generation, synchronization, building, or an agent process is active.
Step 2: MIB Sources
Select Add MIB Files… to choose one or more entry MIBs. MIB files may have any extension.
MIBGen automatically rescans when a MIB is added, removed, or edited in the path field. The status line reports the number of entry modules and supported targets.
Use Add Empty Path when entering a path manually. Imports are resolved relative to each entry MIB's directory.
An entry MIB is the file containing:
MODULE-NAME DEFINITIONS ::= BEGIN
Do not select every imported file individually. Select the entry MIBs whose targets you want; MIBGen follows their imports.
Step 3: Target Selection
Search and select tables, groups, or OBJECT-GROUPs.
- Names are module-qualified, for example
ACME-SENSOR-MIB::acmeSensorTable. - The target summary lists the number of selected scalars and tables.
- Selected target names appear below the count.
- If two choices overlap, the most recent selection replaces the earlier editable selection.
- A new selection cannot replace a target already included in an opened project.
- Advanced manual targets accepts additional
MODULE::targetnames when necessary.
In an opened project, existing targets are marked Included. Select new targets and then select Add Selected Targets. Only the new difference is submitted; existing provider files are not rewritten.
Step 4: Project
For a new project:
- Choose an output directory that does not exist.
- Confirm or select the runtime directory.
- Wait for automatic Rust toolchain validation.
- Select Create Project.
The Cargo package and executable names are derived from the output-directory name.
Replace an existing output directory is destructive and requires confirmation. It is for recreating a project, not for adding targets to an existing project.
For an opened project:
- Check for MIB Changes performs a read-only synchronization preview.
- Synchronize Project updates generator-owned schema files for targets already in the project.
Target addition belongs to Step 3; synchronization never adds newly selected targets.
Step 5: Build and Run
The Configuration field defaults to config/SnmpAgent.xml in the project.
- The pencil icon edits existing attributes in the XML
<properties>element. - Boolean
yes/noattributes use switches. engineBootsis intentionally not editable because the authoritative SNMPv3 engine manages it.- Browse… selects a different XML configuration file.
- Build Agent validates registration, compiles a release executable, and assembles
dist/. - Run Agent launches the built executable with the selected configuration.
- Stop Agent terminates the running agent and its child-process group.
The Properties editor does not manage users, VACM groups/views, trap sinks, MIB entries, or other XML elements. Edit those sections with a text or XML editor. See Agent configuration reference for the complete configuration reference.
Step 6: Activity
Activity displays generator, compiler, and agent output.
- Select and copy individual text directly from the result pane.
- Copy copies the complete retained output and changes briefly to Copied.
- Clear removes retained output from the GUI.
- Build cancellation and agent stop operations terminate the complete process group.
The log is bounded so a long-running agent cannot consume memory without limit.
Tutorial: create an agent
Beginner end-to-end tutorial
If this is your first generated agent, follow
the beginner tutorial bundled with MIBGen. That tutorial
creates /Users/m1/projects/test/example, implements rustExampleScalars and
rustIETFWGTable, verifies them with snmpwalk, and then adds rustHostsTable through MIBGen's
incremental workflow.
The remainder of this section is a shorter reference implementation focused on scalar and hosts providers.
This tutorial uses:
mibs/RUST-EXAMPLES-MIB.txt
and selects:
RUST-EXAMPLES-MIB::rustExampleScalars
RUST-EXAMPLES-MIB::rustHostsTable
The scalar group contains two integer scalars. The table maps hostnames to IPv4 or IPv6 addresses. The finished example reads the operating system's hosts file and refreshes it every five seconds.
Create the project
-
Start MIBGen. Step 1 should show Selected: New Project.
-
In Step 2, select Add MIB Files….
-
Choose
RUST-EXAMPLES-MIB.txt. -
Wait for automatic target discovery.
-
In Step 3, select
RUST-EXAMPLES-MIB::rustExampleScalars. -
Select
RUST-EXAMPLES-MIB::rustHostsTable. -
In Step 4, choose a new output directory, such as:
macOS or Linux: /tmp/rust-hosts-agent Windows: C:\Users\developer\Projects\rust-hosts-agent -
Confirm that the Rust toolchain status is ready.
-
Select Create Project.
MIBGen saves:
<output>/MIBGenProject.mibgen
Open this file through Step 1 in later sessions. It records paths and target names, not XML configuration contents or credentials.
Understand the generated project
A current format-v2 project resembles:
rust-hosts-agent/
├── .mibgen/
│ ├── project.json
│ └── runtime/ # bundled developer kit when applicable
├── config/
│ └── SnmpAgent.xml
├── mibs/ # copied entry MIBs and import closure
├── src/
│ ├── application.rs
│ ├── main.rs
│ ├── providers/
│ │ ├── rust_examples_mib__rust_example_scalars.rs
│ │ └── rust_examples_mib__rust_hosts_table.rs
│ └── mibgen_generated/
│ ├── mod.rs
│ └── targets/
│ ├── rust_examples_mib__rust_example_scalars.rs
│ └── rust_examples_mib__rust_hosts_table.rs
├── tests/
│ ├── mibgen_generated.rs
│ └── providers/
├── Cargo.toml
├── Cargo.lock
├── MIBGenProject.mibgen
├── README.md
├── build.sh
├── build.ps1
└── schema.json
Engineer-owned files
MIBGen creates these files once and does not overwrite them during Add or Synchronize:
src/main.rssrc/application.rs- Everything under
src/providers/ - Everything under
tests/providers/ Cargo.tomlconfig/SnmpAgent.xmlREADME.md- Build scripts
Put application I/O and business logic in these files.
Generator-owned files
Do not edit:
.mibgen/project.jsonschema.json- Managed files under
mibs/ - Everything under
src/mibgen_generated/ tests/mibgen_generated.rs
The manifest records hashes for generator-owned files. Add and Synchronize stop rather than discarding detected manual changes.
Project-wide hooks
src/application.rs contains hooks for changes that apply to the complete agent:
pub fn configure(config: &mut AgentConfig) -> ireasoning_snmp_agent::Result<()>;
pub fn start(
builder: &AgentBuilder,
providers: &GeneratedProviders,
) -> ireasoning_snmp_agent::Result<Vec<tokio::task::JoinHandle<()>>>;
Use configure for programmatic configuration adjustments. Use start for application-wide
background jobs. Target-specific code normally belongs in its file under src/providers/.
Implement generated scalars
Open:
src/providers/rust_examples_mib__rust_example_scalars.rs
The generated model is:
pub struct RustExamplesMibScalars {
pub rust_example_integer: Option<i32>,
pub rust_example_sleeper: Option<i32>,
}
Option controls instance presence:
Some(value)publishes the scalar's.0instance.Noneremoves that scalar instance from the published snapshot.
For this MIB, MIBGen recognizes numeric DEFVAL values and publishes them during generated
startup. To replace those defaults with application values, implement the engineer-owned file as:
use crate::mibgen_generated::targets::rust_examples_mib__rust_example_scalars::*;
use ireasoning_snmp_agent::ManagedObjectError;
use std::sync::Arc;
pub fn start(
providers: Arc<GeneratedProviders>,
) -> ireasoning_snmp_agent::Result<Vec<tokio::task::JoinHandle<()>>> {
let snapshot = collect_rust_examples_mib_scalars()?;
providers.publish_rust_examples_mib_scalars(snapshot)?;
Ok(Vec::new())
}
pub fn collect_rust_examples_mib_scalars() -> Result<RustExamplesMibScalars, ManagedObjectError> {
Ok(RustExamplesMibScalars {
rust_example_integer: Some(42),
rust_example_sleeper: Some(1),
})
}
Replace the literal values with reads from your application state. Return one internally consistent snapshot.
Do not return made-up fallback values when the application cannot provide a required measurement.
Depending on the object contract, retain the last valid snapshot or return
ManagedObjectError::Unavailable.
Implement a generated table
Open:
src/providers/rust_examples_mib__rust_hosts_table.rs
The generated types are:
pub struct RustHostsTableIndex {
pub rust_host_name: Vec<u8>,
}
pub struct RustHostsTableRow {
pub index: RustHostsTableIndex,
pub rust_host_address_type: Option<i32>,
pub rust_host_address: Option<Vec<u8>>,
pub rust_host_storage: Option<i32>,
pub rust_host_row_status: Option<i32>,
}
The index is mandatory. Optional column fields control whether that cell exists. In most normal tables, publish all readable columns for every row.
The following implementation reads a bounded hosts file, creates one row per hostname, publishes an initial snapshot, and refreshes it every five seconds:
use crate::mibgen_generated::targets::rust_examples_mib__rust_hosts_table::*;
use ireasoning_snmp_agent::ManagedObjectError;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::Read;
use std::net::IpAddr;
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
const MAX_HOSTS_FILE_SIZE: u64 = 1024 * 1024;
const REFRESH_INTERVAL: Duration = Duration::from_secs(5);
const INET_ADDRESS_TYPE_IPV4: i32 = 1;
const INET_ADDRESS_TYPE_IPV6: i32 = 2;
const STORAGE_TYPE_NON_VOLATILE: i32 = 3;
const ROW_STATUS_ACTIVE: i32 = 1;
pub fn start(
providers: Arc<GeneratedProviders>,
) -> ireasoning_snmp_agent::Result<Vec<tokio::task::JoinHandle<()>>> {
match collect_rust_hosts_table_rows() {
Ok(rows) => providers.publish_rust_hosts_table(rows)?,
Err(error) => eprintln!("rustHostsTable starts empty: {error}"),
}
let task = tokio::spawn(async move {
let mut timer = tokio::time::interval(REFRESH_INTERVAL);
timer.tick().await;
loop {
timer.tick().await;
let collected = tokio::task::spawn_blocking(collect_rust_hosts_table_rows).await;
match collected {
Ok(Ok(rows)) => {
if let Err(error) = providers.publish_rust_hosts_table(rows) {
eprintln!("rustHostsTable refresh rejected: {error}");
}
}
Ok(Err(error)) => {
eprintln!("rustHostsTable collection failed: {error}");
}
Err(error) => {
eprintln!("rustHostsTable collection task failed: {error}");
}
}
}
});
Ok(vec![task])
}
pub fn collect_rust_hosts_table_rows() -> Result<Vec<RustHostsTableRow>, ManagedObjectError> {
let file = File::open(hosts_file()).map_err(|_| ManagedObjectError::Unavailable)?;
let mut bytes = Vec::new();
file.take(MAX_HOSTS_FILE_SIZE + 1)
.read_to_end(&mut bytes)
.map_err(|_| ManagedObjectError::Unavailable)?;
if bytes.len() as u64 > MAX_HOSTS_FILE_SIZE {
return Err(ManagedObjectError::Unavailable);
}
let text = String::from_utf8(bytes).map_err(|_| ManagedObjectError::Unavailable)?;
Ok(rows_from_hosts_text(&text))
}
fn rows_from_hosts_text(text: &str) -> Vec<RustHostsTableRow> {
let mut hosts = BTreeMap::<Vec<u8>, (i32, Vec<u8>)>::new();
for line in text.lines() {
let data = line.split_once('#').map_or(line, |(data, _)| data);
let mut fields = data.split_whitespace();
let Some(address) = fields.next().and_then(|value| value.parse::<IpAddr>().ok()) else {
continue;
};
let (address_type, address) = match address {
IpAddr::V4(value) => (INET_ADDRESS_TYPE_IPV4, value.octets().to_vec()),
IpAddr::V6(value) => (INET_ADDRESS_TYPE_IPV6, value.octets().to_vec()),
};
for hostname in fields {
let hostname = hostname.as_bytes();
if hostname.is_empty() || hostname.len() > 64 {
continue;
}
hosts
.entry(hostname.to_vec())
.or_insert_with(|| (address_type, address.clone()));
}
}
hosts
.into_iter()
.map(|(hostname, (address_type, address))| RustHostsTableRow {
index: RustHostsTableIndex {
rust_host_name: hostname,
},
rust_host_address_type: Some(address_type),
rust_host_address: Some(address),
rust_host_storage: Some(STORAGE_TYPE_NON_VOLATILE),
rust_host_row_status: Some(ROW_STATUS_ACTIVE),
})
.collect()
}
#[cfg(windows)]
fn hosts_file() -> PathBuf {
let root = std::env::var_os("SystemRoot").unwrap_or_else(|| "C:\\Windows".into());
PathBuf::from(root).join("System32\\drivers\\etc\\hosts")
}
#[cfg(not(windows))]
fn hosts_file() -> PathBuf {
PathBuf::from("/etc/hosts")
}
Why collection uses a background task
The agent processes requests concurrently. Provider get callbacks must remain fast and
thread-safe. They must not perform filesystem, database, shell, or network collection while
handling an SNMP request.
The example:
- Collects outside request processing.
- Uses
spawn_blockingfor filesystem work. - Produces a complete typed row snapshot.
- Calls
publish_rust_hosts_table. - Retains the previous valid snapshot if collection or validation fails.
The agent aborts target startup tasks returned by start during shutdown.
Atomic publication
The generated publication method:
providers.publish_rust_hosts_table(rows)?;
validates:
- Index types and constraints.
- Duplicate indexes.
- Column syntax, ranges, sizes, and enumerations.
- Selected column ownership.
- Provider and instance limits.
- Global OID conflicts.
It then atomically replaces the table instances and refreshes the global ordered OID index. If registry refresh fails, the previous snapshot is restored. GET-NEXT and GET-BULK therefore never traverse a partially rebuilt index.
Build and run the agent
After editing the engineer-owned providers:
- Return to MIBGen.
- Select Build Agent.
- Review compiler and generated registration-test output in Activity.
- When the build succeeds, select Run Agent.
The build performs schema/provider registration validation before replacing dist/. Errors such
as unresolved syntax, malformed index metadata, or duplicate provider claims fail during the
build rather than appearing only after the agent starts. Live values are validated when a
provider publishes them.
The running status reports the bound address, normally:
udp://127.0.0.1:1161
Stop the agent before rebuilding.
Test the agent with SNMP
Use an SNMP manager or MIB browser configured with:
| Setting | Development value |
|---|---|
| Host | 127.0.0.1 |
| UDP port | 1161 |
| Version | SNMPv2c |
| Read community | public |
Load RUST-EXAMPLES-MIB.txt and its imports into the manager for symbolic names.
Verify generated scalars
GET:
RUST-EXAMPLES-MIB::rustExampleInteger.0
RUST-EXAMPLES-MIB::rustExampleSleeper.0
Expected tutorial values:
rustExampleInteger.0 = 42
rustExampleSleeper.0 = 1
The .0 suffix is the scalar instance identifier.
Verify the table
Run GET-SUBTREE or walk:
RUST-EXAMPLES-MIB::rustHostsTable
Rows depend on the local hosts file. Confirm:
- Each hostname has a unique table index.
- IPv4 rows use
rustHostAddressType = ipv4(1). - IPv6 rows use
rustHostAddressType = ipv6(2). - Address bytes correspond to the indexed hostname.
- Storage and row status report the configured enum values.
Verify ordered traversal
Run GET-NEXT starting before the custom enterprise subtree and GET-BULK with several repetitions. Returned OIDs must increase lexicographically without duplicates. The custom providers and built-in providers share one ordered registry.
Verify built-in objects
The generated development configuration enables built-in providers. Verify examples such as:
RFC1213-MIB::sysDescr.0
RFC1213-MIB::ifNumber.0
RFC1213-MIB::ifDescr
IF-MIB::ifXTable
HOST-RESOURCES-MIB::hrSystemUptime.0
Available rows depend on the host operating system.
Test the provider code
Add deterministic parser and publication tests to the target's engineer-owned test file or as a
#[cfg(test)] module in the provider. Tests should use synthetic text or application records, not
the developer machine's current interfaces, processes, or hosts file.
At minimum, test:
- Empty input.
- Valid IPv4 and IPv6 rows.
- Duplicate indexes.
- Malformed input.
- Maximum string lengths.
- Values outside MIB constraints.
- Successful publication and failed-publication rollback.
For the tutorial collector, add this module to the bottom of the engineer-owned table provider:
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_ipv4_ipv6_comments_and_duplicate_names() {
let rows = rows_from_hosts_text(
"127.0.0.1 localhost loopback\n\
::1 localhost ip6-localhost # comment\n\
malformed ignored\n",
);
assert_eq!(rows.len(), 3);
let localhost = rows
.iter()
.find(|row| row.index.rust_host_name == b"localhost")
.unwrap();
assert_eq!(
localhost.rust_host_address_type,
Some(INET_ADDRESS_TYPE_IPV4)
);
assert_eq!(localhost.rust_host_address, Some(vec![127, 0, 0, 1]));
}
}
The first localhost row is retained because a MIB table cannot publish two rows with the same
index.
Add another target
To extend an existing agent:
- Open
MIBGenProject.mibgen. - Add any new entry MIB files in Step 2.
- Select new targets in Step 3.
- Confirm existing targets are marked Included.
- Select Add Selected Targets.
- Implement the newly created engineer-owned provider files.
- Build and test again.
MIBGen submits only targets not already in the manifest. Existing files under src/providers/ and
tests/providers/ remain byte-for-byte unchanged.
Target removal is not currently part of the GUI workflow.
Synchronize a revised MIB
Use synchronization when the definition of an existing target changes.
- Commit or back up the working project.
- Open its
MIBGenProject.mibgen. - Update the entry MIB path or replace the MIB with the revised version.
- Select Check for MIB Changes.
- Review changes to modules, indexes, columns, syntax, and access modes in Activity.
- Select Synchronize Project.
- Update engineer-owned provider code if generated types changed.
- Build and run all provider tests.
Check is read-only. Synchronize updates only generator-owned files and managed MIB copies.
Synchronization stops without modifying the project if:
- A target disappeared or became ambiguous.
- An import cannot be resolved.
- An index became unsupported.
- Target ownership now overlaps.
- A generator-owned file was edited manually.
Compilation after a successful synchronization identifies manual code that needs adaptation.
Provider development rules
Provider checklist
Before considering a provider complete:
- Derive row identities from stable application identities.
- Publish unique indexes that satisfy the MIB's constraints.
-
Return correct
Valuevariants and enum numbers. - Publish a complete, internally consistent snapshot.
- Bound file, command, database, and network collection.
-
Keep request-time
getpaths fast and free of blocking I/O. - Move slow work to background tasks.
- Retain the previous valid snapshot after transient collection failure.
- Avoid logging credentials, process arguments, private data, or entire command output.
- Add deterministic unit and publication tests.
- Test GET, GET-NEXT, GET-BULK, missing instances, and end-of-MIB behavior.
- Document platform-specific unavailable values.
Thread safety
The agent uses a multithreaded Tokio runtime and processes up to maxConcurrentRequests requests
simultaneously. Generated and custom providers implement Send + Sync.
Use:
- Immutable values behind
Arc. RwLockfor read-heavy mutable snapshots.Mutexfor short exclusive state changes.- Atomics for simple independent counters.
- Atomic
publish_*methods for topology replacement.
Do not hold a lock while performing slow I/O. Collect first, validate and construct the new snapshot, then acquire only the locks required to publish it.
Stable indexes
An SNMP table index is part of the management API. Avoid assigning indexes from temporary vector positions when rows may reorder. Prefer:
- Native operating-system IDs.
- Persistent database IDs.
- Stable device or application identifiers.
- A process-lifetime or persisted allocation map when no native integer exists.
Duplicate index values are rejected.
Composite and IMPLIED indexes
Generated index structs contain one field per INDEX component in MIB order. Construct each field
with the generated Rust type. The generated conversion code handles length prefixes and a final
IMPLIED component.
Do not manually append OID arcs or encode string lengths. Use the generated index and row types.
AUGMENTS
For an augmented table, generated metadata inherits the base row's index. Publish corresponding augmented rows with the same index values as the base table. If the MIB requires one-to-one row existence, create both snapshots from the same application inventory.
Absent cells and rows
Use None only when absence is semantically allowed. Do not use None to hide a collection bug.
Removing a table row requires publishing a complete new snapshot without that row.
Error handling
Use typed ManagedObjectError values:
Unavailablefor temporary collection failure.InvalidValuefor application data that cannot satisfy the MIB.Limitwhen a configured resource bound is exceeded.Internalonly when the failure cannot be represented more specifically.
Do not use todo!, unimplemented!, or panic! on runtime paths.
SET support
Generated providers are operationally read-only even when the MIB declares read-write or
read-create.
- SNMPv1 returns
readOnly. - SNMPv2c and SNMPv3 return
notWritable.
Writable support requires explicit transactional hooks:
- Validate every assignment.
- Prepare all affected providers without changing live state.
- Commit only after all assignments prepare successfully.
- Undo earlier commits if a later provider fails.
- Persist the change atomically when it must survive restart.
- Refresh topology only after a successful row create/delete transaction.
See the Agent Architecture Guide bundled with MIBGen before implementing SET or RowStatus.
MIB syntax and Rust values
Generated row and scalar fields use convenient Rust primitives. Generated conversion code maps them to SNMP values.
| Resolved MIB syntax | Generated field | SNMP Value |
|---|---|---|
INTEGER, Integer32, enum | i32 | Value::Integer |
Unsigned32, Gauge32 | u32 | Value::Gauge32 |
Counter32 | u32 | Value::Counter32 |
Counter64 | u64 | Value::Counter64 |
TimeTicks | u32 | Value::TimeTicks |
OCTET STRING, DisplayString, BITS | Vec<u8> | Value::OctetString |
OBJECT IDENTIFIER | Oid | Value::ObjectIdentifier |
IpAddress | [u8; 4] or generated address form | Value::IpAddress |
Opaque | Vec<u8> | Value::Opaque |
Always inspect the actual generated type. Textual conventions can change the resolved type, constraints, display hint, or enum mapping.
MIBGen and the runtime validate:
- Signed and unsigned ranges.
SIZEconstraints.- Enumerated integer values.
- OID and IP-address structure.
- Table-index encoding.
The management agent should publish protocol units declared by the MIB, not presentation units shown by a MIB browser.
Agent configuration reference
MIBGen generates config/SnmpAgent.xml. The same configuration format is used on macOS, Linux,
and Windows. In Step 5, the pencil button edits existing attributes of the properties element.
engineBoots is intentionally excluded because the agent manages it. Edit elements such as
user, group, view, trapSink, and snmpV3TrapSink with a text or XML editor, save the file,
and restart the agent.
The root element must be SnmpAgent, and it must contain one direct properties child. Other
supported direct children are:
userviewgroupvacmSecurityToGroupandvacmAccessin agent-managed blocksmibDirectorymibtrapSinksnmpV3TrapSink
Element order is not significant. The file is UTF-8 XML. Escape XML-sensitive characters in
attribute values, such as &, ", <, and >.
Loading, paths, and persistence
Generated agents load the selected configuration as a file-backed configuration:
- Relative
mibDirectoryandmibpaths are resolved against the XML file's directory. - At startup, the agent advances
engineBootsand atomically rewrites the file. - Dynamically managed USM and VACM rows are also written atomically to this file.
- The process therefore needs read/write access to the file and create/rename access in its directory.
Do not share one writable configuration file between agent processes. Do not edit an agent-managed block while the agent is running. Back up the file before remote USM or VACM provisioning.
Value conventions
| Kind | Accepted form |
|---|---|
| Boolean | yes, no, true, or false, case-insensitively |
| Duration | Decimal milliseconds |
| OID | Dotted decimal, with an optional leading dot |
| Hexadecimal octets | Compact hex or bytes separated by spaces, colons, or hyphens |
| Community list | Comma- or semicolon-separated values |
| Names | Length limits are measured in UTF-8 octets |
Unknown Java-compatible attributes are generally retained and ignored. This makes migration easier, but a misspelled Rust setting may silently leave its default in effect.
The properties element
Only the first direct properties element is used.
Listener, protocol, and communities
| Attribute | Default | Valid values | Purpose |
|---|---|---|---|
version | 3 | 1, 2, 3 | Highest accepted version. 2 accepts v1 and v2c but not v3. |
ipAddress | empty | Numeric IPv4 or IPv6 | Local bind address. Empty means 0.0.0.0; hostnames are not accepted. |
port | 161 | 0..65535 | UDP port. 0 asks the OS for a temporary port. |
maxPacketSize | 32768 | At least 484 | Maximum request and encoded-response size in bytes. |
maxConcurrentRequests | 64 | 1..4096 | Maximum active request tasks. 1 is sequential. |
readCommunity | empty | Community list | Allows GET, GET-NEXT, and GET-BULK. Empty denies community reads. |
writeCommunity | empty | Community list | Allows SET. Empty denies community writes. |
Each community is limited to 255 bytes and comparisons are constant-time. Communities remain
plaintext in XML even though Rust debug output redacts them. SNMPv3 is accepted only when
version="3".
The UDP dispatcher pauses application-level reads at maxConcurrentRequests. Short bursts wait
in the operating-system receive buffer; excess UDP packets can be dropped when that buffer fills.
Responses may complete out of order and are correlated by SNMP identifiers.
Authoritative SNMPv3 engine
| Attribute | Default | Valid values | Purpose |
|---|---|---|---|
engineID | generated | 5–32 hexadecimal octets | Stable authoritative engine identifier. |
engineBoots | 1 | 0..2147483647 | Last persisted engine boot count. |
When engineID is empty, the runtime creates a deterministic enterprise-format ID using
iReasoning PEN 15145 and system.sysName. Keep the engine ID stable: changing it changes USM key
localization and can invalidate manager-side localized keys.
A file-backed agent increments and persists engineBoots before binding. A value already at the
RFC maximum prevents startup. MIBGen deliberately does not offer engineBoots in its properties
editor.
INFORM delivery
| Attribute | Default | Valid values | Purpose |
|---|---|---|---|
informTimeout | 1000 | 1..300000 | Wait time for one INFORM response in milliseconds. |
informRetries | 3 | 0..100 | Retransmissions after the initial INFORM. |
For Java compatibility, these attributes may be on the root SnmpAgent element. A value on
properties takes precedence. Configured notification fan-out uses at most 16 concurrent
deliveries.
MIB-II system values
| Attribute | Default | Returned object |
|---|---|---|
system.sysDescr | Platform and architecture description | sysDescr.0 |
system.sysObjectID | .1.3.6.1.4.1.15145.1.1 | sysObjectID.0 |
system.sysContact | empty | sysContact.0 |
system.sysName | Host name, then localhost | sysName.0 |
system.sysLocation | empty | sysLocation.0 |
system.sysServices | 72 | sysServices.0, range 0..127 |
The system group is operationally read-only. SET does not persist Java-style changes to these attributes.
Built-in provider controls
Every *.enabled setting defaults to yes. Disable a provider only when custom application code
will claim the same objects.
| Attribute | Default | Valid values | Effect |
|---|---|---|---|
interfaces.enabled | yes | Boolean | Enables ifNumber, ifTable, and ifXTable. |
interfaces.refreshIntervalMillis | 1000 | 100..3600000 | Interface refresh period. |
network.addressTranslationEnabled | yes | Boolean | Enables deprecated atTable. |
network.ipEnabled | yes | Boolean | Enables RFC1213 IP data and IP-MIB address inventory. |
network.tcpEnabled | yes | Boolean | Enables TCP scalars and tcpConnTable. |
network.udpEnabled | yes | Boolean | Enables UDP scalars and udpTable. |
network.refreshIntervalMillis | 5000 | 100..3600000 | Network refresh period. |
network.collectionTimeoutMillis | 10000 | 1000..60000 | Limit for platform network commands. |
usmUsers.enabled | yes | Boolean | Exposes writable usmUserSpinLock and usmUserTable. |
vacm.enabled | yes | Boolean | Exposes and enforces VACM for SNMPv3 USM. |
storage.enabled | yes | Boolean | Enables storage, disk, partition, and filesystem data. |
storage.refreshIntervalMillis | 5000 | 100..3600000 | Storage refresh period. |
hostSystem.enabled | yes | Boolean | Enables the seven RFC 2790 hrSystem scalars. |
hostSystem.refreshIntervalMillis | 5000 | 100..3600000 | Host-system refresh period. |
runningSoftware.enabled | yes | Boolean | Enables running-software and performance tables. |
runningSoftware.refreshIntervalMillis | 5000 | 100..3600000 | Process refresh period. |
runningSoftware.includeParameters | no | Boolean | Publishes process arguments after argv[0]. |
installedSoftware.enabled | yes | Boolean | Enables installed-software inventory. |
installedSoftware.refreshIntervalMillis | 900000 | 100..3600000 | Product scan period. |
installedSoftware.scanTimeoutMillis | 60000 | 1000..300000 | Limit for a product scan. |
Process parameters can contain sensitive data. Leave
runningSoftware.includeParameters="no" unless managers are explicitly authorized to see them.
Registry limits
| Attribute | Default | Purpose |
|---|---|---|
maxProviders | 256 | Maximum registered provider count. |
maxObjectsPerProvider | 4096 | Maximum object claims for one provider. |
maxInstancesPerProvider | 250000 | Maximum instances published by one provider. |
maxManagedInstances | 1000000 | Maximum instances in the complete registry. |
maxTraversalCandidates | 1000000 | Maximum candidates examined by one traversal. |
All limits must be positive. A provider refresh that exceeds a limit keeps the last valid snapshot.
The user element
An ordinary user defines one permanent SNMPv3 USM user and maps its security name to a VACM
group:
<user
name="operator"
auth="SHA256"
authPassword="replace-this"
priv="AES256"
privPassword="replace-this"
group="operators" />
| Attribute | Required | Meaning |
|---|---|---|
name | yes | Unique user/security name, 1–32 UTF-8 octets. |
group | yes | Name of an existing group. |
auth | by group | Authentication protocol. |
authPassword | by group | Authentication password. |
priv | no | Privacy protocol; defaults to DES when privacy is required. |
privPassword | no | Privacy password; defaults to authPassword for authPriv. |
Authentication names are MD5, SHA/SHA1, SHA224, SHA256, SHA384, and SHA512.
Privacy names are DES, 3DES/TripleDES, AES/AES128, AES192, and AES256. Names are
case-insensitive and punctuation-insensitive.
The referenced group's security level determines which credentials are active:
| Group security level | Requirement |
|---|---|
noAuthNoPriv | Authentication and privacy attributes are ignored. |
authNoPriv | auth and authPassword are required. |
authPriv | Authentication is required; privacy defaults described above apply. |
Ordinary users accept passwords, not authKey or privKey. Duplicate names, unknown groups,
missing credentials, or unsupported protocols stop configuration loading. Passwords are
zeroizing and redacted in memory, but they are plaintext in the XML file.
Agent-managed USM users
Users created or changed through usmUserTable are persisted in a managed block:
<!-- BEGIN IREASONING RUST MANAGED USM USERS -->
<user
name="provisionedUser"
cloneFrom="operator"
status="active"
publicHex="">
<authKeyChange value="..." />
<privKeyChange value="..." />
</user>
<!-- END IREASONING RUST MANAGED USM USERS -->
Managed attributes include cloneFrom, status (active or notInService), publicHex,
authDisabled, and privDisabled. Key-change children contain RFC 3414 key-change values, not
plaintext passwords or localized keys. Do not hand-edit this block while the agent runs.
The view element
A view is one VACM view-tree family:
<view
name="systemOnly"
type="included"
subTree=".1.3.6.1.2.1.1"
mask="" />
| Attribute | Required | Default | Meaning |
|---|---|---|---|
name | yes | — | View name, 1–32 UTF-8 octets. |
type | yes | — | included/include or excluded/exclude. |
subTree | yes | — | Numeric subtree OID; lowercase subtree also works. |
mask | no | empty | Per-subidentifier significance mask. |
Multiple elements with the same name form one logical view. The same name/subtree pair cannot be
repeated. In a mask, 1 means that subidentifier must match and 0 means wildcard; separators
such as ., :, comma, hyphen, and whitespace are ignored. Missing positions imply 1, and at
most 128 mask bits are accepted.
An exclusion can override a broader inclusion:
<view name="systemExceptContact" type="included"
subTree=".1.3.6.1.2.1.1" mask="" />
<view name="systemExceptContact" type="excluded"
subTree=".1.3.6.1.2.1.1.4" mask="" />
The most specific matching family determines the result. View families are startup XML data;
SNMP modification of vacmViewTreeFamilyTable is not implemented.
The group element
A group creates a permanent active VACM access row for USM:
<group
name="operators"
securityLevel="authPriv"
contextPrefix=""
match="exact"
readView="systemOnly"
writeView="systemOnly"
notifyView="systemOnly" />
| Attribute | Required | Default | Meaning |
|---|---|---|---|
name | yes | — | Unique group name, 1–32 UTF-8 octets. |
securityLevel | yes | — | noAuthNoPriv, authNoPriv, or authPriv. |
contextPrefix | no | empty | Context name or prefix, 0–32 UTF-8 octets. |
match | no | exact | exact or prefix. |
readView | no | empty | View for GET, GET-NEXT, and GET-BULK. |
writeView | no | empty | View for SET. |
notifyView | no | empty | View for configured v3 notifications. |
An empty or undefined view denies that access class. Each ordinary user group="NAME" creates a
permanent USM security-to-group mapping. VACM maps a request user to a group, selects the best
active access row for context/model/level, chooses the operation's view, and checks each OID.
Denied exact reads appear missing; traversal skips denied instances; a denied SET returns
noAccess and the one-based varbind index.
Agent-managed VACM elements
Rows created through writable VACM tables are persisted between these comments:
<!-- BEGIN IREASONING RUST MANAGED VACM -->
...
<!-- END IREASONING RUST MANAGED VACM -->
vacmSecurityToGroup maps a security identity to a group:
<vacmSecurityToGroup
securityModel="3"
securityName="provisionedUser"
groupName="operators"
storageType="nonVolatile"
status="active" />
| Attribute | Required | Default or accepted values |
|---|---|---|
securityModel | yes | v1/1, v2c/2, usm/3, or a positive model |
securityName | yes | 1–32 UTF-8 octets |
groupName | when active | 1–32 UTF-8 octets |
storageType | no | nonVolatile; also volatile, 2, or 3 |
status | no | active; also 1, notInService, 2, notReady, or 3 |
vacmAccess defines a dynamic access row:
<vacmAccess
groupName="operators"
contextPrefix=""
securityModel="usm"
securityLevel="authPriv"
contextMatch="exact"
readView="systemOnly"
writeView="systemOnly"
notifyView="systemOnly"
storageType="nonVolatile"
status="active" />
| Attribute | Required | Default or accepted values |
|---|---|---|
groupName | yes | 1–32 UTF-8 octets |
contextPrefix | no | Empty; at most 32 UTF-8 octets |
securityModel | yes | Models above plus any or 0 |
securityLevel | yes | noAuthNoPriv/1, authNoPriv/2, authPriv/3 |
contextMatch | no | exact; or prefix |
readView, writeView, notifyView | no | Empty; at most 32 UTF-8 octets |
storageType | no | nonVolatile; or volatile, 2, 3 |
status | no | active; or notInService, notReady, 1, 2, 3 |
Duplicate table indexes are rejected. Ordinary user and group rows are permanent and cannot
be modified through these writable tables.
The mibDirectory and mib elements
Add repeatable import directories and modules:
<mibDirectory path="../mibs" />
<mibDirectory path="../vendor-mibs" />
<mib path="ACME-SENSOR-MIB" />
<mib path="../mibs/ACME-ALARM-MIB.mib" />
The path attribute is required. A mib path is tried directly, then in each directory. When no
extension is present, the loader tries .mib, .MIB, .my, and .txt, then performs a
case-insensitive filename/stem search.
Configured modules use strict full-depth parsing with syntax resolution. Missing imports,
ambiguous symbols, or unresolved syntax stop startup. A MIB supplies schema only; a Rust provider
must still publish instances. Generated projects normally append their managed entry MIB paths in
code, so do not add duplicate entries merely because the files appear under the project mibs
directory.
The trapSink element
Configure an SNMPv1 or SNMPv2c destination:
<trapSink
hostname="192.0.2.10"
port="162"
community="public"
version="2"
isInform="no"
enabled="yes" />
| Attribute | Required | Default | Meaning |
|---|---|---|---|
hostname | yes | — | Destination hostname/IP, resolved when sending. |
port | no | 162 | Nonzero UDP destination port. |
community | no | public | Community, at most 255 bytes. |
version | no | 1 | 1 for v1 Trap-PDU or 2 for v2c. |
isInform | no | no | Use INFORM when yes; invalid with version 1. |
enabled | no | yes | Disabled sinks remain configured but are skipped. |
Traps are sent once. INFORMs use informTimeout and informRetries. During v2-to-v1 conversion,
Counter64 varbinds are removed. Two community sinks cannot have the same normalized hostname,
port, version, and trap/INFORM mode, even if their communities differ.
The snmpV3TrapSink element
Configure an SNMPv3 trap or INFORM destination:
<snmpV3TrapSink
hostname="192.0.2.20"
port="162"
userName="notifyUser"
auth="SHA256"
authPassword="replace-this"
priv="AES256"
privPassword="replace-this"
contextName=""
isInform="no"
enabled="yes" />
| Attribute | Required | Default | Meaning |
|---|---|---|---|
hostname | yes | — | Destination hostname or IP address. |
port | no | 162 | Nonzero UDP port. |
userName | yes | — | USM name, 1–32 UTF-8 octets. |
auth | by level | absent | Authentication protocol. |
authPassword | for password auth | absent | Authentication password. |
authKey | for localized-key auth | absent | Localized hexadecimal authentication key. |
priv | no | DES with privacy | Privacy protocol. |
privPassword | for password privacy | absent | Privacy password. |
privKey | for localized-key privacy | absent | Localized hexadecimal privacy key. |
engineID | for raw keys | absent | Engine against which the keys were localized. |
contextName | no | empty | Scoped-PDU context. |
isInform | no | no | Selects INFORM instead of trap. |
enabled | no | yes | Whether fan-out uses this sink. |
Security level is inferred from supplied material: no auth fields means noAuthNoPriv; auth
material means authNoPriv; auth plus privacy material means authPriv. Privacy without
authentication is rejected. Password and localized-key forms cannot be mixed. authKey requires
auth, privKey requires authKey, and raw keys require engineID.
Localized authentication key lengths are MD5 16, SHA-1 20, SHA-224 28, SHA-256 32, SHA-384 48, and SHA-512 64 bytes. Privacy key lengths are DES/AES-128 16, AES-192 24, and 3DES/AES-256 32 bytes.
For a trap, the local agent is authoritative, so a raw key must be localized to the local
engineID. For an INFORM, the receiver is authoritative and engineID seeds or validates
discovery. The sink user's active VACM notifyView is evaluated before configured v3 delivery.
Missing mappings, inactive rows, empty/undefined views, excluded notification OIDs, and context
mismatches skip the sink.
Two v3 sinks cannot have the same normalized hostname, port, user name, and trap/INFORM mode. Declaring a sink does not create notifications automatically; application code initiates delivery through the agent notifier.
Authorization summary
For SNMPv1/v2c, read operations require readCommunity, SET requires writeCommunity, and VACM
does not apply. For SNMPv3, the message needs an active USM user at exactly its configured security
level. When VACM is enabled, its mapping, access row, context, and selected view authorize every
OID. Application-installed policies can restrict further but cannot override a VACM denial.
Complete SNMPv3 configuration example
<?xml version="1.0" encoding="UTF-8"?>
<SnmpAgent>
<properties
version="3"
ipAddress="127.0.0.1"
port="1161"
maxPacketSize="32768"
maxConcurrentRequests="64"
readCommunity=""
writeCommunity=""
engineID="80003b29050102030405060708"
engineBoots="1"
informTimeout="1000"
informRetries="3"
system.sysDescr="ACME Rust SNMP Agent"
system.sysObjectID=".1.3.6.1.4.1.99999.1"
system.sysName="acme-agent"
interfaces.enabled="yes"
network.addressTranslationEnabled="yes"
network.ipEnabled="yes"
network.tcpEnabled="yes"
network.udpEnabled="yes"
storage.enabled="yes"
hostSystem.enabled="yes"
runningSoftware.enabled="yes"
installedSoftware.enabled="yes"
usmUsers.enabled="yes"
vacm.enabled="yes" />
<view name="readView" type="included"
subTree=".1.3.6.1.2.1" mask="" />
<view name="adminView" type="included"
subTree=".1.3.6.1" mask="" />
<group name="readers"
securityLevel="authNoPriv"
readView="readView"
writeView=""
notifyView="" />
<group name="administrators"
securityLevel="authPriv"
readView="adminView"
writeView="adminView"
notifyView="adminView" />
<user name="monitor"
auth="SHA256"
authPassword="replace-this"
group="readers" />
<user name="administrator"
auth="SHA512"
authPassword="replace-this"
priv="AES256"
privPassword="replace-this"
group="administrators" />
<mibDirectory path="../mibs" />
<mib path="ACME-SENSOR-MIB" />
<trapSink
hostname="127.0.0.1"
port="1162"
community="replace-this"
version="2"
isInform="no" />
<snmpV3TrapSink
hostname="127.0.0.1"
port="1162"
userName="administrator"
auth="SHA512"
authPassword="replace-this"
priv="AES256"
privPassword="replace-this"
contextName=""
isInform="no" />
</SnmpAgent>
This example deliberately uses loopback and non-privileged ports. Replace every placeholder secret, engine ID, enterprise OID, address, and access view before production use.
Java configuration compatibility
The Rust agent supports Java-style properties, user, group, view, trapSink, and
snmpV3TrapSink structures. These legacy Java settings are accepted but have no Rust effect:
encryptPasswordAndCommunity
useThreadPool
maxThreadCount
reloadConfigOID
authTrapEnabled
masterAgentPort
remoteMasterAgentPort
remoteMasterAgentIpAddress
subagentIpAddresses
managerIpAddresses
communityViewEnabled
underCreationTimeWindow
The communityView, proxy, and trapProxy elements are also not implemented. In particular,
the Rust agent does not apply Java thread-pool settings, encrypt XML secrets, reload through an
OID, create authentication-failure traps automatically, or enable master/subagent/proxy behavior.
For a low-level man-page version of this reference, including persistence recovery and diagnostic details, see Agent configuration reference.
Troubleshooting
Create Project is disabled
Check:
- At least one valid entry MIB is selected.
- Automatic target discovery completed successfully.
- At least one non-overlapping target is selected.
- The output directory is set.
- The Rust toolchain and runtime were detected.
- No build, generation, synchronization, or agent job is active.
A MIB import cannot be resolved
Place the imported module beside the entry MIB. Confirm the ASN.1 module name, not only the filename. Do not rename two different module versions to the same name.
A target is missing
MIBGen does not offer individual scalars, notifications, compliance statements, inaccessible objects, ambiguous symbols, or targets with unsupported index syntax. Review Activity for strict parser diagnostics.
Targets overlap
A broad subtree and a contained table or OBJECT-GROUP cannot both own the same object. Select
either the broad target or the more specific targets.
No provider file was generated
The target may already be implemented by a built-in provider. Confirm that it is recorded in
.mibgen/project.json and that the corresponding XML feature is enabled.
The agent returns noSuchInstance
The provider is registered but has not published that instance. Check:
- The target
starthook calls its collector andpublish_*. - The collector returns the expected rows or scalar
Somevalues. - Table indexes match the requested instance suffix.
- Publication did not report a validation error.
Build reports unresolved syntax or schema mismatch
Resolve all imported MIBs and run Check/Synchronize after MIB changes. Registration validation is
expected to catch unresolved syntax, invalid index metadata, and provider/schema disagreements
before producing dist/.
A generator-owned file was modified
Restore it from source control or a clean generated project. Move manual code into
src/providers/, src/application.rs, or tests/providers/.
Build Agent is disabled
Open or create a valid project and wait for automatic toolchain validation. The project must contain a valid format-v2 manifest and unmodified generated files.
Run Agent is disabled
Build successfully first. MIBGen enables Run only when the expected executable exists under
dist/.
The agent cannot bind
Another process may use the configured address and port. Stop the earlier agent or choose another non-privileged development port.
SNMP requests time out
Confirm:
- The agent is still running.
- Manager and agent use the same address, port, and version.
- The read community or USM credentials match.
- VACM permits the requested OID and context.
- A host firewall is not blocking UDP.
A table appears empty
Check Activity for collector errors, then verify the source inventory is nonempty. An empty table is valid and is skipped by GET-NEXT and GET-BULK.
Production release checklist
- Commit or archive the MIB sources used to generate the schema.
- Commit engineer-owned provider code and tests.
- Run Check for MIB Changes and review the result.
- Build with the release developer kit and locked dependencies.
- Run unit, integration, GET, GET-NEXT, GET-BULK, and negative tests.
- Replace loopback/development bind settings as required.
-
Replace the
publiccommunity and remove unused community access. - Configure SNMPv3 authentication, privacy, and VACM views.
- Protect configuration files and directories with appropriate permissions.
- Confirm engine ID and engine-boots persistence behavior.
-
Review
maxPacketSize,maxConcurrentRequests, and registry limits. - Confirm every collector is bounded and cannot stall request workers.
- Confirm indexes remain stable across refresh and restart where required.
- Confirm no credentials, keys, private application data, or process arguments are logged.
- Test startup, shutdown, collector failure, malformed requests, and port conflicts.
- Document platform-specific unavailable objects and counter semantics.
- Package the executable, configuration, and required MIB files.
Glossary
| Term | Meaning in MIBGen |
|---|---|
| Entry MIB | A selected file containing a module's DEFINITIONS ::= BEGIN; imports are followed automatically. |
| Target | A selected table, OID subtree/group, or OBJECT-GROUP. |
| Provider | Rust code that owns MIB objects and supplies live instances and values. |
| Scalar instance | A scalar object's concrete .0 instance. |
| Table row index | The ordered values that form a table instance suffix. |
| Schema | Parsed MIB structure, syntax, access, indexes, and OIDs. |
| Snapshot | One internally consistent set of scalar values or table rows. |
| Publication | Validating and atomically replacing a provider snapshot. |
| Built-in target | A selected target implemented by the standard agent runtime rather than generated custom code. |
| Engineer-owned file | A file created once that Add and Synchronize never overwrite. |
| Generator-owned file | A deterministic file managed and hash-checked by MIBGen. |
| Add | Introduce new targets without rewriting existing engineer-owned providers. |
| Check | Preview schema synchronization without writing. |
| Synchronize | Regenerate schema-owned files for existing targets after MIB changes. |
| VACM | SNMPv3 View-based Access Control Model. |
| USM | SNMPv3 User-based Security Model. |
For a concise description of GUI controls, see the MIBGen GUI Guide bundled with MIBGen. For deeper runtime and provider internals, see the Agent Architecture Guide bundled with MIBGen.