core: add nm_ip6_config_find_first_address() function and refactor lookup of code

Instead have one particular nm_ip6_config_get_address_first_nontentative() function,
make it more extendable. Now, we pass a match-type argument, which can control which
element to search.

This patch has no change in behavior, but it already makes clear, that
nm_ip6_config_get_address_first_nontentative() was buggy, because it would
also return addresses that failed DAD.
This commit is contained in:
Thomas Haller 2018-03-09 16:08:52 +01:00
parent fe02bb4f2a
commit 945339cba5
4 changed files with 90 additions and 22 deletions

View file

@ -7207,8 +7207,12 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
s_ip6 = nm_connection_get_setting_ip6_config (connection);
g_assert (s_ip6);
if (priv->ext_ip6_config_captured)
ll_addr = nm_ip6_config_get_address_first_nontentative (priv->ext_ip6_config_captured, TRUE);
if (priv->ext_ip6_config_captured) {
ll_addr = nm_ip6_config_find_first_address (priv->ext_ip6_config_captured,
NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL
| NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL
| NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED);
}
if (!ll_addr) {
_LOGW (LOGD_DHCP6, "can't start DHCPv6: no link-local address");
@ -7425,7 +7429,10 @@ linklocal6_complete (NMDevice *self)
nm_assert (priv->linklocal6_timeout_id);
nm_assert (priv->ext_ip6_config_captured);
nm_assert (nm_ip6_config_get_address_first_nontentative (priv->ext_ip6_config_captured, TRUE));
nm_assert (nm_ip6_config_find_first_address (priv->ext_ip6_config_captured,
NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL
| NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL
| NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED));
nm_clear_g_source (&priv->linklocal6_timeout_id);
@ -7545,7 +7552,10 @@ linklocal6_start (NMDevice *self)
nm_clear_g_source (&priv->linklocal6_timeout_id);
if ( priv->ext_ip6_config_captured
&& nm_ip6_config_get_address_first_nontentative (priv->ext_ip6_config_captured, TRUE))
&& nm_ip6_config_find_first_address (priv->ext_ip6_config_captured,
NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL
| NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL
| NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED))
return TRUE;
connection = nm_device_get_applied_connection (self);
@ -7944,7 +7954,10 @@ ndisc_ra_timeout (NMNDisc *ndisc, NMDevice *self)
* config, consider that sufficient for IPv6 success.
*/
if ( priv->ip6_config
&& nm_ip6_config_get_address_first_nontentative (priv->ip6_config, FALSE))
&& nm_ip6_config_find_first_address (priv->ip6_config,
NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL
| NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL
| NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED))
nm_device_activate_schedule_ip6_config_result (self);
else
nm_device_activate_schedule_ip6_config_timeout (self);
@ -11538,7 +11551,10 @@ update_ip_config (NMDevice *self, int addr_family, gboolean initial)
if ( addr_family == AF_INET6
&& priv->linklocal6_timeout_id
&& priv->ext_ip6_config_captured
&& nm_ip6_config_get_address_first_nontentative (priv->ext_ip6_config_captured, TRUE)) {
&& nm_ip6_config_find_first_address (priv->ext_ip6_config_captured,
NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL
| NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL
| NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED)) {
/* linklocal6 is ready now, do the state transition... we are also
* invoked as g_idle_add, so no problems with reentrance doing it now.
*/
@ -11671,16 +11687,15 @@ queued_ip6_config_change (gpointer user_data)
/* Check if DAD is still pending */
if ( priv->ip6_state == IP_CONF
&& priv->dad6_ip6_config
&& priv->ext_ip6_config_captured) {
if (!nm_ip6_config_has_any_dad_pending (priv->ext_ip6_config_captured,
priv->dad6_ip6_config)) {
_LOGD (LOGD_DEVICE | LOGD_IP6, "IPv6 DAD terminated");
g_clear_object (&priv->dad6_ip6_config);
_set_ip_state (self, AF_INET6, IP_DONE);
check_ip_state (self, FALSE, TRUE);
if (priv->rt6_temporary_not_available)
nm_device_activate_schedule_ip6_config_result (self);
}
&& priv->ext_ip6_config_captured
&& !nm_ip6_config_has_any_dad_pending (priv->ext_ip6_config_captured,
priv->dad6_ip6_config)) {
_LOGD (LOGD_DEVICE | LOGD_IP6, "IPv6 DAD terminated");
g_clear_object (&priv->dad6_ip6_config);
_set_ip_state (self, AF_INET6, IP_DONE);
check_ip_state (self, FALSE, TRUE);
if (priv->rt6_temporary_not_available)
nm_device_activate_schedule_ip6_config_result (self);
}
set_unmanaged_external_down (self, TRUE);

View file

@ -1691,19 +1691,43 @@ nm_ip6_config_lookup_address (const NMIP6Config *self,
}
const NMPlatformIP6Address *
nm_ip6_config_get_address_first_nontentative (const NMIP6Config *self, gboolean linklocal)
nm_ip6_config_find_first_address (const NMIP6Config *self,
NMPlatformMatchFlags match_flag)
{
const NMPlatformIP6Address *addr;
NMDedupMultiIter iter;
g_return_val_if_fail (NM_IS_IP6_CONFIG (self), NULL);
linklocal = !!linklocal;
nm_assert (!NM_FLAGS_ANY (match_flag, ~( NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY
| NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY)));
nm_assert (NM_FLAGS_ANY (match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY));
nm_assert (NM_FLAGS_ANY (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY));
nm_ip_config_iter_ip6_address_for_each (&iter, self, &addr) {
if ( ((!!IN6_IS_ADDR_LINKLOCAL (&addr->address)) == linklocal)
&& !(addr->n_ifa_flags & IFA_F_TENTATIVE))
return addr;
if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) {
if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL))
continue;
} else {
if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL))
continue;
}
if (NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_DADFAILED)) {
if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED))
continue;
} else if ( NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_TENTATIVE)
&& !NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_OPTIMISTIC)) {
if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE))
continue;
} else {
if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL))
continue;
}
return addr;
}
return NULL;

