Commit graph

1105 commits

Author SHA1 Message Date
Thomas Haller
38273a8871 settings: use delegation instead of inheritance for NMSettingsConnection and NMConnection
NMConnection is an interface, which is implemented by the types
NMSimpleConnection (libnm-core), NMSettingsConnection (src) and
NMRemoteConnection (libnm).

NMSettingsConnection does a lot of things already:

  1) it "is-a" NMDBusObject and exports the API of a connection profile
     on D-Bus
  2) it interacts with NMSettings and contains functionality
     for tracking the profiles.
  3) it is the base-class of types like NMSKeyfileConnection and
     NMIfcfgConnection. These handle how the profile is persisted
     on disk.
  4) it implements NMConnection interface, to itself track the
     settings of the profile.

3) and 4) would be better implemented via delegation than inheritance.

Address 4) and don't let NMSettingsConnection implemente the NMConnection
interface. Instead, a settings-connection references now a NMSimpleConnection
instance, to which it delegates for keeping the actual profiles.

Advantages:

  - by delegating, there is a clearer separation of what
    NMSettingsConnection does. For example, in C we often required
    casts from NMSettingsConnection to NMConnection. NMConnection
    is a very trivial object with very little logic. When we have
    a NMConnection instance at hand, it's good to know that it is
    *only* that simple instead of also being an entire
    NMSettingsConnection instance.

    The main purpose of this patch is to simplify the code by separating
    the NMConnection from the NMSettingsConnection. We should generally
    be aware whether we handle a NMSettingsConnection or a trivial
    NMConnection instance. Now, because NMSettingsConnection no longer
    "is-a" NMConnection, this distinction is apparent.

  - NMConnection is implemented as an interface and we create
    NMSimpleConnection instances whenever we need a real instance.
    In GLib, interfaces have a performance overhead, that we needlessly
    pay all the time. With this change, we no longer require
    NMConnection to be an interface. Thus, in the future we could compile
    a version of libnm-core for the daemon, where NMConnection is not an
    interface but a GObject implementation akin to NMSimpleConnection.

  - In the previous implementation, we cannot treat NMConnection immutable
    and copy-on-write.
    For example, when NMDevice needs a snapshot of the activated
    profile as applied-connection, all it can do is clone the entire
    NMSettingsConnection as a NMSimpleConnection.
    Likewise, when we get a NMConnection instance and want to keep
    a reference to it, we cannot do that, because we never know
    who also references and modifies the instance.
    By separating NMSettingsConnection we could in the future have
    NMConnection immutable and copy-on-write, to avoid all unnecessary
    clones.
2018-08-28 22:27:55 +02:00
Thomas Haller
d32da2daaa shared: move nm_utils_array_find_binary_search() to shared utils 2018-08-10 10:38:19 +02:00
Beniamino Galvani
ffb4e36fee manager: fix assuming multi-connect connections
When assuming existing connections, allow the same connection to be
activated on a different device if the connection is multi-connect
capable. Otherwise, when a connection is active on multiple devices
and NM is restarted, we assume only the first instance, and create
in-memory connections for others.
2018-08-08 11:34:02 +02:00
Thomas Haller
16389f1037 core: implement connection.multi-connect to activate profiles multiple times
Make use of the new property, and implement it.

See previous commits for the reasons why.

https://bugzilla.redhat.com/show_bug.cgi?id=1555012
2018-08-08 11:24:29 +02:00
Thomas Haller
07a421913b core: extend nm_manager_get_activatable_connections() for autoconnect and multi-connect
In general, a activatable connection is one that is currently not
active, or supports to be activatable multiple times according to
multi-connect setting. In addition, during autoconnect, a profile
which is marked as multi-connect=manual-multiple will not be avalable.
Hence, add an argument "for_auto_activation".

