Skip to main content

Developer documentation

Build, extend, synchronize, test, and deploy Rust SNMP agents with iReasoning MIBGen.

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

  1. What MIBGen generates
  2. Install MIBGen
  3. Requirements
  4. The six-step workflow
  5. Tutorial: create an agent
  6. Beginner end-to-end tutorial
  7. Understand the generated project
  8. Implement generated scalars
  9. Implement a generated table
  10. Build and run the agent
  11. Test the agent with SNMP
  12. Add another target
  13. Synchronize a revised MIB
  14. Provider development rules
  15. MIB syntax and Rust values
  16. Agent configuration reference
  17. Troubleshooting
  18. Production release checklist
  19. Glossary

What MIBGen generates

A MIB describes the management schema:

  • Numeric OIDs and symbolic names.
  • Scalar and table structure.
  • Table indexes and AUGMENTS relationships.
  • 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 its OBJECTS clause.
  • 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 rustfmt component.
  • 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.mibgen document.
  • 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::target names 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:

  1. Choose an output directory that does not exist.
  2. Confirm or select the runtime directory.
  3. Wait for automatic Rust toolchain validation.
  4. 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/no attributes use switches.
  • engineBoots is 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

  1. Start MIBGen. Step 1 should show Selected: New Project.

  2. In Step 2, select Add MIB Files….

  3. Choose RUST-EXAMPLES-MIB.txt.

  4. Wait for automatic target discovery.

  5. In Step 3, select RUST-EXAMPLES-MIB::rustExampleScalars.

  6. Select RUST-EXAMPLES-MIB::rustHostsTable.

  7. 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
    
  8. Confirm that the Rust toolchain status is ready.

  9. 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.rs
  • src/application.rs
  • Everything under src/providers/
  • Everything under tests/providers/
  • Cargo.toml
  • config/SnmpAgent.xml
  • README.md
  • Build scripts

Put application I/O and business logic in these files.

Generator-owned files

Do not edit:

  • .mibgen/project.json
  • schema.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 .0 instance.
  • None removes 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:

  1. Collects outside request processing.
  2. Uses spawn_blocking for filesystem work.
  3. Produces a complete typed row snapshot.
  4. Calls publish_rust_hosts_table.
  5. 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:

  1. Return to MIBGen.
  2. Select Build Agent.
  3. Review compiler and generated registration-test output in Activity.
  4. 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:

SettingDevelopment value
Host127.0.0.1
UDP port1161
VersionSNMPv2c
Read communitypublic

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:

  1. Open MIBGenProject.mibgen.
  2. Add any new entry MIB files in Step 2.
  3. Select new targets in Step 3.
  4. Confirm existing targets are marked Included.
  5. Select Add Selected Targets.
  6. Implement the newly created engineer-owned provider files.
  7. 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.

  1. Commit or back up the working project.
  2. Open its MIBGenProject.mibgen.
  3. Update the entry MIB path or replace the MIB with the revised version.
  4. Select Check for MIB Changes.
  5. Review changes to modules, indexes, columns, syntax, and access modes in Activity.
  6. Select Synchronize Project.
  7. Update engineer-owned provider code if generated types changed.
  8. 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 Value variants and enum numbers.
  • Publish a complete, internally consistent snapshot.
  • Bound file, command, database, and network collection.
  • Keep request-time get paths 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.
  • RwLock for read-heavy mutable snapshots.
  • Mutex for 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:

  • Unavailable for temporary collection failure.
  • InvalidValue for application data that cannot satisfy the MIB.
  • Limit when a configured resource bound is exceeded.
  • Internal only 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:

  1. Validate every assignment.
  2. Prepare all affected providers without changing live state.
  3. Commit only after all assignments prepare successfully.
  4. Undo earlier commits if a later provider fails.
  5. Persist the change atomically when it must survive restart.
  6. 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 syntaxGenerated fieldSNMP Value
INTEGER, Integer32, enumi32Value::Integer
Unsigned32, Gauge32u32Value::Gauge32
Counter32u32Value::Counter32
Counter64u64Value::Counter64
TimeTicksu32Value::TimeTicks
OCTET STRING, DisplayString, BITSVec<u8>Value::OctetString
OBJECT IDENTIFIEROidValue::ObjectIdentifier
IpAddress[u8; 4] or generated address formValue::IpAddress
OpaqueVec<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.
  • SIZE constraints.
  • 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:

  • user
  • view
  • group
  • vacmSecurityToGroup and vacmAccess in agent-managed blocks
  • mibDirectory
  • mib
  • trapSink
  • snmpV3TrapSink

