Commit graph

1592 commits

Author SHA1 Message Date
Thomas Haller
310ea1bc6a device: fix reapply for policy routing rules
We need to re-sync the rules.
2019-07-29 18:39:49 +02:00
Thomas Haller
9eddf9fb09 settings: track profiles on disk that are shadowed by in-memory connections
Via Update2() D-Bus API there are three ways how a profile can be stored
(or migrated) to in-memory:

  - NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY
  - NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED
  - NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY

With the recent rework of settings I dropped NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY
and it had the same meaning as NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED.

However, the way NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED was implemented is
problematic. The problem is that it leaves the profile on disk but creates an
in-memory representation which shadows the persistent storage. Later,
when storing the profile to disk again, a new filename is chosen.
This allows via D-Bus API to toggle between NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED
and NM_SETTINGS_UPDATE2_FLAG_TO_DISK, and thereby pilling up profiles on disk.
Also, there is no D-Bus API to do anything sensible with these leaked, shadowed
profiles on disk.

Note that if we have a read-only profile in /usr/lib or in ifupdown
plugin, then the problem is not made any worse. That is, because via D-Bus
API such profiles can be made in-memory, and afterwards stored to /etc.
Thereby too the profile gets duplicate on disk, but this game only
works once. Afterwards, you cannot repeat it to create additional
profiles on disk. It means, you can only leak profiles once, and only
if they already exist in read-only storage to begin with.

This problem with NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED already existed
before the settings-delegate-storage rework, and is unrelated to whether in-memory
profiles now happen to be persisted to /run.

Note that NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY is simple and does not suffer
from this problem. When you move a profile to in-memory-only, it gets deleted from
persistent storage and no duplication happens.

The problem is that NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED used to
forget about the profile that it shadows, and that is wrong.

So, first re-add proper support for NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY. This
works by remembering the "shadowed-storage" path for in-memory profiles.
When later saving such a profile to disk again, the shadowed-storage
will be re-used. Likewise, when deleting such a profile, the shadowed
storage will be deleted.

Note that we keep NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED and it
also remembers the shadowed storage (but without "owning" it). That means,
when such a profile gets saved to disk again, the orginal storage is
reused too. As such, during future updates it behaves just like
NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY. The difference is when deleting
such a profile. In this case, the profile is left on storage and a
tombstone gets written. So, how is this better than before and why even
keep this complicated flag?
First, we keep this flag because we really want the ansible role to be
able to do in-memory changes only. That implies being able to delete a
profile from NetworkManager's view, but not from persistent storage. Without
this flag there is no way to do that. You can only modify an on-disk profile
by shadowing it, but you could not delete it form NetworkManager's view
while keeping it on disk.

The new form of NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED is safe and avoids
the duplication problem because also for tombstones it remembers the original
"shadowed-storage". That is, when the profile gets recreated later via
D-Bus API AddConnection, then the re-created profile will still reference
and reuse the shadowed storage that it had before deletion.
2019-07-25 23:27:49 +02:00
Thomas Haller
f13454cb1c device: move check for no-auto-default to "nm-settings.c"
nm_config_set_no_auto_default_for_device() is called by NMSettings,
so it makes sense that also NMSettings checks whether the device is
blocked.

Of course, there is little difference in practice.

The only downside is that most device types don't implement
new_default_connection(). So the previous form performed the
cheaper check first. On the other hand, we do expect to have
profiles for the devices anyway.
2019-07-25 10:48:40 +02:00
Thomas Haller
7644b18443 device: move check for config "no-auto-default" to NMDevice's new_default_connection()
Only NMDeviceEthernet implements new_default_connection(). Anyway, it
makes only sense to do this precheck by the caller first, and not by
each implementation.
2019-07-17 13:55:13 +02:00
Thomas Haller
d35d3c468a settings: rework tracking settings connections and settings plugins
Completely rework how settings plugin handle connections and how
NMSettings tracks the list of connections.

Previously, settings plugins would return objects of (a subtype of) type
NMSettingsConnection. The NMSettingsConnection was tightly coupled with
the settings plugin. That has a lot of downsides.

Change that. When changing this basic relation how settings connections
are tracked, everything falls appart. That's why this is a huge change.
Also, since I have to largely rewrite the settings plugins, I also
added support for multiple keyfile directories, handle in-memory
connections only by keyfile plugin and (partly) use copy-on-write NMConnection
instances. I don't want to spend effort rewriting large parts while
preserving the old way, that anyway should change. E.g. while rewriting ifcfg-rh,
I don't want to let it handle in-memory connections because that's not right
long-term.

--

