# Scripting with NETCONF
NETCONF (Network Configuration Protocol) provides a standardized mechanism for
managing network devices using XML-based RPC operations over SSH (port 830).
This guide shows practical examples for interacting with Infix using NETCONF.
NETCONF offers robust capabilities for network automation:
- **Transactional operations**: Validate before commit, rollback on error
- **Fine-grained locking**: Prevent concurrent configuration conflicts
- **Structured data**: XML with YANG schema validation
- **Standardized operations**: Get, edit-config, copy-config, etc.
## NETCONF vs RESTCONF
Both protocols use the same YANG data models, but differ in approach:
| Feature | NETCONF | RESTCONF |
|------------|--------------------|---------------------------------|
| Transport | SSH | HTTPS |
| Encoding | XML | JSON/XML |
| Operations | RPC-based | REST/HTTP methods |
| Best for | Automation scripts | Web integration, simple queries |
Choose NETCONF when you need:
- Transactional configuration changes
- Configuration validation before commit
- Locking to prevent concurrent changes
- Integration with existing NETCONF tooling
Choose RESTCONF for:
- Simple queries and updates
- Web-based applications
- When you prefer JSON over XML
- RESTful API patterns
## Quick Start with netopeer2-cli
`netopeer2-cli` is an interactive NETCONF client, useful for learning and
testing. Install it:
```bash
~$ sudo apt install netopeer2-cli
```
Connect to your Infix device:
```bash
~$ netopeer2-cli
> connect --host example.local --login admin
admin@example.local password:
> status
Current NETCONF session:
ID : 1
Host : example.local
Port : 830
Transport : SSH
Capabilities: 35
```
### Basic Operations in netopeer2-cli
**Get entire configuration:**
```
> get-config --source running
```
**Get specific subtree (hostname):**
```
> get-config --source running --filter-xpath /system/hostname
example
```
**Get operational state:**
```
> get --filter-xpath /interfaces
```
**Edit configuration:**
```
> edit-config --target candidate --config=/tmp/config.xml
> commit
```
**Disconnect:**
```
> disconnect
> quit
```
## Discovery & Common Patterns
Before working with specific configuration items, you often need to discover
what exists on the system. This section shows common discovery patterns and
practical workflows.
### Discovering Available Interfaces
**List all interface names:**
```xml
```
Using netopeer2-cli:
```
> get --filter-xpath /interfaces/interface/name
```
This returns all interface names, useful for iterating through interfaces
in scripts.
### Get All YANG Capabilities
Discover which YANG modules and features are available:
```
> status
```
Or programmatically via the `` message capabilities received during
connection establishment.
### Get Entire Running Configuration
Useful for exploration or backup:
```xml
```
Using netopeer2-cli:
```
> get-config --source running
```
### Common Workflow Patterns
#### Pattern 1: Find interface by IP address
Get all interfaces with their IPs, then filter:
```
> get --filter-xpath /interfaces
```
Parse the XML output to find which interface has the desired IP.
#### Pattern 2: Check which interfaces are down
```
> get --filter-xpath /interfaces/interface/oper-status
```
Look for interfaces with `down`.
#### Pattern 3: Get interface statistics for monitoring
```xml
```
Returns in-octets, out-octets, in-errors, out-errors for all interfaces.
## Scripting with netconf-client
[netconf-client](https://github.com/wires-se/netconf-client) is a lightweight
Python-based NETCONF client designed for scripting and automation.
### Installation
```bash
~$ pip install netconf-client
```
Or clone and install from source:
```bash
~$ git clone https://github.com/wires-se/netconf-client.git
~$ cd netconf-client
~$ pip install .
```
### Basic Usage
The client provides a simple command-line interface:
```bash
~$ netconf-client --host example.local --user admin --password admin
```
Common operations:
- `get-config` - Retrieve configuration
- `edit-config` - Modify configuration
- `get` - Retrieve operational state
- `copy-config` - Copy between datastores
- `lock/unlock` - Lock datastores
- `commit` - Commit candidate configuration
### Python API
You can also use netconf-client as a Python library:
```python
from netconf_client.client import NetconfClient
# Connect
client = NetconfClient(
host='example.local',
username='admin',
password='admin'
)
# Get configuration
config = client.get_config(source='running')
print(config)
# Edit configuration
xml_config = """
newhostname
"""
client.edit_config(target='candidate', config=xml_config)
client.commit()
# Close connection
client.close()
```
## Configuration Examples
### Read Hostname
**XML request:**
```xml
```
**Using netopeer2-cli:**
```
> get-config --source running --filter-xpath /system/hostname
```
**Using netconf-client:**
```bash
~$ netconf-client --host example.local --user admin \
get-config --source running --xpath /system/hostname
```
**Response:**
```xml
example
```
### Set Hostname
**XML request:**
```xml
newhostname
```
**Using netopeer2-cli:**
Save the config to `/tmp/hostname.xml`:
```xml
newhostname
```
Then apply:
```
> edit-config --target candidate --config=/tmp/hostname.xml
> commit
```
**Using netconf-client:**
```bash
~$ cat > hostname.xml <
newhostname
EOF
~$ netconf-client --host example.local --user admin \
edit-config --target candidate --config hostname.xml
~$ netconf-client --host example.local --user admin commit
```
### Add IP Address to Interface
Save the config to `ip-config.xml`:
```xml
eth0
192.168.1.100
24
```
**Using netconf-client:**
```bash
~$ netconf-client --host example.local --user admin \
edit-config --target candidate --config ip-config.xml
~$ netconf-client --host example.local --user admin commit
```
### Copy Running to Startup
**XML request:**
```xml
```
**Using netopeer2-cli:**
```
> copy-config --source running --target startup
```
**Using netconf-client:**
```bash
~$ netconf-client --host example.local --user admin \
copy-config --source running --target startup
```
## Operational Data Examples
### Read Interface State
**XML request:**
```xml
eth0
```
**Using netopeer2-cli:**
```
> get --filter-xpath /interfaces/interface[name='eth0']
```
**Using netconf-client:**
```bash
~$ netconf-client --host example.local --user admin \
get --xpath "/interfaces/interface[name='eth0']"
```
This returns operational state including admin/oper status, statistics,
MAC address, MTU, and IP addresses.
### Read All Interfaces
**Using netopeer2-cli:**
```
> get --filter-xpath /interfaces
```
**Using netconf-client:**
```bash
~$ netconf-client --host example.local --user admin \
get --xpath /interfaces
```
### Read Routing Table
**Using netconf-client:**
```bash
~$ netconf-client --host example.local --user admin \
get --xpath "/routing/ribs/rib[name='ipv4-default']"
```
### Read OSPF Neighbors
**Using netconf-client:**
```bash
~$ netconf-client --host example.local --user admin \
get --xpath "/routing/control-plane-protocols/control-plane-protocol[type='ietf-ospf:ospfv2'][name='default']/ietf-ospf:ospf"
```
## Advanced Scripting
### Python Script: Backup Configuration
```python
#!/usr/bin/env python3
from netconf_client.client import NetconfClient
from datetime import datetime
import sys
def backup_config(host, user, password, output_file):
try:
# Connect
client = NetconfClient(host=host, username=user, password=password)
# Get running config
config = client.get_config(source='running')
# Save to file with timestamp
timestamp = datetime.now().strftime('%Y%m%d-%H%M%S')
filename = f"{output_file}-{timestamp}.xml"
with open(filename, 'w') as f:
f.write(config)
print(f"Configuration backed up to {filename}")
client.close()
return 0
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
return 1
if __name__ == '__main__':
if len(sys.argv) != 5:
print(f"Usage: {sys.argv[0]} ")
sys.exit(1)
sys.exit(backup_config(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4]))
```
Usage:
```bash
~$ chmod +x backup.py
~$ ./backup.py example.local admin admin config-backup
Configuration backed up to config-backup-20250102-143022.xml
```
### Python Script: Monitor Interface Statistics
```python
#!/usr/bin/env python3
from netconf_client.client import NetconfClient
import xml.etree.ElementTree as ET
import time
import sys
def get_interface_stats(client, interface):
"""Get interface statistics"""
xpath = f"/interfaces/interface[name='{interface}']/statistics"
data = client.get(filter_xpath=xpath)
# Parse XML to extract counters
root = ET.fromstring(data)
ns = {'if': 'urn:ietf:params:xml:ns:yang:ietf-interfaces'}
stats = {}
for stat in root.findall('.//if:statistics/*', ns):
stats[stat.tag.split('}')[1]] = int(stat.text)
return stats
def monitor_interface(host, user, password, interface, interval=5):
"""Monitor interface statistics"""
client = NetconfClient(host=host, username=user, password=password)
print(f"Monitoring {interface} on {host} (Ctrl-C to stop)")
print(f"{'Time':<20} {'RX Packets':<15} {'TX Packets':<15} {'RX Bytes':<15} {'TX Bytes':<15}")
print("-" * 80)
try:
while True:
stats = get_interface_stats(client, interface)
timestamp = time.strftime('%Y-%m-%d %H:%M:%S')
print(f"{timestamp:<20} "
f"{stats.get('in-unicast-pkts', 0):<15} "
f"{stats.get('out-unicast-pkts', 0):<15} "
f"{stats.get('in-octets', 0):<15} "
f"{stats.get('out-octets', 0):<15}")
time.sleep(interval)
except KeyboardInterrupt:
print("\nMonitoring stopped")
finally:
client.close()
if __name__ == '__main__':
if len(sys.argv) < 5:
print(f"Usage: {sys.argv[0]} [interval]")
sys.exit(1)
interval = int(sys.argv[5]) if len(sys.argv) > 5 else 5
monitor_interface(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], interval)
```
Usage:
```bash
~$ chmod +x monitor.py
~$ ./monitor.py example.local admin admin eth0 2
Monitoring eth0 on example.local (Ctrl-C to stop)
Time RX Packets TX Packets RX Bytes TX Bytes
--------------------------------------------------------------------------------
2025-01-02 14:35:10 12453 8932 1847392 892341
2025-01-02 14:35:12 12489 8967 1851204 895673
...
```
### Shell Script: Batch Configuration
```bash
#!/bin/bash
# Apply configuration to multiple devices
DEVICES="device1.local device2.local device3.local"
USER="admin"
PASSWORD="admin"
CONFIG_FILE="$1"
if [ -z "$CONFIG_FILE" ]; then
echo "Usage: $0 "
exit 1
fi
for device in $DEVICES; do
echo "Configuring $device..."
# Edit candidate
netconf-client --host "$device" --user "$USER" --password "$PASSWORD" \
edit-config --target candidate --config "$CONFIG_FILE"
if [ $? -eq 0 ]; then
# Commit if edit succeeded
netconf-client --host "$device" --user "$USER" --password "$PASSWORD" commit
echo " ✓ $device configured successfully"
else
echo " ✗ $device configuration failed"
fi
done
```
## Other NETCONF Tools
### ncclient (Python)
Popular Python library for NETCONF:
```bash
~$ pip install ncclient
```
Example:
```python
from ncclient import manager
with manager.connect(host='example.local', port=830,
username='admin', password='admin',
hostkey_verify=False) as m:
# Get config
c = m.get_config(source='running')
print(c)
```
### Ansible
Ansible includes NETCONF modules for automation:
```yaml
- name: Get interface config
netconf_get:
source: running
filter:
```
### Cisco Tools
- **NSO (Network Services Orchestrator)**: Enterprise orchestration platform
- **YANG Suite**: Web-based YANG exploration and testing tool
- **Cisco pyATS**: Network test automation
## Troubleshooting
### Enable NETCONF Debugging
For netconf-client, use verbose mode:
```bash
~$ netconf-client --host example.local --user admin --verbose get-config
```
For netopeer2-cli, enable debug output:
```
> debug 1
> get-config --source running
```
### Common Issues
**Connection refused:**
- Verify SSH is running on port 830: `ssh -p 830 admin@example.local`
- Check firewall rules
**Authentication failed:**
- Verify credentials
- Check user has NETCONF access permissions
**Operation not supported:**
- Verify NETCONF capability: `netopeer2-cli` → `status` → check capabilities
- Some operations require specific YANG modules
## References
- [NETCONF Protocol (RFC 6241)](https://datatracker.ietf.org/doc/html/rfc6241)
- [netconf-client on GitHub](https://github.com/wires-se/netconf-client)
- [netopeer2 Documentation](https://github.com/CESNET/netopeer2)
- [YANG Data Modeling Language (RFC 7950)](https://datatracker.ietf.org/doc/html/rfc7950)
- [ietf-interfaces YANG module](https://datatracker.ietf.org/doc/html/rfc8343)
- [ietf-system YANG module](https://datatracker.ietf.org/doc/html/rfc7317)
- [ncclient Documentation](https://ncclient.readthedocs.io/)