mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-08 11:50:22 +01:00
cloud-setup,core: merge branch 'th/cloud-setup-preserve-external-ip'
https://bugzilla.redhat.com/show_bug.cgi?id=2132754 https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1476
This commit is contained in:
commit
f0e8b6f0e2
18 changed files with 525 additions and 72 deletions
|
|
@ -182,6 +182,7 @@ EXTRA_DIST += \
|
|||
examples/python/gi/add_connection.py \
|
||||
examples/python/gi/checkpoint.py \
|
||||
examples/python/gi/deactivate-all.py \
|
||||
examples/python/gi/device-reapply.py \
|
||||
examples/python/gi/device-state-ip4config.py \
|
||||
examples/python/gi/dns.py \
|
||||
examples/python/gi/firewall-zone.py \
|
||||
|
|
|
|||
147
examples/python/gi/device-reapply.py
Executable file
147
examples/python/gi/device-reapply.py
Executable file
|
|
@ -0,0 +1,147 @@
|
|||
#!/usr/bin/env python
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import gi
|
||||
|
||||
gi.require_version("NM", "1.0")
|
||||
from gi.repository import NM, GLib, Gio, GObject
|
||||
|
||||
|
||||
def eprint(*args, **kwargs):
|
||||
print(*args, file=sys.stderr, **kwargs)
|
||||
|
||||
|
||||
def kf_from_data(data):
|
||||
kf = GLib.KeyFile.new()
|
||||
kf.load_from_data(data, 18446744073709551615, GLib.KeyFileFlags.NONE)
|
||||
return kf
|
||||
|
||||
|
||||
def kf_to_data(kf):
|
||||
data, l = kf.to_data()
|
||||
return data
|
||||
|
||||
|
||||
def connection_to_kf(connection):
|
||||
return kf_to_data(NM.keyfile_write(connection, NM.KeyfileHandlerFlags.NONE))
|
||||
|
||||
|
||||
def connection_from_kf(data):
|
||||
base_dir = os.getcwd()
|
||||
return NM.keyfile_read(kf_from_data(data), base_dir, NM.KeyfileHandlerFlags.NONE)
|
||||
|
||||
|
||||
def connection_from_stdin():
|
||||
return connection_from_kf(sys.stdin.read())
|
||||
|
||||
|
||||
def device_get_applied_connection(device):
|
||||
mainloop = GLib.MainLoop()
|
||||
r = []
|
||||
|
||||
def cb(device, result):
|
||||
try:
|
||||
connection, version_id = device.get_applied_connection_finish(result)
|
||||
except Exception as e:
|
||||
r.append(e)
|
||||
else:
|
||||
r.append(connection)
|
||||
r.append(version_id)
|
||||
mainloop.quit()
|
||||
|
||||
device.get_applied_connection_async(0, None, cb)
|
||||
mainloop.run()
|
||||
if len(r) == 1:
|
||||
raise r[0]
|
||||
connection, version_id = r
|
||||
return connection, version_id
|
||||
|
||||
|
||||
def device_reapply(device, connection, version_id, reapply_flags):
|
||||
mainloop = GLib.MainLoop()
|
||||
r = []
|
||||
|
||||
def cb(device, result):
|
||||
try:
|
||||
device.reapply_finish(result)
|
||||
except Exception as e:
|
||||
r.append(e)
|
||||
mainloop.quit()
|
||||
|
||||
device.reapply_async(connection, version_id or 0, reapply_flags, None, cb)
|
||||
mainloop.run()
|
||||
if len(r) == 1:
|
||||
raise r[0]
|
||||
|
||||
|
||||
def parse_args():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="device-reapply.py",
|
||||
description="Example program to interact with the applied connection",
|
||||
)
|
||||
|
||||
parser.add_argument("mode", choices=["get", "reapply", "modify"])
|
||||
parser.add_argument("device")
|
||||
parser.add_argument("-V", "--version-id", type=int)
|
||||
parser.add_argument("-s", "--stdin", action="store_true")
|
||||
parser.add_argument("-p", "--preserve-external-ip", action="store_true")
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
|
||||
nmc = NM.Client.new()
|
||||
|
||||
device = [d for d in nmc.get_devices() if d.get_iface() == args.device]
|
||||
if not device:
|
||||
raise Exception(f'Device "{args.device}" not found')
|
||||
if len(device) != 1:
|
||||
raise Exception(f'Not unique device "{args.device}" found')
|
||||
device = device[0]
|
||||
|
||||
assert not args.stdin or args.mode == "modify"
|
||||
assert not args.preserve_external_ip or args.mode in ["modify", "reapply"]
|
||||
|
||||
if args.mode == "get":
|
||||
connection, version_id = device_get_applied_connection(device)
|
||||
|
||||
version_id_matches = args.version_id is None or args.version_id == version_id
|
||||
|
||||
print(
|
||||
f'# Applied connection on "{device.get_iface()}": "{connection.get_id()}" ({connection.get_uuid()}, {connection.get_connection_type()})'
|
||||
)
|
||||
s = "" if version_id_matches else f" (expected {args.version_id})"
|
||||
print(f"# version-id={version_id}{s}")
|
||||
print(f"#")
|
||||
print(f"{connection_to_kf(connection)}")
|
||||
|
||||
if not version_id_matches:
|
||||
eprint(
|
||||
f"Applied version-id does not match (expects {args.version_id} but got {version_id})"
|
||||
)
|
||||
sys.exit(1)
|
||||
sys.exit(0)
|
||||
|
||||
if args.mode == "reapply":
|
||||
new_connection = None
|
||||
elif args.stdin:
|
||||
new_connection = connection_from_stdin()
|
||||
else:
|
||||
new_connection, _ = device_get_applied_connection(device)
|
||||
|
||||
reapply_flags = 0
|
||||
if args.preserve_external_ip:
|
||||
reapply_flags = 1 # NM.DeviceReapplyFlags.PRESERVE_EXTERNAL_IP
|
||||
|
||||
device_reapply(device, new_connection, args.version_id, reapply_flags)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -322,7 +322,7 @@
|
|||
Reapply:
|
||||
@connection: The optional connection settings that will be reapplied on the device. If empty, the currently active settings-connection will be used. The connection cannot arbitrarily differ from the current applied-connection otherwise the call will fail. Only certain changes are supported, like adding or removing IP addresses.
|
||||
@version_id: If non-zero, the current version id of the applied-connection must match. The current version id can be retrieved via GetAppliedConnection. This optional argument allows to catch concurrent modifications between the GetAppliedConnection call and Reapply.
|
||||
@flags: Flags which would modify the behavior of the Reapply call. There are no flags defined currently and the users should use the value of 0.
|
||||
@flags: Flags which would modify the behavior of the Reapply call. Invalid flags are rejected.
|
||||
|
||||
Attempts to update the configuration of a device without deactivating it.
|
||||
NetworkManager has the concept of connections, which are profiles that
|
||||
|
|
@ -344,6 +344,9 @@
|
|||
Reapply can make the applied-connection different from the
|
||||
settings-connection, just like updating the settings-connection can make
|
||||
them different.
|
||||
|
||||
Since 1.42, "preserve-external-ip" flag (0x1) is supported to not remove
|
||||
externally added IP addresses and routes on the device during reapply.
|
||||
-->
|
||||
<method name="Reapply">
|
||||
<arg name="connection" type="a{sa{sv}}" direction="in"/>
|
||||
|
|
|
|||
|
|
@ -456,6 +456,22 @@
|
|||
-->
|
||||
<property name="Version" type="s" access="read"/>
|
||||
|
||||
<!--
|
||||
VersionInfo:
|
||||
|
||||
NetworkManager version and capabilities.
|
||||
|
||||
The first element in the array is the NM_VERSION of the daemon. It is a binary representation
|
||||
of the "Version" and can be compared numerically. The version is encoded as
|
||||
"(major << 16 | minor << 8 | micro)".
|
||||
|
||||
The following elements are a bitfield of static capabilities of the daemon. See
|
||||
#NMVersionInfoCapability for the available capability numbers.
|
||||
|
||||
Since: 1.42
|
||||
-->
|
||||
<property name="VersionInfo" type="au" access="read"/>
|
||||
|
||||
<!--
|
||||
Capabilities:
|
||||
|
||||
|
|
|
|||
|
|
@ -12830,6 +12830,7 @@ reapply_connection(NMDevice *self, NMConnection *con_old, NMConnection *con_new)
|
|||
* the current settings connection
|
||||
* @version_id: either zero, or the current version id for the applied
|
||||
* connection.
|
||||
* @reapply_flags: the #NMDeviceReapplyFlags.
|
||||
* @audit_args: on return, a string representing the changes
|
||||
* @error: the error if %FALSE is returned
|
||||
*
|
||||
|
|
@ -12839,11 +12840,12 @@ reapply_connection(NMDevice *self, NMConnection *con_old, NMConnection *con_new)
|
|||
* Return: %FALSE if the new configuration can not be reapplied.
|
||||
*/
|
||||
static gboolean
|
||||
check_and_reapply_connection(NMDevice *self,
|
||||
NMConnection *connection,
|
||||
guint64 version_id,
|
||||
char **audit_args,
|
||||
GError **error)
|
||||
check_and_reapply_connection(NMDevice *self,
|
||||
NMConnection *connection,
|
||||
guint64 version_id,
|
||||
NMDeviceReapplyFlags reapply_flags,
|
||||
char **audit_args,
|
||||
GError **error)
|
||||
{
|
||||
NMDeviceClass *klass = NM_DEVICE_GET_CLASS(self);
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
|
||||
|
|
@ -13011,7 +13013,12 @@ check_and_reapply_connection(NMDevice *self,
|
|||
|
||||
reactivate_proxy_config(self);
|
||||
|
||||
nm_device_l3cfg_commit(self, NM_L3_CFG_COMMIT_TYPE_REAPPLY, FALSE);
|
||||
nm_device_l3cfg_commit(
|
||||
self,
|
||||
NM_FLAGS_HAS(reapply_flags, NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP)
|
||||
? NM_L3_CFG_COMMIT_TYPE_UPDATE
|
||||
: NM_L3_CFG_COMMIT_TYPE_REAPPLY,
|
||||
FALSE);
|
||||
}
|
||||
|
||||
if (priv->state >= NM_DEVICE_STATE_IP_CHECK)
|
||||
|
|
@ -13028,12 +13035,18 @@ nm_device_reapply(NMDevice *self, NMConnection *connection, GError **error)
|
|||
{
|
||||
g_return_val_if_fail(NM_IS_DEVICE(self), FALSE);
|
||||
|
||||
return check_and_reapply_connection(self, connection, 0, NULL, error);
|
||||
return check_and_reapply_connection(self,
|
||||
connection,
|
||||
0,
|
||||
NM_DEVICE_REAPPLY_FLAGS_NONE,
|
||||
NULL,
|
||||
error);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
NMConnection *connection;
|
||||
guint64 version_id;
|
||||
NMConnection *connection;
|
||||
guint64 version_id;
|
||||
NMDeviceReapplyFlags reapply_flags;
|
||||
} ReapplyData;
|
||||
|
||||
static void
|
||||
|
|
@ -13044,16 +13057,16 @@ reapply_cb(NMDevice *self,
|
|||
gpointer user_data)
|
||||
{
|
||||
ReapplyData *reapply_data = user_data;
|
||||
guint64 version_id = 0;
|
||||
gs_unref_object NMConnection *connection = NULL;
|
||||
GError *local = NULL;
|
||||
gs_free char *audit_args = NULL;
|
||||
guint64 version_id;
|
||||
gs_unref_object NMConnection *connection = NULL;
|
||||
NMDeviceReapplyFlags reapply_flags;
|
||||
GError *local = NULL;
|
||||
gs_free char *audit_args = NULL;
|
||||
|
||||
if (reapply_data) {
|
||||
connection = reapply_data->connection;
|
||||
version_id = reapply_data->version_id;
|
||||
g_slice_free(ReapplyData, reapply_data);
|
||||
}
|
||||
connection = reapply_data->connection;
|
||||
version_id = reapply_data->version_id;
|
||||
reapply_flags = reapply_data->reapply_flags;
|
||||
nm_g_slice_free(reapply_data);
|
||||
|
||||
if (error) {
|
||||
nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_REAPPLY,
|
||||
|
|
@ -13073,6 +13086,7 @@ reapply_cb(NMDevice *self,
|
|||
connection
|
||||
?: nm_device_get_settings_connection_get_connection(self),
|
||||
version_id,
|
||||
reapply_flags,
|
||||
&audit_args,
|
||||
&local)) {
|
||||
nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_REAPPLY,
|
||||
|
|
@ -13106,12 +13120,12 @@ impl_device_reapply(NMDBusObject *obj,
|
|||
ReapplyData *reapply_data;
|
||||
gs_unref_variant GVariant *settings = NULL;
|
||||
guint64 version_id;
|
||||
guint32 flags;
|
||||
guint32 reapply_flags_u;
|
||||
NMDeviceReapplyFlags reapply_flags;
|
||||
|
||||
g_variant_get(parameters, "(@a{sa{sv}}tu)", &settings, &version_id, &flags);
|
||||
g_variant_get(parameters, "(@a{sa{sv}}tu)", &settings, &version_id, &reapply_flags_u);
|
||||
|
||||
/* No flags supported as of now. */
|
||||
if (flags != 0) {
|
||||
if (NM_FLAGS_ANY(reapply_flags_u, ~((guint32) NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP))) {
|
||||
error =
|
||||
g_error_new_literal(NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "Invalid flags specified");
|
||||
nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_REAPPLY,
|
||||
|
|
@ -13124,6 +13138,9 @@ impl_device_reapply(NMDBusObject *obj,
|
|||
return;
|
||||
}
|
||||
|
||||
reapply_flags = reapply_flags_u;
|
||||
nm_assert(reapply_flags_u == reapply_flags);
|
||||
|
||||
if (priv->state < NM_DEVICE_STATE_PREPARE || priv->state > NM_DEVICE_STATE_ACTIVATED) {
|
||||
error = g_error_new_literal(NM_DEVICE_ERROR,
|
||||
NM_DEVICE_ERROR_NOT_ACTIVE,
|
||||
|
|
@ -13161,12 +13178,12 @@ impl_device_reapply(NMDBusObject *obj,
|
|||
nm_connection_clear_secrets(connection);
|
||||
}
|
||||
|
||||
if (connection || version_id) {
|
||||
reapply_data = g_slice_new(ReapplyData);
|
||||
reapply_data->connection = connection;
|
||||
reapply_data->version_id = version_id;
|
||||
} else
|
||||
reapply_data = NULL;
|
||||
reapply_data = g_slice_new(ReapplyData);
|
||||
*reapply_data = (ReapplyData){
|
||||
.connection = connection,
|
||||
.version_id = version_id,
|
||||
.reapply_flags = reapply_flags,
|
||||
};
|
||||
|
||||
nm_device_auth_request(self,
|
||||
invocation,
|
||||
|
|
@ -13202,7 +13219,7 @@ impl_device_get_applied_connection(NMDBusObject *obj,
|
|||
if (flags != 0) {
|
||||
g_dbus_method_invocation_return_error_literal(invocation,
|
||||
NM_DEVICE_ERROR,
|
||||
NM_DEVICE_ERROR_FAILED,
|
||||
NM_DEVICE_ERROR_INVALID_ARGUMENT,
|
||||
"Invalid flags specified");
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ static guint signals[LAST_SIGNAL] = {0};
|
|||
|
||||
NM_GOBJECT_PROPERTIES_DEFINE(NMManager,
|
||||
PROP_VERSION,
|
||||
PROP_VERSION_INFO,
|
||||
PROP_CAPABILITIES,
|
||||
PROP_STATE,
|
||||
PROP_STARTUP,
|
||||
|
|
@ -420,6 +421,31 @@ static NM_CACHED_QUARK_FCN("autoconnect-root", autoconnect_root_quark);
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static GVariant *
|
||||
_version_info_get(void)
|
||||
{
|
||||
const guint32 arr[] = {
|
||||
NM_VERSION,
|
||||
};
|
||||
|
||||
/* The array contains as first element NM_VERSION, which can be
|
||||
* used to numerically compare the version (see also NM_ENCODE_VERSION,
|
||||
* nm_utils_version(), nm_encode_version() and nm_decode_version().
|
||||
*
|
||||
* The following elements of the array are a bitfield of capabilities.
|
||||
* These capabilities should only depend on compile-time abilities
|
||||
* (unlike NM_MANAGER_CAPABILITIES, NMCapability). The supported values
|
||||
* are from NMVersionInfoCapability enum. This way to expose capabilities
|
||||
* is more cumbersome but more efficient compared to NM_MANAGER_CAPABILITIES.
|
||||
* As such, it is cheap to add capabilities for something, where you would
|
||||
* avoid it as NM_MANAGER_CAPABILITIES due to the overhead.
|
||||
*/
|
||||
|
||||
return nm_g_variant_new_au(arr, G_N_ELEMENTS(arr));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static gboolean
|
||||
_connection_is_vpn(NMConnection *connection)
|
||||
{
|
||||
|
|
@ -8133,6 +8159,9 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
|
|||
case PROP_VERSION:
|
||||
g_value_set_string(value, VERSION);
|
||||
break;
|
||||
case PROP_VERSION_INFO:
|
||||
g_value_set_variant(value, _version_info_get());
|
||||
break;
|
||||
case PROP_CAPABILITIES:
|
||||
g_value_set_variant(value,
|
||||
nm_g_variant_new_au(nm_g_array_first_p(priv->capabilities, guint32),
|
||||
|
|
@ -8646,6 +8675,9 @@ static const NMDBusInterfaceInfoExtended interface_info_manager = {
|
|||
NM_MANAGER_ACTIVATING_CONNECTION),
|
||||
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Startup", "b", NM_MANAGER_STARTUP),
|
||||
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Version", "s", NM_MANAGER_VERSION),
|
||||
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("VersionInfo",
|
||||
"au",
|
||||
NM_MANAGER_VERSION_INFO),
|
||||
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Capabilities",
|
||||
"au",
|
||||
NM_MANAGER_CAPABILITIES),
|
||||
|
|
@ -8704,6 +8736,14 @@ nm_manager_class_init(NMManagerClass *manager_class)
|
|||
NULL,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
obj_properties[PROP_VERSION_INFO] =
|
||||
g_param_spec_variant(NM_MANAGER_VERSION_INFO,
|
||||
"",
|
||||
"",
|
||||
G_VARIANT_TYPE("au"),
|
||||
NULL,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
obj_properties[PROP_CAPABILITIES] =
|
||||
g_param_spec_variant(NM_MANAGER_CAPABILITIES,
|
||||
"",
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
(G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_MANAGER, NMManagerClass))
|
||||
|
||||
#define NM_MANAGER_VERSION "version"
|
||||
#define NM_MANAGER_VERSION_INFO "version-info"
|
||||
#define NM_MANAGER_CAPABILITIES "capabilities"
|
||||
#define NM_MANAGER_STATE "state"
|
||||
#define NM_MANAGER_STARTUP "startup"
|
||||
|
|
|
|||
|
|
@ -135,3 +135,64 @@ nmc_client_new_waitsync(GCancellable *cancellable,
|
|||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
guint32
|
||||
nmc_client_has_version_info_v(NMClient *nmc)
|
||||
{
|
||||
const guint32 *ver;
|
||||
gsize len;
|
||||
|
||||
ver = nm_client_get_version_info(nmc, &len);
|
||||
if (len < 1)
|
||||
return 0;
|
||||
return ver[0];
|
||||
}
|
||||
|
||||
gboolean
|
||||
nmc_client_has_version_info_capability(NMClient *nmc, NMVersionInfoCapability capability)
|
||||
{
|
||||
const guint32 *ver;
|
||||
gsize len;
|
||||
gsize idx;
|
||||
gsize idx_hi;
|
||||
gsize idx_lo;
|
||||
|
||||
ver = nm_client_get_version_info(nmc, &len);
|
||||
|
||||
if (len < 2)
|
||||
return FALSE;
|
||||
|
||||
len--;
|
||||
ver++;
|
||||
|
||||
idx = (gsize) capability;
|
||||
if (idx >= G_MAXSIZE - 31u)
|
||||
return FALSE;
|
||||
|
||||
idx_hi = ((idx + 31u) / 32u);
|
||||
idx_lo = (idx % 32u);
|
||||
|
||||
if (idx_hi > len)
|
||||
return FALSE;
|
||||
|
||||
return NM_FLAGS_ANY(ver[idx_hi], (1ull << idx_lo));
|
||||
}
|
||||
|
||||
gboolean
|
||||
nmc_client_has_capability(NMClient *nmc, NMCapability capability)
|
||||
{
|
||||
const guint32 *caps;
|
||||
gsize len;
|
||||
gsize i;
|
||||
|
||||
caps = nm_client_get_capabilities(nmc, &len);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (caps[i] == capability)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,4 +21,8 @@ gboolean nmc_client_new_waitsync(GCancellable *cancellable,
|
|||
const char *first_property_name,
|
||||
...);
|
||||
|
||||
guint32 nmc_client_has_version_info_v(NMClient *nmc);
|
||||
gboolean nmc_client_has_version_info_capability(NMClient *nmc, NMVersionInfoCapability capability);
|
||||
gboolean nmc_client_has_capability(NMClient *nmc, NMCapability capability);
|
||||
|
||||
#endif /* __NM_LIBNM_AUX_H__ */
|
||||
|
|
|
|||
|
|
@ -1881,9 +1881,11 @@ global:
|
|||
|
||||
libnm_1_42_0 {
|
||||
global:
|
||||
nm_client_get_version_info;
|
||||
nm_client_wait_shutdown;
|
||||
nm_client_wait_shutdown_finish;
|
||||
nm_device_loopback_get_type;
|
||||
nm_device_reapply_flags_get_type;
|
||||
nm_range_cmp;
|
||||
nm_range_from_str;
|
||||
nm_range_get_range;
|
||||
|
|
@ -1906,4 +1908,5 @@ global:
|
|||
nm_setting_ovs_port_remove_trunk_by_value;
|
||||
nm_setting_vlan_get_protocol;
|
||||
nm_utils_ensure_gtypes;
|
||||
nm_version_info_capability_get_type;
|
||||
} libnm_1_40_0;
|
||||
|
|
|
|||
|
|
@ -217,6 +217,7 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMClient,
|
|||
PROP_DNS_RC_MANAGER,
|
||||
PROP_DNS_CONFIGURATION,
|
||||
PROP_CHECKPOINTS,
|
||||
PROP_VERSION_INFO,
|
||||
PROP_CAPABILITIES,
|
||||
PROP_PERMISSIONS_STATE, );
|
||||
|
||||
|
|
@ -305,7 +306,9 @@ typedef struct {
|
|||
char *connectivity_check_uri;
|
||||
char *version;
|
||||
guint32 *capabilities_arr;
|
||||
guint32 *version_info_arr;
|
||||
gsize capabilities_len;
|
||||
gsize version_info_len;
|
||||
guint32 connectivity;
|
||||
guint32 state;
|
||||
guint32 metered;
|
||||
|
|
@ -6300,6 +6303,57 @@ nm_client_get_capabilities(NMClient *client, gsize *length)
|
|||
return priv->nm.capabilities_arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_client_get_version_info:
|
||||
* @client: the #NMClient instance
|
||||
* @length: (out): the number of returned capabilities.
|
||||
*
|
||||
* If available, the first element in the array is NM_VERSION which
|
||||
* encodes the daemon version as "(major << 16 | minor << 8 | micro)".
|
||||
* The following elements are a bitfield of %NMVersionInfoCapabilities
|
||||
* that indicate that the daemon supports a certain capability.
|
||||
*
|
||||
* Returns: (transfer none) (array length=length): the
|
||||
* list of capabilities reported by the server or %NULL
|
||||
* if the capabilities are unknown.
|
||||
*
|
||||
* Since: 1.42
|
||||
*/
|
||||
const guint32 *
|
||||
nm_client_get_version_info(NMClient *client, gsize *length)
|
||||
{
|
||||
NMClientPrivate *priv;
|
||||
|
||||
g_return_val_if_fail(NM_IS_CLIENT(client), NULL);
|
||||
g_return_val_if_fail(length, NULL);
|
||||
|
||||
priv = NM_CLIENT_GET_PRIVATE(client);
|
||||
|
||||
*length = priv->nm.version_info_len;
|
||||
return priv->nm.version_info_arr;
|
||||
}
|
||||
|
||||
static NMLDBusNotifyUpdatePropFlags
|
||||
_notify_update_prop_nm_au(guint32 **p_arr, gsize *p_len, GVariant *value)
|
||||
{
|
||||
nm_clear_g_free(p_arr);
|
||||
*p_len = 0;
|
||||
|
||||
if (value) {
|
||||
const guint32 *arr;
|
||||
gsize len;
|
||||
|
||||
arr = g_variant_get_fixed_array(value, &len, sizeof(guint32));
|
||||
*p_len = len;
|
||||
*p_arr = g_new(guint32, len + 1);
|
||||
if (len > 0)
|
||||
memcpy(*p_arr, arr, len * sizeof(guint32));
|
||||
(*p_arr)[len] = 0;
|
||||
}
|
||||
|
||||
return NML_DBUS_NOTIFY_UPDATE_PROP_FLAGS_NOTIFY;
|
||||
}
|
||||
|
||||
static NMLDBusNotifyUpdatePropFlags
|
||||
_notify_update_prop_nm_capabilities(NMClient *self,
|
||||
NMLDBusObject *dbobj,
|
||||
|
|
@ -6311,22 +6365,21 @@ _notify_update_prop_nm_capabilities(NMClient *self,
|
|||
|
||||
nm_assert(G_OBJECT(self) == dbobj->nmobj);
|
||||
|
||||
nm_clear_g_free(&priv->nm.capabilities_arr);
|
||||
priv->nm.capabilities_len = 0;
|
||||
return _notify_update_prop_nm_au(&priv->nm.capabilities_arr, &priv->nm.capabilities_len, value);
|
||||
}
|
||||
|
||||
if (value) {
|
||||
const guint32 *arr;
|
||||
gsize len;
|
||||
static NMLDBusNotifyUpdatePropFlags
|
||||
_notify_update_prop_nm_version_info(NMClient *self,
|
||||
NMLDBusObject *dbobj,
|
||||
const NMLDBusMetaIface *meta_iface,
|
||||
guint dbus_property_idx,
|
||||
GVariant *value)
|
||||
{
|
||||
NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE(self);
|
||||
|
||||
arr = g_variant_get_fixed_array(value, &len, sizeof(guint32));
|
||||
priv->nm.capabilities_len = len;
|
||||
priv->nm.capabilities_arr = g_new(guint32, len + 1);
|
||||
if (len > 0)
|
||||
memcpy(priv->nm.capabilities_arr, arr, len * sizeof(guint32));
|
||||
priv->nm.capabilities_arr[len] = 0;
|
||||
}
|
||||
nm_assert(G_OBJECT(self) == dbobj->nmobj);
|
||||
|
||||
return NML_DBUS_NOTIFY_UPDATE_PROP_FLAGS_NOTIFY;
|
||||
return _notify_update_prop_nm_au(&priv->nm.version_info_arr, &priv->nm.version_info_len, value);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -7541,13 +7594,15 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
|
|||
case PROP_CHECKPOINTS:
|
||||
g_value_take_boxed(value, _nm_utils_copy_object_array(nm_client_get_checkpoints(self)));
|
||||
break;
|
||||
case PROP_VERSION_INFO:
|
||||
case PROP_CAPABILITIES:
|
||||
{
|
||||
const guint32 *arr;
|
||||
GArray *out;
|
||||
gsize len;
|
||||
|
||||
arr = nm_client_get_capabilities(self, &len);
|
||||
arr = (prop_id == PROP_VERSION_INFO) ? nm_client_get_version_info(self, &len)
|
||||
: nm_client_get_capabilities(self, &len);
|
||||
if (arr) {
|
||||
out = g_array_new(TRUE, FALSE, sizeof(guint32));
|
||||
g_array_append_vals(out, arr, len);
|
||||
|
|
@ -8104,6 +8159,10 @@ const NMLDBusMetaIface _nml_dbus_meta_iface_nm = NML_DBUS_META_IFACE_INIT_PROP(
|
|||
NML_DBUS_META_PROPERTY_INIT_B("Startup", PROP_STARTUP, NMClient, _priv.nm.startup),
|
||||
NML_DBUS_META_PROPERTY_INIT_U("State", PROP_STATE, NMClient, _priv.nm.state),
|
||||
NML_DBUS_META_PROPERTY_INIT_S("Version", PROP_VERSION, NMClient, _priv.nm.version),
|
||||
NML_DBUS_META_PROPERTY_INIT_FCN("VersionInfo",
|
||||
PROP_VERSION_INFO,
|
||||
"au",
|
||||
_notify_update_prop_nm_version_info, ),
|
||||
NML_DBUS_META_PROPERTY_INIT_IGNORE("WimaxEnabled", "b"),
|
||||
NML_DBUS_META_PROPERTY_INIT_IGNORE("WimaxHardwareEnabled", "b"),
|
||||
NML_DBUS_META_PROPERTY_INIT_B("WirelessEnabled",
|
||||
|
|
@ -8242,6 +8301,24 @@ nm_client_class_init(NMClientClass *client_class)
|
|||
NULL,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* NMClient:version-info: (type GArray(guint32))
|
||||
*
|
||||
* Expose version info and capabilities of NetworkManager. If non-empty,
|
||||
* the first element is NM_VERSION, which encodes the version of the
|
||||
* daemon as "(major << 16 | minor << 8 | micro)". The following elements
|
||||
* is a bitfields of %NMVersionInfoCapabilities. If a bit is set, then
|
||||
* the running NetworkManager has the respective capability.
|
||||
*
|
||||
* Since: 1.42
|
||||
*/
|
||||
obj_properties[PROP_VERSION_INFO] =
|
||||
g_param_spec_boxed(NM_CLIENT_VERSION_INFO,
|
||||
"",
|
||||
"",
|
||||
G_TYPE_ARRAY,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* NMClient:state:
|
||||
*
|
||||
|
|
|
|||
|
|
@ -2499,7 +2499,7 @@ nm_device_reapply_finish(NMDevice *device, GAsyncResult *result, GError **error)
|
|||
/**
|
||||
* nm_device_get_applied_connection:
|
||||
* @device: a #NMDevice
|
||||
* @flags: the flags argument. Currently, this value must always be zero.
|
||||
* @flags: the flags argument. See #NMDeviceReapplyFlags.
|
||||
* @version_id: (out) (allow-none): returns the current version id of
|
||||
* the applied connection
|
||||
* @cancellable: a #GCancellable, or %NULL
|
||||
|
|
@ -2562,7 +2562,7 @@ nm_device_get_applied_connection(NMDevice *device,
|
|||
/**
|
||||
* nm_device_get_applied_connection_async:
|
||||
* @device: a #NMDevice
|
||||
* @flags: the flags argument. Currently, this value must always be zero.
|
||||
* @flags: the flags argument. See #NMDeviceReapplyFlags.
|
||||
* @cancellable: a #GCancellable, or %NULL
|
||||
* @callback: callback to be called when the reapply operation completes
|
||||
* @user_data: caller-specific data passed to @callback
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ typedef enum /*< flags >*/ {
|
|||
#define NM_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_CLIENT, NMClientClass))
|
||||
|
||||
#define NM_CLIENT_VERSION "version"
|
||||
#define NM_CLIENT_VERSION_INFO "version-info"
|
||||
#define NM_CLIENT_STATE "state"
|
||||
#define NM_CLIENT_STARTUP "startup"
|
||||
#define NM_CLIENT_NM_RUNNING "nm-running"
|
||||
|
|
@ -187,9 +188,13 @@ NM_AVAILABLE_IN_1_22
|
|||
const char *nm_client_get_dbus_name_owner(NMClient *client);
|
||||
|
||||
const char *nm_client_get_version(NMClient *client);
|
||||
NMState nm_client_get_state(NMClient *client);
|
||||
gboolean nm_client_get_startup(NMClient *client);
|
||||
gboolean nm_client_get_nm_running(NMClient *client);
|
||||
|
||||
NM_AVAILABLE_IN_1_42
|
||||
const guint32 *nm_client_get_version_info(NMClient *client, gsize *length);
|
||||
|
||||
NMState nm_client_get_state(NMClient *client);
|
||||
gboolean nm_client_get_startup(NMClient *client);
|
||||
gboolean nm_client_get_nm_running(NMClient *client);
|
||||
|
||||
NMObject *nm_client_get_object_by_path(NMClient *client, const char *dbus_path);
|
||||
|
||||
|
|
|
|||
|
|
@ -90,6 +90,20 @@
|
|||
#define NM_DBUS_INTERFACE_DNS_MANAGER "org.freedesktop.NetworkManager.DnsManager"
|
||||
#define NM_DBUS_PATH_DNS_MANAGER "/org/freedesktop/NetworkManager/DnsManager"
|
||||
|
||||
/**
|
||||
* NMVersionInfoCapability:
|
||||
* %_NM_VERSION_INFO_CAPABILITY_UNUSED: a dummy capability. It has no meaning,
|
||||
* don't use it.
|
||||
*
|
||||
* Currently no enum values are defined. These capabilities are exposed
|
||||
* on D-Bus in the "VersionInfo" bit field.
|
||||
*
|
||||
* Since: 1.42
|
||||
*/
|
||||
typedef enum {
|
||||
_NM_VERSION_INFO_CAPABILITY_UNUSED = 0x7FFFFFFFu,
|
||||
} NMVersionInfoCapability;
|
||||
|
||||
/**
|
||||
* NMCapability:
|
||||
* @NM_CAPABILITY_TEAM: Teams can be managed. This means the team device plugin
|
||||
|
|
@ -1147,6 +1161,22 @@ typedef enum /*< flags >*/ {
|
|||
NM_SETTINGS_UPDATE2_FLAG_NO_REAPPLY = 0x40,
|
||||
} NMSettingsUpdate2Flags;
|
||||
|
||||
/**
|
||||
* NMDeviceReapplyFlags:
|
||||
* @NM_DEVICE_REAPPLY_FLAGS_NONE: no flag set.
|
||||
* @NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP: during reapply,
|
||||
* preserve external IP addresses and routes.
|
||||
*
|
||||
* Flags for the Reapply() D-Bus call of a device and
|
||||
* nm_device_reapply_async().
|
||||
*
|
||||
* Since: 1.42
|
||||
*/
|
||||
typedef enum /*< flags >*/ {
|
||||
NM_DEVICE_REAPPLY_FLAGS_NONE = 0,
|
||||
NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP = 0x1,
|
||||
} NMDeviceReapplyFlags;
|
||||
|
||||
/**
|
||||
* NMTernary:
|
||||
* @NM_TERNARY_DEFAULT: use the globally-configured default value.
|
||||
|
|
|
|||
|
|
@ -1989,6 +1989,20 @@ nm_g_array_unref(GArray *arr)
|
|||
&g_array_index(arr, Type, _len); \
|
||||
})
|
||||
|
||||
#define nm_g_array_append_simple(arr, val) \
|
||||
G_STMT_START \
|
||||
{ \
|
||||
/* Similar to `g_array_append_val()`, but `g_array_append_val()`
|
||||
* only works with lvalues. That makes sense if the value is a larger
|
||||
* struct and you anyway have a pointer to it. It doesn't make sense
|
||||
* if you have a list of int and want to append a number literal.
|
||||
*
|
||||
* nm_g_array_append_simple() is different. It depends on typeof(val)
|
||||
* to be compatible. */ \
|
||||
(*nm_g_array_append_new((arr), typeof(val))) = (val); \
|
||||
} \
|
||||
G_STMT_END
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static inline GPtrArray *
|
||||
|
|
|
|||
|
|
@ -251,24 +251,38 @@ _get_config(GCancellable *sigterm_cancellable, NMCSProvider *provider, NMClient
|
|||
/*****************************************************************************/
|
||||
|
||||
static gboolean
|
||||
_nmc_skip_connection(NMConnection *connection)
|
||||
_nmc_skip_connection_by_user_data(NMConnection *connection)
|
||||
{
|
||||
NMSettingUser *s_user;
|
||||
const char *v;
|
||||
|
||||
s_user = NM_SETTING_USER(nm_connection_get_setting(connection, NM_TYPE_SETTING_USER));
|
||||
if (!s_user)
|
||||
return FALSE;
|
||||
|
||||
#define USER_TAG_SKIP "org.freedesktop.nm-cloud-setup.skip"
|
||||
|
||||
nm_assert(nm_setting_user_check_key(USER_TAG_SKIP, NULL));
|
||||
|
||||
v = nm_setting_user_get_data(s_user, USER_TAG_SKIP);
|
||||
return _nm_utils_ascii_str_to_bool(v, FALSE);
|
||||
s_user = NM_SETTING_USER(nm_connection_get_setting(connection, NM_TYPE_SETTING_USER));
|
||||
if (s_user) {
|
||||
v = nm_setting_user_get_data(s_user, USER_TAG_SKIP);
|
||||
if (_nm_utils_ascii_str_to_bool(v, FALSE))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_nmc_skip_connection_by_type(NMConnection *connection)
|
||||
{
|
||||
if (!nm_streq0(nm_connection_get_connection_type(connection), NM_SETTING_WIRED_SETTING_NAME))
|
||||
return TRUE;
|
||||
|
||||
if (!nm_connection_get_setting_ip4_config(connection))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
_nmc_mangle_connection(NMDevice *device,
|
||||
NMConnection *connection,
|
||||
const NMCSProviderGetConfigResult *result,
|
||||
|
|
@ -291,12 +305,8 @@ _nmc_mangle_connection(NMDevice *device,
|
|||
NM_SET_OUT(out_skipped_single_addr, FALSE);
|
||||
NM_SET_OUT(out_changed, FALSE);
|
||||
|
||||
if (!nm_streq0(nm_connection_get_connection_type(connection), NM_SETTING_WIRED_SETTING_NAME))
|
||||
return FALSE;
|
||||
|
||||
s_ip = nm_connection_get_setting_ip4_config(connection);
|
||||
if (!s_ip)
|
||||
return FALSE;
|
||||
nm_assert(NM_IS_SETTING_IP4_CONFIG(s_ip));
|
||||
|
||||
if ((ac = nm_device_get_active_connection(device))
|
||||
&& (remote_connection = NM_CONNECTION(nm_active_connection_get_connection(ac))))
|
||||
|
|
@ -428,7 +438,6 @@ _nmc_mangle_connection(NMDevice *device,
|
|||
rules_new->len);
|
||||
|
||||
NM_SET_OUT(out_changed, addrs_changed || routes_changed || rules_changed);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -450,6 +459,7 @@ _config_one(GCancellable *sigterm_cancellable,
|
|||
gboolean version_id_changed;
|
||||
guint try_count;
|
||||
gboolean any_changes = FALSE;
|
||||
gboolean maybe_no_preserved_external_ip;
|
||||
|
||||
g_main_context_iteration(NULL, FALSE);
|
||||
|
||||
|
|
@ -483,6 +493,8 @@ _config_one(GCancellable *sigterm_cancellable,
|
|||
try_count = 0;
|
||||
|
||||
try_again:
|
||||
g_clear_object(&applied_connection);
|
||||
g_clear_error(&error);
|
||||
|
||||
applied_connection = nmcs_device_get_applied_connection(device,
|
||||
sigterm_cancellable,
|
||||
|
|
@ -496,23 +508,25 @@ try_again:
|
|||
return any_changes;
|
||||
}
|
||||
|
||||
if (_nmc_skip_connection(applied_connection)) {
|
||||
if (_nmc_skip_connection_by_user_data(applied_connection)) {
|
||||
_LOGD("config device %s: skip applied connection due to user data %s",
|
||||
hwaddr,
|
||||
USER_TAG_SKIP);
|
||||
return any_changes;
|
||||
}
|
||||
|
||||
if (!_nmc_mangle_connection(device,
|
||||
applied_connection,
|
||||
result,
|
||||
config_data,
|
||||
&skipped_single_addr,
|
||||
&changed)) {
|
||||
if (_nmc_skip_connection_by_type(applied_connection)) {
|
||||
_LOGD("config device %s: device has no suitable applied connection. Skip", hwaddr);
|
||||
return any_changes;
|
||||
}
|
||||
|
||||
_nmc_mangle_connection(device,
|
||||
applied_connection,
|
||||
result,
|
||||
config_data,
|
||||
&skipped_single_addr,
|
||||
&changed);
|
||||
|
||||
if (!changed) {
|
||||
if (skipped_single_addr) {
|
||||
_LOGD("config device %s: device needs no update to applied connection \"%s\" (%s) "
|
||||
|
|
@ -538,16 +552,21 @@ try_again:
|
|||
/* we are about to call Reapply(). Even if that fails, it counts as if we changed something. */
|
||||
any_changes = TRUE;
|
||||
|
||||
/* "preserve-external-ip" flag was only introduced in 1.41.6 (but maybe backported!).
|
||||
* If we run 1.41.6+, we are sure that it's gonna work. Otherwise, we take into account
|
||||
* that the call might fail due to the invalid flag and we retry. */
|
||||
maybe_no_preserved_external_ip =
|
||||
(nmc_client_has_version_info_v(nmc) < NM_ENCODE_VERSION(1, 41, 6));
|
||||
|
||||
if (!nmcs_device_reapply(device,
|
||||
sigterm_cancellable,
|
||||
applied_connection,
|
||||
applied_version_id,
|
||||
maybe_no_preserved_external_ip,
|
||||
&version_id_changed,
|
||||
&error)) {
|
||||
if (version_id_changed && try_count < 5) {
|
||||
_LOGD("config device %s: applied connection changed in the meantime. Retry...", hwaddr);
|
||||
g_clear_object(&applied_connection);
|
||||
g_clear_error(&error);
|
||||
try_count++;
|
||||
goto try_again;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -822,6 +822,7 @@ nmcs_device_reapply(NMDevice *device,
|
|||
GCancellable *sigterm_cancellable,
|
||||
NMConnection *connection,
|
||||
guint64 version_id,
|
||||
gboolean maybe_no_preserved_external_ip,
|
||||
gboolean *out_version_id_changed,
|
||||
GError **error)
|
||||
{
|
||||
|
|
@ -829,11 +830,13 @@ nmcs_device_reapply(NMDevice *device,
|
|||
DeviceReapplyData data = {
|
||||
.main_loop = main_loop,
|
||||
};
|
||||
NMDeviceReapplyFlags reapply_flags = NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP;
|
||||
|
||||
again:
|
||||
nm_device_reapply_async(device,
|
||||
connection,
|
||||
version_id,
|
||||
0,
|
||||
reapply_flags,
|
||||
sigterm_cancellable,
|
||||
_nmcs_device_reapply_cb,
|
||||
&data);
|
||||
|
|
@ -841,6 +844,17 @@ nmcs_device_reapply(NMDevice *device,
|
|||
g_main_loop_run(main_loop);
|
||||
|
||||
if (data.error) {
|
||||
if (maybe_no_preserved_external_ip
|
||||
&& reapply_flags == NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP
|
||||
&& nm_g_error_matches(data.error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED)) {
|
||||
/* Hm? Maybe we running against an older version of NetworkManager that
|
||||
* doesn't support "preserve-external-ip" flags? Retry without the flag.
|
||||
*
|
||||
* Note that recent version would reject invalid flags with NM_DEVICE_ERROR_INVALID_ARGUMENT,
|
||||
* but we want to detect old daemon versions here. */
|
||||
reapply_flags = NM_DEVICE_REAPPLY_FLAGS_NONE;
|
||||
goto again;
|
||||
}
|
||||
NM_SET_OUT(
|
||||
out_version_id_changed,
|
||||
g_error_matches(data.error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_VERSION_ID_MISMATCH));
|
||||
|
|
|
|||
|
|
@ -136,6 +136,7 @@ gboolean nmcs_device_reapply(NMDevice *device,
|
|||
GCancellable *sigterm_cancellable,
|
||||
NMConnection *connection,
|
||||
guint64 version_id,
|
||||
gboolean maybe_no_preserved_external_ip,
|
||||
gboolean *out_version_id_changed,
|
||||
GError **error);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue