| Age | Commit message (Collapse) | Author |
|
T3871: bind interface names to hardware slots instead of hw-id
|
|
frrender: T9442: cache the FRR configuration only after it was applied
|
|
A failed reload only dropped the in-memory cache. The record of the
configuration FRR runs still held the previous one, so the DHCP render
helper skipped a return to it while FRR kept a part of the failed
configuration. After a rejected reload test, the rendered file also kept
the rejected configuration.
Change detection now also requires the rendered file to match the
applied one, and a failed reload removes that record. The next commit
then renders and reloads FRR again, even when it returns to the
previous configuration.
A smoketest stops FRR during a commit and verifies that committing again
brings the configuration into FRR.
|
|
Only the first matching link file is applied, and ours sets just the name,
so the address policy shipped with the system never ran on any interface.
Hardware with a permanent address was unaffected - there was nothing to
apply - but a modem, which has none, was left on whatever random address its
driver had picked that boot, a different one every time.
Spell the policy out again. A permanent address is still kept where there is
one, and a device without one is given an address derived from the machine
and the device, which is the same on every boot of that machine. An address
set through the CLI is applied later and is unaffected.
|
|
A modem that reports no permanent address is given a random one by its
driver at every probe. That address was read as if it identified the
hardware, so it never matched what was recorded and the modem was taken for
a different card in the same socket on each boot, warning the operator to
check a port nobody had touched. The map also kept being rewritten with the
address of the boot before, so it could never settle.
Keep no address for a modem, and compare one only where there is one. An
address recorded by an earlier version is dropped on the next pass, so a
machine already carrying one needs nothing done to it.
A card whose address really did change is still reported.
|
|
A Hyper-V NIC is known by its MAC alone. One deleted and created again on
the same VM - an Azure NIC re-created, or a Hyper-V adapter removed and
added - comes back with a new MAC, so nothing on it matched the store: its
name stayed reserved, the new NIC got a new name, and its configuration
was left on a name with no NIC. cloud-init does not run again on the same
instance, so nothing else repairs it.
At boot, a vacant name now goes to a new NIC only when the pairing is not
in doubt:
- exactly one recorded name has no NIC, and exactly one new Hyper-V NIC
appeared. With more of either, the order the NICs come up in does not
say which replaced which, so nothing is handed over and the names stay
reserved, as before;
- the name went missing at this pass. The store records which names were
missing at the last pass, so a NIC removed for good does not hand its
name to a NIC added at a later boot;
- the name's own NIC was a Hyper-V one. The store records which names sat
on a Hyper-V NIC; a MAC-keyed name can belong to other hardware, and a
store written before this was recorded hands nothing over (the boot pass
logs that when it holds a name back);
- only at boot. On a running system the configuration under a name is not
applied to the NIC that takes it, so the hotplug unit passes --hotplug,
which names the new NIC like any other and records the vacant name as
missing, so the next boot does not hand it over either.
An adoption is logged as a warning, reported under 'adopted' in the status
file (kept there across hotplug passes while it holds), and repeated by
vyos-router, as a slot match is: verify the port before relying on its
configuration.
|
|
On Azure every Hyper-V NIC shares one ID_PATH and has no slot, so it is
keyed on its MAC. Its accelerated-networking VF carries the same MAC and
matched the NIC's .link file, so udev tried to give the VF the NIC's name.
The .link file of a Hyper-V NIC now also matches Driver=hv_netvsc, so the
VF cannot match it. This holds for a lone NIC keyed on the VMBus path too.
A NIC absent at a pass cannot say what it is, so its file keeps the pin
it already carries. NICs that are not Hyper-V ones get no Driver line, and
their files do not change. The 34-to-35 migration passes the hardware it
found, so the pin is written on the first boot of an upgrade too.
|
|
ESXi does not lay its adapters out in PCI address order. With four or more it
puts the fourth on a root port sorting ahead of the first three, so naming by
address made Network adapter 4 eth0 and shifted the rest. On the vmware-vsphere
OVA that moved the WAN, because cloud-init takes eth0 from the OVF properties.
The firmware port label carries the adapter order, and is what the VMware udev
rule this series removed matched on. Order by it, ahead of the address, for
hardware the hypervisor presented - recognised by its PCI vendor, or by DMI for
a model whose IDs are not known here. A physical server labels its ports too
and must not be reordered.
The label orders, it never identifies: a relabelled adapter is still the same
card.
|
|
Deleting an ethernet configuration puts the hardware address back. It was
read from the driver, which reports the current address when it cannot report
a permanent one separately - and at that point the current address is still
the custom one being removed, so it was reapplied rather than undone and the
card kept an address the configuration no longer mentioned.
Ask what naming recorded for the interface first, as the reset path already
does. That was taken before any custom address was applied, and the driver
stays the fallback for an interface no pass has seen.
|
|
Replacing the map was atomic but not durable: neither its contents nor the
rename were forced to the disk, so a machine losing power shortly after a
boot could come back to an empty or truncated file. Names are then derived
from the hardware again, which only gives the same answer where they happened
to follow slot order - anywhere else an address moves to another cable.
Force the contents out before the file is put in place, and the directory
entry after, so what comes back is either the names it had before or the ones
just written.
|
|
A recorded slot was enough to claim a name, whatever turned up in it. Pull a
modem and put an ordinary USB NIC in the same port and the NIC was handed
wwan0 - a name 'interfaces wwan' reads, so a modem's configuration would be
applied to a card which can not carry it. The reverse was already handled.
Require the device to belong to the namespace the name is read under. If it
does not, the name stays reserved for the hardware that earned it and the
newcomer is named as what it is.
|
|
Cards rearranged among themselves, or a map edited by hand, leave every name
matched to a card the store knows - just not the one it had. That was filed
as an ordinary match, indistinguishable from a machine where nothing moved,
while the addresses configured under those names had quietly changed cable.
Report it separately. Which name goes to which card is unchanged, the slot
still decides; only the account of what happened is.
|
|
An interface was passed over as soon as it had a master, which covers a VF
datapath but also every bridge, bond and VRF member. Those are still their
own card in their own slot, so the naming pass reported them as hardware
which had not appeared, on any run made while they were in use.
Skip only when the master is a device itself. That is what tells the
accelerated path, which belongs to the interface it is enslaved to, apart
from a member, which does not.
|
|
Anything that was not wireless was named ethN, so an LTE module came up as an
ethernet port: bound, working and invisible, because 'interfaces wwan' looks
at wwanN and nothing else.
Give it its own namespace, keyed on DEVTYPE, and drop what an earlier version
filed under an ethernet name - that entry still matches the modem by path and
would capture it again.
|
|
Every interface created on a radio carries that phy's address, so they are
indistinguishable here. A name recorded against one of them was applied to
whichever appeared next: configuring a second interface on a phy renamed it
on top of the first, and the smoketests lost the interface they had just
asked for.
Nothing anchors a radio, and nothing needs to - wireless names come from
'physical-device'. Stop discovering them, stop writing a .link for them, and
drop what an earlier version recorded so the entry and its file go on
upgrade.
|
|
Deleting the ethernet configuration of a member of a jumbo bond dropped that
member to the default MTU while the bond went on using it at 9000. It stayed
the active slave, so jumbo frames were discarded in both directions, small
ones passed, and nothing was logged.
A bond owns its members' MTU just as it owns their address - the ethernet
path already refuses to let a member set either, and says so. The reset now
waits, like the address, until the bond has released the port.
The bonding smoketest covers both halves on a running system: while the
member is enslaved it must keep the bond's address and MTU, and once the
bond releases it, it must get its own address and the default MTU back.
|
|
The map now records which card each name sat on. A card moved to another slot
keeps its name rather than leaving it behind for whatever turns up next, and
the slot it vacated does not lend that name out.
Where the map and the hardware disagree, the map wins: a card the store
already knows, found in a name's slot, takes that name. Only a card nothing
knows about, sitting in a slot on record, is treated as a replacement - the
one case which can quietly move a configured address onto another cable.
|
|
image
The check guarding that write looked for a marker which an activation
script creates only after interface naming has already run. On a deployed
qcow2 the marker is absent on the first boot, so nothing was recorded and
the next boot named the hardware from scratch. Removing a card then moved
every name below it onto the neighbouring port, taking that interface's
address with it.
Only an encrypted configuration has a volume which may still be locked, so
ask about that instead - everywhere else the directory is already the
persistent one.
|
|
deleted
Every NIC used to carry a hw-id, which was enough to make its node exist.
Without it a bare node is empty and never reaches the running configuration,
so releasing a bond member looked exactly like a deletion: the port was torn
down and left admin-down, with nothing left to bring it back.
An ethernet interface is owned by the Kernel and - like 'lo' - outlives its
configuration. Removing it now resets the port to the Kernel defaults and
leaves the link up.
|
|
The node decides nothing now that the mapping store owns naming, and keeping
it would leave two sources of truth free to disagree.
Existing bindings are carried into the store by matching each hw-id against
the permanent address of the hardware present, so a box named by an older
release keeps exactly the names it had. Entries whose hardware is absent are
skipped - the configuration may well originate from another machine. The
hardware address of an interface is now read off the device rather than from
the configuration.
|
|
Names used to be derived from 'hw-id' in config.boot. A node carrying an
address but no hw-id had to be matched to some NIC, and nothing available at
boot could say which one - every heuristic could bind a configured address to
the wrong physical wire.
Naming authority moves to a mapping store binding a name to the slot the
hardware occupies. The slot is the identity, so a replacement card in that
slot is that interface again. The store renders systemd .link files, leaving
udev to apply names as devices appear.
|
|
A prerouting raw rule with a source or destination fqdn failed to
commit: the rule referenced an FQDN set that was never declared, and
the domain resolver never added addresses to it.
Prerouting is now handled like the other hooks for both IPv4 and IPv6,
so the set is created and filled with the resolved addresses. Added a
smoketest covering both address families.
|
|
The CLI existence check always looked up the interface under the argument
name intf_name, but reset wireguard passes it as interface. The check
therefore only tested whether any WireGuard interface existed: an
unconfigured name slipped through and crashed with a KeyError, or the
error message reported the interface as "None".
The decorator now accepts the name of the argument carrying the interface,
defaulting to intf_name, so existing callers are unchanged and reset
wireguard reports the unconfigured interface by name.
|
|
|
|
The configuration was stored as the cached one before FRR had reloaded
it. If the reload failed, or FRR was down, the next commit found the
configuration unchanged, skipped the reload and reported success while
FRR kept running the old configuration.
Keep the rendered configuration aside and make it the cached one only
after the reload succeeded. A render which does not reach the reload is
not cached either.
If the reload fails, FRR may run a part of the new configuration. The
cache is dropped then, so even a return to the previous configuration
reloads FRR. A reload that succeeds on the last try no longer raises an
error.
|
|
vpp: T9484: keep net.core.rmem_max at VPP's netlink buffer size
|
|
syslog: T9336: Resolve remote FQDN targets within their configured VRF
|
|
VPP requests a 256 MiB netlink receive buffer (nl-rx-buffer-size), but
the kernel caps it at net.core.rmem_max, which VyOS sets to 2 MiB, so
VPP gets 4 MiB. A large routing table over VPP interfaces can overflow
it, and linux-cp then falls back to a full resync.
Setting the sysctl from the CLI does not help at boot: system sysctl
runs after vpp, so VPP has already opened its socket.
- vpp.py raises net.core.rmem_max to the requested size before VPP is
(re)started; a higher value is kept.
- VPP re-opens its netlink socket on every resync and sizes it again, so
system sysctl no longer applies a lower value while VPP is configured;
it uses the required size and prints a warning.
- When VPP is removed, vpp.py sets net.core.rmem_max back to the value
from system sysctl, or to the default from sysctl.d, read with the new
vyos.utils.system.sysctl_read_default().
- startup.conf.j2 takes nl-rx-buffer-size from the same value
(default_resource_map) instead of its own constant.
|
|
firewall: T9474: multiple issues in rule processing (time based rules, fragment matching and failing commits)
|
|
bgp: T9450: stop re-sending unchanged BGP lines to FRR on every commit
|
|
wlb: T9472: silent daemon failures, ignored options and connections broken by commits
|
|
nat: T9475: commit failures and weight issue in load-balancing, translation issues for port-ranges
|
|
Rsyslog resolves remote targets via the process's default routing
context regardless of a per-remote 'vrf' setting, so a remote given
as an FQDN fails to resolve when the only reachable DNS server lives
in a non-default VRF.
Changes:
- `system_syslog.py` pre-resolves FQDN using VRF remotes at commit time
and renders the resolved address instead of the raw FQDN.
- `vyos-domain-resolver` collects VRF-bound FQDN targets from syslog
and handles a resolved-address change for a syslog remote.
|
|
The CLI's XML default for "bgp conditional-advertisement timer" (60)
is always present in the config dict, so the line was rendered on
every commit. FRR's own default is the same value
(DEFAULT_CONDITIONAL_ROUTES_POLL_TIME, bgpd/bgp_conditional_adv.h) and
bgp_config_write() never prints it back when the value equals the
default, so frr-reload saw the line missing on every reload and sent
it again, both in the default instance and in every VRF instance.
Templates cannot query the XML definition while rendering, so frrender
takes the value from the config defaults of "parameters
conditional-advertisement" (conf.get_config_defaults) and adds it to
the BGP dict as the key xml_default_conditional_advertisement_timer,
for the global instance and for every VRF instance, the same pattern
used for "bgp default local-preference" (T9404). bgpd.frr.j2 renders
the line only when the configured value differs from
xml_default_conditional_advertisement_timer, comparing both as
integers so a timer entered as "060" is still treated as 60.
|
|
"ipv6 address autoconf" lives below "ipv6", so an interface which only
gets its address by SLAAC has no "address" node at all. connect_options()
only worked out the IP type when that node existed and fell back to
ipv4 otherwise, which dialled an IPv4-only bearer and left the interface
without any IPv6.
Read the address list with a default instead. All other combinations of
dhcp, dhcpv6 and autoconf give the same IP type as before.
|
|
With load-balance backends, the translation port and any translation
options were placed between "to" and the hash expression, e.g.
"dnat to:80 numgen random ...". nft rejects that and the commit failed.
The port is now part of every backend in the map and the options follow
the map, so load-balanced port forwarding works.
|
|
The hash for load-balanced NAT rules was always taken modulo 100, while
backend weights may add up to any value. With a sum below 100 some hash
values had no backend in the map; commit only warned about it.
The modulus is now the sum of all weights, so every hash value maps to a
backend and weights act as relative shares. Rules whose weights add up to
100 render exactly as before, and the warning is dropped.
|
|
A translation prefix combined with a port range lost the port range when
the rule had no matching source or destination address - the rule only
said "snat prefix to <prefix>" and gave no warning.
nft has no syntax for a prefix plus port range, so such rules now use the
same map form as rules with an address, keyed on 0.0.0.0/0. This keeps the
1:1 prefix mapping and adds the port range.
|
|
nft converts hour matches to UTC when the ruleset is loaded, using the
offset of that moment. After a daylight saving change, or a change of the
system time-zone, every hour window was off until the next firewall commit.
- A new helper loads only the rules with an hour match again, in place, so
sets such as dynamic, domain and GeoIP groups and all counters are kept.
It is scheduled as a systemd timer for the next UTC offset change and
re-arms itself; firewall and policy route commits arm or remove it.
- Changing the time-zone re-runs firewall and policy route.
The smoketest moves the clock to just before a change in Europe/Berlin and
checks that the window is refreshed and a dynamic group entry survives. It
only runs in the smoketest harness, as it changes the system clock.
|
|
Fragments were detected by overwriting the whole packet mark with a fixed
value before reassembly. Any later mark - a raw "set mark" or a policy route
"set table" - replaced it, so "fragment match-frag" no longer matched, and
marks already present on fragments were lost.
Fragments now only get bit 31 of the mark, which no configurable firewall or
routing policy mark uses:
- fragment matching tests the bit, mark matching ignores it
- firewall and policy route mark writers keep it
- policy route and local-route ip rules mask it while fragments are routed
- it is cleared after the forward and input filters, so later consumers such
as QoS or IPVS see the original mark
WAN load-balancing still overwrites the mark and keeps the previous
behaviour for fragments.
|
|
Rules with a start and stop time were rendered as two separate hour
comparisons. nft converts both to UTC when loading the ruleset, so a window
crossing midnight in UTC never matched - e.g. 22:00-06:00 anywhere, or
01:00-02:00 on a system running in CEST. A start or stop time on its own
had the same problem.
Hours are now rendered as a single range, which nft turns into its
complement when it wraps around midnight. A missing start or stop defaults
to the beginning or end of the day.
|
|
The routing table and mark of a WAN interface followed its position in the
sorted interface list. Adding an interface which sorts before the others
renumbered all of them. Existing connections still carried their old mark
in conntrack and were routed into the wrong table - they broke.
Every interface now keeps its table as long as it stays configured, new
interfaces get the lowest free table. The assignment is dropped once WAN
load-balancing is removed.
|
|
The ttl test considered the interface healthy whenever ping failed. A dead
uplink, where nothing answers, therefore stayed ACTIVE, while a target
answering the ping marked the interface FAILED.
The test now passes if the hop where the TTL runs out reports it, or if the
target is closer and answers itself. If nothing answers within resp-time,
the test fails.
|
|
"limit threshold above" was ignored. The rule always matched the traffic
below the rate, the same as the default "below".
With "above" the rule now matches the traffic exceeding the rate.
|
|
The renderer checked a key no CLI node produces, so "per-packet-balancing"
had no effect and every rule balanced per flow only.
With the option set, the rule no longer matches new connections only and
every packet is balanced on its own.
|
|
"inbound-interface any", offered by completion, was rendered as an
interface literally named "any" and matched no packet, so the rule never
balanced anything.
It now matches traffic entering on any interface except the WAN interfaces
themselves. Matching those as well would also restore the routing mark on
replies arriving from an ISP and send them straight back to that ISP.
|
|
policy: T9346: Allow dot in `prefix-list` and `prefix-list6` names
|
|
VyOS 1.3 allowed a dot in `policy prefix-list` and `policy prefix-list6`
names (pattern `^[-_a-zA-Z0-9.]+$`). The XML rewrite dropped the dot from
the allowed characters, so a 1.3 configuration using such names
can no longer be loaded or committed after an
upgrade. FRR itself accepts the dot in prefix-list names.
|
|
The Mikrotik configuration referenced by T9267 uses
matching-type=substring, documented to match the value anywhere within
the option string. This PR's "substring" match instead compared a
fixed-length slice at a fixed byte offset (default 0) for exact
equality - effectively an anchored prefix match, not a substring
search - which does not reliably reproduce the ticket's own use case
of picking a device model string (e.g. "T42S") out of a longer,
variably-formatted hostname.
Rebuild "hostname substring"/"vendor-class-id substring" on Kea's
match()+lcase() instead of substring()==, so a configured value now
matches anywhere in the option content and case-insensitively (options
like vendor-class-id are not guaranteed to arrive in a fixed case).
Drop the "offset" leaf together with it, since it has no remaining
purpose once matching is no longer anchored to a fixed position, and
there is no released behavior to preserve.
Raw hex input and values containing a literal single quote are
rejected for substring matching in verify(), since neither can be
safely embedded into the generated Kea regular expression; exact
"value" matching is unaffected and still accepts both.
Reported by alexk37 in review of PR #5436.
|
|
The byte length compared by a hostname/vendor-class-id "substring"
match is always derived from "value" for a meaningful equality test:
a shorter length never matches (comparing fewer option bytes against
the full value literal), and a longer one is silently clamped by Kea
to the available bytes, turning what looks like a prefix match into
an exact match of the whole remainder. There is no legitimate use for
setting it independently of "value", so drop the leaf rather than add
another verify() constraint around it.
Reported by alexk37 in review of PR #5436.
|