The code is mostly unused but will be used next (except for connections,
which set connection.multi-connect=multiple).
2018-08-08 11:24:29 +02:00
Beniamino Galvani
614f4733e2 manager: use NM_IN_SET()
No functional change.
2018-08-02 16:39:44 +02:00
Beniamino Galvani
8bbe61206f manager: update the device state file upon (dis)connection
Update the device state file every time the device is connected,
disconnected, or becomes unmanaged.  In this way, NM becomes more
robust against crashes or forced terminations because it can resume
the previous device state seamlessly.
2018-08-02 16:39:44 +02:00
Beniamino Galvani
060f2138ee manager: rename nm_manager_write_device_state()
Rename nm_manager_write_device_state() to
nm_manager_write_device_state_all(), and split out the code to write a
single device state to a new function.
2018-08-02 16:39:44 +02:00
Thomas Haller
3000ade72a core: improve error message when activating profile
Before:

    $ nmcli connection up my-wired
    Error: Connection activation failed: No suitable device found for this connection.

After:

    $ nmcli connection up my-wired
    Error: Connection activation failed: No suitable device found for this connection (device eth0 not available because device has no carrier).

This relies on nm_manager_get_best_device_for_connection() giving a
suitable error. That is however a bit complicated, because if no
suitable device is found, it's not immediately clear what is the
exact reason. E.g. if you try to activate a Wi-Fi profile, the
failure reason

    "SSID is not visible"

is better than

    "Wi-Fi profile cannot activate on ethernet device".

This is controlled by carefully setting the failure codes
NM_UTILS_ERROR_CONNECTION_AVAILABLE_* to indicate an absolute
relevance of the failure. And subsequently, by selecting the failure
with the highest relevance. This might still need some improvements,
for example by reordering checks (so that more relevant failures
are handled first) and tweaking the error relevance.
2018-07-24 09:39:09 +02:00
Thomas Haller
e9f6bb0bbb core: improve error message when activating profile on device
Before:

    $ nmcli connection up my-wired ifname eth0
    Error: Connection activation failed: Connection 'my-wired' is not available on the device eth0 at this time.

After:

    $ nmcli connection up my-wired ifname eth0
    Error: Connection activation failed: Connection 'my-wired' is not available on device eth0 because device has no carrier
2018-07-24 09:39:09 +02:00
Thomas Haller
7bad40109e core: return error reason from nm_manager_get_best_device_for_connection()
Still unused, but will be used to give a better failure reason when
no device is found.

The difficulty here is to select the failure message from the most appropriate
device. This might still need some tweaking by setting the error codes accordingly
and re-ordering checks so that failure cares that are more accurate are handled
first.
2018-07-24 09:39:09 +02:00
Thomas Haller
33a88ca566 core: give better error reason why device is incompatible with profile
Note the special error codes  NM_UTILS_ERROR_CONNECTION_AVAILABLE_*.
This will be used to determine, whether the profile is fundamentally
incompatible with the device, or whether just some other properties
mismatch. That information will be importand during a plain `nmcli
connection up`, where NetworkManager searches all devices for a device
to activate. If no device is found (and multiple errors happened),
we want to show the error that is most likely relevant for the user.

Also note, how NMDevice's check_connection_compatible() uses the new
class field "device_class->connection_type_check_compatible" to simplify
checks for compatible profiles.

The error reason is still unused.
2018-07-24 09:39:09 +02:00
Thomas Haller
570e1fa75b core: give better error reason why device is unavailable
The error reason is still unused.
2018-07-24 09:39:09 +02:00
Thomas Haller
e1c7a2b5d0 all: don't use gchar/gshort/gint/glong but C types
We commonly don't use the glib typedefs for char/short/int/long,
but their C types directly.

    $ git grep '\<g\(char\|short\|int\|long\|float\|double\)\>' | wc -l
    587
    $ git grep '\<\(char\|short\|int\|long\|float\|double\)\>' | wc -l
    21114

One could argue that using the glib typedefs is preferable in
public API (of our glib based libnm library) or where it clearly
is related to glib, like during

  g_object_set (obj, PROPERTY, (gint) value, NULL);

However, that argument does not seem strong, because in practice we don't
follow that argument today, and seldomly use the glib typedefs.
Also, the style guide for this would be hard to formalize, because
"using them where clearly related to a glib" is a very loose suggestion.

