# VPP SNMP AgentX Bridge

A Go application that bridges VPP (Vector Packet Processing) interface statistics to SNMP using the
AgentX protocol. It queries VPP interface counters and exposes them via the standard IF-MIB
for SNMP monitoring.

## Features

- **Real-time VPP interface statistics** via SNMP
- **Standard IF-MIB compliance** (ifXTable)
- **AgentX protocol support** (TCP and Unix sockets)
- **Configurable interface index offset** to avoid conflicts
- **Configurable polling intervals**
- **Thread-safe operation** with proper synchronization

## Architecture

```
VPP Stats Socket → VPP Stats Client → Interface MIB → AgentX → SNMPd
```

The application consists of four main components:

1. **VPP Stats Client** (`vppstats/`): Connects to VPP stats socket and retrieves interface counters
2. **Interface MIB** (`ifmib/`): Maps VPP statistics to SNMP IF-MIB structure
3. **AgentX Client** (`agentx/`): Handles AgentX protocol connection and MIB registration
4. **Main Application**: Orchestrates the components and handles configuration

## Build Instructions

### Development Build

```bash
go build -o govpp-snmp-agentx .
```

### Static Binary Build

For deployment without Go runtime dependencies:

```bash
# Linux static binary
CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-extldflags "-static"' -o govpp-snmp-agentx .

# Cross-compile for different architectures
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -ldflags '-extldflags "-static"' -o govpp-snmp-agentx-linux-amd64 .
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -a -ldflags '-extldflags "-static"' -o govpp-snmp-agentx-linux-arm64 .
```

### Release Build with Version Info

```bash
VERSION=$(git describe --tags --always --dirty)
BUILD_TIME=$(date -u '+%Y-%m-%d_%H:%M:%S')
CGO_ENABLED=0 go build -ldflags "-X main.version=${VERSION} -X main.buildTime=${BUILD_TIME}" -o govpp-snmp-agentx .
```

## Usage

### Basic Usage

```bash
# Run with default settings
./govpp-snmp-agentx

# Run with custom AgentX address
./govpp-snmp-agentx -agentx.addr 127.0.0.1:705

# Run with Unix socket AgentX connection
./govpp-snmp-agentx -agentx.addr /var/agentx/master
```

### Command Line Flags

#### General Application Flags

| Flag | Default | Description |
|------|---------|-------------|
| `-debug` | `false` | Enable debug logging |
| `-vppcfg` | `""` | VPP configuration YAML file to read interface descriptions from |

#### AgentX Module Flags

| Flag | Default | Description |
|------|---------|-------------|
| `-agentx.addr` | `localhost:705` | AgentX master agent address (hostname:port or Unix socket path) |

#### VPP Statistics Module Flags

| Flag | Default | Description |
|------|---------|-------------|
| `-vppstats.api.addr` | `/var/run/vpp/api.sock` | VPP API socket path |
| `-vppstats.stats.addr` | `/var/run/vpp/stats.sock` | VPP statistics socket path |
| `-vppstats.period` | `10` | Interval in seconds for querying VPP interface stats |
| `-vppstats.ifindex-offset` | `1000` | Offset to add to VPP interface indices for SNMP |

### Examples

```bash
# Enable debug logging
./govpp-snmp-agentx -debug

# Custom polling interval (5 seconds)
./govpp-snmp-agentx -vppstats.period 5

# Custom VPP stats socket
./govpp-snmp-agentx -vppstats.stats.addr /custom/path/stats.sock

# Custom VPP API socket
./govpp-snmp-agentx -vppstats.api.addr /custom/path/api.sock

# Custom interface index offset (start at 2000)
./govpp-snmp-agentx -vppstats.ifindex-offset 2000

# With VPP configuration file for interface descriptions
./govpp-snmp-agentx -vppcfg /etc/vpp/vppcfg.yaml

# Full configuration
./govpp-snmp-agentx \
  -agentx.addr /var/agentx/master \
  -debug \
  -vppcfg /etc/vpp/vppcfg.yaml \
  -vppstats.api.addr /var/run/vpp/api.sock \
  -vppstats.stats.addr /var/run/vpp/stats.sock \
  -vppstats.period 5 \
  -vppstats.ifindex-offset 1000
```

## VPP Configuration File

The `-vppcfg` flag accepts a YAML configuration file that describes VPP interfaces and their descriptions. This file is used to populate the `ifAlias` (.18) field in the ifXTable with meaningful interface descriptions.

### YAML Format Example

```yaml
interfaces:
  GigabitEthernet82/0/0:
    description: 'Infra: Management interface'
  TenGigabitEthernet1/0/2:
    description: 'Infra: Core uplink'
    sub-interfaces:
      100:
        description: 'Cust: Customer VLAN 100'
      200:
        description: 'Transit: Provider VLAN 200'
loopbacks:
  loop0:
    description: 'Core: Router loopback'
```

### Description Mapping

- **Main interfaces**: Use the `description` field directly
- **Sub-interfaces**: Use the `description` field from the `sub-interfaces` section
- **Loopbacks**: Use the `description` field from the `loopbacks` section
- **Fallback**: If no description is found, the interface name is used as the alias

## SNMP Interface Mapping

VPP interfaces are mapped to SNMP indices with a configurable offset (default 1000):

- **VPP Interface 0** → **SNMP Index 1000**
- **VPP Interface 1** → **SNMP Index 1001**
- **VPP Interface N** → **SNMP Index (N + offset)**

