When hostname changes, resolv.conf should be rewritten to update the
"search" option with the new domain parameters. If no device is
active nor going to activate, skip triggering resolv.conf update.
The state-change of a device has a reason argument, which is mostly for information
only.
There are many places in code that are the source of a state-reason.
Mostly these are calls to:
- nm_device_state_changed()
- nm_device_queue_state()
- nm_device_queue_recheck_available()
- nm_device_set_unmanaged_by_*()
- nm_device_master_release_one_slave()
- nm_device_ip_method_failed()
- nm_modem_emit_prepare_result()
- nm_modem_emit_ppp_failed()
- nm_manager_deactivate_connection()
- NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_*);
However, there are a few places in code that look at the reason
to decide how to proceed. I think this is a bad pattern, because
cause and effect are decoupled and it gets hard to understand where
a certain reason is set and what consequences that has.
Add a nop-function nm_device_state_reason_check() to mark all uses
of the device state reason that derive decisions from it. That is,
highlight the "effect" part.
Don't reuse NMDeviceStateReason for the autoconnect-blocked-reason. There are
only two cases we care: blocked-due-to-no-secrets, blocked-otherwise.
Encode these values in a new enum type.
NMPolicy's auto_activate_device() wants to sort by autoconnect-priority,
nm_utils_cmp_connection_by_autoconnect_priority() but fallback to the default
nm_settings_connection_cmp_default(), which includes the timestamp.
Extend nm_settings_connection_cmp_default() to consider the
autoconnect-priority as well. Thus change behavior so that
nm_settings_connection_cmp_default() is the sort order that
auto_activate_device() wants. That makes sense, as
nm_settings_connection_cmp_default() already considered the
ability to autoconnect as first. Hence, it should also honor
the autoconnect priority.
When doing that, rename nm_settings_connection_cmp_default()
to nm_settings_connection_cmp_autoconnect_priority().
We call these functions a lot. A GSList is just the wrong tool for the
job. Refactor the code to use instead a sorted array everywhere.
This means, we malloc() one array for all connections instead
slice-allocate a GSList item for each. Also, sorting an array
is faster then sorting a GSList.
Technically, the GSList implementation had the same big-O runtime
complexity, but using an array is still faster. That is, sorting
an array and a GSList is both O(n*log(n)).
Actually, nm_settings_get_connections_sorted() used
g_slist_insert_sorted() instead of g_slist_sort(). That results
in O(n^2). That could have been fixed to have O(n*log(n)), but
instead refactor the code to use an array.
Have a proper cmp() function and a wrapper *_p_with_data() that can be
used for g_qsort_with_data().
Thus, establish a naming scheme (*_p_with_data()) for these compare
wrappers that we need all over the place. Note, we also have
nm_strcmp_p_with_data() for the same reason and later more such
functions will follow.
Keep the include paths clean and separate. We use directories to group source
files together. That makes sense (I guess), but then we should use this
grouping also when including files. Thus require to #include files with their
path relative to "src/".
Also, we build various artifacts from the "src/" tree. Instead of having
individual CFLAGS for each artifact in Makefile.am, the CFLAGS should be
unified. Previously, the CFLAGS for each artifact differ and are inconsistent
in which paths they add to the search path. Fix the inconsistency by just
don't add the paths at all.
The policy listens to signals from shared devices that need subnets and
requesting devices that provide prefixes. Whenever a subnet is needed,
policy tries to obtain a subnets from all of default6 device's prefixes.
When it fails to get any, it asks for more prefixes.
This way we make it possible for the delegating router to either
provide us with a /64 for each of our shared interfaces, or provide a
larger prefix that we could subnet.
The policy also updates the shared device's DNS information to keep it in sync
with the best requesting device changes.
- use _NM_GET_PRIVATE() and _NM_GET_PRIVATE_PTR() everywhere.
- reorder statements, to have GObject related functions (init, dispose,
constructed) at the bottom of each file and in a consistent order w.r.t.
each other.
- unify whitespaces in signal and properties declarations.
- use NM_GOBJECT_PROPERTIES_DEFINE() and _notify()
- drop unused signal slots in class structures
- drop unused header files for device factories
NMPolicy:auto_activate_device() would wrongly not free the
specific_object, although it is documented as transfer-full.
The only implementation of can_auto_connect() that returned
a specific-object is NMDeviceWifi:can_auto_connect(). So, there
wasn't any actual bug or memory leak.
Fixes: 4c028c7cef
Even if we know that the new hostname being set is equal to the cached
old one, the user may have manually changed the kernel hostname in the
meanwhile. For example:
# hostname
host123
# hostname localhost
# nmcli connection up eth1
# (now NM receives 'host123' from DHCP, but
# believes it's already set and doesn't update it)
# hostname
localhost
Let's always try to update the kernel (transient) hostname, unless it
is really already set (as returned by gethostname()).
https://bugzilla.redhat.com/show_bug.cgi?id=1356015
(cherry picked from commit 51b2cef04f)
Commit 9446481f4c ("policy: update system hostname when DHCP
configuration changes") tried to fix the missing hostname change when
IPv4 receives a hostname through DHCP but terminates after IPv6, by
calling update_routing_and_dns() as soon as the new DHCP configuration
was received.
It turns out that doing so is not always effective because the device
must be the "best" device (the one with default route) in order to
trigger a hostname change, but the best device status is decided
later. Updating the hostname in device_ipx_config_changed() should
cover all cases.
Fixes: 9446481f4chttps://bugzilla.redhat.com/show_bug.cgi?id=1356015https://bugzilla.redhat.com/show_bug.cgi?id=1364393
If both IPv4 and IPv6 are enabled and IPv6 terminates first (and
ipv4.may-fail=yes), the device becomes ACTIVATED and we try to update
the system hostname from the DHCP lease, if necessary. But later, the
termination of DHCPv4 doesn't trigger a new update and so it's
possible that the system hostname remains unset even if the DHCPv4
lease specifies a hostname.
To have a deterministic behavior we should always try to update the
system hostname when a DHCP transaction terminates.
https://bugzilla.redhat.com/show_bug.cgi?id=1356015
A infinite activation loop can arise when the master repeatedly fails
activating: slave's _internal_activate_device() calls
ensure_master_active_connection() to activate the master connection
and during master activation activate_slave_connections() resets the
retry counter of slaves.
The autoconnect retry counter of a slave should only be reset for
explicit master activations, not for auto-activations.
https://bugzilla.redhat.com/show_bug.cgi?id=1270814
Since 027f4c65ac, the ip_iface for
nm_dns_manager_add_ip_config() must be set.
Wit interface-less VPN types like libreswan, we thus hit the assertion
nm_dns_manager_add_ip_config: assertion 'iface && iface[0]' failed
Fix that, by fallback to the interface name of the parent device.
Fixes: 027f4c65ac
and nm_vpn_connection_get_ip_ifindex(). For VPN types that have no own
IP interface, we often want instead lookup the IP interface from the
parent device.
nm_settings_get_connections() returns a sorted list. We have many users
of nm_connection_provider_get_connection(), which returns the same result,
but undefined order.
Next NMConnectionProvider will be dropped. Thus, we don't want to
seamlessly replace nm_connection_provider_get_connection() by a sorted
version nm_settings_get_connections().
Rename nm_settings_get_connections() to make clear it is sorted.
This is mostly interesting of NMPolicy, which no longer needs to
subscribe to two almost identical signals (where the by-user signal
was always invoked together with the plain "updated" signal).
schedule_activate_all() needs to iterate over all devices and is thus
relatively costly (and scales O(n^2)).
By scheduling the action on an idle handler we delay and combine
multiple redundant requests.
Another reason is that NM_SETTINGS_CONNECTION_UPDATED is currently
executed on an idle handler which first leads to
NM_SETTINGS_SIGNAL_CONNECTION_UPDATED signal and eventually calls
schedule_activate_all().
I want to change that to emit the connection update signal immediately,
thus to preserve the delay, we delay handling in NMPolicy.
We want to unregister the signals at cleanup time via
g_signal_handlers_disconnect_by_data(). This saves us from
storing the signal handler id or by naming the function
explicitly via g_signal_handlers_disconnect_by_func().
However, the registered user-data @self is a public pointer. That
is ugly, because potentially another component could register a
signal with passing the public @self pointer as user-data.
Although that doesn't currently happen, it is more correct to register
with a private pointer to avoid this case altogether.
Instead of a G_TYPE_INSTANCE_GET_PRIVATE() call every time,
fetching the private data becomes a pointer dereference.
As only one instance of NMPolicy exists, this costs us only
one additional pointer of memory.
If we want to ensure that we create only one single instance of
NMPolicy, just don't create multiple instances. The nm_policy_new()
method should not be restriced and behave like other *new() functions
and create a new object as requested.