diff options
author | Thomas Haller <thaller@redhat.com> | 2016-12-26 11:12:39 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2017-01-04 14:18:01 +0100 |
commit | f703f4bb659ddea63c437929439c738d053244b6 (patch) | |
tree | dcf89e10ee1527efb7e3e51e7eb6f43f35a75ab7 | |
parent | bd09decf160c4a5a1b6239fbb79f189202e44fff (diff) | |
download | NetworkManager-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.c | 149 | ||||
-rw-r--r-- | src/devices/nm-device.h | 17 | ||||
-rw-r--r-- | src/nm-manager.c | 36 |
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. */ |