core: add NMManager:primary-connection and :activating-connection

Add properties to track the "primary" connection (ie, the active
connection with either the default route, or the route to the VPN with
the default route), and the active connection that is currently
activating, and likely to become the :primary-connection when it
completes.

https://bugzilla.gnome.org/show_bug.cgi?id=704841
This commit is contained in:
Dan Winship 2013-08-22 13:06:51 -04:00
parent 5c716c8af8
commit 8267f5d198
5 changed files with 340 additions and 38 deletions

View file

@ -315,6 +315,25 @@
</tp:docstring>
</property>
<property name="PrimaryConnection" type="o" access="read">
<tp:docstring>
The object path of the "primary" active connection being used
to access the network. In particular, if there is no VPN
active, or the VPN does not have the default route, then this
indicates the connection that has the default route. If there
is a VPN active with the default route, then this indicates
the connection that contains the route to the VPN endpoint.
</tp:docstring>
</property>
<property name="ActivatingConnection" type="o" access="read">
<tp:docstring>
The object path of an active connection that is currently
being activated and which is expected to become the new
PrimaryConnection when it finishes activating.
</tp:docstring>
</property>
<property name="Startup" type="b" access="read">
<tp:docstring>
Indicates whether NM is still starting up; this becomes FALSE

View file

@ -217,6 +217,8 @@ typedef struct {
GSList *active_connections;
guint ac_cleanup_id;
NMActiveConnection *primary_connection;
NMActiveConnection *activating_connection;
GSList *devices;
NMState state;
@ -298,6 +300,8 @@ enum {
PROP_WIMAX_HARDWARE_ENABLED,
PROP_ACTIVE_CONNECTIONS,
PROP_CONNECTIVITY,
PROP_PRIMARY_CONNECTION,
PROP_ACTIVATING_CONNECTION,
/* Not exported */
PROP_HOSTNAME,
@ -4179,6 +4183,68 @@ firmware_dir_changed (GFileMonitor *monitor,
}
}
static void
policy_default_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data)
{
NMManager *self = NM_MANAGER (user_data);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMDevice *best;
NMActiveConnection *ac;
/* Note: this assumes that it's not possible for the IP4 default
* route to be going over the default-ip6-device. If that changes,
* we need something more complicated here.
*/
best = nm_policy_get_default_ip4_device (priv->policy);
if (!best)
best = nm_policy_get_default_ip6_device (priv->policy);
if (best)
ac = NM_ACTIVE_CONNECTION (nm_device_get_act_request (best));
else
ac = NULL;
if (ac != priv->primary_connection) {
g_clear_object (&priv->primary_connection);
priv->primary_connection = ac ? g_object_ref (ac) : NULL;
nm_log_dbg (LOGD_CORE, "PrimaryConnection now %s", ac ? nm_active_connection_get_name (ac) : "(none)");
g_object_notify (G_OBJECT (self), NM_MANAGER_PRIMARY_CONNECTION);
}
}
static void
policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data)
{
NMManager *self = NM_MANAGER (user_data);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMDevice *activating, *best;
NMActiveConnection *ac;
/* We only look at activating-ip6-device if activating-ip4-device
* AND default-ip4-device are NULL; if default-ip4-device is
* non-NULL, then activating-ip6-device is irrelevant, since while
* that device might become the new default-ip6-device, it can't
* become primary-connection while default-ip4-device is set to
* something else.
*/
activating = nm_policy_get_activating_ip4_device (priv->policy);
best = nm_policy_get_default_ip4_device (priv->policy);
if (!activating && !best)
activating = nm_policy_get_activating_ip6_device (priv->policy);
if (activating)
ac = NM_ACTIVE_CONNECTION (nm_device_get_act_request (activating));
else
ac = NULL;
if (ac != priv->activating_connection) {
g_clear_object (&priv->activating_connection);
priv->activating_connection = ac ? g_object_ref (ac) : NULL;
nm_log_dbg (LOGD_CORE, "ActivatingConnection now %s", ac ? nm_active_connection_get_name (ac) : "(none)");
g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVATING_CONNECTION);
}
}
#define NM_PERM_DENIED_ERROR "org.freedesktop.NetworkManager.PermissionDenied"
#define DEV_PERM_DENIED_ERROR "org.freedesktop.NetworkManager.Device.PermissionDenied"
@ -4360,6 +4426,14 @@ nm_manager_new (NMSettings *settings,
priv = NM_MANAGER_GET_PRIVATE (singleton);
priv->policy = nm_policy_new (singleton, settings);
g_signal_connect (priv->policy, "notify::" NM_POLICY_DEFAULT_IP4_DEVICE,
G_CALLBACK (policy_default_device_changed), singleton);
g_signal_connect (priv->policy, "notify::" NM_POLICY_DEFAULT_IP6_DEVICE,
G_CALLBACK (policy_default_device_changed), singleton);
g_signal_connect (priv->policy, "notify::" NM_POLICY_ACTIVATING_IP4_DEVICE,
G_CALLBACK (policy_activating_device_changed), singleton);
g_signal_connect (priv->policy, "notify::" NM_POLICY_ACTIVATING_IP6_DEVICE,
G_CALLBACK (policy_activating_device_changed), singleton);
priv->connectivity = nm_connectivity_new ();
g_signal_connect (priv->connectivity, "notify::" NM_CONNECTIVITY_STATE,
@ -4491,11 +4565,15 @@ dispose (GObject *object)
g_object_unref (iter->data);
}
g_slist_free (priv->active_connections);
g_clear_object (&priv->primary_connection);
g_clear_object (&priv->activating_connection);
g_clear_object (&priv->connectivity);
g_free (priv->hostname);
g_signal_handlers_disconnect_by_func (priv->policy, G_CALLBACK (policy_default_device_changed), singleton);
g_signal_handlers_disconnect_by_func (priv->policy, G_CALLBACK (policy_activating_device_changed), singleton);
g_object_unref (priv->policy);
g_object_unref (priv->settings);
@ -4739,6 +4817,14 @@ get_property (GObject *object, guint prop_id,
case PROP_CONNECTIVITY:
g_value_set_uint (value, nm_connectivity_get_state (priv->connectivity));
break;
case PROP_PRIMARY_CONNECTION:
path = priv->primary_connection ? nm_active_connection_get_path (priv->primary_connection) : "/";
g_value_set_boxed (value, path);
break;
case PROP_ACTIVATING_CONNECTION:
path = priv->activating_connection ? nm_active_connection_get_path (priv->activating_connection) : "/";
g_value_set_boxed (value, path);
break;
case PROP_HOSTNAME:
g_value_set_string (value, priv->hostname);
break;
@ -5011,6 +5097,22 @@ nm_manager_class_init (NMManagerClass *manager_class)
NM_CONNECTIVITY_UNKNOWN, NM_CONNECTIVITY_FULL, NM_CONNECTIVITY_UNKNOWN,
G_PARAM_READABLE));
g_object_class_install_property
(object_class, PROP_PRIMARY_CONNECTION,
g_param_spec_boxed (NM_MANAGER_PRIMARY_CONNECTION,
"Primary connection",
"Primary connection",
DBUS_TYPE_G_OBJECT_PATH,
G_PARAM_READABLE));
g_object_class_install_property
(object_class, PROP_ACTIVATING_CONNECTION,
g_param_spec_boxed (NM_MANAGER_ACTIVATING_CONNECTION,
"Activating connection",
"Activating connection",
DBUS_TYPE_G_OBJECT_PATH,
G_PARAM_READABLE));
/* Hostname is not exported over D-Bus */
g_object_class_install_property
(object_class, PROP_HOSTNAME,

View file

@ -61,6 +61,8 @@ typedef enum {
#define NM_MANAGER_WIMAX_HARDWARE_ENABLED "wimax-hardware-enabled"
#define NM_MANAGER_ACTIVE_CONNECTIONS "active-connections"
#define NM_MANAGER_CONNECTIVITY "connectivity"
#define NM_MANAGER_PRIMARY_CONNECTION "primary-connection"
#define NM_MANAGER_ACTIVATING_CONNECTION "activating-connection"
/* Not exported */
#define NM_MANAGER_HOSTNAME "hostname"

View file

@ -59,8 +59,8 @@ typedef struct {
NMSettings *settings;
NMDevice *default_device4;
NMDevice *default_device6;
NMDevice *default_device4, *activating_device4;
NMDevice *default_device6, *activating_device6;
GResolver *resolver;
GInetAddress *lookup_addr;
@ -79,6 +79,15 @@ typedef struct {
G_DEFINE_TYPE (NMPolicy, nm_policy, G_TYPE_OBJECT)
enum {
PROP_0,
PROP_DEFAULT_IP4_DEVICE,
PROP_DEFAULT_IP6_DEVICE,
PROP_ACTIVATING_IP4_DEVICE,
PROP_ACTIVATING_IP6_DEVICE
};
#define RETRIES_TAG "autoconnect-retries"
#define RETRIES_DEFAULT 4
#define RESET_RETRIES_TIMESTAMP_TAG "reset-retries-timestamp-tag"
@ -89,7 +98,7 @@ static void schedule_activate_all (NMPolicy *policy);
static NMDevice *
get_best_ip4_device (NMManager *manager)
get_best_ip4_device (NMManager *manager, gboolean fully_activated)
{
GSList *devices, *iter;
NMDevice *best = NULL;
@ -101,6 +110,7 @@ get_best_ip4_device (NMManager *manager)
for (iter = devices; iter; iter = g_slist_next (iter)) {
NMDevice *dev = NM_DEVICE (iter->data);
NMDeviceType devtype = nm_device_get_device_type (dev);
NMDeviceState state = nm_device_get_state (dev);
NMActRequest *req;
NMConnection *connection;
NMIP4Config *ip4_config;
@ -108,12 +118,23 @@ get_best_ip4_device (NMManager *manager)
int prio;
const char *method = NULL;
if ( nm_device_get_state (dev) != NM_DEVICE_STATE_ACTIVATED
&& nm_device_get_state (dev) != NM_DEVICE_STATE_SECONDARIES)
if ( state <= NM_DEVICE_STATE_DISCONNECTED
|| state >= NM_DEVICE_STATE_DEACTIVATING)
continue;
if (fully_activated && state < NM_DEVICE_STATE_SECONDARIES)
continue;
ip4_config = nm_device_get_ip4_config (dev);
if (!ip4_config)
if (ip4_config) {
/* Make sure the device has a gateway */
if (!nm_ip4_config_get_gateway (ip4_config) && (devtype != NM_DEVICE_TYPE_MODEM))
continue;
/* 'never-default' devices can't ever be the default */
if (nm_ip4_config_get_never_default (ip4_config))
continue;
} else if (fully_activated)
continue;
req = nm_device_get_act_request (dev);
@ -121,22 +142,17 @@ get_best_ip4_device (NMManager *manager)
connection = nm_act_request_get_connection (req);
g_assert (connection);
/* Never set the default route through an IPv4LL-addressed device */
s_ip4 = nm_connection_get_setting_ip4_config (connection);
if (s_ip4)
if (s_ip4) {
/* Never set the default route through an IPv4LL-addressed device */
method = nm_setting_ip4_config_get_method (s_ip4);
if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL))
continue;
if (s_ip4 && !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL))
continue;
/* Make sure the device has a gateway */
if (!nm_ip4_config_get_gateway (ip4_config) && (devtype != NM_DEVICE_TYPE_MODEM))
continue;
/* 'never-default' devices can't ever be the default */
if ( (s_ip4 && nm_setting_ip4_config_get_never_default (s_ip4))
|| nm_ip4_config_get_never_default (ip4_config))
continue;
/* 'never-default' devices can't ever be the default */
if (nm_setting_ip4_config_get_never_default (s_ip4))
continue;
}
prio = nm_device_get_priority (dev);
if (prio > 0 && prio < best_prio) {
@ -145,11 +161,25 @@ get_best_ip4_device (NMManager *manager)
}
}
if (!best)
return NULL;
if (!fully_activated) {
NMDeviceState state = nm_device_get_state (best);
/* There's only a best activating device if the best device
* among all activating and already-activated devices is a
* still-activating one.
*/
if (state >= NM_DEVICE_STATE_SECONDARIES)
return NULL;
}
return best;
}
static NMDevice *
get_best_ip6_device (NMManager *manager)
get_best_ip6_device (NMManager *manager, gboolean fully_activated)
{
GSList *devices, *iter;
NMDevice *best = NULL;
@ -161,6 +191,7 @@ get_best_ip6_device (NMManager *manager)
for (iter = devices; iter; iter = g_slist_next (iter)) {
NMDevice *dev = NM_DEVICE (iter->data);
NMDeviceType devtype = nm_device_get_device_type (dev);
NMDeviceState state = nm_device_get_state (dev);
NMActRequest *req;
NMConnection *connection;
NMIP6Config *ip6_config;
@ -168,12 +199,21 @@ get_best_ip6_device (NMManager *manager)
int prio;
const char *method = NULL;
if ( nm_device_get_state (dev) != NM_DEVICE_STATE_ACTIVATED
&& nm_device_get_state (dev) != NM_DEVICE_STATE_SECONDARIES)
if ( state <= NM_DEVICE_STATE_DISCONNECTED
|| state >= NM_DEVICE_STATE_DEACTIVATING)
continue;
if (fully_activated && state < NM_DEVICE_STATE_SECONDARIES)
continue;
ip6_config = nm_device_get_ip6_config (dev);
if (!ip6_config)
if (ip6_config) {
if (!nm_ip6_config_get_gateway (ip6_config) && (devtype != NM_DEVICE_TYPE_MODEM))
continue;
if (nm_ip6_config_get_never_default (ip6_config))
continue;
} else if (fully_activated)
continue;
req = nm_device_get_act_request (dev);
@ -181,20 +221,15 @@ get_best_ip6_device (NMManager *manager)
connection = nm_act_request_get_connection (req);
g_assert (connection);
/* Never set the default route through an IPv4LL-addressed device */
s_ip6 = nm_connection_get_setting_ip6_config (connection);
if (s_ip6)
if (s_ip6) {
method = nm_setting_ip6_config_get_method (s_ip6);
if (!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL))
continue;
if (method && !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL))
continue;
if (!nm_ip6_config_get_gateway (ip6_config) && (devtype != NM_DEVICE_TYPE_MODEM))
continue;
/* 'never-default' devices can't ever be the default */
if (s_ip6 && nm_setting_ip6_config_get_never_default (s_ip6))
continue;
if (nm_setting_ip6_config_get_never_default (s_ip6))
continue;
}
prio = nm_device_get_priority (dev);
if (prio > 0 && prio < best_prio) {
@ -203,6 +238,20 @@ get_best_ip6_device (NMManager *manager)
}
}
if (!best)
return NULL;
if (!fully_activated) {
NMDeviceState state = nm_device_get_state (best);
/* There's only a best activating device if the best device
* among all activating and already-activated devices is an
* activating one.
*/
if (state >= NM_DEVICE_STATE_SECONDARIES)
return NULL;
}
return best;
}
@ -346,9 +395,9 @@ update_system_hostname (NMPolicy *policy, NMDevice *best4, NMDevice *best6)
/* Try automatically determined hostname from the best device's IP config */
if (!best4)
best4 = get_best_ip4_device (priv->manager);
best4 = get_best_ip4_device (priv->manager, TRUE);
if (!best6)
best6 = get_best_ip6_device (priv->manager);
best6 = get_best_ip6_device (priv->manager, TRUE);
if (!best4 && !best6) {
/* No best device; fall back to original hostname or if there wasn't
@ -543,7 +592,7 @@ get_best_ip4_config (NMPolicy *policy,
/* If no VPN connections, we use the best device instead */
if (!ip4_config) {
device = get_best_ip4_device (priv->manager);
device = get_best_ip4_device (priv->manager, TRUE);
if (device) {
ip4_config = nm_device_get_ip4_config (device);
g_assert (ip4_config);
@ -602,7 +651,13 @@ update_ip4_routing (NMPolicy *policy, gboolean force_update)
*/
ip4_config = get_best_ip4_config (policy, FALSE, &ip_iface, &ip_ifindex, &best_ac, &best, &vpn);
if (!ip4_config) {
gboolean changed;
changed = (priv->default_device4 != NULL);
priv->default_device4 = NULL;
if (changed)
g_object_notify (G_OBJECT (policy), NM_POLICY_DEFAULT_IP4_DEVICE);
return;
}
g_assert ((best || vpn) && best_ac);
@ -646,6 +701,7 @@ update_ip4_routing (NMPolicy *policy, gboolean force_update)
connection = nm_active_connection_get_connection (best_ac);
nm_log_info (LOGD_CORE, "Policy set '%s' (%s) as default for IPv4 routing and DNS.",
nm_connection_get_id (connection), ip_iface);
g_object_notify (G_OBJECT (policy), NM_POLICY_DEFAULT_IP4_DEVICE);
}
static NMIP6Config *
@ -714,7 +770,7 @@ get_best_ip6_config (NMPolicy *policy,
/* If no VPN connections, we use the best device instead */
if (!ip6_config) {
device = get_best_ip6_device (priv->manager);
device = get_best_ip6_device (priv->manager, TRUE);
if (device) {
req = nm_device_get_act_request (device);
g_assert (req);
@ -773,7 +829,13 @@ update_ip6_routing (NMPolicy *policy, gboolean force_update)
*/
ip6_config = get_best_ip6_config (policy, FALSE, &ip_iface, &ip_ifindex, &best_ac, &best, &vpn);
if (!ip6_config) {
gboolean changed;
changed = (priv->default_device6 != NULL);
priv->default_device6 = NULL;
if (changed)
g_object_notify (G_OBJECT (policy), NM_POLICY_DEFAULT_IP6_DEVICE);
return;
}
g_assert ((best || vpn) && best_ac);
@ -827,6 +889,7 @@ update_ip6_routing (NMPolicy *policy, gboolean force_update)
connection = nm_active_connection_get_connection (best_ac);
nm_log_info (LOGD_CORE, "Policy set '%s' (%s) as default for IPv6 routing and DNS.",
nm_connection_get_id (connection), ip_iface);
g_object_notify (G_OBJECT (policy), NM_POLICY_DEFAULT_IP6_DEVICE);
}
static void
@ -851,6 +914,30 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update)
g_object_unref (mgr);
}
static void
check_activating_devices (NMPolicy *policy)
{
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy);
GObject *object = G_OBJECT (policy);
NMDevice *best4, *best6 = NULL;
best4 = get_best_ip4_device (priv->manager, FALSE);
best6 = get_best_ip6_device (priv->manager, FALSE);
g_object_freeze_notify (object);
if (best4 != priv->activating_device4) {
priv->activating_device4 = best4;
g_object_notify (object, NM_POLICY_ACTIVATING_IP4_DEVICE);
}
if (best6 != priv->activating_device6) {
priv->activating_device6 = best6;
g_object_notify (object, NM_POLICY_ACTIVATING_IP6_DEVICE);
}
g_object_thaw_notify (object);
}
static void
set_connection_auto_retries (NMConnection *connection, guint retries)
{
@ -1420,6 +1507,8 @@ device_state_changed (NMDevice *device,
default:
break;
}
check_activating_devices (policy);
}
static void
@ -1988,11 +2077,61 @@ nm_policy_new (NMManager *manager, NMSettings *settings)
return policy;
}
NMDevice *
nm_policy_get_default_ip4_device (NMPolicy *policy)
{
return NM_POLICY_GET_PRIVATE (policy)->default_device4;
}
NMDevice *
nm_policy_get_default_ip6_device (NMPolicy *policy)
{
return NM_POLICY_GET_PRIVATE (policy)->default_device6;
}
NMDevice *
nm_policy_get_activating_ip4_device (NMPolicy *policy)
{
return NM_POLICY_GET_PRIVATE (policy)->activating_device4;
}
NMDevice *
nm_policy_get_activating_ip6_device (NMPolicy *policy)
{
return NM_POLICY_GET_PRIVATE (policy)->activating_device6;
}
static void
nm_policy_init (NMPolicy *policy)
{
}
static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
NMPolicy *policy = NM_POLICY (object);
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy);
switch (prop_id) {
case PROP_DEFAULT_IP4_DEVICE:
g_value_set_object (value, priv->default_device4);
break;
case PROP_DEFAULT_IP6_DEVICE:
g_value_set_object (value, priv->default_device6);
break;
case PROP_ACTIVATING_IP4_DEVICE:
g_value_set_object (value, priv->activating_device4);
break;
case PROP_ACTIVATING_IP6_DEVICE:
g_value_set_object (value, priv->activating_device6);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
dispose (GObject *object)
{
@ -2067,5 +2206,35 @@ nm_policy_class_init (NMPolicyClass *policy_class)
g_type_class_add_private (policy_class, sizeof (NMPolicyPrivate));
object_class->get_property = get_property;
object_class->dispose = dispose;
g_object_class_install_property
(object_class, PROP_DEFAULT_IP4_DEVICE,
g_param_spec_object (NM_POLICY_DEFAULT_IP4_DEVICE,
"Default IP4 device",
"Default IP4 device",
NM_TYPE_DEVICE,
G_PARAM_READABLE));
g_object_class_install_property
(object_class, PROP_DEFAULT_IP6_DEVICE,
g_param_spec_object (NM_POLICY_DEFAULT_IP6_DEVICE,
"Default IP6 device",
"Default IP6 device",
NM_TYPE_DEVICE,
G_PARAM_READABLE));
g_object_class_install_property
(object_class, PROP_ACTIVATING_IP4_DEVICE,
g_param_spec_object (NM_POLICY_ACTIVATING_IP4_DEVICE,
"Activating default IP4 device",
"Activating default IP4 device",
NM_TYPE_DEVICE,
G_PARAM_READABLE));
g_object_class_install_property
(object_class, PROP_ACTIVATING_IP6_DEVICE,
g_param_spec_object (NM_POLICY_ACTIVATING_IP6_DEVICE,
"Activating default IP6 device",
"Activating default IP6 device",
NM_TYPE_DEVICE,
G_PARAM_READABLE));
}

View file

@ -32,6 +32,11 @@
#define NM_IS_POLICY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_POLICY))
#define NM_POLICY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_POLICY, NMPolicyClass))
#define NM_POLICY_DEFAULT_IP4_DEVICE "default-ip4-device"
#define NM_POLICY_DEFAULT_IP6_DEVICE "default-ip6-device"
#define NM_POLICY_ACTIVATING_IP4_DEVICE "activating-ip4-device"
#define NM_POLICY_ACTIVATING_IP6_DEVICE "activating-ip6-device"
typedef struct {
GObject parent;
} NMPolicy;
@ -45,4 +50,9 @@ GType nm_policy_get_type (void);
NMPolicy *nm_policy_new (NMManager *manager, NMSettings *settings);
NMDevice *nm_policy_get_default_ip4_device (NMPolicy *policy);
NMDevice *nm_policy_get_default_ip6_device (NMPolicy *policy);
NMDevice *nm_policy_get_activating_ip4_device (NMPolicy *policy);
NMDevice *nm_policy_get_activating_ip6_device (NMPolicy *policy);
#endif /* NM_POLICY_H */