## Supported MIB Objects

The application implements the ifXTable (1.3.6.1.2.1.31.1.1.1) with the following objects:

| OID | Object | Type | Description |
|-----|--------|------|-------------|
| `.1.{index}` | ifName | DisplayString | Interface name |
| `.2.{index}` | ifInMulticastPkts | Counter32 | RX multicast packets |
| `.3.{index}` | ifInBroadcastPkts | Counter32 | RX broadcast packets |
| `.4.{index}` | ifOutMulticastPkts | Counter32 | TX multicast packets |
| `.5.{index}` | ifOutBroadcastPkts | Counter32 | TX broadcast packets |
| `.6.{index}` | ifHCInOctets | Counter64 | RX bytes (high capacity) |
| `.7.{index}` | ifHCInUcastPkts | Counter64 | RX unicast packets (high capacity) |
| `.8.{index}` | ifHCInMulticastPkts | Counter64 | RX multicast packets (high capacity) |
| `.9.{index}` | ifHCInBroadcastPkts | Counter64 | RX broadcast packets (high capacity) |
| `.10.{index}` | ifHCOutOctets | Counter64 | TX bytes (high capacity) |
| `.11.{index}` | ifHCOutUcastPkts | Counter64 | TX unicast packets (high capacity) |
| `.12.{index}` | ifHCOutMulticastPkts | Counter64 | TX multicast packets (high capacity) |
| `.13.{index}` | ifHCOutBroadcastPkts | Counter64 | TX broadcast packets (high capacity) |
| `.18.{index}` | ifAlias | DisplayString | Interface description/alias (from VPP config or interface name) |

## SNMP Query Examples

### Query Interface Names

```bash
# Get all interface names
snmpwalk -v2c -c public localhost 1.3.6.1.2.1.31.1.1.1.1

# Get specific interface name (interface 0 with default offset)
snmpget -v2c -c public localhost 1.3.6.1.2.1.31.1.1.1.1.1000
```

### Query Interface Descriptions

```bash
# Get all interface descriptions/aliases
snmpwalk -v2c -c public localhost 1.3.6.1.2.1.31.1.1.1.18

# Get specific interface description (interface 0 with default offset)
snmpget -v2c -c public localhost 1.3.6.1.2.1.31.1.1.1.18.1000
```

### Query Interface Counters

```bash
# Get RX bytes for interface 0
snmpget -v2c -c public localhost 1.3.6.1.2.1.31.1.1.1.6.1000

# Get TX bytes for interface 1
snmpget -v2c -c public localhost 1.3.6.1.2.1.31.1.1.1.10.1001

# Walk all interface counters
snmpwalk -v2c -c public localhost 1.3.6.1.2.1.31.1.1.1
```

### Query with Custom Offset

If running with `-vppstats.ifindex-offset 2000`:

```bash
# Interface 0 counters at index 2000
snmpget -v2c -c public localhost 1.3.6.1.2.1.31.1.1.1.6.2000
```

## Prerequisites

### VPP Requirements

- VPP must be running with stats socket enabled
- Stats socket accessible at `/var/run/vpp/stats.sock` (or custom path)
- Application must have read permissions on the stats socket

### SNMP Requirements

- SNMP master agent running (net-snmp's snmpd)
- AgentX protocol enabled in snmpd configuration
- AgentX socket accessible (TCP port 705 or Unix socket)

### SNMP Agent Configuration

Add to `/etc/snmp/snmpd.conf`:

```
# Enable AgentX
master agentx
agentXSocket tcp:localhost:705
# or for Unix socket:
# agentXSocket /var/agentx/master
```

## Troubleshooting

### Common Issues

1. **"Failed to connect to VPP stats"**
   - Check VPP is running: `vppctl show version`
   - Verify stats socket exists: `ls -la /var/run/vpp/stats.sock`
   - Check permissions on stats socket

2. **"Failed to dial AgentX"**
   - Verify SNMP agent is running: `systemctl status snmpd`
   - Check AgentX is enabled in snmpd.conf
   - Test AgentX socket: `netstat -ln | grep 705`

3. **"Failed to register IF-MIB: ErrorDuplicateRegistration"**
   - Another agent is already serving the IF-MIB
   - Check with: `snmpwalk -v2c -c public localhost 1.3.6.1.2.1.31.1.1.1`

4. **"Retrieved stats for 0 interfaces"**
   - VPP may have no interfaces configured
   - Check VPP interfaces: `vppctl show interface`

### Debug Commands

```bash
# Check VPP interfaces
vppctl show interface

# Check VPP stats
vppctl show stats

# Test SNMP master agent
snmpwalk -v2c -c public localhost 1.3.6.1.2.1.1

# Check AgentX registration
snmpwalk -v2c -c public localhost 1.3.6.1.2.1.31.1.1.1
```

## License

This project uses the LGPL 3.0 licensed go-agentx library. It has been modified due to a bug,
see details in [[GitHub PR#7](https://github.com/posteo/go-agentx/pull/11)], and as such is
licensed also LGPL 3.0. The go-agentx source code in this project will be removed once the
upstream PR is merged.

## Contributing

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests if applicable
5. Submit a pull request

## Version History

- **v1.0.0**: Initial release with IF-MIB support
- **v1.1.0**: Added configurable interface index offset
- **v1.2.0**: Added Unix socket support for AgentX