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:
@@ -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;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user