For simple matches like match.interface-name, match.driver, and
match.path, arguably what we had was fine. There each element
(like "eth*") is a wildcard for a single name (like "eth1").
However, for match.kernel-command-line, the elements match individual
command line options, so we should have more flexibility of whether
a parameter is optional or mandatory. Extend the syntax for that.
- the elements can now be prefixed by either '|' or '&'. This makes
optional or mandatory elements, respectively. The entire match
evaluates to true if all mandatory elements match (if any) and
at least one of the optional elements (if any).
As before, if neither '|' nor '&' is specified, then the element
is optional (that means, "foo" is the same as "|foo").
- the exclamation mark is still used to invert the match. If used
alone (like "!foo") it is a shortcut for defining a mandatory match
("&!foo").
- the backslash can now be used to escape the special characters
above. Basically, the special characters ('|', '&', '!') are
stripped from the start of the element. If what is left afterwards
is a backslash, it also gets stripped and the remainder is the
pattern. For example, "\\&foo" has the pattern "&foo" where
'&' is no longer treated specially. This special handling of
the backslash is only done at the beginning of the element (after
the optional special characters). The remaining string is part
of the pattern, where backslashes might have their own meaning.
This change is mostly backward compatible, except for existing matches
that started with one of the special characters '|', '&', '!', and '\\'.
(cherry picked from commit 824ad6275d)
The 7th field of:
ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|ibft}:[:[<mtu>][:<macaddr>]]
specifies which kind of autoconfiguration to do. 'none' and 'off' mean
static addresses.
The old network module of dracut used to leave kernel IPv6
autoconfiguration enabled when IPv4 static addresses were
configured. With NM, this corresponds to enabling IPv6 auto method.
https://bugzilla.redhat.com/show_bug.cgi?id=1848943
(cherry picked from commit a39eb9ac14)
When the initrd generator creates a connection with IPv6 method
'ignore', the kernel will do IPv6 autoconfiguration on the
interface. However, it is preferable to let NetworkManager configure
the interface directly instead of relying on kernel. Therefore, change
the IPv6 method to 'auto'. Note that we still set ipv6.may-fail to
'yes' so that a failure during IPv6 autoconfiguration doesn't bring
down the interface.
(cherry picked from commit f6d654b18f)
The kernel command line supports escaping and quoting (at least,
according to systemd's parser, which is our example to follow).
Use nm_utils_strsplit_quoted() which supports that.
(cherry picked from commit 27041e9f05)
The commit breaks many nmstate CI tests. It also breaks the
autoconnect-slaves functionality: if the master gets reactivated and
the slave was active, the slave is not reconnected.
A different solution is needed for the original issue.
This reverts commit 024e983c8e.
Add a new "path" property to the match setting, which can be used to
restrict a connection to devices with a given hardware path. The new
property is a list of patterns that are matched against the ID_PATH
udev property of devices.
ID_PATH represents the topological persistent path of a device and
typically contains a subsystem string (pci, usb, platform, etc.) and a
subsystem-specific identifier. Some examples of paths are:
pci-0000:00:02.0
pci-0000:00:14.0-usb-0:5:1.0
platform-1c40000.ethernet
systemd-networkd also has a "Path=" option to match a device by udev
ID_PATH.
Do what systemd does with sd_lldp_neighbor_get_chassis_id_as_string()
and sd_lldp_neighbor_get_port_id_as_string(). Maybe we should use the
systemd functions directly, however that is not done because the way
how we convert the values to string is part of our stable API. Let's not
rely on systemd for that.
Also, support SD_LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS and SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS
types. Use the same formatting scheme as systemd ([1]) and lldpd ([2]).
[1] a07e962549/src/libsystemd-network/lldp-neighbor.c (L422)
[2] d21599d2e6/src/lib/atoms/chassis.c (L125)
Also, in case we don't support the type or the type contains unexpected
data, fallback to still expose the LLDP neighbor, and convert the value
to a hex string (like systemd does). This means, lldp_neighbor_new()
in practice can no longer fail and the error handling for that can be
dropped.
There is one tiny problem: now as fallback we expose the
chassis-id/port-id as hex string. That means, if we in the future
recognize a new type, we will have to change API for those types.
The alternative would be to either hide the neighbor completely from the
D-Bus API (as previously done), or not expose the hex strings on D-Bus.
Neither seems very attractive, so expose the value (and reserve the
right to change API in the future).
For the ID of LLDP neighbors follow what systemd does (w.r.t. what it
consideres equality of two neighbors).
Note that previously we did almost the same thing. Except, we compared
priv->chassis_id and priv->port_id, but these values are string
representations of the original (binary value). Don't use the pretty
strings as ID but the original binary value.
An invalid destination address doesn't need to break the LLDL neighbor entirely.
In fact, systemd will already filter out such addresses. So in practice,
the neighbor always has a valid destination address.
There is thus no need to parse it already during lldp_neighbor_new().
When the instance is not running (after creation or after stop), there
is no need to keep the GHashTable around.
Create it when needed (during start) and clear it during stop. This
makes it slightly cheaper to keep a NMLldpListener instance around,
if it's currently not running.
NMDevice already keeps the NMLldpListener around, even after stopping
it. It's not clear whether the instance will be started again, so also
clear the GHashTable. Also, one effect is that if you initially were in
a network with many LLDP neibors, after stop and start, the GHashTable
now gets recreated and may not need to allocate a large internal array
as before.
We already rate limit change events by two seconds. When we notice
that something changed, we call data_changed_schedule().
Previously, that would immediately issue the change notification,
if ratelimiting currently was not in effect. That means, if we happen
go receive two LLDP neighbor events in short succession, then the
first one will trigger the change notification right away, while
the second will be rate limited.
Avoid that by always issue scheduling the change notification in
the background. And if we currently are not rate limited, with
an idle handler with low priority.
This changes the order to what the code did previously, before switching
from GVariantDict to GVariantBuilder. But it changes the actually
serialized order in the variant.
GVariantDict is basically a GHashTable, and during g_variant_dict_end()
it uses a GVariantBuilder to create the variant.
This is totally unnecessary in this case. It's probably unnecessary in
most use cases, because commonly we construct variants in a determined series
of steps and don't need to add/remove keys.
Aside the overhead, GHashTable also does not give a stable sort order,
which seems a pretty bad property in this case.
Note that the code changes the order in which we call
g_variant_builder_add() for the fields in code, to preserve the previous
order that GVariantDict actually created (at least, with my version of
glib).
The intermediate parsing step serves very little purpose.
The only use is to ensure that we always add the keys in a stable
order, but we can easily ensure that otherwise.
We only need to parse them to construct the GVariant. There is
no need to keep them around otherwise.
We still keep LldpAttrs array and don't construct the GVariant right
away. The benefit is that this way while parsing we set the array
fields, and afterwards, when we generate the string dictionary, the
keys are sorted.
Move the parsing of the LLDP attributes to a separate function.
In the next step, we will no longer keep all attribute around
and no longer parse them during lldp_neighbor_new().
One effect is that we can no longer (easily) declare the LLDP message as
invalid, if parsing the attributes fails. That makes IMO more sense,
because we should try to expose what little we could parse, and not
be forgiving to unexpected data. If we wanted, we still could hide such
neighbors entirely from being exposed, but that is not done, because
it seems better to expose the parts that were valid.
We actually only need to parse the attributes while constructing
the GVariant. In a first step decouple the tracking of the parsed
attributes from LldpNeighbor struct. More will follow.
Also, track sd_lldp_neighbor instance directly.
sd_lldp_neighbor is a perfectly reasonable container for keeping
track of the LLDP neighbor information. Just keep a reference to
it, and don't clone the data. Especially since the LLDP library
keeps a reference to this instance as well.
Also, to compare whether two neighbors are the same, it is sufficient
to only consider the raw data. Everything else depends on these fields
anyway.
This is only possible and useful becuase sd_lldp_neighbor is of course
immutable. It wouldn't make sense otherwise, but it also would be bad
design to mutate the sd_lldp_neighbor instances.
This couples our code slightly more to the systemd code, which we usually
try to avoid. But when we move away in the future from systemd LLDP library,
we anyway need to rework this heavily (and then too, we wouldn't want
to clone the data, when we could just share the reference).
Allocating and growing the buffer with realloc isn't really
complicated. Do that instead of using a CList.
Also, if there is only one element, then we can track it in-place.
NM_UTILS_LOOKUP_STR_DEFINE() is implemented via a switch statement.
You'd expect that the compiler could optimize that to plain lookup,
since all indexes are consecutive numbers. Anyway, my compiler doesn't,
so use the array ourself.
Note that NM_UTILS_LOOKUP_STR_DEFINE() is exactly intended to lookup
by enum/integer, if the enum values are not consecutive numbers. It may
not be best, when you can directly use the numbers as lookup index.
VARDICT sounds like it would be a variant of "a{sv}" type. But it
can be really any GVariant. Rename to make the type more generic.
This will be used to also hold a binary variant of type "ay".
Currently the LLDP parsing code uses GVariantBuild, which possibly does not
ensure a stable order of elements. Thus the test may not be stable.
However, that will be fixed very soon.