15 Commits
Author SHA1 Message Date
Christian Manivong 7103cefc41 refactor!: rename get_dot1x_config to get_dot1x_ports
SwitchDriver and AccessPointDriver both declared get_dot1x_config, but they
meant different things and returned different shapes — Dot1XPortDict per port on
a switch, Dot1XConfigDict per SSID on an access point. A device that is both
could not satisfy both contracts.

napalm-device-types v1.0 names them apart. This is the switch side.

BREAKING CHANGE: get_dot1x_config is now get_dot1x_ports on NetgearPlusDriver.
2026-08-21 12:50:10 +07:00
Christian Manivong efe004a295 fix(lldp): parse the v7 neighbour table, which uses a different command
get_lldp_neighbors() existed but spoke to the older CLI generation: it ran
`show lldp remote-device all` and expected FASTPATH-style `0/1` ports in
whitespace-separated columns. v7 firmware answers `Unknown command` — as it
does for `show lldp remote-device`, a bare `show lldp`, and the plural
`show lldp neighbors`. Only the singular works, though `show ?` lists `lldp`
plainly enough:

     Port |   Device ID       |     Port ID      |      SysName      | ...
     ---- + ----------------- + ---------------- + ----------------- + ...
       g9 | 10:01:02:44:37:26 |10:01:02:44:37:28 | pve-eze.eze.local | ...

Ports are named g9, and the columns are separated by `|` with irregular
padding, so splitting on whitespace tears the values apart. The port ID is
not always a port name either — a neighbour may identify its port by MAC.

_get_lldp_table() now branches on _detect_cli_v7() into a second parser, the
same shape get_mac_address_table() already uses for this divergence.
get_lldp_neighbors() itself is untouched.

Confirmed against a GS110TPv3 on 7.1.1.17: _detect_cli_v7() returns True
there, and the switch reports two neighbours it had never surfaced. Without
them NetOrk's map had nothing to draw for the site this switch serves, so
four APs and a firewall behind it stood unconnected.
2026-08-18 15:18:56 +07:00
Christian Manivong 5317af0be1 fix(config): drop the uptime line from get_config()
`show running-config` is preceded by a header block, and one of its lines
reports the system uptime. That value necessarily differs between any two
reads, so every caller comparing consecutive configs sees a change each
time.

Measured on a GS110TPv3 under NetOrk: 876 of 894 stored config snapshots
marked as changed, one git commit and one config_changed warning per poll,
while every other device at the same installation sat between 2 and 18. The
history was worthless for that switch — a genuine change would have been
invisible among hundreds of uptime diffs.

Only the uptime line is removed. Model, firmware version, serial and MAC are
stable and belong in a config backup; a changed firmware version is exactly
the kind of change worth recording.

netgear_plus is unaffected — its get_config() returns empty strings.

The first read after this lands reports one real change, since the line
disappears from the stored config. That is unavoidable and happens once.
2026-08-18 10:30:11 +07:00
Christian Manivong 20460e7a5a refactor(warnings): report raw signal only, no severity/presentation
get_device_warnings() now returns only {code, meta} — severity, title,
message, and action are resolved centrally by netork's
WARNING_CATALOG (netork/core/device_warnings.py), not by the driver.
Keeps this driver independent of netork and avoids per-vendor drift in
how the same warning code is presented.
2026-07-20 09:58:21 +02:00
Christian Manivong 46e419d232 fix(get_config): use paged send for show running-config/startup-config
"v7" CLI firmware has no "terminal length 0" equivalent (see
_send_paged_command's docstring), so a config long enough to paginate
emits "--More--" prompts that _send_command's expect_string=base_prompt
match never sees. On real hardware (GS110TPv3, 7 VLANs, 10 interfaces)
this hung every scheduled config-backup poll for 30s and failed with
"Pattern not detected: '<prompt>[>#]' in output.", so the config was
never actually backed up. get_mac_address_table()/get_vlans() already
use _send_paged_command() for the same reason on other long outputs;
get_config() now does too.

Also fixed tests/unit/test_driver.py's import/patch target
(napalm_netgear_plus -> napalm_netgear, the actual package name) —
the whole file has been uncollectable since its initial commit, no CI
was wired up here to catch it. And removed a dead unreachable
`return {"success": ..., "output": ...}` line after get_health_metrics's
real return (undefined names, ruff F821), unrelated leftover found
while fixing the above.
2026-07-10 09:54:29 +02:00
Christian Manivong 383563d714 fix(deps): pin paramiko>=5.0.0 (CVE-2026-44405) 2026-07-02 12:22:55 +02:00
Christian ManivongandClaude Sonnet 4.6 17a0b36dce feat: OUI_PREFIXES für MAC/ARP-Fingerprinting
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 15:41:45 +02:00
Christian ManivongandClaude Sonnet 4.6 36a239692b feat: Fingerprint-Attribute für Discovery-Scoring
Ergänzt DRIVER_NAME, HTTP_FINGERPRINT, SNMP_FINGERPRINT, SSH_FINGERPRINT,
PORT_SPECS und SNMP_OBJECT_ID_PREFIX gemäß docs/DISCOVERY_FINGERPRINTING.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 14:47:08 +02:00
Christian Manivong aef5eb1487 feat: include remote chassis MAC in LLDP neighbor entries
Enables MAC-based topology matching against devices that report their
own MAC but not a usable system name.
2026-06-12 21:08:26 +02:00
Christian ManivongandClaude Sonnet 4.6 96ae50551b fix: case-insensitive config prompt match and fast-fail fix_snmp on v7 CLI
_conf_prompt() only matched the legacy "(Config)" prompt, so on v7
"Cisco-like" CLI (lowercase "(config)") _enter_config_mode() blocked for
the full read_timeout - this was the cause of fix_snmp hanging.

_action_fix_snmp() also never returned a result on the legacy path, and
v7 firmware has no snmp-server/show snmp commands at all. It now detects
v7 CLI up front and returns a clear failure message instead of hanging.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 19:16:47 +02:00
Christian ManivongandClaude Sonnet 4.6 0ba59750d2 feat: add PoE config and LAG/trunk membership support
get_poe_status()/set_poe() implement PoE port config via the ProSafe CLI's
'power inline' interface sub-commands. get_interfaces() now enriches chN
LAG entries and their member ports with trunk_group/lag_members/lag_mode
by parsing 'show port-channel all'. New set_lag_members() adds/removes
members via addport/deleteport.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 14:47:27 +02:00
Christian ManivongandClaude Sonnet 4.6 5e2c6249fb feat: add get_health_metrics() via Netgear proprietary OIDs
SNMP health metrics using Netgear enterprise MIB (OID 4526) for
memory free/total and CPU utilization string parsing, plus IF-MIB counters.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 00:43:43 +02:00
Christian ManivongandClaude Sonnet 4.6 54fe6ddea1 fix: correct module import path and add SNMP_CAPABLE=False for Plus switches
- __init__.py imported from non-existent napalm_netgear_plus module; fixed to napalm_netgear
- NetgearPlusDriver.SNMP_CAPABLE = False signals HTTP-only device — suppresses
  misleading SNMP-not-configured warnings during device polls

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 13:28:04 +02:00
Christian ManivongandClaude Sonnet 4.6 64eb2551a4 feat: SNMP support — get_snmp_config(), fix_snmp for Smart switches
NetgearPlus: get_snmp_config() returns None (SNMP not accessible via HTTP API).
NetgearSmart: get_snmp_config() reads current community, fix_snmp configures
'snmp-server community public ro' via CLI.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 13:10:03 +02:00
Christian Manivong a8ce5a8033 initial commit 2026-05-29 09:13:59 +02:00