all: add connection.multi-connect property for wildcard profiles

Add a new option that allows to activate a profile multiple times
(at the same time). Previoulsy, all profiles were implicitly
NM_SETTING_CONNECTION_MULTI_CONNECT_SINGLE, meaning, that activating
a profile that is already active will deactivate it first.

This will make more sense, as we also add more match-options how
profiles can be restricted to particular devices. We already have
connection.type, connection.interface-name, and (ethernet|wifi).mac-address
to restrict a profile to particular devices. For example, it is however
not possible to specify a wildcard like "eth*" to match a profile to
a set of devices by interface-name. That is another missing feature,
and once we extend the matching capabilities, it makes more sense to
activate a profile multiple times.

See also https://bugzilla.redhat.com/show_bug.cgi?id=997998, which
previously changed that a connection is restricted to a single activation
at a time. This work relaxes that again.

This only adds the new property, it is not used nor implemented yet.

https://bugzilla.redhat.com/show_bug.cgi?id=1555012
This commit is contained in:
Thomas Haller 2018-04-10 11:45:35 +02:00 committed by Beniamino Galvani
parent 2ead94d5f9
commit 55ae69233d
15 changed files with 795 additions and 512 deletions

View file

@ -5569,6 +5569,14 @@ static const NMMetaPropertyInfo *const property_infos_CONNECTION[] = {
),
),
),
PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_MULTI_CONNECT,
.property_type = &_pt_gobject_enum,
.property_typ_data = DEFINE_PROPERTY_TYP_DATA (
PROPERTY_TYP_DATA_SUBTYPE (gobject_enum,
.get_gtype = nm_connection_multi_connect_get_type,
),
),
),
PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_AUTH_RETRIES,
.property_type = &_pt_gobject_int,
),

View file

@ -138,6 +138,7 @@
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MASTER N_("Interface name of the master device or UUID of the master connection.")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MDNS N_("Whether mDNS is enabled for the connection. The permitted values are: yes: register hostname and resolving for the connection, no: disable mDNS for the interface, resolve: do not register hostname but allow resolving of mDNS host names. When updating this property on a currently activated connection, the change takes effect immediately. This feature requires a plugin which supports mDNS. One such plugin is dns-systemd-resolved.")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_METERED N_("Whether the connection is metered. When updating this property on a currently activated connection, the change takes effect immediately.")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MULTI_CONNECT N_("Specifies whether the profile can be active multiple times at a particular moment. The value is of type NMConnectionMultiConnect.")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_PERMISSIONS N_("An array of strings defining what access a given user has to this connection. If this is NULL or empty, all users are allowed to access this connection; otherwise users are allowed if and only if they are in this list. When this is not empty, the connection can be active only when one of the specified users is logged into an active session. Each entry is of the form \"[type]:[id]:[reserved]\"; for example, \"user:dcbw:blah\". At this time only the \"user\" [type] is allowed. Any other values are ignored and reserved for future use. [id] is the username that this permission refers to, which may not contain the \":\" character. Any [reserved] information present must be ignored and is reserved for future use. All of [type], [id], and [reserved] must be valid UTF-8.")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_READ_ONLY N_("FALSE if the connection can be modified using the provided settings service's D-Bus interface with the right privileges, or TRUE if the connection is read-only and cannot be modified.")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_SECONDARIES N_("List of connection UUIDs that should be activated when the base connection itself is activated. Currently only VPN connections are supported.")

View file