Element order is not significant. The file is UTF-8 XML. Escape XML-sensitive characters in attribute values, such as &amp;, &quot;, &lt;, and &gt;.

Loading, paths, and persistence

Generated agents load the selected configuration as a file-backed configuration:

  • Relative mibDirectory and mib paths are resolved against the XML file's directory.
  • At startup, the agent advances engineBoots and 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

KindAccepted form
Booleanyes, no, true, or false, case-insensitively
DurationDecimal milliseconds
OIDDotted decimal, with an optional leading dot
Hexadecimal octetsCompact hex or bytes separated by spaces, colons, or hyphens
Community listComma- or semicolon-separated values
NamesLength 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

AttributeDefaultValid valuesPurpose
version31, 2, 3Highest accepted version. 2 accepts v1 and v2c but not v3.
ipAddressemptyNumeric IPv4 or IPv6Local bind address. Empty means 0.0.0.0; hostnames are not accepted.
port1610..65535UDP port. 0 asks the OS for a temporary port.
maxPacketSize32768At least 484Maximum request and encoded-response size in bytes.
maxConcurrentRequests641..4096Maximum active request tasks. 1 is sequential.
readCommunityemptyCommunity listAllows GET, GET-NEXT, and GET-BULK. Empty denies community reads.
writeCommunityemptyCommunity listAllows 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

AttributeDefaultValid valuesPurpose
engineIDgenerated5–32 hexadecimal octetsStable authoritative engine identifier.
engineBoots10..2147483647Last 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

AttributeDefaultValid valuesPurpose
informTimeout10001..300000Wait time for one INFORM response in milliseconds.
informRetries30..100Retransmissions 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

AttributeDefaultReturned object
system.sysDescrPlatform and architecture descriptionsysDescr.0
system.sysObjectID.1.3.6.1.4.1.15145.1.1sysObjectID.0
system.sysContactemptysysContact.0
system.sysNameHost name, then localhostsysName.0
system.sysLocationemptysysLocation.0
system.sysServices72sysServices.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.

AttributeDefaultValid valuesEffect
interfaces.enabledyesBooleanEnables ifNumber, ifTable, and ifXTable.
interfaces.refreshIntervalMillis1000100..3600000Interface refresh period.
network.addressTranslationEnabledyesBooleanEnables deprecated atTable.
network.ipEnabledyesBooleanEnables RFC1213 IP data and IP-MIB address inventory.
network.tcpEnabledyesBooleanEnables TCP scalars and tcpConnTable.
network.udpEnabledyesBooleanEnables UDP scalars and udpTable.
network.refreshIntervalMillis5000100..3600000Network refresh period.
network.collectionTimeoutMillis100001000..60000Limit for platform network commands.
usmUsers.enabledyesBooleanExposes writable usmUserSpinLock and usmUserTable.
vacm.enabledyesBooleanExposes and enforces VACM for SNMPv3 USM.
storage.enabledyesBooleanEnables storage, disk, partition, and filesystem data.
storage.refreshIntervalMillis5000100..3600000Storage refresh period.
hostSystem.enabledyesBooleanEnables the seven RFC 2790 hrSystem scalars.
hostSystem.refreshIntervalMillis5000100..3600000Host-system refresh period.
runningSoftware.enabledyesBooleanEnables running-software and performance tables.
runningSoftware.refreshIntervalMillis5000100..3600000Process refresh period.
runningSoftware.includeParametersnoBooleanPublishes process arguments after argv[0].
installedSoftware.enabledyesBooleanEnables installed-software inventory.
installedSoftware.refreshIntervalMillis900000100..3600000Product scan period.
installedSoftware.scanTimeoutMillis600001000..300000Limit for a product scan.

Process parameters can contain sensitive data. Leave runningSoftware.includeParameters="no" unless managers are explicitly authorized to see them.

Registry limits

AttributeDefaultPurpose
maxProviders256Maximum registered provider count.
maxObjectsPerProvider4096Maximum object claims for one provider.
maxInstancesPerProvider250000Maximum instances published by one provider.
maxManagedInstances1000000Maximum instances in the complete registry.
maxTraversalCandidates1000000Maximum 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" />
AttributeRequiredMeaning
nameyesUnique user/security name, 1–32 UTF-8 octets.
groupyesName of an existing group.
authby groupAuthentication protocol.
authPasswordby groupAuthentication password.
privnoPrivacy protocol; defaults to DES when privacy is required.
privPasswordnoPrivacy 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 levelRequirement
noAuthNoPrivAuthentication and privacy attributes are ignored.
authNoPrivauth and authPassword are required.
authPrivAuthentication 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="" />
AttributeRequiredDefaultMeaning
nameyesView name, 1–32 UTF-8 octets.
typeyesincluded/include or excluded/exclude.
subTreeyesNumeric subtree OID; lowercase subtree also works.
masknoemptyPer-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" />
AttributeRequiredDefaultMeaning
nameyesUnique group name, 1–32 UTF-8 octets.
securityLevelyesnoAuthNoPriv, authNoPriv, or authPriv.
contextPrefixnoemptyContext name or prefix, 0–32 UTF-8 octets.
matchnoexactexact or prefix.
readViewnoemptyView for GET, GET-NEXT, and GET-BULK.
writeViewnoemptyView for SET.
notifyViewnoemptyView 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" />
AttributeRequiredDefault or accepted values
securityModelyesv1/1, v2c/2, usm/3, or a positive model
securityNameyes1–32 UTF-8 octets
groupNamewhen active1–32 UTF-8 octets
storageTypenononVolatile; also volatile, 2, or 3
statusnoactive; 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" />
AttributeRequiredDefault or accepted values
groupNameyes1–32 UTF-8 octets
contextPrefixnoEmpty; at most 32 UTF-8 octets
securityModelyesModels above plus any or 0
securityLevelyesnoAuthNoPriv/1, authNoPriv/2, authPriv/3
contextMatchnoexact; or prefix
readView, writeView, notifyViewnoEmpty; at most 32 UTF-8 octets
storageTypenononVolatile; or volatile, 2, 3
statusnoactive; 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" />
AttributeRequiredDefaultMeaning
hostnameyesDestination hostname/IP, resolved when sending.
portno162Nonzero UDP destination port.
communitynopublicCommunity, at most 255 bytes.
versionno11 for v1 Trap-PDU or 2 for v2c.
isInformnonoUse INFORM when yes; invalid with version 1.
enablednoyesDisabled 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" />
AttributeRequiredDefaultMeaning
hostnameyesDestination hostname or IP address.
portno162Nonzero UDP port.
userNameyesUSM name, 1–32 UTF-8 octets.
authby levelabsentAuthentication protocol.
authPasswordfor password authabsentAuthentication password.
authKeyfor localized-key authabsentLocalized hexadecimal authentication key.
privnoDES with privacyPrivacy protocol.
privPasswordfor password privacyabsentPrivacy password.
privKeyfor localized-key privacyabsentLocalized hexadecimal privacy key.
engineIDfor raw keysabsentEngine against which the keys were localized.
contextNamenoemptyScoped-PDU context.
isInformnonoSelects INFORM instead of trap.
enablednoyesWhether 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 start hook calls its collector and publish_*.
  • The collector returns the expected rows or scalar Some values.
  • 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 public community 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

TermMeaning in MIBGen
Entry MIBA selected file containing a module's DEFINITIONS ::= BEGIN; imports are followed automatically.
TargetA selected table, OID subtree/group, or OBJECT-GROUP.
ProviderRust code that owns MIB objects and supplies live instances and values.
Scalar instanceA scalar object's concrete .0 instance.
Table row indexThe ordered values that form a table instance suffix.
SchemaParsed MIB structure, syntax, access, indexes, and OIDs.
SnapshotOne internally consistent set of scalar values or table rows.
PublicationValidating and atomically replacing a provider snapshot.
Built-in targetA selected target implemented by the standard agent runtime rather than generated custom code.
Engineer-owned fileA file created once that Add and Synchronize never overwrite.
Generator-owned fileA deterministic file managed and hash-checked by MIBGen.
AddIntroduce new targets without rewriting existing engineer-owned providers.
CheckPreview schema synchronization without writing.
SynchronizeRegenerate schema-owned files for existing targets after MIB changes.
VACMSNMPv3 View-based Access Control Model.
USMSNMPv3 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.