| Age | Commit message (Collapse) | Author |
|
VPP now rejects an MTU above the NIC limit, but the CI NICs are capped
at 1500, so tests using MTU 2500 on eth1 failed. The rejected commit
also left a queued initial VPP dependency in the commit daemon, which
the next commit ran with the old config, so every following test failed
too. Pending initial dependents are now cleared before each script run
in vyos-configd and vyos-commitd, and the tests use MTUs that fit any
NIC.
|
|
Reconciling the FRR configuration after a DHCP lease event was requested from
the configuration daemon over the socket the commit pipeline uses. The daemon
serves one client at a time and assumes it is the running commit, so
the request either landed in the middle of the handshake which hands over the
configuration, or kept the daemon busy past the 10ms a commit waits for it.
Either way the commit fell back to running the conf-mode scripts directly.
Those never render FRR, only the daemon does, so the commit succeeded while FRR
kept the configuration rendered before it, until the next lease event.
A lease event now renders FRR in its own process, and a commit which could not
use the daemon renders FRR itself instead of skipping the reload. Both take the
same lock. A commit post-hook would remove the second case, for a full render
on every commit.
|
|
http-api: T8989: Hotfix to enforce audience validation if OIDC is configured
|
|
wwan: T9350: possible dead interface after boot, disconnect does not stick
|
|
|
|
op-mode: T9354: replace "reset connection" with "reconnect interface"
|
|
Whether an address may be bound is not the same question as whether it is
currently configured somewhere: the kernel permits binding a foreign address
once the non-local bind sysctl is set, which is how a failover address is
commonly handed over after the commit. Callers can now opt into that, the
default is unchanged.
A lookup no longer skips the VRF device itself, which carries the addresses
of its own L3 domain, and an interface name can be retrieved for an address
without the caller asking a yes/no question in the first place.
Address and range validation is split into separate checks, so a caller no
longer has to accept ranges where only an address is meaningful. The two
duplicated version checks are dropped in favour of the existing ones.
Co-authored-by: Christian Breunig <christian@breunig.cc>
|
|
"connect interface" and "disconnect interface" cannot be combined to restart a
dialer interface when the CLI session runs over that very interface, yet the
command which does cover it was filed under an unrelated top-level node and
was hard to find.
It is now "reconnect interface <ifname>", mirroring the existing connect and
disconnect commands. "reset connection" is removed, no alias is kept.
The removed command was reachable through the REST API as a "reset" path. A
dedicated "/reconnect" endpoint takes its place, so the operation stays
available to API consumers.
|
|
A modem is on the bus while still probing, so a dial could start too early and
leave the interface without a session until something re-dialled it.
|
|
Two things kept an operator disconnect from taking effect.
vyos-netlinkd re-dials every configured WWAN interface that has lost its
session. It cannot tell a session lost to RF signal loss from one that was
taken down on purpose, so the disconnect was undone on the next reconcile
pass, at most 30 seconds later:
$ disconnect interface wwan0
08:53:33 t+10s state=registered
08:53:43 t+20s state=registered
08:53:53 t+30s state=connected <- re-dialled
08:54:03 t+40s state=connected
vyos-netlinkd: WWAN interface wwan0 is not connected, re-dialling...
vyos-netlinkd: Re-dialled WWAN interface wwan0
Record the intent instead of inferring it from the session state. op-mode
"disconnect" drops a marker in /run/vyos-wwan, which _reconcile_wwan() honours
and "connect" removes again. conf_mode removes it too, so a commit keeps
re-asserting the configured state - the marker only survives for as long as
nobody says otherwise, and never across a reboot.
|
|
/etc/cron.d/vyos-wwan re-ran the conf_mode script every 5 minutes via
op-mode "connect interface wwanN" to re-establish a session lost to RF
signal loss. Re-entering conf_mode from cron is unsafe: the cron job knows
nothing about the boot commit or about a commit in flight, so when a tick
lands before the running config is populated, get_config() returns nothing
but {'ifname', 'deleted'} and apply() takes the teardown branch instead of
dialling. It then stops the DHCP clients, stops ModemManager and unlinks its
own cron file, leaving wwan0 down with no way to recover until the next
commit:
CRON[1869]: (root) CMD (/usr/libexec/vyos/vyos-check-wwan.py)
systemd[1]: Stopping DHCP client on wwan0...
systemd[1]: Stopping Modem Manager...
This is timing dependent - it only bites when a */5 tick coincides with
boot - which is why it presents as an intermittently dead WWAN interface.
Move the re-dial into vyos-netlinkd, which already tracks these interfaces
for DHCP and already gates all of its work behind boot_configuration_complete()
and commit_in_progress2(). A re-dial can therefore no longer land on a
half-applied configuration. It also dials ModemManager directly rather than
re-entering conf_mode, so the teardown branch is no longer reachable from
the recovery path at all.
|
|
- Remove fallback 'oidc-client' identity - tokens without sub/client_id
are now rejected
- Suppress OIDC validation error details from stdout
- Cache discovered JWKS URI back to session to avoid per-request discovery
- token_op now accepts X-API-Key header alongside form field
- Reset REST/OIDC session attributes on SIGHUP reload to prevent stale
config persisting after nodes are removed
|
|
- Restore mask_dict/config_dict variable names in _execute_configure_op
(shadowing of Config object was causing potential crash on delete ops)
- Fix load_section_tree() call to pass correct 3 arguments
- Pass data.destructive to merge_config() to preserve destructive behavior
|
|
|
|
- Use OpenID Connect discovery (/.well-known/openid-configuration) to
resolve JWKS URI when jwks-url is not explicitly configured
- Add optional audience validation via new oidc audience config node
- Require exp claim in OIDC tokens
- Reject jwks-url without issuer at commit time
|
|
Add support for validating OIDC Bearer tokens issued by external identity
providers (Keycloak, Azure AD, Okta, Vault, etc.) against the configured
JWKS endpoint.
Configuration:
set service https api rest authentication oidc issuer <url>
set service https api rest authentication oidc jwks-url <url>
If jwks-url is not set, it is derived from the issuer URL using the
standard OpenID Connect discovery path.
Auth priority: mTLS -> VyOS JWT -> OIDC -> API key
|
|
- Make ApiModel.key optional to allow Bearer/X-API-Key/mTLS auth
without requiring a dummy key field in the request body
- Add thread safety to REST token secret initialization
- Cast rest_token_exp and rest_secret_len to int on load
- Use defensive dict.get() for authentication config access
|
|
Co-authored-by: Viacheslav Hletenko <seversss265@gmail.com>
|
|
|
|
Add support for mutual TLS (mTLS) authentication to the VyOS REST API.
When configured, nginx requests a client certificate and verifies it
against the configured CA chain. FastAPI reads the X-Client-Verify
header set by nginx and bypasses API key/token authentication when
the client certificate is valid.
Configuration:
set service https certificates ca-certificate <name>
set service https certificates verify-client <optional|required>
Note: requires TLSv1.2 due to nginx 1.22 TLSv1.3 post-handshake
authentication limitations. TLSv1.3 support pending nginx upgrade.
|
|
Add JWT Bearer token support to the REST API, as an additional
authentication method alongside the existing form-field key and
X-API-Key header.
- New POST /token endpoint mints a JWT for a valid API key
- auth_required() accepts Authorization: Bearer <token> alongside
existing key/X-API-Key auth
- New config nodes: service https api rest authentication
{expiration, secret-length} (defaults: 3600s / 32 bytes)
- REST tokens use an independent signing secret from GraphQL's,
since GraphQL may not be enabled on all deployments and the two
subsystems have different expiry requirements
- nginx location regex updated to allow /token
- service_https.py default-value merge generalized to also apply
to the rest node, not just graphql, so REST authentication
defaults populate correctly on commit
|
|
http-api: T9223: add VRF option to traceroute REST API endpoint
|
|
|
|
http-api: T9224: add ping endpoint to REST API
|
|
A verify() failure in one conf_mode script (e.g. "policy prefix-list")
did not stop vyos-configd/vyos-commitd from still pushing the shared
FRR configuration to vtysh once the last script in the same commit
batch happened to succeed on its own, since the render step only checked
that last script's own result. Track whether any earlier script in the
batch failed and gate the shared FRR render on it in both commit daemons.
|
|
|
|
Original bug: while a commit held the lock, the daemon called sleep(1)
without reading the netlink socket. The pending message stayed queued
in the kernel buffer, so once the commit ended, a stale event (e.g. a
DOWN from a disable that had already been re-enabled) got processed as
if it were fresh - stopping dhclient on an interface that was actually
back UP.
The applied fix keeps only the two pieces that are actually
load-bearing:
1. Drain instead of sleep - while commit_in_progress2() is true, still
call ipr.get() to read and discard any pending netlink messages, so
nothing stale survives to be processed after the commit ends.
2. Reconcile on commit end - once the commit finishes, walk all
matching interfaces, compare live sysfs operstate against the last
state the daemon acted on (_iface_prev_operstate), and run the
normal DHCP handler for any that disagree. This catches a real
transition that happened only inside the drain window and would
otherwise be silently lost.
Dropped from the original fix: an unconditional live-sysfs override
inside _handle_dhcp_events() that ran on every event, not just around
commits - redundant with reconcile, and risked discarding genuine fast
link flaps unrelated to any commit.
Co-authored-by: Christian Breunig <christian@breunig.cc>
|
|
The state tracker starts empty whenever vyos-netlinkd starts, so the first same-state RTM_NEWLINK UP notification is treated as a transition and unnecessarily restarts DHCP.
Seed matching interface states from the kernel link dump after binding the rtnetlink socket. This preserves real DOWN-to-UP handling while suppressing the first redundant UP notification.
|
|
firewall: T9076: add per-remote-group update interval
|
|
Complete the safer-subprocess migration started by the cmdl()/ifconfig
refactoring and convert every remaining vyos.utils.process.cmd() call site to
the list-based cmdl().
Drop the vyos.utils.process.cmd() implementation as it is no longer in use.
|
|
Add 'set firewall group remote-group <name> interval <value>' to
control how often each remote group list is re-downloaded,
independent of the global resolver-interval that also drives
domain-group/FQDN resolution.
The value accepts plain seconds or time-unit suffixes s/m/h/d/w
(e.g. 4h), range 60 seconds to 4 weeks, enforced at commit time
after conversion. When unset, the group keeps following
'firewall global-options resolver-interval', so existing
configurations are unaffected.
vyos-domain-resolver now tracks a last-update timestamp per
remote group and sleeps until the next due update instead of a
fixed resolver-interval tick, honoring per-group intervals both
shorter and longer than the global one. A group is only stamped
as updated after a successful download; failed downloads fall
back to the cached list and are retried at the resolver cadence
rather than after the full group interval.
human_to_seconds() now treats a plain number as seconds instead
of returning 0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
|
|
|
remote: T8829: fall back to GET when HEAD is not supported
|
|
Reaches a clean typos baseline for the T8490 ruleset pilot. Categories:
- Comments/docs: recursivly, taret, passsed, characted, arhive, AtrributeError;
"ned" -> "new" (migration comments).
- Messages/strings: writeable -> writable (x5); OCaml log "Commandis" -> "Command is".
- Local variables (all refs in-function): commited, formating, presistent;
inpt_range -> input_range; tz_datas -> tz_data_raw (avoids the tz_data collision).
- Self-contained renames (definition + all references in-file): formated_stats,
_get_formatted_output_conections -> ..._connections, expension_failure ->
expansion_failure (ping + traceroute), snmpd_restart_reqired -> ..._required.
False positives are allowlisted centrally (vyos/.github, separate PR), NOT changed
here: mke2fs, Maya-calendar "Mak", RFC 4122 "IDentifier" (hostapd), and VPP's
"U-Forwrd" bridge-domain column header (op_mode/vpp.py + the VPP smoketest assert
the real upstream `vppctl` output). Verified: typos clean, py_compile of every
edited .py, zero remaining old-identifier references.
🤖 Generated by [robots](https://vyos.io)
|
|
The previous vyos-netlinkd implementation for QoS policy re-apply was very heavy.
It conducted a full CLI validation and re-apply on every interface. Instead we
do not only re-apply the QoS configuration to the interface which has had an
address change detected by vyos-netlinkd.
This can be tested by checking "tc qdisc show" before disconnecting a PPPoE
interface and during/after reconnect. There will be no qdisc until the dynamic
interface has received an IP address - then the qdisc will be re-applied.
|
|
HttpC.download() always probed remote URLs with HEAD before GET to
discover redirects and Content-Length. Some APIs (e.g. AbuseIPDB)
reject HEAD with 405 Method Not Allowed, causing firewall remote-group
downloads to fail and leave empty cached list files.
Treat HEAD 405/501 as unsupported and proceed with GET using the
original URL. When HEAD does not provide Content-Length, read it from
the GET response headers instead. Validate available storage after
determining file size and before opening the destination file.
Log sanitized download errors in vyos-domain-resolver when a remote-
group list-file fetch fails. Add unit tests with mock servers that
return 405 or 501 on HEAD and 200 on GET.
|
|
Re-apply QoS after dynamic interfaces get addresses after connect/disconnect.
When PPPoE interfaces re-connect we need to re-do QoS settings.
|
|
|
|
DHCP restarts
_handle_dhcp_events() restarts dhclient/dhcp6c on every RTM_NEWLINK
that carries operstate=UP, regardless of whether the interface was
already UP. Normal kernel events that re-notify UP without a preceding
DOWN (e.g. post-migration gratuitous-ARP, promiscuous-mode toggles)
trigger unnecessary DHCP restarts. Each restart also creates a feedback
loop: dhclient-script runs "ip link set dev <if> up" during PREINIT,
which emits another RTM_NEWLINK(UP), which triggers another restart.
One seed event becomes 10+ restarts in 15 seconds.
Add a module-level dict tracking the last observed operstate per
interface. Only proceed with the DHCP restart when the transition is
DOWN-to-UP or when no previous state is recorded (first boot / service
restart). UP-to-UP re-notifications are suppressed with a LOG_DEBUG
message.
Validated on a production VyOS 2026.05.26-1327-rolling router: a
controlled KVM live migration after the patch produced zero DHCP
restarts (all UP-to-UP events suppressed), with no impact on normal
DOWN-to-UP DHCP recovery.
|
|
|
|
Not all pyroute2 versions which ship IPRoute() support subscribing to RTNL
multicast groups. If subscribing fails, fallback to all messages.
|
|
Move to the re-implementation of the commit in progress check added in
commit 002d45b70efd ("vyos.commit: T8781: move from O(n) to O(1) for
commit_in_progress() checks").
|
|
message (#5199)
* vyos-netlinkd: T8781: do not call commit_in_progress() for EVERY netlink message
Signed-off-by: Fabrizzio Petrucci <fabrizziopm@compumundohipermegared.one>
* vyos-netlinkd: T8781: restrict netlink subscription to link multicast group
Bind IPRoute with RTMGRP_LINK only so route/rule/neighbour/address updates
(e.g. full-table BGP) are not delivered to this socket.
Add a match wildcard so unexpected message types do not raise MatchError and
get logged as generic errors.
---------
Signed-off-by: Fabrizzio Petrucci <fabrizziopm@compumundohipermegared.one>
Co-authored-by: Fabrizzio Petrucci <fabrizziopm@compumundohipermegared.one>
|
|
Failures appear during PPPoEIf.remove() -> flush_addrs() -> set_dhcpv6(False),
where disable uses self._cmd(f'systemctl stop ...'), which raises on any
non-zero exit code of cmd().
PermissionError: [Errno 1] is misleading: cmd() raises OSError(exit_code,
feedback); exit code 1 maps to PermissionError in Python 3, so logs point at
"permissions" while the real signal is systemctl stop returned 1 (job failure,
timeout, restart contention with Restart=always on dhcp6c@.service.
Add a small systemd teardown helper stop_systemd_unit() validating the return
codes from the "systemctl stop" calls.
|
|
strace: Process 16362 attached
[pid 16362] execve("/bin/cli-shell-api", ["/bin/cli-shell-api", "--show-active-only", "showConfig", "interfaces"], ...) = 0
[pid 16362] +++ exited with 0 +++
--- SIGCHLD ...
strace: Process 16363 attached
[pid 16363] execve("/bin/cli-shell-api", ["/bin/cli-shell-api", "--show-active-only", "showConfig", "interfaces"], ...) = 0
[pid 16363] +++ exited with 0 +++
--- SIGCHLD ...
This would appear to be due to vyos-netlinkd calling op_mode_config_dict() more
than is necessary: it can be called only when it may be applicable (this patch).
Co-Authored-by: John Estabrook <jestabro@vyos.io>
|
|
vyos-netlinkd: T8047: replacement of netplugd
|
|
Fix typos and mistakes
No functional changes
|
|
Fix typos and mistakes in the commands and comments
No functional changes
|
|
Implementing a daemon that listens for netlink messages in Python was discussed
for many years. This is a proof-of-concept implementation how we can listen for
netlink messages and process them in Python.
Python 3.10 minimum is required due to the use of case statements which mimics
C-style switch/case instructions.
Add example:
set interfaces ethernet eth1 vif 21 address dhcp
set interfaces ethernet eth1 vif 21 address dhcpv6
commit
If network cable is unplugged:
vyos-netlinkd[12681]: RTM_NEWLINK -> eth3.10, state=DOWN, mac=00:50:56:b3:9d:8e
vyos-netlinkd[12681]: Stopping dhclient@eth3.10.service...
vyos-netlinkd[12681]: Stopping dhcp6c@eth3.10.service...
If cable is plugged back in:
vyos-netlinkd[12681]: RTM_NEWLINK -> eth3.10, state=DOWN, mac=00:50:56:b3:9d:8e
vyos-netlinkd[12681]: RTM_NEWLINK -> eth3.10, state=UP, mac=00:50:56:b3:9d:8e
vyos-netlinkd[12681]: Restarting dhclient@eth3.10.service...
vyos-netlinkd[12681]: Restarting dhcp6c@eth3.10.service...
|
|
The HTTPS API config-file handler previously used a blocking
threading.Lock in an async FastAPI endpoint, which can block the
event loop and make the API unresponsive under concurrent load.
This commit replaces the blocking lock with an asyncio.Lock to
serialize config operations without blocking async execution,
resolving the reported deadlock when concurrent /config-file
load operations occur.
The behavior of run_in_threadpool and background task scheduling
remains consistent with prior logic, so the handler preserves
existing commit and commit-confirm semantics.
|