Add firewall address-sets: named sets of IP addresses and networks,
usable as zone sources for per-IP access control, issue #1189. Static
entries are part of the configuration; dynamic entries are managed at
runtime with new add/remove/flush actions, from the CLI or over
NETCONF/RESTCONF. Dynamic entries survive firewall configuration
changes but are not saved to the configuration. Sets with a timeout
expire their entries automatically.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
gen-hostname baked the last three MAC octets straight into the generated
hostname, so the actual MAC ended up stored in the configuration. Copy
that config to another device and its hostname no longer matched the
hardware.
Emit the %h and %m format specifiers and let confd expand them when the
config is applied, so the MAC is resolved per device and never written
to a saved config. This also drops the /run/system.json lookup.
Closes#1554
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
In netdag_gen_ethtool_autoneg() the unmapped and "exactly one entry"
checks already guarantee a forced PMD link mode is selected, but
Coverity cannot see the correlation and flags the later deref. Fold
!forced into the entry-count guard to make the invariant explicit.
Fixes Coverity CID 561388.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
lydx_get_cattr() yields NULL for an absent leaf or a failed radio
component lookup; that NULL was passed straight to strcmp() on several
WiFi paths (wifi_chan_to_freq, the wifi_gen_mesh width branches,
wifi_find_higher_band_twin, dep_radio_components), risking a crash.
Guard each value before use.
Fixes Coverity CID 561387, 561389, 561390, 561391, 561392.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
When a veth pair has one end in a container and the other in the host
namespace, removing it failed: the container end's teardown deleted the
whole pair, so the host end's own delete then failed ("Cannot find
device") and aborted the teardown, leaving the interface behind.
The host-namespace delete added for the both-ends-in-container case was
emitted for every container veth end. Restrict it to the primary end,
which for a host/container pair is the host end that already deletes the
pair itself.
Extend the container veth tests to remove the pair and verify it is gone,
covering both the single-end (regression) and both-ends teardown paths.
Fixes: #1546
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
crond shipped auto-enabled in finit (symlinked into enabled/), so it ran
on every boot. With no cron jobs /var/spool/cron/crontabs does not exist
and 'crond -f' exits non-zero, which finit then crash-loops until it gives
up ("Service crond keeps crashing, not restarting").
Ship crond available-only and let confd manage it: the schedule plugin
already rebuilds the crontab on every change, so enable + touch crond when
at least one consumer is active and disable it otherwise. No jobs, no
crond, no crash loop.
Signed-off-by: Mattias Walström <lazzer@gmail.com>
Previously at least one end of a veth pair had to remain in the host
namespace, because that end created and destroyed the pair. Assigning
both ends to containers left no one to create it.
Select a deterministic primary end so exactly one side creates the pair.
When the primary is itself a container interface, create the pair in the
host namespace before the container starts; CNI host-device then moves
each end into its container. Teardown is deferred to the container
removal script so the pair does not linger and block re-creation.
Drop the now-obsolete limitation notes from the documentation and YANG,
and add a regression test connecting two containers over a veth pair.
Fixes: #941
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Add conditional YANG feature 'web-ui' to infix-services.yang, set when
the webui is built. This feature is what the test now looks for to
determine if it should be skipped or not.
Also, clean up remnant of old test, which was entirely replaced by
Mattias' login/csrf test.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Two unrelated must expressions referenced schema nodes that don't exist,
emitting warnings on every schema load (and in netopeer2-cli):
- NTP: the iburst/burst deviations put the must on the leaf, so
"ntp:iburst"/"ntp:burst" resolved as a child of the leaf. Use ".".
- WireGuard: deref() of a key *-ref lands on the key's "name" leaf, so
"deref(.)/ks:public-key-format" looked under "name". Use
"deref(.)/../...", and descend into the "public-key" list for the
truststore public-key-bag.
Import ieee802-ethernet-interface@2025-09-10.yang, from IEEE 802.3.2-2025,
and companion ieee802-ethernet-phy-type.yang, replacing the 2019 revision.
Operational interface speed moves to ietf-interfaces:speed, RFC 8343,
eth:speed is now obsolete. Bump infix-interfaces.yang revision to track
the upgrade.
The CLI 'show interface' command renders interfaces as bottom-up layered
protocol rows. Ethernet interfaces a new IEEE link-mode row (1000baseT,
10GbaseLR, ...) is added with 'duplex: full|half' in the DATA column.
Without link the ethernet row is the first row. Tunnels and wifi follow
the same layering: gre/vxlan rows carry remote:/vni: tokens with optional
ethernet sub-row for the L2-bearing variants; wifi rows carry 'station' or
'access-point' ssid:, signal:, stations: tokens.
admin@bpi-76-8f-c2:/> show interface
⚑ INTERFACE PROTOCOL STATE DATA
⇅ lo loopback UP
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
⇅ br0 bridge DOWN
│ ethernet 32:2e:3f:76:8f:c2
│ ipv4 192.168.0.1/24 (static)
⇅ ├ lan0 bridge LOWER-DOWN
⇅ ├ lan1 bridge LOWER-DOWN
⇅ ├ lan2 bridge LOWER-DOWN
⇅ └ lan3 bridge LOWER-DOWN
⇅ gre0 gre UP remote: 198.51.100.7
ipv4 10.255.0.1/30 (static)
⇅ sfp1 ethernet DOWN ca:59:f0:77:80:5b
⇅ wan 1000baseT UP duplex: full
ethernet 32:2e:3f:76:8f:c2
ipv4 192.168.0.235/24 (dhcp)
ipv6 fe80::302e:3fff:fe76:8fc2/64 (link-layer)
⇅ wan.10 vlan UP vid: 10
│ ipv4 10.0.10.1/24 (static)
└ wan
⇅ wan.10.20 vlan UP vid: 20
│ ipv4 10.0.10.20/28 (static)
└ wan.10
⇅ wifi0 wifi UP station ssid: corp-net signal: good
ethernet dc:a6:32:00:11:22
ipv4 192.168.7.42/24 (dhcp)
yanger populates phy-type and pmd-type from a static ETHTOOL link-mode
identity table keyed on (port, speed, duplex). Both leaves are populated
for unambiguous media (copper, DAC, copper-T); for generic fiber where
the (port, speed, duplex) tuple can map to multiple PMDs (SR vs LR vs
ER, etc.) only the phy-type family identity is emitted — guessing the
PMD would be misleading. cli_pretty prefers pmd-type (specific) and
falls back to phy-type (family) for display.
yanger also emits ietf-interfaces:speed and fixes a long-standing
'auto-negotation' typo (yanger had never matched ethtool's correctly-
spelled JSON field, so operational auto-negotiation always read
'unknown').
Filling the WG's gap on fixed-speed config
------------------------------------------
IEEE Std 802.3.2-2025 obsoleted the eth:speed leaf without providing a
config-true replacement; the standards-correct way to express what
older Infix configurations called 'fixed speed' is to restrict the set
of PMDs auto-negotiation may advertise. Augment auto-negotiation with
two leaf-lists:
auto-negotiation/advertised-pmd-types config-true, leaf-list of pmd-type
ethernet/supported-pmd-types config-false, leaf-list of pmd-type
Pinning a port to a single mode is now expressed as a single-entry
advertised-pmd-types list. The kernel-supported set is exposed as
operational state for diagnosis — SFP/SFP+ cages report the inserted
module's capabilities, narrowing the list to a single PMD when the
optic only supports one mode (as suggested by @wkz in PR review).
When the supported list collapses to a single entry, yanger uses it
to refine the operational pmd-type leaf — more accurate than the
(port, speed, duplex) lookup for fiber.
confd C apply path (src/confd/src/ieee802-ethernet-interface.c)
translates each advertised pmd-type identity to the corresponding
ETHTOOL_LINK_MODE_*_BIT_*, ORs them into a mask, and emits
'ethtool --change <if> autoneg on advertise 0x<mask>'. An empty
list keeps the historical default of advertising every supported
mode. The (legacy) 'auto-negotiation/enable = false' + speed/duplex
branch is removed — it has no model representation any more.
cli_pretty's detail view gains 'advertised' and 'supported' rows
listing the PMDs in each set. A new _pr_label_list() helper unifies
multi-row rendering across these new rows and the pre-existing
ipv4/ipv6 address rows.
The detailed interface view also gains a 'link mode' row carrying the
pmd-type / phy-type-derived label.
Migration of existing startup configurations
--------------------------------------------
Bump confd version 1.8 → 1.9 to trigger the migration on upgrade.
share/migrate/1.9/10-ethernet-advertise.sh translates old configs of
the form
ethernet { auto-negotiation { enable false; } speed S; duplex D; }
into
ethernet { auto-negotiation { advertised-pmd-types [PMD]; } duplex D; }
mapping (S, D) → PMD via a static lookup covering the copper-T speeds
the deprecated speed leaf historically supported (10/100/1000/2.5G/
5G/10G). Interfaces that don't disable auto-negotiation, or that
lack a speed leaf, are passed through untouched.
Closes#530Closes#805
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Move the hostname-triggers-dhcp-client logic from dhcp-client.c into
the centralized dep_hostname() dependency tracker. When the hostname
changes, all interfaces with DHCP client configured are now added to
the diff by the core dependency resolver, so dhcp_client_change() picks
them up through its normal diff-based interface iteration.
When keystore keys change, trigger regeneration of wireguard
interfaces that reference them:
- Asymmetric key change: triggers interfaces using it as private-key
- Symmetric key change: triggers interfaces using it as preshared-key
(both at peers bag-level and individual peer-level)
Was not correct handled before, a few assumptions was made,
but did not work in reality.
* Fix correct channels for WiFi 6E
* Add missing parameters required for 6ghz to work
The \r-overwrite of an in-progress line breaks when something else
writes to stderr between conout(3) and the final call, leaving blank
"[ OK ]" lines. Cache the description and reprint it whole, so the
final status line is robust to intervening output.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
When an interface has been handed off to a container it lives in
another netns, so `ip neigh/addr flush dev FOO` fails on the host.
The failure aborts dagger, and since interfaces_change() runs before
containers_change() in change_cb(), the container delete path is
never reached -- the stale container keeps the interface trapped in
its netns, breaking the next reconfiguration.
Guard both the neighbor and address flush exit scripts with
`if_nametoindex(ifname)` -- true exactly when the interface is in
the host netns, false for both "in a container" and "already gone".
This replaces the pre-existing `!cni_find(ifname) && if_nametoindex(
ifname)` guard at the addr site: cni_find() added no information
for this check and would popen(container find) for nothing when the
interface had been deleted entirely.
Also harden wrap() in /usr/sbin/container so a stale setup pidfile
doesn't short-circuit Finit's stop attempt -- kill the setup PID and
still ask podman to stop the container.
Fixes#1493
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Add support for static ARP (IPv4) and neighbor cache (IPv6) entries per
interface. Static entries are installed as permanent kernel neighbor
table entries that are never evicted by normal ARP/NDP aging.
Fixes#819
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
On multi-chip DSA hardware (e.g., boards with multiple mv88e6xxx
chips), each switch chip has its own independent PHC device. With
boundary_clock_jbod enabled, ptp4l starts but only disciplines the
active slave port's PHC — the others drift.
Automatically start phc2sys -a alongside any BC or TC instance using
hardware timestamping. It subscribes to ptp4l's UDS socket, tracks
BMCA, and disciplines all non-active PHCs to match the active one.
On single-chip hardware it is a harmless no-op.
CLOCK_REALTIME is intentionally left untouched. Syncing the system
clock to PTP (phc2sys -rr), feeding the PHC from GPS/NTP (ts2phc,
phc2sys reverse), and full multi-source coordination (timemaster) are
planned as follow-on phases; see the issue tracker for the roadmap.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
A container's command line, as reported by podman, may comtain environment
variables, which the current regexp (added in ed4fe58) does not support.
Extend the regexp to allow environment variables and add an operational,
config false, 'cmdline' leaf node to allow any characters to be reported
for the full command line in the operational output.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Unfortunatly the fix was entered in 25.10, but confd was not stepped
up until 25.11, so this should be for 25.10 but now it is for confd
version 1.6 (infix 25.11), as close as we can get.
this is a follwup for commit 7e37fc49a3
confd: prevent IP addresses on bridge ports
Bridge ports should not have IP addresses configured. The IP address
should be configured on the bridge interface itself, not its member ports.
Add YANG must expression to enforce this rule at configuration time.
Fixes#1122
The setting 'stratumweight 0.0' disables stratum in Chrony source
selection (pure distance-based), making client_stratum_selection
non-deterministic on a LAN. Setting it to 1.0 gives srv1 a 1-second
effective advantage per stratum level, which no realistic distance
fluctuation can overcome.
Also correct the YANG descriptions in infix-system and infix-ntp which
had the semantics backwards — claiming 0.0 "ensures lower stratum is
always preferred" when in fact higher values do that.
Fixes#1361
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
After a successful bootstrap confd writes a sentinel to /run/confd.boot
If Finit restarts confd — whether after a crash or a clean exit — the
sentinel is found and the destructive bootstrap phases are skipped:
- gen-config fork (factory/failure configs already exist)
- wipe_sysrepo_shm() (other daemons, e.g. statd, are live)
- sr_install_factory_config() (datastores are already initialised)
- sr_replace_config(NULL, NULL) (running datastore is consistent)
- bootstrap_config() / load startup-config (not needed; sysrepo has
the right state; plugins resync via SR_EV_ENABLED on re-subscribe)
On restart confd reconnects to sysrepo, re-initialises plugins (which
re-subscribe and receive SR_EV_ENABLED to resync with the live running
datastore), then enters the steady-state event loop.
The sentinel lives on tmpfs so a real reboot always produces a clean
slate. Crash-loop protection is delegated to Finit's max-restarts (10).
As a side-effect this also enables a future "run-once" mode for resource
constrained systems: confd can exit after bootstrap and the sentinel
ensures any later restart just re-attaches without re-bootstrapping.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Add a finit_enable/disable/reload() family in core.c that directly
manipulates Finit's service state without fork+exec overhead:
finit_enable(svc) -- create symlink in /etc/finit.d/enabled/
finit_disable(svc) -- remove symlink from /etc/finit.d/enabled/
finit_delete(svc) -- remove both symlink and service entirely
finit_reload(svc) -- utimensat() on .conf to schedule reload
Printf-style variants (finit_enablef/disablef/reloadf) handle
template instance names such as container@foo and hostapd@wlan0.
All systemf("initctl ... enable/disable/touch ...") call sites across
containers, dhcp-server, firewall, hardware, ntp, routing, services,
syslog, and system are converted to the new API.
As a related cleanup in services.c, drop the remaining srx_enabled()
calls in favour of reading the already-fetched config tree directly
via lydx_is_enabled(lydx_get_xpathf(config, ...)), eliminating the
last sysrepo round-trips from that module.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Previously svc_enadis() would call 'initctl enable + touch' for every
config change event, even when the service's enabled state was unchanged.
This caused rousette to be unnecessarily restarted on every test_reset(),
racing with the active RESTCONF connection on slow hardware.
Replace svc_enadis() and svc_change() with svc_enable() which only
manages nginx symlinks and calls 'initctl enable/disable' -- never touch.
Each handler now checks the diff for the specific leaf that changed:
- If /enabled appears in diff: call svc_enable() to start or stop it
- If other config leaves changed with service already enabled: touch only
This ensures rousette, ttyd, netbrowse, avahi, sshd, and lldpd are only
restarted when their configuration actually requires it.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Save a few CPU cycles by skipping a new dagger generation when no
interfaces have been modified/added/deleted.
Uses d->next_fp as the sentinel: NULL means no claim was made for this
transaction. dagger_evolve() and dagger_abandon() now NULL it after
fclose, so subsequent unclaimed transactions also get the clean early
return.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
- Use same log frameworks as reset of confd
- Use existing primitives from libite + libsrx
- Drop remaining pthreads
- Coding style fixes
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Only install the keys on CHANGE event, fixes this annoying issue:
Nov 5 01:32:10 ix confd[2011]: Installing HTTPS gencert certificate "self-signed"
Nov 5 01:32:10 ix confd[2011]: Installing SSH host key "genkey".
Nov 5 01:32:11 ix confd[2011]: Installing HTTPS gencert certificate "self-signed
Nov 5 01:32:11 ix confd[2011]: Installing SSH host key "genkey".
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>