If the settings plugins themself create subtypes of NMSettingsConnection
instances, then a lot of knowledge about tracking connections moves
to the plugins.
Just try to follow the code what happend during nm_settings_add_connection().
Note how the logic is spread out:
 - nm_settings_add_connection() calls plugin's add_connection()
 - add_connection() creates a NMSettingsConnection subtype
 - the plugin has to know that it's called during add-connection and
   not emit NM_SETTINGS_PLUGIN_CONNECTION_ADDED signal
 - NMSettings calls claim_connection() which hocks up the new
   NMSettingsConnection instance and configures the instance
   (like calling nm_settings_connection_added()).
This summary does not sound like a lot, but try to follow that code. The logic
is all over the place.

Instead, settings plugins should have a very simple API for adding, modifying,
deleting, loading and reloading connections. All the plugin does is to return a
NMSettingsStorage handle. The storage instance is a handle to identify a profile
in storage (e.g. a particular file). The settings plugin is free to subtype
NMSettingsStorage, but it's not necessary.
There are no more events raised, and the settings plugin implements the small
API in a straightforward manner.
NMSettings now drives all of this. Even NMSettingsConnection has now
very little concern about how it's tracked and delegates only to NMSettings.

This should make settings plugins simpler. Currently settings plugins
are so cumbersome to implement, that we avoid having them. It should not be
like that and it should be easy, beneficial and lightweight to create a new
settings plugin.

Note also how the settings plugins no longer care about duplicate UUIDs.
Duplicated UUIDs are a fact of life and NMSettings must handle them. No
need to overly concern settings plugins with that.

--

NMSettingsConnection is exposed directly on D-Bus (being a subtype of
NMDBusObject) but it was also a GObject type provided by the settings
plugin. Hence, it was not possible to migrate a profile from one plugin to
another.
However that would be useful when one profile does not support a
connection type (like ifcfg-rh not supporting VPN). Currently such
migration is not implemented except for migrating them to/from keyfile's
run directory. The problem is that migrating profiles in general is
complicated but in some cases it is important to do.

For example checkpoint rollback should recreate the profile in the right
settings plugin, not just add it to persistent storage. This is not yet
properly implemented.

--

Previously, both keyfile and ifcfg-rh plugin implemented in-memory (unsaved)
profiles, while ifupdown plugin cannot handle them. That meant duplication of code
and a ifupdown profile could not be modified or made unsaved.
This is now unified and only keyfile plugin handles in-memory profiles (bgo #744711).
Also, NMSettings is aware of such profiles and treats them specially.
In particular, NMSettings drives the migration between persistent and non-persistent
storage.

Note that a settings plugins may create truly generated, in-memory profiles.
The settings plugin is free to generate and persist the profiles in any way it
wishes. But the concept of "unsaved" profiles is now something explicitly handled
by keyfile plugin. Also, these "unsaved" keyfile profiles are persisted to file system
too, to the /run directory. This is great for two reasons: first of all, all
profiles from keyfile storage in fact have a backing file -- even the
unsaved ones. It also means you can create "unsaved" profiles in /run
and load them with `nmcli connection load`, meaning there is a file
based API for creating unsaved profiles.
The other advantage is that these profiles now survive restarting
NetworkManager. It's paramount that restarting the daemon is as
non-disruptive as possible. Persisting unsaved files to /run improves
here significantly.

--

In the past, NMSettingsConnection also implemented NMConnection interface.
That was already changed a while ago and instead users call now
nm_settings_connection_get_connection() to delegate to a
NMSimpleConnection. What however still happened was that the NMConnection
instance gets never swapped but instead the instance was modified with
nm_connection_replace_settings_from_connection(), clear-secrets, etc.
Change that and treat the NMConnection instance immutable. Instead of modifying
it, reference/clone a new instance. This changes that previously when somebody
wanted to keep a reference to an NMConnection, then the profile would be cloned.
Now, it is supposed to be safe to reference the instance directly and everybody
must ensure not to modify the instance. nmtst_connection_assert_unchanging()
should help with that.
The point is that the settings plugins may keep references to the
NMConnection instance, and so does the NMSettingsConnection. We want
to avoid cloning the instances as long as they are the same.
Likewise, the device's applied connection can now also be referenced
instead of cloning it. This is not yet done, and possibly there are
further improvements possible.

--

Also implement multiple keyfile directores /usr/lib, /etc, /run (rh #1674545,
bgo #772414).

It was always the case that multiple files could provide the same UUID
(both in case of keyfile and ifcfg-rh). For keyfile plugin, if a profile in
read-only storage in /usr/lib gets modified, then it gets actually stored in
/etc (or /run, if the profile is unsaved).

--

While at it, make /etc/network/interfaces profiles for ifupdown plugin reloadable.

--

https://bugzilla.gnome.org/show_bug.cgi?id=772414
https://bugzilla.gnome.org/show_bug.cgi?id=744711
https://bugzilla.redhat.com/show_bug.cgi?id=1674545
2019-07-16 19:09:08 +02:00
Thomas Haller
adb51c2a7f device: fix reapplying changes to connection ID and UUID
4 properties are not really relevant for an already activated connection
or it makes not sense to change them. These are connection.id, connection.uuid,
connection.autoconnect and connection.stable-id.

For convenience, we allow to reapply these. This way, one can take
a different setting (e.g. with a different connection.id or
connection.uuid) and reapply them, but such changes are silently
ignored.

However this was done wrongly. Instead of reverting the change to the new
applied connection, we would change the input connection.

This is bad, for example with

  nmcli connection up uuid cb922f18-e99a-49c6-b200-1678b5070a82
  nmcli connection modify cb922f18-e99a-49c6-b200-1678b5070a82 con-name "bogus"
  nmcli device reapply eth0

the last re-apply would reset the settings-connection's connection ID to
what was before, while accepting the new name on the applied-connection
(while it should have been rejected).

Fixes: bf3b3d444c ('device: avoid changing immutable properties during reapply')
2019-07-16 10:48:30 +02:00
Thomas Haller
15b1304477 policy-routing: take ownership of externally configured rules
IP addresses, routes, TC and QDiscs are all tied to a certain interface.
So when NetworkManager manages an interface, it can be confident that
all related entires should be managed, deleted and modified by NetworkManager.

Routing policy rules are global. For that we have NMPRulesManager which
keeps track of whether NetworkManager owns a rule. This allows multiple
connection profiles to specify the same rule, and NMPRulesManager can
consolidate this information to know whether to add or remove the rule.

NMPRulesManager would also support to explicitly block a rule by
tracking it with negative priority. However that is still unused at
the moment. All that devices do is to add rules (track with positive
priority) and remove them (untrack) once the profile gets deactivated.

As rules are not exclusively owned by NetworkManager, NetworkManager
tries not to interfere with rules that it knows nothing about. That
means in particular, when NetworkManager starts it will "weakly track"
all rules that are present. "weakly track" is mostly interesting for two
cases:

  - when NMPRulesManager had the same rule explicitly tracked (added) by a
    device, then deactivating the device will leave the rule in place.

  - when NMPRulesManager had the same rule explicitly blocked (tracked
    with negative priority), then it would restore the rule when that
    block gets removed (as said, currently nobody actually does this).

Note that when restarting NetworkManager, then the device may stay and
the rules kept. However after restart, NetworkManager no longer knows
that it previously added this route, so it would weakly track it and
never remove them again.

That is a problem. Avoid that, by whenever explicitly tracking a rule we
also make sure to no longer weakly track it. Most likely this rule was
indeed previously managed by NetworkManager. If this was really a rule
added by externally, then the user really should choose distinct
rule priorities to avoid such conflicts altogether.
2019-07-16 10:16:07 +02:00
Beniamino Galvani
c7fd4aeecf device: properly honor flags when checking connection availability
The previous code returned that the device was available when it had
only unmanaged-flags that can be overridden by user, without actually
considering the @flags argument.

Fixes: 920346a5b9 ('device: add and use overrule-unmanaged flag for nm_device_check_connection_available()')
2019-07-08 13:51:30 +02:00
Beniamino Galvani
40babe1c44 dhcp: pass broadcast address to clients
Read the broadcast address from platform and pass it to
clients. Currently only the nettool backends uses it.
2019-07-05 11:06:01 +02:00
Beniamino Galvani
1609f50866 core: drop nm_platform_link_get_address_as_bytes()
Drop nm_platform_link_get_address_as_bytes() and introduce
nmp_link_address_get_as_bytes() so that it becomes possible to obtain
also the broadcast address without an additional lookup of the link.
2019-07-05 11:06:01 +02:00
Tom Gundersen
401fee7c20 dhcp: support notifying the client of the result of DAD
The DHCP client is not meant to use the assigned address before DAD
has completed successfully, if enabled. And if DAD fails, the server
should be notified with a DECLINE, in order to potentially blacklist
the address.

Currently, none of the clients support this, but add the required
callbacks, and allow clients to opt in if they want.
2019-07-05 11:04:32 +02:00
Thomas Haller
d1f269ab36 core: ensure normalized connection during add-and-activate
nm_connection_verify() returns success for fully valid (normalized)
connections and also connections that are NM_SETTING_VERIFY_NORMALIZABLE.

We really want to fully normalize the profiles during add-and-activate.
2019-06-26 12:26:11 +02:00
Beniamino Galvani
e4ce9bd7af device: set IPv6 token only when necessary
Setting the IPv6 token triggers a new router solicitation from kernel
and so we should avoid when not strictly necessary.

https://mail.gnome.org/archives/networkmanager-list/2019-May/msg00004.html
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/issues/179
2019-06-26 09:04:00 +02:00
Thomas Haller
5a416a9da1 Revert "Coerce connectivity "LIMITED" to "NONE" when device is disconnected"
NMConnectivity can now distinguish between LIMITED and NONE connectivity
and it does so based on whether IP addresses and routes are configured.

Previously, NMConnectivity would not differenciate between limited and
no connectivity, which is why NMDevice added some additional logic on top
to coerce LIMITED to NONE (if the device is not logically connected).

But note that the connectivity state (whether a network is reachable on
an interface) depends on what is configured in kernel and whether the
internet is reachable on that interface. It does not depend on the
logical device state.

On the other hand, whether the device is configured in a manner to have
connectivity depends on the logical state of the device (as NetworkManager
is configuring the device).

So, in many cases, the logical state and the connectivity state agree now,
but for the right reasons.

This reverts commit 4c4dbcb78d.
2019-06-18 15:49:09 +02:00
Beniamino Galvani
91d447df19 device: don't start connectivity check on unconfigured devices
If the interface has no carrier, no addresses or no routes there is no
point in starting a connectivity check on it because it will fail.
Moreover, doing the check on a device without routes causes the
addition of a negative entry in the ARP table for each of the
addresses associated with the connectivity check host; this can lead
to poor network performances.

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/issues/181
2019-06-18 15:49:09 +02:00
Thomas Haller
2630ebd7b9 device: support reapplying route-table
Changing "ipv4.route-table" and "ipv6.route-table" was not allowed
during reapply.

The main difficulty for supporting that is changing the sync-mode.

With route-table 0, we don't sync all tables but only the main table.
So, when reapply changes from full-sync to no-full-sync, it's slightly
more complicated.

But it's probably not too complicated either. The change from
no-full-sync to full-sync is simple: we just start doing a full-sync.
The reverse change is slightly more complicated, because we need to
do one last full-sync, to get rid of routes that we configured on those
other tables.
2019-06-17 11:36:33 +02:00
Thomas Haller
bb3726acc2 device: use nm_platform_sysctl_ip_conf_get_rp_filter_ipv4() for warning about rp-filter 2019-06-17 11:36:33 +02:00
Beniamino Galvani
e6628fa27c ipv6: add 'disabled' method
Add a new ipv6.method value 'disabled' that completely disables IPv6
for the interface.

https://bugzilla.redhat.com/show_bug.cgi?id=1643841
2019-06-11 16:22:04 +02:00
Beniamino Galvani
5be69ba794 device: reset cached route tables when starting new activation
The values cached in the device may be stale when we start a new
activation because in a disconnected state we might have called
ip_config_merge_and_apply() which cached the main table value.
2019-06-11 15:34:59 +02:00
Thomas Haller
c0e075c902 all: drop emacs file variables from source files
We no longer add these. If you use Emacs, configure it yourself.

Also, due to our "smart-tab" usage the editor anyway does a subpar
job handling our tabs. However, on the upside every user can choose
whatever tab-width he/she prefers. If "smart-tabs" are used properly
(like we do), every tab-width will work.

No manual changes, just ran commands:

    F=($(git grep -l -e '-\*-'))
    sed '1 { /\/\* *-\*-  *[mM]ode.*\*\/$/d }'     -i "${F[@]}"
    sed '1,4 { /^\(#\|--\|dnl\) *-\*- [mM]ode/d }' -i "${F[@]}"

Check remaining lines with:

    git grep -e '-\*-'

The ultimate purpose of this is to cleanup our files and eventually use
SPDX license identifiers. For that, first get rid of the boilerplate lines.
2019-06-11 10:04:00 +02:00
Thomas Haller
10623654f9 platform: handle IFLA_BROADCAST in platform cache for links
While at it, rename the "addr" field to "l_address". The term "addr" is
used over and over. Instead we should use distinct names that make it
easier to navigate the code.
2019-06-11 08:41:26 +02:00
Beniamino Galvani
3c54b5eb2b device: fix matching parent device by connection UUID
We must compare the UUID with the one on the *parent* device.

Also, simplify the checks to only return TRUE at the end of function.

Fixes: 27c281ac5a ('device: deduplicate match_parent()')

https://bugzilla.redhat.com/show_bug.cgi?id=1716438
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/176
2019-06-05 11:50:56 +02:00
Lubomir Rintel
48710fbf8d device: after completing a connection, check it's compatible 2019-05-28 15:03:20 +02:00
Beniamino Galvani
121c58f0c4 core: set number of SR-IOV VFs asynchronously
When changing the number of VFs the kernel can block for very long
time in the write() to sysfs, especially if autoprobe-drivers is
enabled. Turn the nm_platform_link_set_sriov_params() into an
asynchronous function.
2019-05-28 10:35:04 +02:00
Thomas Haller
55be5166f0 dispatcher: cleanup nm_dispatcher_call_cancel()
Remove the call-id from the requests hash before invoking the callback.
This prevents the user to cancel the request from within the callback.
Supporting such a use case is not necessary so prevent it and tighten
the callers up.
2019-05-27 12:42:51 +02:00
Thomas Haller
c3e2959a5a dispatcher: replace guint call-id by opaque NMDispatcherCallId
A guint value can wrap, so we would need to check that we don't allocate duplicate
IDs (which we currently don't, and it's likely never to actually hit).

Just expose the (opaque) pointer of the call-id.

We still keep a "request_id", but that is only for logging purpose.
2019-05-27 12:39:37 +02:00
Beniamino Galvani
58db61545d device: don't wait udev for devices created by us
If we created a software interface it is because we already decided
that it should be managed, and so there is no point in waiting udev to
check that the interface is not udev-unmanaged.

We still wait udev for software interfaces created externally.
2019-05-20 14:49:59 +02:00
Beniamino Galvani
831f079e55 device: use variable for platform in realize_start_setup() 2019-05-20 13:57:35 +02:00
Thomas Haller
83476a3fb6 pacrunner: refactor pacrunner to use GDBusConnection
- use GDBusConnection instead of GDBusProxy.

- rename "call-id" to "conf-id". It's really not a "call" but
  configuration that gets added and NMPacrunnerManager ensures that
  the configuration is send to pacrunner.

- let "conf-id" keep a reference to NMPacrunnerManager. For one,
  when we remove configurations we need to call DestroyProxyConfiguration
  to remove it again. We cannot just abort the requests but must linger
  around until our configuration is properly cleaned up. Hence, we
  anyway cannot destroy the NMPacrunnerManager earlier.
  With respect to fixing shutdown not to leak anything, this merely
  means that we must wait (and iterate the main loop) as long as
  NMPacrunnerManager singleton still exits (that is anyway the plan
  how to fix shutdown).
  With these considerations it's also clear that our D-Bus calls must
  have a stricter timeout: NM_SHUTDOWN_TIMEOUT_MS.
  This is also nice because nm_pacrunner_manager_remove() no longer
  needs a manager parameter, it can just rely on having a reference
  to the manager.

- for logging the configuration IDs, don't log pointer values.
  Logging pointer values should be avoided as it defeats ASLR.
  Instead, give them a "log_id" number.

- pacrunner is a D-Bus activatable service. D-Bus activatable services
  needs special care. We don't want to start it over and over again.
  Instead, we only try to "StartServiceByName" if

    - we have any configuration to add

    - if pacrunner is currently confirmed not to be running (by watching
      name owner changes)

    - we didn't try to start it already. That means, only start it
      at the beginning and afterwards set a flag to block it. When
      we see pacrunner appear on D-Bus we always clear that flag,
      that means if pacrunner drops of, we will try to restart it
      (once).
2019-05-13 09:24:02 +02:00
Beniamino Galvani
18d2edfaa1 device: fix intersecting IPv6 configurations
If the link is down we shouldn't drop the link-local address from
configuration as it wasn't removed by user but by kernel.
2019-05-08 13:35:59 +02:00
Beniamino Galvani
d0b16b9283 device: unconditionally reapply IP configuration on link up
Consider the situation in which ipv4.method=auto and there is an
address configured. Also, the DHCP timeout is long and there is no
DHCP server. If the link is brought down temporarily, the prefix route
for the static address is lost and not restored by NM because we
reapply the IP configuration only when the IP state is DONE.

The same can happen also for IPv6, but in that case also static IPv6
addresses are lost.

We should always reapply the IP configuration when the link goes up.
2019-05-08 13:35:59 +02:00
Beniamino Galvani
4735d6764a all: fix typos (milli seconds -> milliseconds) 2019-05-08 13:35:59 +02:00
Thomas Haller
f2ae994b23 device/trivial: add comment about lifetime of "kind" in tc_commit()
In general, all fields of public NMPlatform* structs must be
plain/simple. Meaning: copying the struct must be possible without
caring about cloning/duplicating memory.
In other words, if there are fields which lifetime is limited,
then these fields cannot be inside the public part NMPlatform*.

That is why

  - "NMPlatformLink.kind", "NMPlatformQdisc.kind", "NMPlatformTfilter.kind"
    are set by platform code to an interned string (g_intern_string())
    that has a static lifetime.

  - the "ingress_qos_map" field is inside the ref-counted struct NMPObjectLnkVlan
    and not NMPlatformLnkVlan. This field requires managing the lifetime
    of the array and NMPlatformLnkVlan cannot provide that.

See also for example NMPClass.cmd_obj_copy() which can deep-copy an object.
But this is only suitable for fields in NMPObject*. The purpose of this
rule is that you always can safely copy a NMPlatform* struct without
worrying about the ownership and lifetime of the fields (the field's
lifetime is unlimited).

This rule and managing of resource lifetime is the main reason for the
NMPlatform*/NMPObject* split. NMPlatform* structs simply have no mechanism
for copying/releasing fields, that is why the NMPObject* counterpart exists
(which is ref-counted and has a copy and destructor function).

This is violated in tc_commit() for the "kind" strings. The lifetime
of these strings is tied to the setting instance.

We cannot intern the strings (because these are arbitrary strings
and interned strings are leaked indefinitely). We also cannot g_strdup()
the strings, because NMPlatform* is not supposed to own strings.

So, just add comments that warn about this ugliness.

The more correct solution would be to move the "kind" fields inside
NMPObjectQdisc and NMPObjectTfilter, but that is a lot of extra effort.
2019-05-07 21:05:12 +02:00
Thomas Haller
9eefe27a1c device: don't rely on nm_platform_link_get_ifindex() returning 0
While nm_platform_link_get_ifindex() is documented to return 0 if the device
is not found, don't rely on it. Instead, check that a valid(!) ifindex was
returned, and only then set the ifindex. Otherwise leave it at zero. There
is of course no difference in practice, but we generally treat invalid ifindexes
as <= 0, so it's not immediately clear what nm_platform_link_get_ifindex()
returns to signal no device.
2019-05-07 20:58:17 +02:00
Thomas Haller
9399297a82 device/trivial: add space between macro name and arguments and vertically align lines
Also calling macros we commonly put a space between the macro name and
the parenthesis.

Also align the parameters. Otherwise it's hard to read for me.
2019-05-07 20:58:17 +02:00
Thomas Haller
666d58802b libnm: rename "memory" parameter of fq_codel QDisc to "memory_limit"
Kernel calls the netlink attribute TCA_FQ_CODEL_MEMORY_LIMIT. Likewise,
iproute2 calls this "memory_limit".

Rename because TC parameters are inherrently tied to the kernel
implementation and we should use the familiar name.
2019-05-07 20:58:17 +02:00
Thomas Haller
973db2d41b platform: fix handling of default value for TCA_FQ_CODEL_CE_THRESHOLD
iproute2 uses the special value ~0u to indicate not to set
TCA_FQ_CODEL_CE_THRESHOLD in RTM_NEWQDISC. When not explicitly
setting the value, kernel treats the threshold as disabled.

However note that 0xFFFFFFFFu is not an invalid threshold (as far as
kernel is concerned). Thus, we should not use that as value to indicate
that the value is unset. Note that iproute2 uses the special value ~0u
only internally thereby making it impossible to set the threshold to
0xFFFFFFFFu). But kernel does not have this limitation.

Maybe the cleanest way would be to add another field to NMPlatformQDisc:

    guint32 ce_threshold;
    bool ce_threshold_set:1;

that indicates whether the threshold is enable or not.
But note that kernel does:

    static void codel_params_init(struct codel_params *params)
    {
    ...
            params->ce_threshold = CODEL_DISABLED_THRESHOLD;

    static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt,
                               struct netlink_ext_ack *extack)
    {
    ...
            if (tb[TCA_FQ_CODEL_CE_THRESHOLD]) {
                    u64 val = nla_get_u32(tb[TCA_FQ_CODEL_CE_THRESHOLD]);

                    q->cparams.ce_threshold = (val * NSEC_PER_USEC) >> CODEL_SHIFT;
            }

    static int fq_codel_dump(struct Qdisc *sch, struct sk_buff *skb)
    {
    ...
            if (q->cparams.ce_threshold != CODEL_DISABLED_THRESHOLD &&
                nla_put_u32(skb, TCA_FQ_CODEL_CE_THRESHOLD,
                            codel_time_to_us(q->cparams.ce_threshold)))
                    goto nla_put_failure;

This means, kernel internally uses the special value 0x83126E97u to indicate
that the threshold is disabled (WTF). That is because

  (((guint64) 0x83126E97u) * NSEC_PER_USEC) >> CODEL_SHIFT == CODEL_DISABLED_THRESHOLD

So in kernel API this value is reserved (and has a special meaning
to indicate that the threshold is disabled). So, instead of adding a
ce_threshold_set flag, use the same value that kernel anyway uses.
2019-05-07 20:58:17 +02:00
Thomas Haller
46a904389b platform: fix handling of fq_codel's memory limit default value
The memory-limit is an unsigned integer. It is ugly (if not wrong) to compare unsigned
values with "-1". When comparing with the default value we must also use an u32 type.
Instead add a define NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET.

Note that like iproute2 we treat NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET
to indicate to not set TCA_FQ_CODEL_MEMORY_LIMIT in RTM_NEWQDISC. This
special value is entirely internal to NetworkManager (or iproute2) and
kernel will then choose a default memory limit (of 32MB). So setting
NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET means to leave it to kernel to
choose a value (which then chooses 32MB).

See kernel's net/sched/sch_fq_codel.c:

    static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt,
                             struct netlink_ext_ack *extack)
    {
    ...
            q->memory_limit = 32 << 20; /* 32 MBytes */

    static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt,
                               struct netlink_ext_ack *extack)
    ...
            if (tb[TCA_FQ_CODEL_MEMORY_LIMIT])
                    q->memory_limit = min(1U << 31, nla_get_u32(tb[TCA_FQ_CODEL_MEMORY_LIMIT]));

Note that not having zero as default value is problematic. In fields like
"NMPlatformIP4Route.table_coerced" and "NMPlatformRoutingRule.suppress_prefixlen_inverse"
we avoid this problem by storing a coerced value in the structure so that zero is still
the default. We don't do that here for memory-limit, so the caller must always explicitly
set the value.
2019-05-07 20:58:17 +02:00
Thomas Haller
438855e915 device: fix type of loop variable in tc_commit()
nqdiscs and ntfilters are unsigned integers. The loop variable must agree in
range and signedness.
2019-05-07 20:58:17 +02:00
Thomas Haller
8a78493de1 settings: cache keyfile databases for "timestamps" and "seen-bssids"
Only read the keyfile databases once and cache them for the remainder of
the program.

- this avoids the overhead of opening the file over and over again.

- it also avoids the data changing without us expecting it. The state
  files are internal and we don't support changing it outside of
  NetworkManager. So in the base case we read the same data over
  and over. In the worst case, we read different data but are not
  interested in handling the changes.

- only write the file when the content changes or before exiting
  (normally).

- better log what is happening.

- our state files tend to grow as we don't garbage collect old entries.
  Keeping this all in memory might be problematic. However, the right
  solution for this is that we come up with some form of garbage
  collection so that the state files are reaonsably small to begin with.
2019-05-07 16:41:21 +02:00
Beniamino Galvani
4ed72fa658 device: fix reapply of MTU
When we set the MTU on the link we remember its previous source
(ip-config, parent-device or connection profile) and don't change it
again afterwards to avoid interfering with user's manual changes. The
only exceptions when we change it again are (1) if the parent device
MTU changes and (2) if the new MTU has higher priority than the one
previously set.

To allow a live reapply of the MTU property we also need to clear the
saved source, or the checks described above will prevent setting the
new value.

Fixes: 2f8917237f ('device: rework mtu priority handling')

https://bugzilla.redhat.com/show_bug.cgi?id=1702657
2019-05-06 10:19:19 +02:00
Lubomir Rintel
900292147d tc/tfilter: add mirred action 2019-04-30 15:59:41 +02:00
Lubomir Rintel
1efe982e39 tc/qdisc: add support for fq_codel attributes 2019-04-30 15:59:41 +02:00
Thomas Haller
284ac92eee shared: build helper "libnm-libnm-core-{intern|aux}.la" library for libnm-core
"libnm-core" implements common functionality for "NetworkManager" and
"libnm".

Note that clients like "nmcli" cannot access the internal API provided
by "libnm-core". So, if nmcli wants to do something that is also done by
"libnm-core", , "libnm", or "NetworkManager", the code would have to be
duplicated.

Instead, such code can be in "libnm-libnm-core-{intern|aux}.la".
Note that:

  0) "libnm-libnm-core-intern.la" is used by libnm-core itsself.
     On the other hand, "libnm-libnm-core-aux.la" is not used by
     libnm-core, but provides utilities on top of it.

  1) they both extend "libnm-core" with utlities that are not public
     API of libnm itself. Maybe part of the code should one day become
     public API of libnm. On the other hand, this is code for which
     we may not want to commit to a stable interface or which we
     don't want to provide as part of the API.

  2) "libnm-libnm-core-intern.la" is statically linked by "libnm-core"
     and thus directly available to "libnm" and "NetworkManager".
     On the other hand, "libnm-libnm-core-aux.la" may be used by "libnm"
     and "NetworkManager".
     Both libraries may be statically linked by libnm clients (like
     nmcli).

  3) it must only use glib, libnm-glib-aux.la, and the public API
     of libnm-core.
     This is important: it must not use "libnm-core/nm-core-internal.h"
     nor "libnm-core/nm-utils-private.h" so the static library is usable
     by nmcli which couldn't access these.

