Skip to content

Yangerd - #1536

Merged
mattiaswal merged 21 commits into
mainfrom
yangerd
Oct 24, 2026
Merged

Yangerd#1536
mattiaswal merged 21 commits into
mainfrom
yangerd

Conversation

@mattiaswal

@mattiaswal mattiaswal commented Jun 12, 2026 •

Copy link
Copy Markdown
Contributor

Description

Checklist

Tick relevant boxes, this PR is-a or has-a:

  • Bugfix
    • Regression tests
    • ChangeLog updates (for next release)
  • Feature
    • YANG model change => revision updated?
    • Regression tests added?
    • ChangeLog updates (for next release)
    • Documentation added?
  • Test changes
    • Checked in changed Readme.adoc (make test-spec)
    • Added new test to group Readme.adoc and yaml file
  • Code style update (formatting, renaming)
  • Refactoring (please detail in commit messages)
  • Build related changes
  • Documentation content changes
    • ChangeLog updated (for major changes)
  • Other (please describe):

@mattiaswal mattiaswal added the ci:main Build default defconfig, not minimal label Jun 12, 2026
@mattiaswal
mattiaswal force-pushed the yangerd branch 3 times, most recently from 3ec2747 to 71d50ea Compare June 19, 2026 09:38
@mattiaswal
mattiaswal force-pushed the yangerd branch 3 times, most recently from 7537929 to 8e6b2a1 Compare August 17, 2026 11:52
@mattiaswal
mattiaswal force-pushed the yangerd branch 4 times, most recently from 01b4d8f to ba1a1b3 Compare October 5, 2026 11:22
@mattiaswal
mattiaswal force-pushed the yangerd branch 6 times, most recently from bcaa779 to 1dc7c7e Compare October 12, 2026 15:51
@mattiaswal
mattiaswal force-pushed the yangerd branch 6 times, most recently from 75139f7 to 293898e Compare October 16, 2026 22:40
@mattiaswal mattiaswal removed the ci:main Build default defconfig, not minimal label Oct 18, 2026
@mattiaswal mattiaswal added the ci:main Build default defconfig, not minimal label Oct 19, 2026
@mattiaswal
mattiaswal force-pushed the yangerd branch 2 times, most recently from 428b415 to c292ba9 Compare October 21, 2026 06:15

@troglobit troglobit left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️ Awesome work on this, approved!

@mattiaswal
mattiaswal force-pushed the yangerd branch 6 times, most recently from 8bd79ab to 4ba048a Compare October 24, 2026 17:14
A Go daemon replacing the Python yanger scripts that statd forked on
every GET.  It keeps operational state in memory, driven by netlink,
nl80211, D-Bus, ZAPI, inotify and the FRR vty sockets, polls only what
has no events, and serves it to statd over a Unix socket as JSON.
Covers interfaces, routing, system, hardware, NTP, LLDP, containers,
firewall, DHCP, TFTP, PTP and WiFi.  The RIB comes from zebra when
built with FRR and from the kernel table otherwise.

Interface queries go through a long-lived 'ip -batch' process.  A
failing command prints nothing, [] or [{}] before its "Command failed"
line depending on the iproute2 version, and stdout and stderr race on
separate pipes, so the pipes are merged and every command is followed
by one that always fails, whose failure line delimits the answer.

inotify and the wireguard device dump are thin layers over x/sys/unix
and the mdlayher/genetlink stack already used for ethtool and nl80211,
rather than fsnotify and wgctrl, which brought their BSD, Darwin and
Windows backends and x/crypto into vendor.  The inotify watcher must
not leave a goroutine blocked in poll(2) per event: each pinned an OS
thread, 1300 of them after an hour of tests on a DUT.

A route change is the one event FRR gives for a neighbor loss, so the
ZAPI watcher pokes the routing collector instead of waiting for the
10 s poll, and the rauc software object is re-read once rauc appears
on the bus, since on the styx boards yangerd came up before it.

The bridge FDB is read with -s from a bridge batch of its own, for
every bridge at start and again when a bridge appears, and shaped per
VLAN or at the bridge level as the Python yanger did.  Entries are
tracked by bridge index: link and neighbour events come on separate
channels, and on a slow box the delete of a replaced bridge arrived
after the FDB events of its successor.  The canary after a batch
restart carries no dev filter, bridge leaks it into every later
'fdb show'.

Signed-off-by: Mattias Walström <lazzer@gmail.com>
Buildroot builds with -mod=vendor and no network access.

Signed-off-by: Mattias Walström <lazzer@gmail.com>
Finit service with readiness notification.  Build-time feature flags
in /etc/default/yangerd mirror the packages selected, so yangerd only
runs the monitors that have something to monitor.

