Christian Manivong c686fac55e fix(vlans): read bridge-vlan membership from UCI, repair stale tests
get_vlans() relied on `bridge vlan show` for port membership. On devices
whose BusyBox ships without the bridge/ip-full packages the command does
not exist, _send_command returns the shell error, and the parser silently
finds nothing in it. All that survived was the sub-interface fallback,
which restates the bridge topology (br-ap tagged, br-ap.10 untagged) and
never names the uplink port — the only port whose tagging matters.

Measured on two Sophos AP100 (BusyBox 1.37.0): eth0 was absent from the
output entirely, while UCI held ports='eth0:u*' for the management VLAN
and 'eth0:t' for the rest.

UCI bridge-vlan sections are now parsed as a second source. They are
readable without the bridge binary and describe the configured state.
Section collection goes through the type declaration, so named sections
(network.apbr_vlan10) are recognised alongside anonymous ones — the old
regex matched only @bridge-vlan[N], so a hand-built bridge was invisible
even for name lookup. Runtime data keeps precedence where it exists,
since that is what the kernel actually enforces.

Option values are kept raw through collection; stripping quotes there
would collapse ports='lan1:t' 'lan2:t' into a single mangled item.

Also repairs TestGetVlans, red on master since get_vlans() moved to
separate tagged/untagged lists while the tests still asserted the old
'interfaces' key, and TestGetFacts, which never learned about the
number_of_interfaces key get_facts() sets deliberately. Both had left
the interesting behaviour uncovered.
2026-08-17 22:50:08 +07:00
2026-05-29 09:10:40 +02:00
2026-05-29 09:10:40 +02:00
2026-05-29 09:10:40 +02:00

napalm-openwrt

NAPALM community driver for OpenWrt routers and access-points.

Communicates over SSH using Netmiko (linux device type).
Requires OpenWrt 19.07 or newer.

Tested devices

Model OpenWrt version Tested
TP-Link TL-WR1043N/ND v5 23.05.3 ✅

Contributions for additional devices and firmware versions are welcome.

Requirements

Dependency Minimum version
Python 3.8
NAPALM 4.0
Netmiko 4.0

Installation

From source:

git clone https://github.com/napalm-automation-community/napalm-openwrt
cd napalm-openwrt
pip install -e .

Quick start

from napalm import get_network_driver

driver = get_network_driver("openwrt")
device = driver("192.168.1.1", "root", "")

device.open()

facts = device.get_facts()
print(facts)

interfaces = device.get_interfaces()
print(interfaces)

device.close()

Supported NAPALM getters

Getter Supported Notes
get_facts ✅ Uses /etc/openwrt_release, /tmp/sysinfo/model, /proc/uptime
get_interfaces ✅ Uses ip link show
get_interfaces_ip ✅ Uses ip addr show
get_interfaces_counters ✅ Uses /proc/net/dev
get_arp_table ✅ Uses ip neigh show
get_mac_address_table ✅ Uses bridge fdb show
get_config ✅ Uses uci export
get_environment ✅ CPU from /proc/stat, memory from /proc/meminfo
get_lldp_neighbors ✅ Requires lldpd package installed on device
get_lldp_neighbors_detail ✅ Requires lldpd package installed on device

Configuration management

Configuration is managed via UCI (Unified Configuration Interface).

Merge candidate

device.load_merge_candidate(config="""
uci set system.@system[0].hostname='my-router'
uci set network.lan.ipaddr='10.0.0.1'
""")

print(device.compare_config())
device.commit_config()

Replace candidate

with open("full-config.uci") as f:
    device.load_replace_candidate(config=f.read())

print(device.compare_config())
device.commit_config()

Rollback

# Reverts to the config state before the last commit_config call
device.rollback()

Development

# Create and activate a virtual environment
python -m venv .venv
source .venv/bin/activate

# Install with dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Lint
ruff check napalm_openwrt/
S
Description
No description provided
Readme
427 KiB
Languages
Python 100%