Note that "shared/nm-meta-setting.c" is an entirely different case,
because it behaves differently depending on whether linking against
"libnm-core" or the client programs. As such, this file must be compiled
twice.

(cherry picked from commit af07ed01c0)
2019-04-18 20:07:44 +02:00
Thomas Haller
d984b2ce4a shared: move most of "shared/nm-utils" to "shared/nm-glib-aux"
From the files under "shared/nm-utils" we build an internal library
that provides glib-based helper utilities.

Move the files of that basic library to a new subdirectory
"shared/nm-glib-aux" and rename the helper library "libnm-core-base.la"
to "libnm-glib-aux.la".

Reasons:

 - the name "utils" is overused in our code-base. Everything's an
   "utils". Give this thing a more distinct name.

 - there were additional files under "shared/nm-utils", which are not
   part of this internal library "libnm-utils-base.la". All the files
   that are part of this library should be together in the same
   directory, but files that are not, should not be there.

 - the new name should better convey what this library is and what is isn't:
   it's a set of utilities and helper functions that extend glib with
   funcitonality that we commonly need.

There are still some files left under "shared/nm-utils". They have less
a unifying propose to be in their own directory, so I leave them there
for now. But at least they are separate from "shared/nm-glib-aux",
which has a very clear purpose.

(cherry picked from commit 80db06f768)
2019-04-18 19:57:27 +02:00
Thomas Haller
0a6f21fb8d shared: split C-only helper "shared/nm-std-aux" utils out of "shared/nm-utils"
"shared/nm-utils" contains general purpose utility functions that only
depend on glib (and extend glib with some helper functions).