View file

@ -149,7 +149,8 @@ void _nmtst_ip6_config_del_address (NMIP6Config *self, guint i);
guint nm_ip6_config_get_num_addresses (const NMIP6Config *self);
const NMPlatformIP6Address *nm_ip6_config_get_first_address (const NMIP6Config *self);
const NMPlatformIP6Address *_nmtst_ip6_config_get_address (const NMIP6Config *self, guint i);
const NMPlatformIP6Address *nm_ip6_config_get_address_first_nontentative (const NMIP6Config *self, gboolean linklocal);
const NMPlatformIP6Address *nm_ip6_config_find_first_address (const NMIP6Config *self,
NMPlatformMatchFlags match_flag);
gboolean nm_ip6_config_address_exists (const NMIP6Config *self, const NMPlatformIP6Address *address);
const NMPlatformIP6Address *nm_ip6_config_lookup_address (const NMIP6Config *self,
const struct in6_addr *addr);

View file

@ -171,6 +171,34 @@ typedef enum { /*< skip >*/
NM_PLATFORM_ERROR_CANT_SET_MTU,
} NMPlatformError;
typedef enum {
/* match-flags are strictly inclusive. That means,
* by default nothing is matched, but if you enable a particular
* flag, a candidate that matches passes the check.
*
* In other words: adding more flags can only extend the result
* set of matching objects.
*
* Also, the flags form partitions. Like, an address can be either of
* ADDRTYPE_NORMAL or ADDRTYPE_LINKLOCAL, but never both. Same for
* the ADDRSTATE match types.
*/
NM_PLATFORM_MATCH_WITH_NONE = 0,
NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL = (1LL << 0),
NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL = (1LL << 1),
NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY = NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL
| NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL,
NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL = (1LL << 2),
NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE = (1LL << 3),
NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED = (1LL << 4),
NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY = NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL
| NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE
| NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED,
} NMPlatformMatchFlags;
#define NM_PLATFORM_LINK_OTHER_NETNS (-1)
#define __NMPlatformObject_COMMON \