@ -484,12 +484,12 @@ NAME UUID TYPE DEVICE
con-1 5fcfd6d7-1e63-3332-8826-a7eda103792d ethernet --
<<<
size: 1118
size: 1171
location: clients/tests/test-client.py:859:test_002()/23
cmd: $NMCLI c s con-1
lang: C
returncode: 0
stdout: 990 bytes
stdout: 1042 bytes
>>>
connection.id: con-1
connection.uuid: 5fcfd6d7-1e63-3332-8826-a7eda103792d
@ -499,6 +499,7 @@ connection.interface-name: --
connection.autoconnect: yes
connection.autoconnect-priority: 0
connection.autoconnect-retries: -1 (default)
connection.multi-connect: 0 (default)
connection.auth-retries: -1
connection.timestamp: 0
connection.read-only: no
@ -514,12 +515,12 @@ connection.lldp: default
connection.mdns: -1 (default)
<<<
size: 1130
size: 1183
location: clients/tests/test-client.py:859:test_002()/24
cmd: $NMCLI c s con-1
lang: pl_PL.UTF-8
returncode: 0
stdout: 992 bytes
stdout: 1044 bytes
>>>
connection.id: con-1
connection.uuid: 5fcfd6d7-1e63-3332-8826-a7eda103792d
@ -529,6 +530,7 @@ connection.interface-name: --
connection.autoconnect: tak
connection.autoconnect-priority: 0
connection.autoconnect-retries: -1 (default)
connection.multi-connect: 0 (default)
connection.auth-retries: -1
connection.timestamp: 0
connection.read-only: nie

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -2081,6 +2081,32 @@ nm_connection_get_interface_name (NMConnection *connection)
return s_con ? nm_setting_connection_get_interface_name (s_con) : NULL;
}
NMConnectionMultiConnect
_nm_connection_get_multi_connect (NMConnection *connection)
{
NMSettingConnection *s_con;
NMConnectionMultiConnect multi_connect;
const NMConnectionMultiConnect DEFAULT = NM_CONNECTION_MULTI_CONNECT_SINGLE;
/* connection.multi_connect property cannot be specified via regular
* connection defaults in NetworkManager.conf, because those are per-device,
* and we need to determine the multi_connect independent of a particular
* device.
*
* There is however still a default-value, so theoretically, the default
* value could be specified in NetworkManager.conf. Just not as [connection*]
* and indepdented of a device. */
s_con = nm_connection_get_setting_connection (connection);
if (!s_con)
return DEFAULT;
multi_connect = nm_setting_connection_get_multi_connect (s_con);
return multi_connect == NM_CONNECTION_MULTI_CONNECT_DEFAULT
? DEFAULT
: multi_connect;
}
gboolean
_nm_connection_verify_required_interface_name (NMConnection *connection,
GError **error)

View file

@ -437,6 +437,8 @@ _nm_connection_get_uuid (NMConnection *connection)
return connection ? nm_connection_get_uuid (connection) : NULL;
}
NMConnectionMultiConnect _nm_connection_get_multi_connect (NMConnection *connection);
/*****************************************************************************/
typedef enum {

View file

@ -655,6 +655,30 @@ typedef enum {
NM_METERED_GUESS_NO = 4,
} NMMetered;
/**
* NMConnectionMultiConnect:
* @NM_CONNECTION_MULTI_CONNECT_DEFAULT: indicates that the per-connection
* setting is unspecified. In this case, it will fallback to the default
* value, which is @NM_CONNECTION_MULTI_CONNECT_SINGLE.
* @NM_CONNECTION_MULTI_CONNECT_SINGLE: the connection profile can only
* be active once at each moment. Activating a profile that is already active,
* will first deactivate it.
* @NM_CONNECTION_MULTI_CONNECT_MANUAL_MULTIPLE: the profile can
* be manually activated multiple times on different devices. However,
* regarding autoconnect, the profile will autoconnect only if it is
* currently not connected otherwise.
* @NM_CONNECTION_MULTI_CONNECT_MULTIPLE: the profile can autoactivate
* and be manually activated multiple times together.
*
* Since: 1.14
*/
typedef enum {
NM_CONNECTION_MULTI_CONNECT_DEFAULT = 0,
NM_CONNECTION_MULTI_CONNECT_SINGLE = 1,
NM_CONNECTION_MULTI_CONNECT_MANUAL_MULTIPLE = 2,
NM_CONNECTION_MULTI_CONNECT_MULTIPLE = 3,
} NMConnectionMultiConnect;
/**
* NMActiveConnectionState:
* @NM_ACTIVE_CONNECTION_STATE_UNKNOWN: the state of the connection is unknown

View file

@ -72,6 +72,7 @@ typedef struct {
gboolean autoconnect;
int autoconnect_priority;
int autoconnect_retries;
int multi_connect;
guint64 timestamp;
gboolean read_only;
char *zone;
@ -93,6 +94,7 @@ enum {
PROP_AUTOCONNECT,
PROP_AUTOCONNECT_PRIORITY,
PROP_AUTOCONNECT_RETRIES,
PROP_MULTI_CONNECT,
PROP_TIMESTAMP,
PROP_READ_ONLY,
PROP_ZONE,
@ -554,6 +556,22 @@ nm_setting_connection_get_autoconnect_retries (NMSettingConnection *setting)
return NM_SETTING_CONNECTION_GET_PRIVATE (setting)->autoconnect_retries;
}
/**
* nm_setting_connection_get_multi_connect:
* @setting: the #NMSettingConnection
*
* Returns: the #NMSettingConnection:multi-connect property of the connection.
*
* Since: 1.14
**/
NMConnectionMultiConnect
nm_setting_connection_get_multi_connect (NMSettingConnection *setting)
{
g_return_val_if_fail (NM_IS_SETTING_CONNECTION (setting), -1);
return (NMConnectionMultiConnect) NM_SETTING_CONNECTION_GET_PRIVATE (setting)->multi_connect;
}
/**
* nm_setting_connection_get_auth_retries:
* @setting: the #NMSettingConnection
@ -1087,6 +1105,19 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return FALSE;
}
if (!NM_IN_SET (priv->multi_connect, (int) NM_CONNECTION_MULTI_CONNECT_DEFAULT,
(int) NM_CONNECTION_MULTI_CONNECT_SINGLE,
(int) NM_CONNECTION_MULTI_CONNECT_MANUAL_MULTIPLE,
(int) NM_CONNECTION_MULTI_CONNECT_MULTIPLE)) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("value %d is not valid"), priv->multi_connect);
g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME,
NM_SETTING_CONNECTION_MULTI_CONNECT);
return FALSE;
}
/* *** errors above here should be always fatal, below NORMALIZABLE_ERROR *** */
if (!priv->uuid) {
@ -1328,6 +1359,9 @@ set_property (GObject *object, guint prop_id,
case PROP_AUTOCONNECT_RETRIES:
priv->autoconnect_retries = g_value_get_int (value);
break;
case PROP_MULTI_CONNECT:
priv->multi_connect = g_value_get_int (value);
break;
case PROP_TIMESTAMP:
priv->timestamp = g_value_get_uint64 (value);
break;
@ -1423,6 +1457,9 @@ get_property (GObject *object, guint prop_id,
case PROP_AUTOCONNECT_RETRIES:
g_value_set_int (value, nm_setting_connection_get_autoconnect_retries (setting));
break;
case PROP_MULTI_CONNECT:
g_value_set_int (value, priv->multi_connect);
break;
case PROP_TIMESTAMP:
g_value_set_uint64 (value, nm_setting_connection_get_timestamp (setting));
break;
@ -1764,6 +1801,30 @@ nm_setting_connection_class_init (NMSettingConnectionClass *setting_class)
NM_SETTING_PARAM_FUZZY_IGNORE |
G_PARAM_STATIC_STRINGS));
/**
* NMSettingConnection:multi-connect:
*
* Specifies whether the profile can be active multiple times at a particular
* moment. The value is of type #NMConnectionMultiConnect.
*
* Since: 1.14
*/
/* ---ifcfg-rh---
* property: multi-connect
* variable: MULTI_CONNECT(+)
* description: whether the profile can be active on multiple devices at a given
* moment. The values are numbers corresponding to #NMConnectionMultiConnect enum.
* example: ZONE=3
* ---end---
*/
g_object_class_install_property
(object_class, PROP_MULTI_CONNECT,
g_param_spec_int (NM_SETTING_CONNECTION_MULTI_CONNECT, "", "",
G_MININT32, G_MAXINT32, NM_CONNECTION_MULTI_CONNECT_DEFAULT,
G_PARAM_READWRITE |
NM_SETTING_PARAM_FUZZY_IGNORE |
G_PARAM_STATIC_STRINGS));
/**
* NMSettingConnection:timestamp:
*

View file

@ -52,6 +52,7 @@ G_BEGIN_DECLS
#define NM_SETTING_CONNECTION_AUTOCONNECT "autoconnect"
#define NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY "autoconnect-priority"
#define NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES "autoconnect-retries"
#define NM_SETTING_CONNECTION_MULTI_CONNECT "multi-connect"
#define NM_SETTING_CONNECTION_TIMESTAMP "timestamp"
#define NM_SETTING_CONNECTION_READ_ONLY "read-only"
#define NM_SETTING_CONNECTION_PERMISSIONS "permissions"
@ -145,6 +146,8 @@ gboolean nm_setting_connection_get_autoconnect (NMSettingConnection *set
int nm_setting_connection_get_autoconnect_priority (NMSettingConnection *setting);
NM_AVAILABLE_IN_1_6
int nm_setting_connection_get_autoconnect_retries (NMSettingConnection *setting);
NM_AVAILABLE_IN_1_14
NMConnectionMultiConnect nm_setting_connection_get_multi_connect (NMSettingConnection *setting);
guint64 nm_setting_connection_get_timestamp (NMSettingConnection *setting);
gboolean nm_setting_connection_get_read_only (NMSettingConnection *setting);

View file

@ -480,6 +480,7 @@ static gboolean
verify (NMSetting *setting, NMConnection *connection, GError **error)
{
NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting);
NMSettingConnection *s_con;
if (!priv->service_type) {
g_set_error_literal (error,
@ -509,6 +510,16 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return FALSE;
}
if ( connection
&& (s_con = nm_connection_get_setting_connection (connection))
&& nm_setting_connection_get_multi_connect (s_con) != NM_CONNECTION_MULTI_CONNECT_DEFAULT) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("cannot set connection.multi-connect for VPN setting"));
return FALSE;
}
return TRUE;
}

View file

@ -2595,6 +2595,7 @@ test_connection_diff_a_only (void)
{ NM_SETTING_CONNECTION_AUTOCONNECT, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_CONNECTION_MULTI_CONNECT, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_CONNECTION_READ_ONLY, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_CONNECTION_PERMISSIONS, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_CONNECTION_ZONE, NM_SETTING_DIFF_RESULT_IN_A },

View file

@ -1385,6 +1385,7 @@ global:
nm_connection_get_setting_6lowpan;
nm_connection_get_setting_sriov;
nm_connection_get_setting_wpan;
nm_connection_multi_connect_get_type;
nm_device_6lowpan_get_type;
nm_device_wireguard_get_fwmark;
nm_device_wireguard_get_listen_port;
@ -1392,6 +1393,7 @@ global:
nm_device_wireguard_get_type;
nm_device_wpan_get_type;
nm_setting_6lowpan_get_type;
nm_setting_connection_get_multi_connect;
nm_setting_sriov_add_vf;
nm_setting_sriov_clear_vfs;
nm_setting_sriov_get_autoprobe_drivers;

View file

@ -239,6 +239,9 @@ make_connection_setting (const char *file,
NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES,
(int) svGetValueInt64 (ifcfg, "AUTOCONNECT_RETRIES", 10,
-1, G_MAXINT32, -1),
NM_SETTING_CONNECTION_MULTI_CONNECT,
(gint) svGetValueInt64 (ifcfg, "MULTI_CONNECT", 10,
G_MININT32, G_MAXINT32, NM_CONNECTION_MULTI_CONNECT_DEFAULT),
NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES,
svGetValueBoolean (ifcfg, "AUTOCONNECT_SLAVES", NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_DEFAULT),
NM_SETTING_CONNECTION_LLDP, lldp,

View file

@ -1746,6 +1746,11 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg)
vint != -1,
vint);
vint = nm_setting_connection_get_multi_connect (s_con);
svSetValueInt64_cond (ifcfg, "MULTI_CONNECT",
vint != NM_CONNECTION_MULTI_CONNECT_DEFAULT,
vint);
/* Only save the value for master connections */
type = nm_setting_connection_get_connection_type (s_con);
if (_nm_connection_type_is_master (type)) {