device: refactor nm_device_set_ip_ifindex() and set_ip_iface()

- don't even bother to look into the platform cache, but use
  if_indextoname() / if_nametoindex(). In most cases, we obtained
  the ifindex/ifname not from the platform cache in the first
  place. Hence, there is a race, where the interface might not
  exist.
  However, try to process events of the platform cache, hoping
  that the cache contains an interface for the given ifindex/ifname.

- let set_ip_ifindex() and set_ip_iface() both return a boolean
  value to indicate whether a ip-interface is set or not. That is,
  whether we have a positive ip_ifindex. That seems more interesting
  information, then to return whether anything changed.

- as before, set_ip_ifindex() can only clear an ifindex/ifname,
  or error out without doing anything. That is different from
  set_ip_iface(), which will also set an ifname if no ifindex
  can be resolved. That is curreently ugly, because then ip-ifindex
  and ip-iface don't agree. That shall be improved in the future
  by:
  - trying to set an interface that cannot be resolved shall
    lead to a disconnect in any case.
  - we shall make less use of the ip-iface and rely more on the
    ifindex.
This commit is contained in:
Thomas Haller
2018-01-10 16:33:13 +01:00
parent 79980536b9
commit ab4578302d
2 changed files with 66 additions and 90 deletions

View File

@@ -1282,126 +1282,102 @@ nm_device_get_ip_ifindex (const NMDevice *self)
return priv->ip_iface ? priv->ip_ifindex : priv->ifindex; return priv->ip_iface ? priv->ip_ifindex : priv->ifindex;
} }
gboolean static void
nm_device_set_ip_ifindex (NMDevice *self, int ifindex) _set_ip_ifindex (NMDevice *self,
int ifindex,
const char *ifname)
{ {
NMDevicePrivate *priv; NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMPlatform *platform; NMPlatform *platform;
const char *name = NULL; gboolean eq_name;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); /* we can set only the ifname without ifindex (to indicate that this
* is an ip-interface, but lookup for the ifindex failed.
* But we cannot just set ifindex > 0 without an ifname. */
nm_assert (ifindex <= 0 || ifname);
priv = NM_DEVICE_GET_PRIVATE (self); /* normalize ifindex */
platform = nm_device_get_platform (self); if (ifindex < 0)
ifindex = 0;
if (ifindex > 0) { eq_name = nm_streq0 (priv->ip_iface, ifname);
const NMPlatformLink *plink;
plink = nm_platform_link_get (platform, ifindex); if ( eq_name
if (!plink) { && priv->ip_ifindex == ifindex)
nm_platform_process_events (platform); return;
plink = nm_platform_link_get (NM_PLATFORM_GET, ifindex);
}
if (!plink) {
_LOGW (LOGD_DEVICE, "ip-ifindex: ifindex %d not found", ifindex);
return FALSE;
}
name = plink->name;
} else
g_return_val_if_fail (ifindex == 0, FALSE);
if (priv->ip_ifindex == ifindex) _LOGD (LOGD_DEVICE, "ip-ifindex: update ip-interface to %s%s%s, ifindex %d",
return TRUE; NM_PRINT_FMT_QUOTE_STRING (ifname),
ifindex);
_LOGD (LOGD_DEVICE, "ip-ifindex: update ifindex to %d", ifindex);
priv->ip_ifindex = ifindex; priv->ip_ifindex = ifindex;
if (!nm_streq0 (priv->ip_iface, name)) { if (!eq_name) {
_LOGD (LOGD_DEVICE, "ip-ifindex: update ip-iface to %s%s%s", g_free (priv->ip_iface);
NM_PRINT_FMT_QUOTED (name, "\"", name, "\"", "NULL")); priv->ip_iface = g_strdup (ifname);
priv->ip_iface = g_strdup (name);
_notify (self, PROP_IP_IFACE); _notify (self, PROP_IP_IFACE);
} }
if (priv->ip_ifindex > 0) { if (priv->ip_ifindex > 0) {
if (nm_platform_check_kernel_support (nm_device_get_platform (self), platform = nm_device_get_platform (self);
NM_PLATFORM_KERNEL_SUPPORT_USER_IPV6LL))
nm_platform_link_set_user_ipv6ll_enabled (nm_device_get_platform (self), priv->ip_ifindex, TRUE);
if (!nm_platform_link_is_up (nm_device_get_platform (self), priv->ip_ifindex)) nm_platform_process_events_ensure_link (platform,
nm_platform_link_set_up (nm_device_get_platform (self), priv->ip_ifindex, NULL); priv->ip_ifindex,
priv->ip_iface);
if (nm_platform_check_kernel_support (platform,
NM_PLATFORM_KERNEL_SUPPORT_USER_IPV6LL))
nm_platform_link_set_user_ipv6ll_enabled (platform, priv->ip_ifindex, TRUE);
if (!nm_platform_link_is_up (platform, priv->ip_ifindex))
nm_platform_link_set_up (platform, priv->ip_ifindex, NULL);
} }
/* We don't care about any saved values from the old iface */ /* We don't care about any saved values from the old iface */
g_hash_table_remove_all (priv->ip6_saved_properties); g_hash_table_remove_all (priv->ip6_saved_properties);
}
return TRUE; gboolean
nm_device_set_ip_ifindex (NMDevice *self, int ifindex)
{
char ifname_buf[IFNAMSIZ];
const char *ifname = NULL;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
if (ifindex > 0) {
ifname = nm_platform_if_indextoname (nm_device_get_platform (self), ifindex, ifname_buf);
if (!ifname) {
_LOGW (LOGD_DEVICE, "ip-ifindex: ifindex %d not found", ifindex);
return FALSE;
}
}
_set_ip_ifindex (self, ifindex, ifname);
return ifindex > 0;
} }
/** /**
* nm_device_set_ip_iface: * nm_device_set_ip_iface:
* @self: the #NMDevice * @self: the #NMDevice
* @iface: the new IP interface name * @ifname: the new IP interface name
* *
* Updates the IP interface name and possibly the ifindex. * Updates the IP interface name and possibly the ifindex.
* *
* Returns: %TRUE if the anything (name or ifindex) changed, %FALSE if nothing * Returns: %TRUE if an interface with name @ifname exists,
* changed. * and %FALSE, if @ifname is %NULL or no such interface exists.
*/ */
gboolean gboolean
nm_device_set_ip_iface (NMDevice *self, const char *iface) nm_device_set_ip_iface (NMDevice *self, const char *ifname)
{ {
NMDevicePrivate *priv; int ifindex = 0;
int ifindex;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
priv = NM_DEVICE_GET_PRIVATE (self); if (ifname)
if (nm_streq0 (iface, priv->ip_iface)) { ifindex = nm_platform_if_nametoindex (nm_device_get_platform (self), ifname);
if (!iface)
return FALSE;
ifindex = nm_platform_if_nametoindex (nm_device_get_platform (self), iface);
if ( ifindex <= 0
|| priv->ip_ifindex == ifindex)
return FALSE;
priv->ip_ifindex = ifindex; _set_ip_ifindex (self, ifindex, ifname);
_LOGD (LOGD_DEVICE, "ip-ifname: update ifindex for ifname '%s': %d", iface, priv->ip_ifindex); return ifindex > 0;
} else {
g_free (priv->ip_iface);
priv->ip_iface = g_strdup (iface);
if (iface) {
/* The @iface name is not in sync with the platform cache.
* So, there is no point asking the platform cache to resolve
* the ifindex. Instead, we can only hope that the interface
* with this name still exists and we resolve the ifindex
* anew.
*/
priv->ip_ifindex = nm_platform_if_nametoindex (nm_device_get_platform (self), iface);
if (priv->ip_ifindex > 0)
_LOGD (LOGD_DEVICE, "ip-ifname: set ifname '%s', ifindex %d", iface, priv->ip_ifindex);
else
_LOGW (LOGD_DEVICE, "ip-ifname: set ifname '%s', unknown ifindex", iface);
} else {
priv->ip_ifindex = 0;
_LOGD (LOGD_DEVICE, "ip-ifname: clear ifname");
}
}
if (priv->ip_ifindex > 0) {
if (nm_platform_check_kernel_support (nm_device_get_platform (self),
NM_PLATFORM_KERNEL_SUPPORT_USER_IPV6LL))
nm_platform_link_set_user_ipv6ll_enabled (nm_device_get_platform (self), priv->ip_ifindex, TRUE);
if (!nm_platform_link_is_up (nm_device_get_platform (self), priv->ip_ifindex))
nm_platform_link_set_up (nm_device_get_platform (self), priv->ip_ifindex, NULL);
}
/* We don't care about any saved values from the old iface */
g_hash_table_remove_all (priv->ip6_saved_properties);
_notify (self, PROP_IP_IFACE);
return TRUE;
} }
static gboolean static gboolean
@@ -12941,7 +12917,7 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type)
* those are identified by ip_iface, not by iface (which might be a tty * those are identified by ip_iface, not by iface (which might be a tty
* or ATM device). * or ATM device).
*/ */
nm_device_set_ip_iface (self, NULL); _set_ip_ifindex (self, 0, NULL);
} }
/* /*

View File

@@ -263,17 +263,17 @@ static void
data_port_changed_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) data_port_changed_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data)
{ {
NMDevice *self = NM_DEVICE (user_data); NMDevice *self = NM_DEVICE (user_data);
gboolean changed; gboolean has_ifindex;
/* We set the IP iface in the device as soon as we know it, so that we /* We set the IP iface in the device as soon as we know it, so that we
* properly ifup it if needed */ * properly ifup it if needed */
changed = nm_device_set_ip_iface (self, nm_modem_get_data_port (modem)); has_ifindex = nm_device_set_ip_iface (self, nm_modem_get_data_port (modem));
/* Disable IPv6 immediately on the interface since NM handles IPv6 /* Disable IPv6 immediately on the interface since NM handles IPv6
* internally, and leaving it enabled could allow the kernel's IPv6 * internally, and leaving it enabled could allow the kernel's IPv6
* RA handling code to run before NM is ready. * RA handling code to run before NM is ready.
*/ */
if (changed) if (has_ifindex)
nm_device_ipv6_sysctl_set (self, "disable_ipv6", "1"); nm_device_ipv6_sysctl_set (self, "disable_ipv6", "1");
} }