Later, we should move all such objects. And we should rename
the API to have a unique prefix, like "NMPPlObjIP[4]Address".
This is just a first step that introduces more inconsistencies than it
solves. It will get better afterwards.
This changes a few places where we might have looked up the ifname in
NMPlatform to only print the ifindex. Since the ifindex is the real identifier,
and the logfile is already full of lines that associate the ifname with the ifindex,
this is fine.
On netlink API, the attribute is indeed u32. However, this is an ifindex
which in most other kernel APIs and in NetworkManager code is a signed
integer. Note that of course kernel would only ever assign numbers that
are valid ifindexes, thus in the suitable range.
This optimization seems unnecessary. Just initialize a new route struct
and use it. The advantage is that we can have the variable in the scope
closer to where it's used, and don't need to think about what happens
outside the scope.
Previously, nm_platform_ip_address_sync() would always add the "IFA_F_NOPREFIXROUTE"
flag. Add a way to let the caller control that.
Add a flags argument, with a new flag "with-noprefixroute". By default
(with flags "none"), nm_platform_ip_address_sync() would no longer
add "IFA_F_NOPREFIXROUTE" flag, but the caller can now opt-in to that.
The purpose is that on "lo" interface we will want to let kernel
handle the prefix route. So have a per-ifindex opt-in for controlling
this.
During nm_platform_ip_address_flush() we use "none" flags, because the
function anyway doesn't add any addresses, so it wouldn't matter.
There is no change in behavior.
Co-authored-by: Thomas Haller <thaller@redhat.com>
This flag won't be used. Instead we will pass a flag to
nm_platform_ip_route_sync() to disable addition of the prefix route
flag.
This reverts commit bd84ae4dc5.
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
The removed signal did not log the interface name.
That's because _LOG3D() takes the ifindex and looks into the platform
cache to find the interface name. However, if the link is already
removed, it won't find it.
Fix that by explicitly using the right name.
Before:
<debug> [1660070838.2976] platform: signal: link removed: 602: testX6 <DOWN;broadcast,multicast> mtu 1500
Now:
<debug> [1660070838.2976] platform: (testX6) signal: link removed: 602: testX6 <DOWN;broadcast,multicast> mtu 1500
Since the generic netlink API does (currently) not support notifications
about changes of the MPTCP addresses, we won't get notifications when
they change, and it seems wrong to put such things in the NMPlatform
cache.
We can just get the list of endpoints by polling, so add a function
nm_platform_mptcp_addrs_dump() for that.
Also, add nm_platform_mptcp_addr_update() which can add/remove/update
MPTCP addresses.
We already have two hash functions for MPTCP addresses:
nmp_object_id_hash*() which compares the identity of objects
and nm_platform_mptcp_addr_hash*(), which compares all fields.
There is also a need to hash only the address. Add it. Will be used
next.
Since we don't get netlink notifications when the MPTCP endpoints
change, we don't cache them. And since we don't cache them,
there is less need to mark whether they were received from kernel
or created internally.
sysfs is deprecated and kernel people will not add new bond options to
sysfs. Netlink is a stable API and therefore is the right method to
communicate with kernel in order to set the link options.
`nm_platform_ip_address_sync()` likes to add IFA_F_NOPREFIXROUTE flag
for all addresses, regardless of `a_ifi_flags` property. By setting this
boolean, that automatism can be suppressed, and the noprefixroute flag
does not get added automatically.
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1307
An NMPObject is hashable, can be compared and printed. That is useful.
Make an NMPObject for MPTCP addresses. It will hold the content of
MPTCP_PM_ATTR_ADDR netlink attribute. But like other NMPObject types it
will also be used to represent the data as NetworkManager tracks it.
For generic netlink, the family-id is important. It changes when
loading/unloading a module, so we should not cache it indefinitely.
To get this right, takes some effort. For "nl80211", "nl802154"
and "wireguard", we only cache the family ID in relation to an
interface. If the module gets unloaded, the family ID also becomes
irrelevant and we need to re-fetch it the next time.
For generic families like "mptcp_pm" or "ethtool", they are commonly not
kernel modules and cannot be unloaded. So caching them would be
(probably) fine.
Still. Some generic netlink families emit notifications, and it will
be interesting to be able to handle them. Since that will be useful later,
start by doing something simple: let the generic netlink family also be
cached this way. Generic netlink will send notifications when a family gets
added/deleted, and we can use that to reliably cache the family ID.
We only care about a well-known set of generic families. Unlike libnl
(which has "struct genl_family" object to handle any family), we can hard
code the few we care about (NMPGenlFamilyType).
This adds the necessary infrastructure of NMLinuxPlatform to listen to
events on the generic netlink socket.
The genl types that we care about are well known. Add an enum
for them, so we can do a lookup by index.
To kernel, the corresponding names (like "wireguard") are also well
known. However, the family-id, that we need when using genl are
allocated dynamically. So we need to lookup the family-id, and by having
an enum for the genl type, we can do so generically.
In the past, nmp_lookup_init_object() could both lookup all object for a
certain ifindex, and lookup all objects of a type. That fallback path
already leads to an assertion failure fora while now, so nobody should
be using this function to lookup all objects of a certain type (for
what, we have nmp_lookup_init_obj_type()).
Now, remove the fallback path, and rename the function to what it really
does.
IPv6 temporary addresses are configured by kernel, with the
"ipv6.ip6-privacy" setting ("use_tempaddr" sysctl) and the
IFA_F_MANAGETEMPADDR flag.
As such, the idea was that during reapply we would not remove them.
However, that is wrong.
The only case when we want to keep those addresses, is if during reapply
we are going to configure the same primary address (with mngtmpaddr
flag) again. Otherwise, theses addresses must always go away.
This is quite serious. This not only affects Reapply. Also during disconnect
we clear IP configuration via l3cfg.
Have an ethernet profile active with "ipv6.ip6-privacy". Unplug
the cable, the device disconnects but the temporary IPv6 address is not
cleared. As such, nm_device_generate_connection() will now generate
an external profile (with "ipv6.method=disabled" and no manual IP addresses).
The result is, that the device cannot properly autoconnect again,
once you replug the cable.
This is serious for disconnect. But I could not actually reproduce the
problem using reapply. That is, because during reapply we usually
toggle ipv6_disable sysctl, which drops all IPv6 addresses. I still
went through the effort of trying to preserve addresses that we still
want to have, because I am not sure whether there are cases where we
don't toggle ipv6_disable. Also, doing ipv6_disable during reapply is
bad anyway, and we might want to avoid that in the future.
Fixes: 58287cbcc0 ('core: rework IP configuration in NetworkManager using layer 3 configuration')
(cherry picked from commit 518f6124c6)
Since commit 528a63d9cc ('platform: avoid unnecessary configuration of
IP address in nm_platform_ip_address_sync()'), we no longer configure the
IP address if it is in the platform cache. But the cache might not be
up to date. Process any pending netlink events.
https://bugzilla.redhat.com/show_bug.cgi?id=2073926
Fixes: 528a63d9cc ('platform: avoid unnecessary configuration of IP address in nm_platform_ip_address_sync()')
(cherry picked from commit 7f427ac4e6)
Try to do one change at a time when reconfiguring addresses, to not
remove several/all addresses at once.
For IP addresses, kernel cares about the order in which they were added.
This mostly affects source address selection, and the "secondary" flag
for IPv4 addresses. The order is thus related to the priority of an
address.
There is no direct kernel API to change the order. Instead, we have to
add them in the correct order. During a sync, if an address already
exists in the wrong order, we need to remove it, and re-add it.
Btw, with IPv4 addresses added first via netlink are the primary
address, while with IPv6 it's reverse.
Previously, we would first iterate over all addresses and remove those
that had a conflicting order. This means, that we would potentially
remove all addresses for a short while, before readding them. That seems
problematic.
Instead, first track all addresses that are in the wrong order. And in
the step when we add/update the address, remove it. We now only remove
and address shortly before re-adding it. This way the time for which the
address on the interface is missing is shorter. More importantly, we will
never remove all addresses at the same time.
(cherry picked from commit a6fd641634)
The order of addresses can matter for source address selection.
This is described in RFC 6724 section 5, but if the rules don't
determine a clear winner, the order matters.
Change the relative order of IPv6 addresses. Previously, we would prefer
autoconf6, over DHCPv6, over manual addresses. Now that got reverted
to make more sense and be consistent with IPv4.
Also, if we had multiple autoconf6 addresses (received at different
moments in time), then previously a newly received address would be
added with highest priority. Now, the older address will be preferred
and that order will be enforced (this can be a problem, see (*) below).
For IPv4, it's all simple and sensible. When we add addresses in kernel
via netlink, the first address (of a subnet) becomes the primary.
Note that we only control the order of addresses of the same subnet.
The addresses in ipv4.addresses" are sorted with primary address first.
In the same way is the order for addresses in NML3ConfigData and for
@known_addresses in nm_platform_ip_address_sync(), all primary-first.
Also, manual addresses are sorted with higher priority compared to DHCPv4
addresses (at least since NetworkManager 1.36). That means the way how we
merge NML3ConfigData makes sense (nm_l3_config_data_merge()) because we first
merge the static configuration, then the DHCPv4 configuration, where we just
append the lower priority DHCPv4 addresses.
For IPv6, the address priority is messed up. On netlink/kernel, the last added
address becomes the preferred one (we thus need to add them in the order of
lowest priority first). Consequently and historically, the IPv6 addresses in
@known_addresses parameter to nm_platform_ip_address_sync() were
lowest priority first. And so they were tracked in NML3ConfigData
and in the profile ("ipv6.addresses"). That is confusing.
Also, we usually want to merge NML3ConfigData with different priorities
(e.g. static configuration from the profile before autoconf6/DHCPv6),
as we do with IPv4. However, since internally IPv6 addresses are tracked in
reverse order, it means later NML3ConfigData would be appended and get effectively
a higher priority. That means, autoconf6 addresses were preferred over DHCPv6 and
over manual "ipv6.addresses", respectively. That seems undesirable and inconsistent
with IPv4. Change that. This is a change in behavior.
Note that changing the order of addresses means to remove and re-add
them in the right (inverse) order, with lease important first. This
means, when we add a new address with lower priority, we need to remove
all higher priority addresses temporarily, before readding them. That
is a problem(*).
Note that in the profile, "ipv6.addresses" is still tracked in reverse
order. This did not change, but might change later.
(cherry picked from commit 4a548423b9)
These string functions allow to omit the string buffer. This is for
convenience, to use a global (thread-local) buffer. I think that is
error prone and we should drop that "convenience" feature.
At various places, pass a stack allocated buffer.
(cherry picked from commit b87afac8e8)
We call sync many times. Often there is nothing to update. Check the
cache first, before (re) adding it.
Note that many addresses have a limited lifetime, that is, a lifetime
that keeps counting down with seconds granularity. For those (common)
cases we will only avoid the call to kernel if there are two syncs
within less than a second.
(cherry picked from commit 528a63d9cc)
It is rather unlikely, that we call this function with no existing
routes/addresses. Hence, usually this does not safe an allocation
of the GPtrArray.
However, it's slightly less code and makes more sense this way
(instead of checking afterwards, whether the array is empty and
destroy it).
(cherry picked from commit 6bc9b73c55)
The code is disabled at compile time. It's only useful for printf
debugging to modify the source to get more logging.
(cherry picked from commit fcb4033a81)
ASSUME is causing more troubles than benefits it provides. This patch is
dropping NM_L3_CFG_COMMIT_TYPE_ASSUME and assume_config_once. NM3LCfg
will commit as if the sys-iface-state is MANAGED.
This patch is part of the effort to remove ASSUME from NetworkManager.
After ASSUME is dropped when starting NetworkManager it will take full
control of the interface, re-configuring it. The interface will be
managed from the start instead of assumed and then managed.
This will solve the situations where an interface is half-up and then a
restart happens. When NetworkManager is back it won't add the missing
addresses (which is what assume does) so the interface will fail during
the activation and will require a full activation.
https://bugzilla.redhat.com/show_bug.cgi?id=2050216https://bugzilla.redhat.com/show_bug.cgi?id=2077605https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1196
(cherry picked from commit bf5927b978)
We already have a comparison of NMPlatformIPXAddress with the modes
"full" and "id". The former is needed to fully compare two addresses,
the latter as identity for tracking addresses in the cache.
In NetworkManager we also use the NMPlatformIP[46]Address structure to
track the addresses we want to configure. When we add them in kernel,
we will later see them in the platform cache. However, some fields
will be slightly different. For example, "addr_source" address will
always be "kernel", because that one is not a field we configure in
kernel. Also, the "n_ifa_flags" probably differ (getting "permanent"
and "secondary" flags).
Add a compare function that can ignore such differences.
Also add nm_platform_vtable_address for accessing the IPv4 and IPv6
methods generically (based on an "IS_IPv4" variable).
(cherry picked from commit ef1b60c061)
nmp_utils_lifetime_get() calculates the lifetime of addresses,
and it bases the result on a "now" timestamp.
If you have two addresses and calculate their expiry, then we want to
base it on top of the same "now" timestamp, meaning, we should
only call nm_utils_get_monotonic_timestamp_sec() once. This is also a
performance optimization. But much more importantly, when we make a
comparison at a certain moment, we need that all sides have the same
understanding of the current timestamp.
But nmp_utils_lifetime_get() does not always require the now timestamp.
And the caller doesn't know, whether it will need it (short of knowing
how nmp_utils_lifetime_get() is implemented). So, make the now parameter
an in/out argument. If we pass in an already valid now timestamp, use
that. Otherwise, fetch the current time and also return it.
(cherry picked from commit deb37401e9)
The entire point of the dance in nm_platform_ip_address_sync() is to ensure that
conflicting IPv4 addresses are in their right order, that is, they have
the right primary/secondary flag.
Kernel only sets secondary flags for addresses that are in the same
subnet, and we also only care about the relative order of addresses
that are in the same subnet. In particular, because we rely on kernel's
"secondary" flag to implement this.
But kernel only treads addresses as secondary, if they share the exact
same subnet. For example, 192.168.0.5/24 and 192.168.0.6/25 would not
be treated as primary/secondary but just as unrelated addresses, even if
the address cleared of it's host part is the same.
This means, we must not only hash the network part of the addresses, but
also the prefix length. Implement that, by tracking the full NMPObject.
(cherry picked from commit 619dc2fcab)