Commit graph

17138 commits

Author SHA1 Message Date
Thomas Haller
0e30415575
core: assert that tracked objects in NML3Cfg don't have metric_any
It wouldn't work otherwise. The object state is used to track routes
and compare them to what we find in platform.

A "metric_any" is useful at higher layers, to track a route where the
metric is decided by somebody else. But at the point when we add such an
object to the object-state, a fixed metric must be chosen.

Assert for that.

Also add some code comment to nm_platofmr_ip_route_normalize() related
to this.
2023-11-29 12:18:59 +01:00
Thomas Haller
ca7cbf6fea
core: fix nm_netns_ip_route_ecmp_commit() to return regular single-hop route
nm_netns_ip_route_ecmp_commit() returns the ECMP routes that didn't find
a merge-partner. It expects NML3Cfg to configure such routes in
platform.

Note that these routes have a positive "weight", which was used for
tracking the ECMP information in NML3Cfg and NMNetns.

But in kernel, single-hop routes don't have a weight. All routes in
NMPlatform will have a zero weight. While it somewhat works to call
nm_platform_ip_route_add() with a single-hop route of non-zero weight,
the result will be a different(!) route. This means for example that
nm_platform_ip_route_sync() will search the NMPlatform cache for whether
the routes exist, but in the cache single-hop routes with positive weight
never exist.

The proper solution is that nm_netns_ip_route_ecmp_commit() does not
tell NML3Cfg to add a route, that cannot be added. Instead, it must
first normalize the weight to zero, to have a "regular" single-hop
route.

Fixes: 5b5ce42682 ('nm-netns: track ECMP routes')
2023-11-29 11:24:53 +01:00
Thomas Haller
389ac096e3
platform: fix handling "weight" for IPv4 routes
The hash/cmp functions were wrong with respect to IPv4 routes. Fix that.

- the weight was cast to a guint8, which is too small to hold all
  values.

- NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID comparison would normalize a zero
  weight to one

    NM_CMP_DIRECT(NM_MAX(a->weight, 1u), NM_MAX(b->weight, 1u));

  That was very wrong.

Clean this up. How the weight is handled, depends on the n_nexthops
parameter.

The remarkable thing is that upper layers find it useful to track IPv4
single-hop routes with a non-zero weight. Consequently, this is honored
by NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID which treats single-hop routes
different, if their weight differs. However, adding such a route in
kernel will not work. In kernel, single-hop routes have no weight. While
the route exists as distinct according to the implemented identity, it never
exists in kernel. Well, you can call nm_platform_ip_route_add() with such
a route, but the result will have a weight of zero (being a different
route). See also nm_platform_ip_route_normalize().

This works all mostly fine. The only thing to take care is that you
cannot look into the NMPlatform cache and ever find a IPv4 single-hop
route with a non-zero weight. If you preform such a lookup, realize that
such routes don't exist in platform. You can however normalize the
weight to zero first (nm_platform_ip_route_normalize()) and look for a
similar route with a zero weight.

Fixes: 1bbdecf5e1 ('platform: manage ECMP routes')
2023-11-29 11:23:44 +01:00
Thomas Haller
d3e1de5000
fixup! l3cfg: handle dynamic added routes tracking and deletion
A "os_non_dynamic" flag is required.

A ObjStateData is alive as long as it either has a static route (from
the combined l3cd) or a dynamic (from nm_netns_ip_route_ecmp_commit()).
Note that it can be both!

So, _obj_states_track_prune_dirty() (formerly
_obj_states_remove_track()) needs to be able to look at an obj_state and
determine whether it's still kept alive (by either).

You might think, "but it cannot be both". The routes from the
non-dynamic combined-l3cd are IPv4 single-hop routes with a weight of
zero. On the other hands, the routes from nm_netns_ip_route_ecmp_commit()
are the ones we passed to NMNetns that didn't find an ECMP merge
partner. They should have a positive "weight", and compare different.

Wrong. The route that comes back from nm_netns_ip_route_ecmp_commit()
must have a weight of zero too. The following commit will normalize
the weight of those routes to zero. Then indeed the non-dynamic and
dynamic routes both have weight zero, and they compare equal.

Just try it by configuring two routes that are identical except one has
weight zero and the other weight 42. (note that to see it, you will need
to follow-up patch to normalize the weight).