GOMEMLIMIT caps the Go heap at 64 MiB.  The live tree is under 1 MiB
but RSS drifted past 100 MiB, enough for the OOM killer to pick
yangerd while rauc held a bundle in tmpfs on a 512 MiB box.
Dependabot tracks the Go dependencies on the same weekly schedule as
webui and netbrowse, and re-vendors on every bump.

Signed-off-by: Mattias Walström <lazzer@gmail.com>
Replaces forking the Python yanger scripts with a query over yangerd's
Unix socket.  Nested subscriptions graft only the requested node into
the parent sysrepo passes, control-plane-protocols is one merged
subscription so config-only instances stay, and an empty answer from a
yangerd still starting is no data rather than an error.  Entries
libyang rejects are dropped instead of failing the whole GET.

Signed-off-by: Mattias Walström <lazzer@gmail.com>
Nudges yangerd to re-read its polled sources after a configuration
change.  Best effort, the commit must not fail when yangerd is not
installed or not yet running.

Signed-off-by: Mattias Walström <lazzer@gmail.com>
Room for yangerd on the virtual DUTs.

Signed-off-by: Mattias Walström <lazzer@gmail.com>
Operational data now comes from yangerd.  Interfaces, routes and
containers are reactive, the rest is polled, so checks that read a
value once right after a change now poll with until().  Also dumps AP
and client state when a WiFi check gives up, and updates the generated
test specifications.

Signed-off-by: Mattias Walström <lazzer@gmail.com>
The derived address is numbered by the interface's position among the
interfaces on its radio, sorted by name.  Renaming the access points to
wifi1-home and wifi1-guest swapped their order, so the home AP got the
third address and the test failed in CI, and the later steps that add
wifi10 between wifi1 and wifi2 still used the old names anyway.

Signed-off-by: Mattias Walström <lazzer@gmail.com>
Each daemon keeps its design rules next to its code; the skill only
pointed at the WebUI's.

Signed-off-by: Mattias Walström <lazzer@gmail.com>
Signed-off-by: Mattias Walström <lazzer@gmail.com>
A generated /etc/default/yangerd was a second copy of the Buildroot
selection that could drift from what the model advertises.  confd
installs the optional modules and enables their features from the
same options, and ietf-yang-library reports them, so read sysrepo's
module list once at start instead.  The env file keeps only the log
level and the heap limit.

Signed-off-by: Mattias Walström <lazzer@gmail.com>
Both decide what the device has from the YANG model, the WebUI from
ietf-yang-library over RESTCONF, yangerd from the sysrepo module list
the library is served from.  One Go module holds the table and both
parsers, vendored into each, so a new optional part is added in one
place.

Signed-off-by: Mattias Walström <lazzer@gmail.com>
Nothing checked router-ports, which yangerd now reports per VLAN.

Signed-off-by: Mattias Walström <lazzer@gmail.com>
On boards whose factory config bridges the management port, the reset
tears down the bridge carrying the NETCONF session and the action never
answers.  The reboot alone restores the baseline: the startup override
was used up by the factory boot, so the test-config is loaded again.

Signed-off-by: Mattias Walström <lazzer@gmail.com>
A switch learns and ages out addresses without telling the bridge, so
keeping the FDB current in operational data meant polling every bridge
with switch ports.  Read it when asked instead.

Signed-off-by: Mattias Walström <lazzer@gmail.com>
The developer guide, the statd README and the skill still sent anyone
working on operational data to the Python yanger, which statd no longer
runs.

Signed-off-by: Mattias Walström <lazzer@gmail.com>
statd no longer runs the Python yanger, so replaying its captured
commands tested dead code.  The fixtures are now read from the
operational datastore of a DUT, the data the CLI renders.

Signed-off-by: Mattias Walström <lazzer@gmail.com>
statd asks yangerd for operational data, so the yanger collectors, the
FRR and DHCP status scripts only they called, and the rtnetlink loop
that tracked last-change are dead code.

Signed-off-by: Mattias Walström <lazzer@gmail.com>
An interface handed to a container leaves the host link dump, and with
it the operational data.  Collect them again after every container
change and every link or address event in a container namespace, which
the host netlink subscriptions never see.

Signed-off-by: Mattias Walström <lazzer@gmail.com>
@mattiaswal
mattiaswal merged commit 6f399eb into main Oct 24, 2026
12 of 13 checks passed
@mattiaswal
mattiaswal deleted the yangerd branch October 24, 2026 21:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:main Build default defconfig, not minimal

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants