summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2016-12-26 11:12:39 +0100
committerThomas Haller <thaller@redhat.com>2017-01-04 14:18:01 +0100
commitf703f4bb659ddea63c437929439c738d053244b6 (patch)
treedcf89e10ee1527efb7e3e51e7eb6f43f35a75ab7
parentbd09decf160c4a5a1b6239fbb79f189202e44fff (diff)
downloadNetworkManager-f703f4bb659ddea63c437929439c738d053244b6.tar.gz
device: track parent device in NMDevice
Multiple subclasses have a parent/link interface (NMDeviceIPTunnel, NMDeviceVlan). Tracking the parent interface properly is midly complicated to get right. So, instead of repeating it in each subclass, track it in the parent device.
-rw-r--r--src/devices/nm-device.c149
-rw-r--r--src/devices/nm-device.h17
-rw-r--r--src/nm-manager.c36
3 files changed, 202 insertions, 0 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 6931e3b608..e8bfdea74b 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -123,6 +123,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDevice,
PROP_PHYSICAL_PORT_ID,
PROP_IS_MASTER,
PROP_MASTER,
+ PROP_PARENT,
PROP_HW_ADDRESS,
PROP_PERM_HW_ADDRESS,
PROP_HAS_PENDING_ACTION,
@@ -225,10 +226,14 @@ typedef struct _NMDevicePrivate {
GSList *pending_actions;
GSList *dad6_failed_addrs;
+ NMDevice *parent_device;
+
char * udi;
char * iface; /* may change, could be renamed by user */
int ifindex;
+ int parent_ifindex;
+
union {
const guint8 hw_addr_len; /* read-only */
guint8 hw_addr_len_;
@@ -874,6 +879,132 @@ _ip_iface_update (NMDevice *self, const char *ip_iface)
/*****************************************************************************/
+int
+nm_device_parent_get_ifindex (NMDevice *self)
+{
+ NMDevicePrivate *priv;
+
+ g_return_val_if_fail (NM_IS_DEVICE (self), 0);
+
+ priv = NM_DEVICE_GET_PRIVATE (self);
+ return priv->parent_ifindex;
+}
+
+NMDevice *
+nm_device_parent_get_device (NMDevice *self)
+{
+ NMDevicePrivate *priv;
+
+ g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
+
+ priv = NM_DEVICE_GET_PRIVATE (self);
+ return priv->parent_device;
+}
+
+static void
+parent_changed_notify (NMDevice *self,
+ int old_ifindex,
+ NMDevice *old_parent,
+ int new_ifindex,
+ NMDevice *new_parent)
+{
+ /* empty handler to allow subclasses to always chain up the virtual function. */
+}
+
+static gboolean
+_parent_set_ifindex (NMDevice *self,
+ int parent_ifindex,
+ gboolean force_check)
+{
+ NMDevicePrivate *priv;
+ NMDevice *parent_device;
+ gboolean changed = FALSE;
+ int old_ifindex;
+ NMDevice *old_device;
+
+ g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
+
+ priv = NM_DEVICE_GET_PRIVATE (self);
+
+ if (parent_ifindex <= 0)
+ parent_ifindex = 0;
+
+ old_ifindex = priv->parent_ifindex;
+ old_device = priv->parent_device;
+
+ if (priv->parent_ifindex == parent_ifindex) {
+ if (parent_ifindex > 0) {
+ if ( !force_check
+ && priv->parent_device
+ && nm_device_get_ifindex (priv->parent_device) == parent_ifindex)
+ return FALSE;
+ } else {
+ if (!priv->parent_device)
+ return FALSE;
+ }
+ } else {
+ priv->parent_ifindex = parent_ifindex;
+ changed = TRUE;
+ }
+
+ if (parent_ifindex > 0) {
+ parent_device = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex);
+ if (parent_device == self)
+ parent_device = NULL;
+ } else
+ parent_device = NULL;
+
+ if (parent_device != priv->parent_device) {
+ priv->parent_device = parent_device;
+ changed = TRUE;
+ }
+
+ if (changed) {
+ if (priv->parent_ifindex <= 0)
+ _LOGD (LOGD_DEVICE, "parent: clear");
+ else if (!priv->parent_device)
+ _LOGD (LOGD_DEVICE, "parent: ifindex %d, no device", priv->parent_ifindex);
+ else {
+ _LOGD (LOGD_DEVICE, "parent: ifindex %d, device %p, %s", priv->parent_ifindex,
+ priv->parent_device, nm_device_get_iface (priv->parent_device));
+ }
+
+ NM_DEVICE_GET_CLASS (self)->parent_changed_notify (self, old_ifindex, old_device, priv->parent_ifindex, priv->parent_device);
+
+ _notify (self, PROP_PARENT);
+ }
+ return changed;
+}
+
+void
+nm_device_parent_set_ifindex (NMDevice *self,
+ int parent_ifindex)
+{
+ _parent_set_ifindex (self, parent_ifindex, FALSE);
+}
+
+gboolean
+nm_device_parent_notify_changed (NMDevice *self,
+ NMDevice *change_candidate,
+ gboolean device_removed)
+{
+ NMDevicePrivate *priv;
+
+ nm_assert (NM_IS_DEVICE (self));
+ nm_assert (NM_IS_DEVICE (change_candidate));
+
+ priv = NM_DEVICE_GET_PRIVATE (self);
+
+ if (priv->parent_ifindex > 0) {
+ if ( priv->parent_device == change_candidate
+ || priv->parent_ifindex == nm_device_get_ifindex (change_candidate))
+ return _parent_set_ifindex (self, priv->parent_ifindex, device_removed);
+ }
+ return FALSE;
+}
+
+/*****************************************************************************/
+
static void
_stats_update_counters (NMDevice *self,
guint64 tx_bytes,
@@ -2622,6 +2753,8 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error)
NM_DEVICE_GET_CLASS (self)->unrealize_notify (self);
+ _parent_set_ifindex (self, 0, FALSE);
+
if (priv->ifindex > 0) {
priv->ifindex = 0;
_notify (self, PROP_IFINDEX);
@@ -12722,6 +12855,8 @@ dispose (GObject *object)
_LOGD (LOGD_DEVICE, "disposing");
+ _parent_set_ifindex (self, 0, FALSE);
+
platform = NM_PLATFORM_GET;
g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (device_ipx_changed), self);
g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (link_changed_cb), self);
@@ -12758,6 +12893,11 @@ dispose (GObject *object)
link_disconnect_action_cancel (self);
+ if (priv->ifindex > 0) {
+ priv->ifindex = 0;
+ _notify (self, PROP_IFINDEX);
+ }
+
if (priv->settings) {
g_signal_handlers_disconnect_by_func (priv->settings, cp_connection_added, self);
g_signal_handlers_disconnect_by_func (priv->settings, cp_connection_updated, self);
@@ -13036,6 +13176,9 @@ get_property (GObject *object, guint prop_id,
case PROP_MASTER:
g_value_set_object (value, nm_device_get_master (self));
break;
+ case PROP_PARENT:
+ nm_utils_g_value_set_object_path (value, priv->parent_device);
+ break;
case PROP_HW_ADDRESS:
g_value_set_string (value, priv->hw_addr);
break;
@@ -13140,6 +13283,7 @@ nm_device_class_init (NMDeviceClass *klass)
klass->get_ip_iface_identifier = get_ip_iface_identifier;
klass->unmanaged_on_quit = unmanaged_on_quit;
klass->deactivate_reset_hw_addr = deactivate_reset_hw_addr;
+ klass->parent_changed_notify = parent_changed_notify;
obj_properties[PROP_UDI] =
g_param_spec_string (NM_DEVICE_UDI, "", "",
@@ -13294,6 +13438,11 @@ nm_device_class_init (NMDeviceClass *klass)
NM_TYPE_DEVICE,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
+ obj_properties[PROP_PARENT] =
+ g_param_spec_string (NM_DEVICE_PARENT, "", "",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
obj_properties[PROP_HW_ADDRESS] =
g_param_spec_string (NM_DEVICE_HW_ADDRESS, "", "",
NULL,
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index dfd7b36b56..6afe83dc6a 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -66,6 +66,9 @@
#define NM_DEVICE_LLDP_NEIGHBORS "lldp-neighbors"
#define NM_DEVICE_REAL "real"
+/* "parent" will later be exposed by some subclasses */
+#define NM_DEVICE_PARENT "parent"
+
/* the "slaves" property is internal in the parent class, but exposed
* by the derived classes NMDeviceBond, NMDeviceBridge and NMDeviceTeam.
* It is thus important that the property name matches. */
@@ -316,6 +319,12 @@ typedef struct {
void (* notify_new_device_added) (NMDevice *self, NMDevice *new_device);
+ void (* parent_changed_notify) (NMDevice *self,
+ int old_ifindex,
+ NMDevice *old_parent,
+ int new_ifindex,
+ NMDevice *new_parent);
+
/**
* component_added:
* @self: the #NMDevice
@@ -390,6 +399,14 @@ void nm_device_replace_vpn6_config (NMDevice *dev,
void nm_device_capture_initial_config (NMDevice *dev);
+int nm_device_parent_get_ifindex (NMDevice *dev);
+NMDevice *nm_device_parent_get_device (NMDevice *dev);
+void nm_device_parent_set_ifindex (NMDevice *self,
+ int parent_ifindex);
+gboolean nm_device_parent_notify_changed (NMDevice *self,
+ NMDevice *change_candidate,
+ gboolean device_removed);
+
/* Master */
gboolean nm_device_is_master (NMDevice *dev);
diff --git a/src/nm-manager.c b/src/nm-manager.c
index f35c485d97..0441905bc9 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -950,6 +950,26 @@ settings_startup_complete_changed (NMSettings *settings,
}
static void
+_parent_notify_changed (NMManager *self,
+ NMDevice *device,
+ gboolean device_removed)
+{
+ GSList *iter;
+
+ nm_assert (NM_IS_DEVICE (device));
+ nm_assert (NM_IS_MANAGER (self));
+
+ for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; ) {
+ if (nm_device_parent_notify_changed (iter->data, device, device_removed)) {
+ /* in the unlikely event that this changes anything, we start iterating
+ * again, to be sure that the device list is up-to-date. */
+ iter = NM_MANAGER_GET_PRIVATE (self)->devices;
+ } else
+ iter = iter->next;
+ }
+}
+
+static void
remove_device (NMManager *self,
NMDevice *device,
gboolean quitting,
@@ -985,6 +1005,8 @@ remove_device (NMManager *self,
nm_settings_device_removed (priv->settings, device, quitting);
priv->devices = g_slist_remove (priv->devices, device);
+ _parent_notify_changed (self, device, TRUE);
+
if (nm_device_is_real (device)) {
gboolean unconfigure_ip_config = !quitting || unmanage;
@@ -1861,6 +1883,14 @@ recheck_assume_connection_cb (NMDevice *device, gpointer user_data)
}
static void
+device_ifindex_changed (NMDevice *device,
+ GParamSpec *pspec,
+ NMManager *self)
+{
+ _parent_notify_changed (self, device, FALSE);
+}
+
+static void
device_ip_iface_changed (NMDevice *device,
GParamSpec *pspec,
NMManager *self)
@@ -1998,6 +2028,10 @@ add_device (NMManager *self, NMDevice *device, GError **error)
G_CALLBACK (device_ip_iface_changed),
self);
+ g_signal_connect (device, "notify::" NM_DEVICE_IFINDEX,
+ G_CALLBACK (device_ifindex_changed),
+ self);
+
g_signal_connect (device, "notify::" NM_DEVICE_IFACE,
G_CALLBACK (device_iface_changed),
self);
@@ -2047,6 +2081,8 @@ add_device (NMManager *self, NMDevice *device, GError **error)
nm_device_notify_new_device_added (d, device);
}
+ _parent_notify_changed (self, device, FALSE);
+
/* Virtual connections may refer to the new device as
* parent device, retry to activate them.
*/