But why normalize the weight? Because when we get a route back from
nm_netns_ip_route_ecmp_commit(), we want to be able to look into the
platform cache (whether the route exists). NML3Cfg also tracks routes
from platform, and associates them with the obj-state. The Routes from
platform all have "weight" zero. Normalizing the route from
ecmp_commit() is necessary to be the route we want to add and as it
appears in platform (that is, the route with a zero weight).
2023-11-29 11:22:54 +01:00
Fernando Fernandez Mancera
3dbe8234df l3cfg: handle dynamic added routes tracking and deletion
Dynamic added routes i.e ECMP single-hop routes, are not managed by l3cd
as the other ones. Therefore, they need to be tracked properly and
marked as dirty when they are.

This way, NetworkManager makes sure there are no leftovers from merging
ECMP multi-hop routes.
2023-11-28 16:09:46 +01:00
Fernando Fernandez Mancera
37703b6176 l3cfg: track obj-state for single-hop route after ECMP commit
Before ECMP commit we don't know if the single-hop route is going to be
merged as ECMP multi-hop route. Therefore if the route has a weight
bigger than zero, it is going to be tracked only after the ECMP commit.
2023-11-28 12:22:10 +01:00
Fernando Fernandez Mancera
93ea02bb9f netns: schedule a commit when a single-hop route is merged
When a single-hop route is merged with another single-hop route from a
different interface creating a new ECMP route, NetworkManager needs to
schedule a commit on the l3cfg that is managing the first single-hop
route. Otherwise, the single-hop will continue to be there until a new
commit is scheduled.

Fixes: d9d33e2acc ('netns: fix configuring onlink routes for ECMP routes')
2023-11-28 12:19:43 +01:00
Jan Vaclav
ffb34d2485 build/meson: fix gtkdoc dependencies
This commit fixes the build process for the documentation that was previously
unable to build separately via meson due to a dependency issue.

Previously, trying to build the API documentation via `ninja NetworkManager-doc`
failed due to missing dependencies (for example, `nm-dbus-types.xml` was not built).
I believe this happens due to some different handling of static paths vs. custom_target
by meson in this case.

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1801
Fixes: 03637ad8b5 ('build: add initial support for meson build system')
2023-11-24 07:40:44 +00:00
Thomas Haller
cf0b482f93
libnm: implement "{ipv4,ipv6}.dns-options" as direct STRV property
"nm_sett_info_propert_type_direct_strv" is the way, now STRV properties
should be implemented. Adjust the "dns-options" property..
2023-11-23 17:19:10 +01:00
Thomas Haller
9f4cd6b03f
libnm: add option for direct STRV properties to preseve/distinguish empty arrays
For most strv or string properties, we cannot distinguish between
NULL/unset/default and empty.

It would be difficult to enter in nmcli or grasp how it differs. There
are probably many bugs, where we accept empty strings, and fail to
handle them correctly.

Anyway. For most strv arrays, and empty array and NULL/unset/default are
treated the same. That means, g_object_get() tends to always return NULL
(never an empty strv array) and g_object_set() of an empty strv array
will internally leave the GArray at NULL.

For a few properties, there is a difference. See "ipv[46].dns-options".
See also "clear_emptyunset_fcn" hook in libnm-setting.

Add a way to handle such strv properties with the "direct" mechanism.
2023-11-23 17:18:32 +01:00
Thomas Haller
189bddc99b
libnm: handle empty strv array same as NULL for compare/to-dbus
For now, our "direct" strv properties cannot distinguish between
NULL/unset/default and empty.

Adjust the to-dbus() and compare() hooks to honor that.
2023-11-23 17:17:52 +01:00
Thomas Haller
563fad718c
glib-aux: refactor nm_strvarray_get_strv*() and nm_strvarray_set_strv*() helpers
Unfortunately, there are several possibilities how to handle NULL and
empty arrays. Therefore we have different variants.

Clean this up, and add a way to preserve whether the array is empty
(previous variants could not distinguish that).

Functions are also renamed, so that if you backport a user of the new
API, you'll get a compiler error if this patch is missing.

Also, nm_strvarray_get_strv_notnull() no longer takes a pointer to a
"GArray*". Previously, it used that to fake an empty strv array. Now
this returns NM_STRV_EMPTY_CC().
2023-11-23 17:17:52 +01:00
Thomas Haller
e48fc3ee3e
glib-aux: add "const" to arguments of nm_strvarray_*() helpers 2023-11-23 17:17:51 +01:00
Thomas Haller
3f8431f069
libnm: refactor "ipv6" argument of _nm_utils_dns_option_validate()
_nm_utils_dns_option_validate() allows specifying the address family,
and filters based on that. Note that all options are valid for IPv6,
but some are not valid for IPv4.