Also note that glib typedefs will always just be typedefs of the
underlying C types. There is no danger of glib changing the meaning
of these typedefs (because that would be a major API break of glib).

A simple style guide is instead: don't use these typedefs.

No manual actions, I only ran the bash script:

  FILES=($(git ls-files '*.[hc]'))
  sed -i \
      -e 's/\<g\(char\|short\|int\|long\|float\|double\)\>\( [^ ]\)/\1\2/g' \
      -e 's/\<g\(char\|short\|int\|long\|float\|double\)\>  /\1   /g' \
      -e 's/\<g\(char\|short\|int\|long\|float\|double\)\>/\1/g' \
      "${FILES[@]}"
2018-07-11 12:02:06 +02:00
Beniamino Galvani
522e49edd6 policy: track best active connections rather than best devices
If a VPN with default route is activated, the Manager's
PrimaryConnection property is not updated to indicate the VPN as
primary connection.

This happens because the PrimaryConnection property gets updated when
the default_ipX_device property of NMPolicy changes, and the primary
connection is set to the activation request currently pending on the
default device. We select the base (for example, ethernet) device as
best device and therefore the NMActRequest active on it is selected as
primary connection.

This patch fixes the problem by properly selecting the VPN as
primary. It seems a better choice to track best active connections
directly from NMPolicy instead of going through two steps.
2018-07-09 14:56:59 +02:00
Beniamino Galvani
e205664ba8 manager: accept non-null device for VPN activations
Commit 10753c3616 ("manager: merge VPN handling into
_new_active_connection()") added a check to fail the activation of
VPNs when a device is passed to ActivateConnection(), since the device
argument is ignored for VPNs.

This broke activating VPNs from nm-applet as nm-applet sets both the
specific_object (parent-connection) and device arguments in the
activation request.

Note that we already check in _new_active_connection() that when a
device is supplied, it matches the device of the parent
connection. Therefore, the check can be dropped.

Reported-by: Michael Biebl <biebl@debian.org>
Fixes: 10753c3616

https://github.com/NetworkManager/NetworkManager/pull/159
2018-07-09 13:28:47 +02:00
Francesco Giudici
7443e75d22 manager/trivial: fix typo in comment 2018-06-27 14:44:24 +02:00
Thomas Haller
31245cdd62 manager: return NULL for invalid ifindex in nm_manager_get_device_by_ifindex()
Internally, the device migth have negative or zero ifindex.
When calling nm_manager_get_device_by_ifindex(), the caller
wants to find a device with a valid ifindex, hence filter
out non-positive values.
2018-06-22 16:39:01 +02:00
Beniamino Galvani
a2b85d5c6e manager: fix typo in 'PrimaryConnectionType' D-Bus property name
Fixes: 297d4985ab
2018-06-22 15:53:46 +02:00
Alfonso Sánchez-Beato
ca3bbede74 core: don't shutdown interfaces if they have wowlan enabled
This is to support the S5 case, where usually the NM process is
stopped. If we are stopping and WoWLAN is set for the interface,
we do not deconfigure it and keep the connection alive so we
can receive packages that will potentially wake up the system.

Note that for this work, wpa_supplicant needs to be modified too
so it does not deconfigure the wireless interface either when
stopped. The needed patches for wpa_supplicant can be found in
http://lists.infradead.org/pipermail/hostap/2018-June/038644.html
2018-06-15 09:46:26 +02:00
Beniamino Galvani
7696e6c1fa manager: fix failed assertion on user activations
We can't use g_steal_pointer(&active) in the argument list if another
argument uses @active because the order of evaluation is not defined.

This fixes the following bug:

 src/nm-manager.c:511:_async_op_complete_ac_auth_cb: assertion failed: (active == async_op_data->ac_auth.active)

Fixes: f4fc62bad8

https://bugzilla.redhat.com/show_bug.cgi?id=1585494
2018-06-04 18:06:47 +02:00
Lubomir Rintel
e69d386975 all: use the elvis operator wherever possible
Coccinelle:

  @@
  expression a, b;
  @@
  -a ? a : b
  +a ?: b

Applied with:

  spatch --sp-file ternary.cocci --in-place --smpl-spacing --dir .

With some manual adjustments on spots that Cocci didn't catch for
reasons unknown.

Thanks to the marvelous effort of the GNU compiler developer we can now
spare a couple of bits that could be used for more important things,
like this commit message. Standards commitees yet have to catch up.
2018-05-10 14:36:58 +02:00
Thomas Haller
5ab7f6f108 manager: search all existing active connections during nm_manager_get_best_device_for_connection()
In nm_manager_get_best_device_for_connection(), not only check whether the first found
active-connection has a device. There might be multiple candidates, in which case iterate
over them and figure out which one is the most suitable.

Also, despite the found @ac has the same settings-connection, it does not
mean that the connection is available on the device. Extend the check and
only return compatible and ready devices. This can easily happen that
the settings-connection was modified in the meantime and no longer is
compatible with the device (despite currently being active on the
device, but with the previous settings).
2018-04-30 16:36:30 +02:00
Thomas Haller
f1a58e7517 manager: disconnect all conflicting concurrent active connections in _internal_activate_device()
It is possible, that there are multiple such conflicting connections.
Maybe not now, but with connecition cardinality it will soon be.

Find and disconnect them all.
2018-04-30 16:36:30 +02:00
Thomas Haller
9ab3d019e4 core: rework nm_device_steal_connection()
nm_device_steal_connection() was a bit misleading. It only had one caller,
and what _internal_activate_device() really wants it to deactivate all
other active-connections for the same connection. Hence, it already
performed a lookup for the active-connection that should be disconnected,
only to then lookup the device, and tell it to steal the connection.

Note, that if existing_ac happens to be neither the queued nor the currenct
active connection, then previously it would have done nothing. It's
unclear when that exactly can happen, however, we can avoid that
question entirely.

Instead of having steal-connection(), have a disconnect-active-connection().
If there is no matching device, it will just set the active-connection's
state to DISCONNECTED. Which in turn does nothing, if the state is
already DISCONNECTED.
2018-04-30 16:36:30 +02:00
Thomas Haller
3a2fbab09b core: don't consider deactivating active-connection when checking for concurrent activations
At various places we check whether we have an active-connection already.

For example, when activating a new connection in _internal_activate_device(),
we might want to "nm_device_steal_connection()" if the same profile is
already active.

However, the max-state argument was not accurate in several cases. For
the purpose of finding concurrent activations, we don't care about
active-connections that are already in state DEACTIVATING. Only those
that are ACTIVATED or before.
2018-04-30 16:36:30 +02:00
Thomas Haller
36ed7ef084 manager: minor refactoring of active_connection_find_by_connection()
active_connection_find_by_connection() (or how it was called previously) is
a simpler wrapper around active_connection_find(), which accepts a NMConnection
argument, that may or may not be a NMSettingsConnection.

It always passed NM_ACTIVE_CONNECTION_STATE_DEACTIVATING as max_state, and I think
that one of the two callers don't should do that. A later commit will change that.
So, we also want to pass @max_state as argument to active_connection_find_by_connection().
At that point, make active_connection_find_by_connection() identical to
active_connection_find(), with the only exception, that it accepts a
NMConnection and does automatically do the right thing (either lookup by
pointer equality or by uuid).
2018-04-30 16:36:29 +02:00
Thomas Haller
9424aa0562 manager: extend helper function to find all matching active-connections
... instead of just the first.

It's not used yet, and there is no change in behavior.
2018-04-30 16:36:29 +02:00
Thomas Haller
9c2785f31c core: only abort conflicting activations for certain activation types
There are various places where we do an internal activation (with an
internal auth-subject). In several of these places, the
ACTIVATION_REASON is USER_REQUEST.

I think it is wrong to generally abort all internal activations, except
AUTOCONNECT_SLAVES ones. I think, aborting an activation should be
opt-in instead of opt-out.

To me it seems, we want to abort the activation based on the activation
reason. For now, opt-in to EXTERNAL, ASSUME and AUTOCONNECT only. If
there are additional cases where we should abort activation, we should
add yet another reason and not use USER_REQUEST.
2018-04-30 16:36:29 +02:00
Thomas Haller
5a1f84b085 core: add activation-reasons for external/assume connections
Until now, we only really cared about whether a connection was activated
with reason NM_ACTIVATION_REASON_AUTOCONNECT_SLAVES or not.

Now however, we will care about whether a connection was activated via
(genuine) autoconnect by NMPolicy, or external/assume by NMManager.
Add a new reason to distinguish between them.
2018-04-30 16:36:29 +02:00
Beniamino Galvani
e09b2314b9 manager: fix assertion in nm_manager_activate_connection()
nm_manager_activate_connection() should not require a device to be
passed in for VPN connections because when the argument is NULL the
actual device will be determined by _new_active_connection().

Fixes: 10753c3616
https://bugzilla.redhat.com/show_bug.cgi?id=1570545
https://github.com/NetworkManager/NetworkManager/pull/109
2018-04-30 16:23:01 +02:00
Thomas Haller
3d2da8cd05 core/dbus: stop NMDBusManager and reject future method calls
During shutdown, we will need to still iterate the main loop
to do a coordinated shutdown. Currently we do not, and we just
exit, leaving a lot of objects hanging.

If we are going to fix that, we need during shutdown tell
NMDBusManager to reject all future operations.

Note that property getters and "GetManagerObjects" call is not
blocked. It continues to work.

Certainly for some operations, we want to allow them to be called even
during shutdown. However, these have to opt-in.

This also fixes an uglyness, where nm_dbus_manager_start() would
get the set-property-handler and the @manager as user-data. However,
NMDBusManager will always outlife NMManager, hence, after NMManager
is destroyed, the user-data would be a dangling pointer. Currently
that is not an issue, because
  - we always leak NMManager
  - we don't run the mainloop during shutdown
2018-04-24 10:25:26 +02:00
Thomas Haller
5b199b2e7d core/trivial: add FIXME comments about clean shutdown at exit 2018-04-24 10:25:26 +02:00
Thomas Haller
8b5f641211 settings: pass in authentication subject to nm_settings_add_connection_dbus()
nm_settings_add_connection_dbus() has two callers. One of them is NMManager
during AddAndActivate. In this case, the NMActiveConnection already created
an auth-subject. Re-use it.

Note how creating an auth-subject involves reading procfs to determine
whether the process still exists. This is not about the additional
overhead of that, but about the race where the process could drop
of in the meantime. The calling process might be gone now, and we would
fail creating the auth-subject. There is no need for that, because we
already evaluated all information we need. Quite likely, in the case
of this race, PolicyKit will also determine that the process is gone
and fail authorization too. But that's PolicyKit's decision to make,
not nm_settings_add_connection_dbus()'s.
2018-04-24 10:25:26 +02:00
Thomas Haller
f4fc62bad8 manager: track pending authorizations for activating connections
We cannot just fire off asynchronous actions without keeping a handle
to them. Otherwise, it's impossible for NMManager to know which
asynchronous operations are pending, and more importantly: it cannot
cancel them.

One day, I want that we do a clean shutdown, where NetworkManager stops
all pending operations, and cleans up everything. That implies, that
every operation is cancellable in a timely manner.

Rework pending nm_active_connection_authorize() calls to be tracked in a
list, so that they are still reachable to NMManager. Note that currently
NMManager does not yet try to cancel these operations ever. However, it
would now be possible to do so.
2018-04-24 10:25:26 +02:00
Thomas Haller
e8c3fcae2a manager: use nm_utils_user_data_pack() instead of explicit AddAndActivateInfo structure 2018-04-24 09:03:39 +02:00
Thomas Haller
9abe3dc1a4 core: rework passing user-data to nm_active_connection_authorize()
Previously, nm_active_connection_authorize() accepts two user-data
pointers for convenience.

nm_active_connection_authorize() has three callers. One only requires
one user-data, one passes two user-data pointers, and one requires
three pointer.

Also, the way how the third passes the user data (via
g_object_set_qdata_full()) is not great.

Let's only use one user-data pointer. We commonly do that, and it's easy
enough to allocate a buffer to pack multiple pointers together.
2018-04-24 09:03:39 +02:00
Beniamino Galvani
edcb80d1b0 manager: fix assertions when activating VPNs
_new_active_connection() can be called with both a device and a
specific object set when activating secondaries.

Fixes: 10753c3616
2018-04-20 16:26:26 +02:00
Beniamino Galvani
e732403a9b manager: fix activating VPN connections
nm_manager_activate_connection() is also called for VPNs.

Fixes: 3e3d53ce69
2018-04-20 16:26:26 +02:00
Beniamino Galvani
8cbce0e18f manager: fix auth-subject cleanup
Fixes: bac7a2821f
2018-04-19 11:54:03 +02:00
Beniamino Galvani
236edfc908 manager: trust the state file more when assuming connections
If we can't generate a connection and maybe_later is TRUE, it means
that the device can generate/assume connections but it failed for the
moment due to missing master/slaves/addresses. In this case, just
assume the connection from state file.

https://bugzilla.redhat.com/show_bug.cgi?id=1551958
2018-04-19 10:30:19 +02:00
Beniamino Galvani
aca671fff0 all: replace "it's" with "its" where needed 2018-04-18 14:14:07 +02:00
Thomas Haller
c3fb02641a device: set device's sys-iface-state only shortly before activating device
During _new_active_connection() we just create the NMActiveConnection
instance to proceed with authorization. The caller might not even
authorize, so we must not touch the device yet.

Do that only later.
2018-04-18 07:55:15 +02:00
Thomas Haller
9fe4239f33 manager: some refactoring of error paths to return early
Often, functions perform a series of steps, and when they fail,
they bail out. It's simpler if the code is structured that way,
so you can read it from top to bottom and whenever something is
wrong, either return directly (or goto a cleanup label at the
bottom).
2018-04-18 07:55:15 +02:00
Thomas Haller
5c4a6e9b6d manager: ensure valid specific_object path is passed to _new_active_connection()
From the D-Bus layer, no specific-object is represented by "/". We
should early on normalize such values to NULL, and not expect or
handle them later (like during _new_active_connection()).
2018-04-18 07:55:15 +02:00
Thomas Haller
10753c3616 manager: merge VPN handling into _new_active_connection()
Merge _new_vpn_active_connection() into _new_active_connection(). It was the
only caller, and it is simpler to have all the code visible at one place.

That also shows, that the device argument is ignored and not handled.
Ensure that no device is specified for VPN type activations.
2018-04-18 07:55:15 +02:00
Thomas Haller
0458e4bb28 manager: use cleanup attribute in impl_manager_add_and_activate_connection() and related
Also, in _add_and_activate_auth_done(), always steal the connection
from active's user-data. Otherwise, the lifetime of the connection
is extended until active gets destroyed. For example, if we would leak
active, we would also leak connection that way.
2018-04-18 07:55:15 +02:00
Thomas Haller
3e3d53ce69 manager: add is-vpn argument to _new_active_connection() and avoid searching existing activations
- pass is-vpn to _new_active_connection(). It is confusing that _new_active_connection()
  would re-determine whether a connection is a VPN type, although that was already
  established previously. The confusing part is: will they come to the
  same result? Why? What if not?
  Instead pass it as argument and assert that we got it right.

- the check for existing connections should look whether there is an existing
  active connection of type NMVpnConnection. Instead, what matters is,
  - do we have a connection of type VPN (otherwise, don't even bother
    to search for existing-ac)
  - is the connection already active?
  Checking whether the connection is already active, and ask backwards
  whether it's of type NMVpnConnection is odd, maybe even wrong in
  some cases.
2018-04-18 07:55:15 +02:00
Thomas Haller
7fcdca29b6 manager: add _connection_is_vpn() helper to unify checks for VPN type 2018-04-18 07:55:15 +02:00
Thomas Haller
bdc622fd31 manager/trivial: rename boolean variable "vpn" to "is_vpn" 2018-04-18 07:55:15 +02:00