We will also add code that does not use glib, hence it would be good
if the part of "shared/nm-utils" that does not depend on glib, could be
used by these future projects.

Also, we use the term "utils" everywhere. While that covers the purpose
and content well, having everything called "nm-something-utils" is not
great. Instead, call this "nm-std-aux", inspired by "c-util/c-stdaux".

(cherry picked from commit b434b9ec07)
2019-04-18 19:17:23 +02:00
Thomas Haller
bf36fa11d2 platform: refactor detecting kernel features
Next we will need to detect more kernel features. First refactor the
handling of these to require less code changes and be more efficient.
A plain nm_platform_kernel_support_get() only reqiures to access an
array in the common case.

The other important change is that the function no longer requires a
NMPlatform instance. This allows us to check kernel support from
anywhere. The only thing is that we require kernel support to be
initialized before calling this function. That means, an NMPlatform
instance must have detected support before.

(cherry picked from commit ee269b318e)
2019-04-18 11:19:26 +02:00
Beniamino Galvani
82c74eb4e2 device: fix memory leak 2019-04-12 11:19:58 +02:00
Beniamino Galvani
c0d5b58332 core: don't realize unmanaged software devices
Currently, if user configuration or settings specify that a software
device is unmanaged, for example:

 [device-bond-unmanaged]
 match-device=interface-name:bond*
 managed=0

or

 [keyfile]
 unmanaged-devices=interface-name:bond*

and there is a connection for the device with autoconnect=yes, NM
creates the platform link and a realized device in unmanaged
state. Fix this, the device should not be realized if it is unmanaged.

https://bugzilla.redhat.com/show_bug.cgi?id=1679230
2019-04-12 10:34:20 +02:00
Beniamino Galvani
adbf368511 device: allow matching device spec from any state
nm_device_spec_match_list_full() calls
nm_device_get_permanent_hw_address() which freezes the MAC address, so
currently callers must avoid the function when the device is not
completely platform-initialized.

Instead, use nm_device_get_permanent_hw_address_full() to avoid
freezing the MAC when the device is not platform-initialized. In this
way nm_device_spec_match_list_full() can be called from any state
without side effects.
2019-04-12 10:34:20 +02:00