It's not obvious, that such filtering is only performed if
"option_descs" argument is provied. Otherwise, the "ipv6" argument is
ignored.

Regardless, it's also confusing to have a boolean "ipv6". When most
callers don't want a filtering based on the address family. They
actually don't want any filtering at all, as they don't pass an
"option_descs". At the same time passing a TRUE/FALSE "ipv6" is
redundant and ignored. It should be possible, to explicitly not select
an address family (as it's ignored anyway).

Instead, make the "gboolean ipv6" argument an "int addr_family".
Selecting AF_UNSPEC means clearly to accept any address family.
2023-11-23 17:17:51 +01:00
Thomas Haller
405a2fa166
libnm/tests: add more tests about dns-options in NMSettingIPConfig 2023-11-23 17:17:51 +01:00
Wen Liang
21a6d7a0b6 device: change port deactivation reason upon user-request controller deactivation
When connection down is explicitly called on the controller, the port
connection should also be deactivated with the reason user-requested,
otherwise any following connection update on the controller profile
will unblock the port connection and unnessarily make the port to
autoconnet again.

Fixes: 645a1bb0ef ('core: unblock autoconnect when master profile changes')
https://gitlab.freedesktop.org/NetworkManager/NetworkManager-ci/-/merge_requests/1568
2023-11-21 20:01:12 -05:00
Thomas Haller
c9742cec2a
libnm/doc: fix typo documenting NMCheckpointCreateFlags
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1429
2023-11-20 15:27:28 +01:00
Thomas Haller
d210923c0f
wifi: add "wifi.cloned-mac-address=stable-ssid"
Add a new "stable-ssid" mode that generates the MAC address based on the
Wi-Fi's SSID.

Note that this gives the same MAC address as setting

    connection.stable-id="${NETWORK_SSID}"
    wifi.cloned-mac-address="stable"

The difference is that changing the stable ID of a profile also affects
"ipv6.addr-gen-mode=stable-privacy" and other settings.
2023-11-16 13:07:54 +01:00
Thomas Haller
587f5afb5a
all: differentiate NM_CLONED_MAC_IS_SPECIAL() for wired/wireless
Will be used next, when we support "stable-ssid" for
"wifi.cloned-mac-address" property.
2023-11-16 13:07:53 +01:00
Thomas Haller
901a1b096b
core: support "${NETWORK_SSID}" for connection.stable-id
For Wi-Fi profiles, this will encode the SSID in the stable-id.
For other profiles, this encodes the connection UUID (but the SSID and
the UUID will always result in distinct stable IDs).

Also escape the SSID, so that the generated stable-id is always valid
UTF-8.
2023-11-16 13:07:53 +01:00
Thomas Haller
8079e8969d
libnm: implement "ipv4.dhcp-reject-servers" as direct-strv property 2023-11-15 17:59:28 +01:00
Thomas Haller
4cd58207c1
libnm: implement "ipv4.dns-search" as direct-strv property 2023-11-15 17:59:27 +01:00
Thomas Haller
eed4a21fa3
libnm: use nm_strvarray_*() helpers for strv properties
We have many properties, and we aim that they have a small set of
"types". The purpose is that we can treat similar properties (with the
same type) alike.

One type are "direct" strv properties. Those still require some
C functions, like get-length(), clear(), add(), get-at-index().
The implementation of those functions should also be similar, so that
strv properties behave similar.

For that, make use of helper functions, so that little duplicate logic
is there.

Use some new nm_strvarray_*() functions, and unify/cleanup some code.
All related to strv properties in NMSetting classes.
2023-11-15 17:59:27 +01:00
Thomas Haller
3435bc3011
libnm: move NMValueStrv definition in header 2023-11-15 17:59:26 +01:00
Thomas Haller
7b5e8381f0
glib-aux: assert against NULL arguments for nm_strvarray_add() 2023-11-15 17:59:26 +01:00
Thomas Haller
2d8c4cfe05
glib-aux: add nm_strvarray_add_take() helper 2023-11-15 17:59:26 +01:00
Thomas Haller
60375218d1
glib-aux: add nm_strvarray_remove_index() helper 2023-11-15 17:59:25 +01:00
Thomas Haller
6c83f7bd67
glib-aux: add nm_strvarray_ensure_and_add() helper 2023-11-15 17:59:25 +01:00
Thomas Haller
73947cdfd0
glib-aux: add nm_strvarray_clear() helper 2023-11-15 17:59:25 +01:00
Thomas Haller
7ab9a2b69f
glib-aux: add nm_strvarray_contains() helper 2023-11-15 17:58:04 +01:00
Thomas Haller
9f9a89d778
glib-aux: cleanup assertions for GArray element size in nm_strvarray helpers
The check "sizeof(const char *const *) ==
g_array_get_element_size((GArray *) strv)" is wrong, but probably
harmless, because most likely on our supported architectures all pointer
sizes are the same size.

Also, just use `sizeof(char *)` instead of `sizeof(const char *)`. Not
that it matters, but the GArray holds pointers of `char *`.

Also, consistently place the "sizeof()" on the left side of the
comparison.
2023-11-15 17:57:57 +01:00
Thomas Haller
cce8106a37
libnm: fix broken assertion in _permissions_user_allowed()
Fixes: b2b2823c53 ('core: avoid getpwuid() unless necessary in permission check')
2023-11-15 10:41:11 +01:00
Thomas Haller
36629ae710
libnm: rename "ethtool.eee" property to "ethtool.eee-enabled"
There are various properties related to EEE, that we might want to add
support for in the future (for example, "ethtool.eee-advertise").

Don't use up the base name "eee", instead make it "eee-enabled". All
properties should have different prefixes, and "ethtool.eee" would be a
prefix of "ethtool.eee-advertise".

Also, the #define is already called NM_ETHTOOL_OPTNAME_EEE_ENABLED. This
also should be consistent.

Rename.

Fixes: 3165d9a2de ('ethtool: introduce EEE support')

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1792
2023-11-15 09:36:29 +01:00
Thomas Haller
38ad9e5211
cli: sort nmcli device output by active-connection first
Previously, we first sort by the device's state, then by the active
connection's state. Contrast to `nmcli connection`, which first sorts
by the active connection's state.

It means, the sort order is somewhat different. Fix that.

In most cases, that shouldn't make a difference, because the
device's state and the active-connection's state should
correspond. However, it matters as we now treat external activations
different, and that is tied to the active connection.
2023-11-15 09:34:47 +01:00
Thomas Haller
a5f9f2fbfc
cli: sort external connections later in nmcli connection|device
EXTERNAL connections are special. Sort them later. This affects output
of `nmcli connection` and `nmcli device`.
2023-11-15 09:34:47 +01:00
Thomas Haller
8ccd1f7bfe
cli: refactor active_connection_get_state_ord()
Additional logic will be added, that makes the switch() approach
more cumbersome. Use a sorted array instead to find the priority.
2023-11-15 09:34:46 +01:00
Thomas Haller
8e1330964d
cli: fix sorting of active connections
CMP() is a confusing pattern. Sure enough, the sort order was wrong, for
example, `nmcli connection` would show

    $ nmcli -f STATE,UUID,DEVICE c
    STATE       UUID                                  DEVICE
    activating  3098c902-c59c-45f4-9e5a-e4cdb79cfe1b  nm-bond
    activated   e4fc23ac-54ab-4b1a-932a-ebed12c96d9b  eth1

("activating" shown before "activated").

With `nmcli device`, we sort with compare_devices(). This first sorts by
device state (with "connected" being sorted first). Only when the device
state is equal, we fallback to nmc_active_connection_cmp().  So with
`nmcli device` we usually get "connected" devices first, and we don't
really notice that there is a problem with nmc_active_connection_cmp().

On the other hand, `nmcli connection` likes to sort first via
nmc_active_connection_cmp(), which gets it wrong. Profiles in
"activating" state are sorted first. That's inconsistent with `nmcli
device`, but it's also not what is intended.

Fix that.

Note the change in the test output. Both eth1 and eth0 are connected to
to the same profile, but one "eth0" the active-connection's state is
DEACTIVATING, while on "eth1" it's ACTIVATED (but both device's states
are "CONNECTED"). That's why "eth1" is now sorted first (as desired).

Fixes: a1b25a47b0 ('cli: rework printing of `nmcli connection` for multiple active connections')
2023-11-15 09:34:46 +01:00
Thomas Haller
ca5fb29b7e
client/tests: add checks to "test-client.py"
- test for "-order" option with `nmcli connection show`.

- test for order of activated devices. Optimally, the devices
  should be in activating vs. activated state. I fail to do that,
  the mock implementation is cumbersome to use. It still seems useful
  to have this (maybe it could be improved).
2023-11-15 09:34:45 +01:00
Thomas Haller
21c979eb17
glib: undef MIN()/MAX() to make it unusable (use NM variants)
NM variants:

- evaluate arguments only once
- have a static assertion that the signedness of the argument agrees.

Like MIN()/MAX(), NM_MIN()/NM_MAX() now also evaluate to a constant
expression, if the arguments are already constant. That means, the only
reason why MIN()/MAX() was preferable over NM_MIN()/NM_MAX() is no
longer relevant. Except there are a few places where NM_MIN()/NM_MAX()
cannot be used. In those places use NM_MIN_CONST()/NM_MAX_CONST().
2023-11-15 09:32:22 +01:00
Thomas Haller
bee14cf47c
all: use NM_MAX() instead of MAX() 2023-11-15 09:32:21 +01:00
Thomas Haller
b4dd83975e
all: use NM_MIN() instead of MIN() 2023-11-15 09:32:20 +01:00
Thomas Haller
559d071f8d
std-aux: remove NM_CONST_MAX()
We now can use either NM_MAX() or NM_MAX_CONST() instead. Drop this.
2023-11-15 09:32:20 +01:00
Thomas Haller
ca4401e327
all: use NM_MAX() instead of NM_CONST_MAX()
NM_CONST_MAX() is going to be replaced by NM_MAX() (or, in cases where
NM_MAX() cannot be used, by NM_MAX_CONST()). Replace usage.
2023-11-15 09:32:19 +01:00
Thomas Haller
5acd30ca44
all: use NM_MIN_CONST()/NM_MAX_CONST() instead of MIN()/MAX()
glib's MIN()/MAX() will be replaced by NM_MIN()/NM_MAX().
There are however a few places where NM_MIN()/NM_MAX() cannot
be used.

Adjust those places to use NM_MIN_CONST()/NM_MAX_CONST() instead.
2023-11-15 09:32:19 +01:00
Thomas Haller
fa500e5540
glib-aux: let NM_MIN()/NM_MAX() return a compile time constant
Glib's MIN()/MAX() should not be used, in favor of NM_MIN()/NM_MAX().
That's because the NM variants

- evaluate arguments only once
- have a static assertion that the signedness of the arguments matches

However, previously those macros never evaluated to a compile time
constant. Unlike the glib variants, which do so when the arguments are
compile time constants. That is sometimes important when using the
macros in a context that requires a constant.

Extend NM_MIN()/NM_MAX() to be a compile time constant, when possible.

Note that there are still a few places where NM_MIN()/NM_MAX() cannot be
used due to the expression statement. For those cases, there is
NM_MIN_CONST()/NM_MAX_CONST().
2023-11-15 09:32:19 +01:00
Thomas Haller
6f4a60b6f2
all: ensure same signedness of arguments to MIN()/MAX()
Comparing integers of different signedness gives often unexpected
results. Adjust usages of MIN()/MAX() to ensure that the arguments agree
in signedness.
2023-11-15 09:32:18 +01:00
Thomas Haller
5671d73fb5
std-aux: don't use G_STATIC_ASSERT() in "nm-std-aux.h"
libnm-std-aux must not have any glib dependencies. That's why it has
NM_STATIC_ASSERT().
2023-11-15 09:32:08 +01:00
Íñigo Huguet
539d6f436a
gen-metadata-nm-settings-nmcli: fix some printf warnings on 32 bit platforms
The specifiers %ld and %lu are not correct for 64 bit integers on 32 bit
platforms, triggering a warning. Use instead the GLib constants to
correctly define them.

Fixes: 925d4df801 ('man nm-settings-nmcli: add "Valid values" field')
Fixes: 5c6ae44e00 ('man nm-settings-nmcli: add "Special values" field')

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1790
2023-11-14 19:14:12 +01:00
Thomas Haller
4f62600e21
all: use NM_HASH_SEED_16() macro 2023-11-14 14:15:42 +01:00
Thomas Haller
27ae71b504
core: generate fixed fallback timestamp in _host_id_read_timestamp()
nm_hash_siphash42() uses a randomized seed like nm_hash*(). In this case,
we want to always generate the same fake timestamp, based on the host-id.

In practice, it doesn't really matter, because this is only the fallback
path for something gone horribly wrong already.
2023-11-14 14:15:42 +01:00