Since the event loop isn't running on quit, but we want to ensure that
scripts can fully process the DOWN event, block on scripts completing
when disconnecting the VPN when quitting.
This event runs before a connection/device is announced as
"activated" or "connected", to enable scripts to do things
before applications begin using connectivity. For example,
this could be used to manage /etc/resolv.conf outside of
NetworkManager and ensure that resolv.conf had correct
information before DNS is used.
Note that this is different than the Debian or Gentoo "pre-up"
event used in /etc/network/interfaces, as that event runs before
any L2 configuration has started. If we really need an event
like that, we'll add it later as "lower-up".
Thomas pointed out that using the address of the DispatcherInfo
structure as the dispatcher call ID could cause a mis-cancelation
if malloc re-used the same block in the future. While the code
should be correctly clearing call IDs after the callback runs
or is canceled, just use numeric IDs to avoid potential crashses.
On shutdown we can't defer the response to a callback, so we need to
use synchronous D-Bus calls. Second, sometimes we want to block on
the dispatcher response, like for pre-down.
If there are no dispatcher scripts, don't bother dispatching any
events. This saves some time configuring networking if the event
would have no effect anyway.
The NMDevice dispose() function contained some badly-duplicated logic
about when to deactivate a device on its last ref. This logic should
only run when the device is removed by the manager, since the manager
controls the device's life-cycle, and the manager knows best when to
clean up the device. But since it was tied to the device's refcount,
it could have run later than the manager wanted, or not at all.
It gets better. Dispose duplicated logic that was already done in
nm_device_cleanup(), and then *called* nm_device_cleanup() if the
device was still activated and managed. But the manager already
unmanages the device when removing it, which triggers a call to
nm_device_cleanup(), takes the device down, and resets the IPv6
sysctl properties, which dispose() duplicated too. So by the time
dispose() runs, the device should already be unmanaged if the
manager wants to deconfigure it, and most of the dispose() code
should be a no-op.
Clean all that up and remove duplicated functions. Now, the flow
should be like this:
1) manager decides to remove the device and calls remove_device()
2) if the device should be deconfigured, the manager unmanages
the device
3) the NMDevice state change handler tears down the active connection
via nm_device_cleanup() and resets IPv6 sysctl properties
4) when the device's last reference is finally released, only internal
data members are freed in dispose() because the device should
already have been cleaned up by the manager and be unmanaged
5) if the device should be left running because it has an assumable
connection, then the device is not unmanaged, and no cleanup
happens in the state change handler or in dispose()
Ensure autoip4 is cleaned up when disposing, like we clean up DHCP.
Move things that only free stuff to finalize(), and move things that
unref stuff to dispose (eg, the Firewall Manager stuff).
The following procedure leaves an NMActiveConnection around for a deactivated
device, which causes errors in libnm-glib clients when they cannot create the
GObject for the non-existent device of the AC.
1) allow a device which can assume connections to be activated
2) stop NM, which should leave the device's IP configuration up
3) start NM and allow it to assume the device's existing connection
4) remove the device, either by unplugging it or 'rmmod'
The device is removed by nm-manager.c::remove_device(), but the device object
is not moved to UNMANAGED state, leaving the NMActiveConnection completely
unaware the device has gone away.
The nm-manager.c::remove_device() code did not correctly handle moving a
forcibly removed (eg, by unplugging or 'ip link del' or 'rmmod') device to
the UNMANAGED state when the device was active with an assumed connection.
To fix this, make the conditions when the device should be deactivated
on removal much more explicit.
A device should be deactivated on removal if:
1) it is forcibly removed, eg by the kernel network interface being
removed due to 'ip link del' or hotplugging, or internally by NM due
to a parent WWAN interface taking priority over a WWAN ethernet interface
2) if the device cannot assume connections, in which case NetworkManager
must have activated the device and since we cannot assume the connection
on restart, we should deactivate it
3) if the device is not activated, to ensure that its IPv6 parameters
and other things get reset to the pre-NetworkManager values
https://bugzilla.gnome.org/show_bug.cgi?id=729833
dhcp6_cleanup() frees priv->dhcp6_ip6_config so dispose() doesn't need
to do that. Also use g_clear_object() when appropriate.
Lastly, notify that the DHCP4/6 config objects have changed *after*
clearing them, so that the PropertiesChanged signal is emitted with a
blank path to indicate the object is gone. Previously the PC signal
would have been emitted with the valid path of the DHCP4/6 config object,
but the object would already be dead.
For any function in nm-device.h which is not used outside of
nm-device.c, remove the public prototypes. Functions that
are actually used get moved above their caller, and functions
that have no callers are removed.
Move the GObject-related stuff to the bottom of the file and get
rid of no-longer-necessary forward prototypes since the stuff that
required those prototypes is now below the implementation.
Future patches will allow blocking dispatcher calls, which we
don't want to happen when deactivating a VPN connection during
normal operation. So move code that stops VPN connections outside
of the VPNService object's dispose() function and require the object
that owns the VPNService (the VPNManager) to stop connections at the
right times.
When quitting, blocking calls are acceptable (because NetworkManager's
D-Bus interface is no longer useful, plus we can't easily schedule
callbacks because no mainloop is running), so it's ok to stop
connections from NMVPNManager:dispose.
D-Bus already watches the life-cycle, and we'll get a NameOwnerChanged
signal when the VPN service daemon quit. So the GLib child watch is
just duplicated code that we don't need. Remove it.
Since NM_VPN_CONNECTION_STATE_* are linear in number and defined API,
we can't add a DEACTIVATING state in the right place. So create a
NMVPNConnection internal VPN state and convert that to the old
NM_VPN_CONNECTION_STATE_* numbers at exit points from the object.
(This will also allow us to get rid of priv->secrets_req in the future
and fold that into the VPN states)
Instead of telling a VPN service to quit, leave that up to the service
itself. Services based on libnm-glib-vpn already have a quit timeout
of 20 seconds. We also eventually want to D-Bus activate the VPN
services, and at that point we won't have a PID we can send signals
to.
CC nm-linux-platform.lo
platform/nm-linux-platform.c: In function '_nm_platform_link_get':
platform/nm-linux-platform.c:161:17: error: 'rtnllink' may be used uninitialized in this function [-Werror=maybe-uninitialized]
nl_object_put (*object);
^
platform/nm-linux-platform.c:1923:35: note: 'rtnllink' was declared here
auto_nl_object struct rtnl_link *rtnllink;
^
cc1: all warnings being treated as errors
Signed-off-by: Thomas Haller <thaller@redhat.com>
When only the lifetime of an address changes, we did not get a platform signal
as libnl does not consider the time fields in nl_object_diff().
Workaround by comparing the timestamps manually.
Signed-off-by: Thomas Haller <thaller@redhat.com>
Moving setting the source of the address to the init_* functions.
This also has the advantage, that the platform internal to_string functions have the proper
source set.
Signed-off-by: Thomas Haller <thaller@redhat.com>
Change the to_string functions to convert the lifetime/preferred values
to the time remaining when the function is evaluated. These functions
are used for printing/debugging, so it's more sensible to show the
remaining time.
On the other hand, for debugging, it's better to see the raw values (also).
In addition to the remaining time we keep to print the timestamps+now if the
address is not permanent. So when inspecting the logs it is possible to figure
out the real values.
Signed-off-by: Thomas Haller <thaller@redhat.com>
Replace the calls to subtract_guint32() by _rebase_relative_time_on_now()
and _address_get_lifetime().
Signed-off-by: Thomas Haller <thaller@redhat.com>
The kernel tells the address lifetimes in the 'struct ifa_cacheinfo'
attribute. This contains two timestamps (cstamp and tstamp) and two
relative lifetimes (ifa_prefered and ifa_valid).
The timestamps are equal to clock_gettime(CLOCK_MONOTONIC) scale in
1/100th of a second (wrapping every 497 days).
The preferred/valid times are re-adjusted everytime when sending the
message and count down as the time goes by. In other words, they are
anchored relatively to the moment of when kernel creates the netlink
message.
As platform is caching the rtnl_addr object, the information of *when* the
lifetimes started counting is not available.
This patch fixes reading these values by hacking the libnl object
when it gets received, so that valid and preferred are instead absolute
expiration timestamps in scale nm_utils_get_monotonic_timestamp_s() --
which NM internally is used for address timestamps.
There are two minor downsides to this hack:
- the valid and preferred properties of a cached rtnl_addr object have
an unexpected meaning, i.e. they are absolute and in a different time
scale.
- later when converting rtnl_addr to NMPlatformIPAddress, the base
timestamp is set to "1", i.e. an NMPlatformIPAddress has no knowledge
of when the address was created or last modified. The timestamp
property of NMPlatformIPAddress is solely there to anchor the relative
timestamps lifetime and preferred. Do not use it for anything
else.
Another reason the timestamp property is meaningless is that
its scale nm_utils_get_monotonic_timestamp_s() starts counting at
process start. So addresses that existed before would have a negative
or zero timestamp, which we avoid. This in turn could be solved by either
allowing negative timestamps or by shifting
nm_utils_get_monotonic_timestamp_*(). Both is viable, but not
necessary (ATM), because the age of an address has no other apparent
use then to anchor the relative timestamps.
Another implication is, that we potentially could get rid of the
timestamp completely, and insteat make preferred and lifetime be
absolute expiries.
This will be fixed properly later, by not caching libnl objects but instead
native NMPlatform objects. For those we have full control over their properties.
https://bugzilla.gnome.org/show_bug.cgi?id=727382
Signed-off-by: Thomas Haller <thaller@redhat.com>