Summary
Add a CLI option under service ntp (either globally or per server) to bind the local source address used for outgoing NTP client requests — analogous to bindacqaddress in the underlying chrony daemon. Currently VyOS only exposes interface (which restricts which interface(s) chronyd listens/responds on in its *server* role) and per-server options (interleave, noselect, nts, pool, prefer, ptp-transport) — none of which control the source address chrony uses when *sending* client requests to upstream NTP servers.
Motivation / real-world use case
We run edge routers (VyOS 1.5.1, FRR 10.5.2) with full BGP tables from multiple transit/peering sessions in a single default VRF. One peering interface (an IX peering LAN, RFC-style shared segment) carries an address space that is intentionally not globally routable beyond that exchange fabric — by design, not a misconfiguration.
BGP sessions are unaffected by this: every peer-group explicitly sets update-source bound to the router's loopback, so BGP traffic always uses a globally-reachable source address regardless of which physical interface the underlying route happens to egress through.
Ordinary OS-level services have no equivalent mechanism. NTP client requests (and DNS resolver queries, which have the same problem but no dedicated VyOS service to configure in the first place) use the kernel's default source-address selection for whatever route wins for a given destination. When BGP best-path selection for a given NTP/DNS server happens to prefer the interface facing the non-globally-routable IX peering LAN, chronyd's request goes out with that interface's own address as the source — and the reply can never find its way back, since that address isn't routable outside the exchange fabric. This causes intermittent, best-path-dependent NTP (and DNS) failures that are confusing to diagnose because they come and go as BGP paths change, with no configuration change on our side.
We verified via live tab-completion on production hardware (VyOS 1.5.1) that no source-address option exists anywhere in the service ntp config tree:
vyos@r1# set service ntp ?
Possible completions:
> allow-client Restrict to allowed IP client addresses
interface Interface
leap-second Leap second behavior (default: timezone)
+ listen-address Local IP addresses to listen on
local-stratum Local reference stratum
> offload Configurable offload options
ptp-transport Enables the PTP transport for NTP packets
+> server Network Time Protocol (NTP) server
vrf VRF instance name
vyos@r1# set service ntp interface <TAB>
<text> bond0 bond0.200 bond0.201 bond0.211 bond0.213 bond0.300 bond0.313
eth0 eth1 eth2 eth3 eth4 eth5 eth6 eth7 eth7.800 lo
vyos@r1# set service ntp server 1.1.1.1 ?
Possible completions:
interleave Use the interleaved mode for the server
noselect Marks the server as unused
nts Enable Network Time Security (NTS) for the server
pool Associate with a number of remote servers
prefer Marks the server as preferred
ptp-transport Use the PTP transport for the serverinterface restricts the *server*/listening role; it does not affect which local address chronyd uses as the source when it initiates a request to an upstream server.
What we actually want
A way to pin the source address chronyd uses for outbound client requests to a stable, globally-reachable address (typically the router's loopback) — mirroring what update-source already does for BGP — independent of which physical interface the kernel's route selection happens to prefer for a given upstream NTP server at any given moment.
Current workaround (and why it's not ideal)
The generic Linux-level workaround is source-address-based policy routing (an ip rule plus a routing table with an explicit src on the relevant routes), which would work for any local service and isn't specific to NTP. We are still evaluating whether VyOS's policy route CLI can express this at all (checking set policy route <name> rule <n> set ? for a usable action); this is not yet confirmed to be exposed either, and even if it is, it's an indirect, harder-to-audit fix for what chrony can already do directly and cleanly with one config line.
Absent either option, the only "fix" available today is hoping BGP best-path selection doesn't route the relevant destinations over the affected interface — not an actual fix, just living with an intermittent, hard-to-explain failure mode.
Requested syntax (example)
set service ntp source-address '185.137.128.1'
or, if per-server granularity is preferred to match chrony's own per-directive flexibility:
set service ntp server 1.1.1.1 source-address '192.168.128.1'
This maps directly to chrony's existing bindacqaddress directive (source address used for client requests to NTP sources), which chrony has supported since 4.0. This is not a request for new chrony functionality — the underlying daemon already does exactly this — the ask is purely to expose it through VyOS's declarative config schema (interface-definitions XML), the same pattern as our earlier fib daddr type request.
Why this matters beyond our specific case
Any router or host that (a) participates in more than one routing domain with asymmetric reachability (multiple transit/peering paths, VRFs, IX fabrics with private addressing) and (b) needs its own local services — not just BGP — to always speak from a stable, globally-reachable identity, hits this same gap. BGP, BFD, and similar routing-protocol daemons in VyOS already solve this via update-source/equivalent; general host services (NTP, and by extension anything else chrony-adjacent) currently cannot, even though the daemon underneath already has the capability.
Environment
- VyOS 1.5.1 (circinus), official generic ISO, FRR 10.5.2
- Verified via live CLI tab-completion on production hardware (HP ProLiant DL360p Gen8)
Will send patch in some minutes