core: fuzzier matching of generated connections to persistent ones

When generating a connection, if the device has no non-link-local IPv6
address, then it's unclear whether (a) the connection was link-local
originally, or (b) the connection was 'auto' but IPv6 failed or timed
out.

In this case, if there is a persistent connection that is 'auto' but
the generated connection is 'link-local', the persistent connection
should be used.

Add a more-testable framework for doing the connection matching to
handle this.
This commit is contained in:
Dan Williams
2013-11-15 13:09:12 -06:00
parent 75d694db9b
commit befa9083e8
5 changed files with 124 additions and 24 deletions

View File

@@ -659,3 +659,93 @@ nm_utils_read_resolv_conf_nameservers (const char *rc_contents)
return nameservers;
}
static NMConnection *
check_possible_match (NMConnection *orig,
NMConnection *candidate,
GHashTable *settings)
{
GHashTable *props;
const char *orig_ip6_method, *candidate_ip6_method;
NMSettingIP6Config *candidate_ip6;
g_return_val_if_fail (settings != NULL, NULL);
props = g_hash_table_lookup (settings, NM_SETTING_IP6_CONFIG_SETTING_NAME);
if ( !props
|| (g_hash_table_size (props) != 1)
|| !g_hash_table_lookup (props, NM_SETTING_IP6_CONFIG_METHOD)) {
/* For now 'method' is the only difference we handle here */
return NULL;
}
/* If the original connection is 'link-local' and the candidate is both 'auto'
* and may-fail=TRUE, then the candidate is OK to use. may-fail is included
* in the decision because if the candidate is 'auto' but may-fail=FALSE, then
* the connection could not possibly have been previously activated on the
* device if the device has no non-link-local IPv6 address.
*/
orig_ip6_method = nm_utils_get_ip_config_method (orig, NM_TYPE_SETTING_IP6_CONFIG);
candidate_ip6_method = nm_utils_get_ip_config_method (candidate, NM_TYPE_SETTING_IP6_CONFIG);
candidate_ip6 = nm_connection_get_setting_ip6_config (candidate);
if ( strcmp (orig_ip6_method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0
&& strcmp (candidate_ip6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0
&& (!candidate_ip6 || nm_setting_ip6_config_get_may_fail (candidate_ip6))) {
return candidate;
}
return NULL;
}
/**
* nm_utils_match_connection:
* @connections: a (optionally pre-sorted) list of connections from which to
* find a matching connection to @original based on "inferrable" properties
* @original: the #NMConnection to find a match for from @connections
* @match_filter_func: a function to check whether each connection from @connections
* should be considered for matching. This function should return %TRUE if the
* connection should be considered, %FALSE if the connection should be ignored
* @match_compat_data: data pointer passed to @match_filter_func
*
* Checks each connection from @connections until a matching connection is found
* considering only setting properties marked with %NM_SETTING_PARAM_INFERRABLE
* and checking a few other characteristics like IPv6 method. If the caller
* desires some priority order of the connections, @connections should be
* sorted before calling this function.
*
* Returns: the best #NMConnection matching @original, or %NULL if no connection
* matches well enough.
*/
NMConnection *
nm_utils_match_connection (GSList *connections,
NMConnection *original,
NMUtilsMatchFilterFunc match_filter_func,
gpointer match_filter_data)
{
NMConnection *best_match = NULL;
GSList *iter;
for (iter = connections; iter; iter = iter->next) {
NMConnection *candidate = NM_CONNECTION (iter->data);
GHashTable *diffs = NULL;
if (match_filter_func) {
if (!match_filter_func (candidate, match_filter_data))
continue;
}
if (!nm_connection_diff (original, candidate, NM_SETTING_COMPARE_FLAG_INFERRABLE, &diffs)) {
if (!best_match)
best_match = check_possible_match (original, candidate, diffs);
g_hash_table_unref (diffs);
continue;
}
/* Exact match */
return candidate;
}
/* Best match (if any) */
return best_match;
}