The current implementation of libnm guarantees that "o" and "ao"
properties are cleared when the device object goes away, i.e. when all
its interfaces disappear from the bus.
The "manager:device-removed" signal is emitted just before the device
is unexported, and usually properties are not cleared at that
time. So, the assertions about empty available connections and active
connection during "device-removed" seem wrong; remove them.
Whether the test passes or not depends on a race condition in the way
the mock NM service is stopped: we first close the pipe to the process
to force a clean shutdown (where all objects are orderly unexported)
but just after that we send SIGTERM which causes the service to drop
from the bus.
If libnm sees the service dropping from the bus, it deletes all
objects (thus clearing properties) and then emits
"device-removed"; in this case the test passes.
However in case of a clean shutdown, NM first emits the
"device-removed" signal and then unexports devices, leading to a
failure.
Fixes: aaa9a9cd25 ('libnm/client: don't reset properties when interface goes away')
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1486
The types NMBridgeVlan, NMIPRoutingRule, NMRange, NMWireGuardPeer
are immutable (or immutable, after the seal() function is called).
Immutable types are great, as it means a reference to them can be shared
without doing a full clone. Hence the G_DEFINE_BOXED_TYPE() for these
types prefers to take a reference instead of cloning the objects. Except
for sealable types, where it will prefer to clone unsealed values.
Likewise, nm_simple_connection_new_clone() probably will just take
another reference to the value, instead of doing a deep clone.
libnm is not a thread-safe library in the sense that you could pass a
NMConnection or NMClient instance to multiple threads and access them
without your own synchronization. However, it should be possible that
multiple threads access (seemingly) distinct objects.
As the copy function of these boxed types (and nm_simple_connection_new_clone()
and similar) prefers to share the references to immutable types, it is important
that the ref function is thread-safe too. Otherwise you cannot just clone a
NMConnection on thread1, hand the clone to thread2 and operate on the
clone and the original independently. If you do before this patch, you would
hit a subtle race condition.
Avoid that. While atomic operations have a runtime overhead, being safe
is more important. Also, we already save a full malloc()/free() by
having immutable, ref-counted types. We just need to make it safe to use
in order to fully benefit from it.
G_TYPE_CHECK_INSTANCE_CAST() can trigger a "-Wcast-align":
src/core/devices/nm-device-macvlan.c: In function 'parent_changed_notify':
/usr/include/glib-2.0/gobject/gtype.h:2421:42: error: cast increases required alignment of target type [-Werror=cast-align]
2421 | # define _G_TYPE_CIC(ip, gt, ct) ((ct*) ip)
| ^
/usr/include/glib-2.0/gobject/gtype.h:501:66: note: in expansion of macro '_G_TYPE_CIC'
501 | #define G_TYPE_CHECK_INSTANCE_CAST(instance, g_type, c_type) (_G_TYPE_CIC ((instance), (g_type), c_type))
| ^~~~~~~~~~~
src/core/devices/nm-device-macvlan.h:13:6: note: in expansion of macro 'G_TYPE_CHECK_INSTANCE_CAST'
13 | (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_MACVLAN, NMDeviceMacvlan))
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
Avoid that by using _NM_G_TYPE_CHECK_INSTANCE_CAST().
This can only be done for our internal usages. The public headers
of libnm are not changed.
Reapply() is supposed to make sure that the system (the interface)
is configured as indicated by the applied-connection. That means,
it will remove/add configuration to make the system match the requested
configuration.
Add a flag "preserve-external-ip" which relaxes this. During reapply,
IP addresses/routes that exist on the interface and which are not known
(or added) by NetworkManager will be left alone.
This will be used by nm-cloud-setup, so that it can reconfigure the
interface in a less destructive way, which does not conflict with
external `ip addr/route` calls.
Note that the previous commit just adds "VersionInfo" and the
possibility to expose capabilities (patch-level). This is not used
for the new reapply flag, because, while we might backport the
reapply flag, we won't backport the "VersionInfo" property. Exposing
new capabilities via the "VersionInfo" property will only become useful
in the future, where we can backport a capability to older NM versions
(but those that have "VersionInfo" too).
This exposes NM_VERSION as number (contrary to the "Version", which is a
string). That is in particular useful, because the number can be
compared with <> due to the encoding of the version.
While at it, don't make it a single number. Expose an array of numbers,
where the following numbers are a bitfield of capabilities.
Note that before commit 3c67a1ec5e ('cli: remove version check against
NM'), we used to parse the "Version" string to detect the version. As
such, the information that "VersionInfo" exposes now, was already
(somewhat) available, you just had to parse the string. The main benefit of
"VersionInfo" is that it can expose capabilities (patched behavior) in
in a lightweight bitfield. To include the numerical version there is
just useful on top.
Currently no additional capabilities are exposed. The idea is of course
to have a place in the future, where we can expose additional
capabilities. Adding a capability flag is most useful for behavior that we
backport to older branches. Otherwise, we could just check the daemon version
alone. But since we only add "VersionInfo" property only now, we cannot backport
any capability further than this, because the "VersionInfo" property itself
won't be backported. As such, this will only be useful in the future by having
a place where we can add (and backport) capabilities.
Note that there is some overlap with the existing "Capability" property
and NMCapability enum. The difference is that adding a capability via "VersionInfo"
is only one bit, and thus cheaper. Most importantly, having it cheaper means
the downsides of adding a capability flag is significantly removed. In
practice, we could live without capabilities for a long time, so they
must be very cheap for them to be worth to add. Another difference might be,
that we will want that the VersionInfo is about compile time defaults (e.g.
a certain patch/behavior that is in or not), while NM_CAPABILITY_TEAM depends on
whether the team plugin is loaded at runtime.
Introduce a "vlan.protocol" property that specifies the protocol of a
VLAN, which controls the tag (EtherType) used for encapsulation.
Regular VLANs use 802.1Q (tag 0x8100). To implement VLAN stacking it's
sometimes useful to have 802.1ad VLANs with tag 0x88A8.
The property is a string instead of e.g. an enum because this allows
maximum flexibility in the future. For example, it becomes possible to
specify an arbitrary number in case if the kernel ever allows it.
The warning "-Wcast-align=strict" seems useful and will be enabled
next. Fix places that currently cause the warning by using the
new macro NM_CAST_ALIGN(). This macro also nm_assert()s that the alignment
is correct.
Add a new "ovs-port.trunks" property that indicates which VLANs are
trunked by the port.
At ovsdb level the property is just an array of integers; on the
command line, ovs-vsctl accepts ranges and expands them.
In NetworkManager the ovs-port setting stores the trunks directly as a
list of ranges.
The next commit is going to introduce a new object in libnm to
represent a range of ovs-port VLANs. A "range of integers" object
seems something that can be used for other purposes in the future, so
instead of adding an object specific for this case
(e.g. NMOvsPortVlanRange), introduce a generic NMRange object that
generically represents a range of non-negative integers.
Support managing the loopback interface through NM as the users want to
set the proper mtu for loopback interface when forwarding the packets.
Additionally, the IP addresses, DNS, route and routing rules are also
allowed to configure for the loopback connection profiles.
https://bugzilla.redhat.com/show_bug.cgi?id=2060905
This is the version shipped in Fedora 37. As Fedora 37 is now out, the
core developers switch to it. Our gitlab-ci will also use that as base
image for the check-{patch.tree} tests and to generate the pages. There
is a need that everybody agrees on which clang-format version to use,
and that version should be the one of the currently used Fedora release.
Also update the used Fedora image in "contrib/scripts/nm-code-format-container.sh"
script.
The gitlab-ci still needs update in the following commit. The change
in isolation will break the "check-tree" test.
Most users included this by accident, by including nm-connection.h. That
is not too great, becuase stuff it contains is by no means specific to
NMConnection.
Anyways, it's not like it would matter too that. I mainly care about it
being included in NetworkManager.h, so that there's one less special
case in a test that makes sure useful stuff from NetworkManager.h ends up
in gtk-doc (a separate commit).
libnm-core-impl/nm-setting-bond.c:1276: warning: Symbol name not found at the start of the comment block.
libnm-core-impl/nm-setting-vpn.c:1135: warning: Symbol name not found at the start of the comment block.
libnm-core-impl/nm-setting-vpn.c:1158: warning: Symbol name not found at the start of the comment block.
libnm-core-impl/nm-setting-wired.c:1560: warning: Symbol name not found at the start of the comment block.
libnm-client-impl/nm-dhcp-config.c:149: warning: Symbol name not found at the start of the comment block.
libnm-client-impl/nm-secret-agent-old.c:967: warning: Symbol name not found at the start of the comment block.
libnm-client-impl/nm-secret-agent-old.c:1010: warning: Symbol name not found at the start of the comment block.
libnm-client-impl/nm-secret-agent-old.c:1037: warning: Symbol name not found at the start of the comment block.
We got a typedef of the same name, and that causes gtk-doc to generate
invalid docbook and complain aloud:
../xml/nm-client.xml:4118: element refsect2: validity error : ID NMDnsEntry already defined
<refsect2 id="NMDnsEntry" role="typedef" condition="since:1.6">
Warning: multiple "IDs" for constraint linkend: NMDnsEntry.
In case the D-Bus interfaces start dropping off (typically all off them go
one by one when the object is being deleted), don't reset all the properties.
In particular, keep most properties around, only tear down "o" and "ao",
so that the object dependencies get torn down, but we still get enough
properties around to identify what the dead object was its heyday.
One example of where this is not good is when the device-removed signal
is emmitted, the device no longer has the ifname:
$ nmcli monitor
<quit NetworkManager>
(null): device removed
(null): device removed
...
Currently we assert that properties are reset on client teardown. That
is not the right thing to do and we're not going to do that in future.
However, what is important to test is that the properties are reset when
the daemon goes away. Test that.
The part where a device was created and its cleanup on client
description was only run randomly.
This is silly and gave me hard time. No reason not to be always running
it.
This verifies that what's in our public headers has version nodes, and
that they match Since: tags.
Not pretty (because python) but discovered a *lot* of issues.
"gen-metadata-nm-settings-libnm-core.xml" now contains also the names of
the NMSetting types, like "NMSettingConnection". That can be useful
to create NMSetting instances generically (that is, without knowing
the C API that gets called).
So you might be tempted to run
#!/bin/python
import gi
gi.require_version("NM", "1.0")
from gi.repository import GObject, NM
connection = NM.SimpleConnection()
# NM.utils_ensure_gtypes()
gtype_name = "NMSetting6Lowpan"
gtype = GObject.type_from_name(gtype_name)
setting = GObject.new(gtype)
connection.add_setting(setting)
However, without NM.utils_ensure_gtypes() that would not work, because
the GType is not yet created. For a user who doesn't know a priory all
setting types, it's not entirely clear how to make this work. Well, a
GObject introspection user could iterate over al NM.Setting* names and
try to instantiate the classes. However, that is still cumbersome, and not
accessible to a C user (without GI) and the currently loaded libnm
library may be newer and have unknown setting types.
In particular plain C user would need to know to call all the right
nm_setting_*_get_type(), functions, so it needs to know all the existing
52 type getters (and cannot support those from a newer libnm version).
With nm_utils_ensure_gtypes(), the user can get the typename and create
instances generically only using g_type_from_name().
Possible alternatives:
- libnm also has _nm_utils_init() which runs as __attribute__((constructor)).
We could also always instantiate all GType there. However, I don't like running
non-trivial, absolutely necessary code before main().
- hook nm_setting_get_type() to create all GType for the NMSetting
subclasses too. The problem is, that it's not entirely trivial to
avoid deadlock.
- hook nm_connection_get_type() to create all NMSetting types. That
would not deadlock, but it still is questionable whether we should
automatically, at non-obvious times instantiate all GTypes.
These are present in a public header yet are not properly commented,
versioned or exported.
Export them now. Another option would be to move them to a private
header; but I suspect someone has intended them to be exported at some
point.
Add them to @libnm_1_40_4 as opposed to @libnm_1_42_0 because we now know
this is going to be backported to 1.40.4 first.
Remove the functions from a public header. They were missing from
libnm.ver and thus never actually exported.
There's no point in salvaging them now as the whole NMVpnPluginOld has
been replaced NMVpnServicePlugin and new uses are discouraged.
Remove the function from a public header. It was missing from libnm.ver
and thus never actually exported.
There's no point in salvaging it now as it nm_device_get_hw_address()
exists as a better option.
Remove the function from a public header. It was missing from libnm.ver
and thus never actually exported.
There's no point in salvaging it now as it nm_device_get_hw_address()
exists as a better option.
Fix up the doc comment so that the gir data gets that right.
Fixes: 90d0ae0faf ('libnm: implement nm_client_activate_connection()/nm_client_add_and_activate_connection*() by using GDBusConnection directly')
g_memdup()'s size argument is a guint. There was CVE-2021-27219
about an integer overflow, which results in a buffer overflow.
In response to that, g_memdup2() was introduced in 2.68.
We can't use g_memdup2(), because our currently required glib
version is still 2.40.
There was no bug at those two places where g_memdup() was used.
It's just that g_memdup() is a code smell. Prevent any questions that
a reader of the code might have regarding the correctness of g_memdup()
(w.r.t. integer/buffer overflow), by not using it.
Instead use our internal nm_memdup() variant, which exactly exists for
this reason.
See-also: https://gitlab.gnome.org/GNOME/glib/-/issues/2319
Add a fire-and-forget function to wait for shutdown to be complete.
It's not entirely trivial to ensure all resources of NMClient are
cleaned up. That matters only if NMClient uses a temporary GMainContext
that the user wants to release while the application continues. For
example, to do some short-lived operations an a worker thread. It's
not trivial also because glib provides no convenient API to integrate
a GMainContext in another GMainContext. We have that code as
nm_utils_g_main_context_create_integrate_source(), so add a helper
function to allow the user to do this.
The function allows to omit the callback, in which case the caller
wouldn't know when shutdown is complete. That would still be useful
however, when integrating the client's context into the caller's
context, so that the client's context gets automatically iterated
until completion.
The following test script will run out of file descriptors,
when wait_shutdown() is not used:
#!/bin/python
import gi
gi.require_version("NM", "1.0")
from gi.repository import NM, GLib
for i in range(1200):
print(f">>>{i}")
ctx = GLib.MainContext()
ctx.push_thread_default()
nmc = NM.Client.new()
ctx.pop_thread_default()
def cb(unused, result, i):
try:
NM.Client.wait_shutdown_finish(result)
except Exception:
# cannot happen
assert False
else:
print(f">>>>> {i} complete")
nmc.wait_shutdown(True, None, cb, i)
while GLib.MainContext.default().iteration(False):
pass
When using async initialization with GAsyncInitable, the user usually can
only know that initialization is complete by passing a callback.
In simple cases, that can be cumbersome.
Also expose a flag that allows to poll that information.
Reuse the existing NM_CLIENT_INSTANCE_FLAGS for that. There is an
ugliness here, that suddenly there are instance flags that cannot be
set, but are still returned by the getter. But as this is a relatively
obscure feature, it seems more lightweight to implement it this way
(instead of adding a separate property and getter function).
NMConnection is an interface, implemented by NMSimpleConnection and
NMRemoteConnection.
For the most part, an NMConnection is only the content of the profile
(the settings). The "path" of the connection refers to the D-Bus path,
and wouldn't really make sense of the NMConnection interface or the
NMSimpleConnection type.
As such, the daemon (which only uses NMConnection and
NMSimpleConnection) never sets the path. Only libnm does.
NMClient uses NMRefString extensively for the D-Bus interface and the
path is already internalized. Take advantage of that. It is very likely,
that we are able to share the path instance in libnm at which point it
makes sense to use NMRefString.
Also, during nm_simple_connection_new_clone(), we can just take another
reference instead of cloning the string.
Have "len" before "elem_size". That is consistent with g_qsort_with_data()
and bsearch(), and is also what I would expect.
Note that the previous commit just renamed the function. If a user
of the new, changed API gets backported to an older branch, we will
get a compilation error and note that the arguments need to be adjusted.
The "nm_utils_" prefix is just too verbose. Drop it.
Also, Posix has a bsearch function. As this function
is similar, rename it.
Note that currently the arguments are provided in differnt
order from bsearch(). That will be partly addressed next.
That is the main reason for the rename. The next commit
will swap the arguments, so do a rename first to get a compilation
error when backporting a patch that uses the changed API.
Add option to set ofport_request when configuring ovs interface. When
connection with ofport_request configured is activated ovsdb will first
try to activated on the port set by ofport_request.
- 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
Various synchronous methods (D-Bus calls) in libnm's NMClient API were
deprecated. The problem is that NMClient contains a cache of D-Bus
objects, and it gets updated by asynchronous events (D-Bus signals).
Those events get only processed when iterating the GMainContext, but
they are ordered.
When we perform a pseudo blocking D-Bus call with
g_dbus_connection_call_sync(), then GDBus creates a temporary
GMainContext, sends the request and iterates the internal context
blocking for the response. That is, this reply is not synchrounized with
the events that update the NMClient cache.
That is a problem for methods like nm_remote_connection_delete(),
because you call blocking delete, but afterwards the object is still in
the NMClient cache. That's why most blocking methods are deprecated.
While such blocking calls are therefore problematic, they can still be
very convenient to call from a simple script, a test tool or the python
REPL. See "examples/python/gi/nm-wg-set" which calls
nm_remote_connection_get_secrets(), and it would be (unnecessarily)
cumbersome to do the correct thing or using async API.
In particular, nm_remote_connection_get_secrets() doesn't retrieve an object
that is in the NMClient cache in the first place. Sure, the result is
out of order with the cache, but it's not obviously related and in most
cases it wouldn't matter to the user. So undeprecate this function again.
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1345