return allow;
}
+static int
+route_compare (NMIPRoute *route1, NMIPRoute *route2, gint64 default_metric)
+{
+ gint64 r, metric1, metric2;
+
+ r = g_strcmp0 (nm_ip_route_get_dest (route1), nm_ip_route_get_dest (route2));
+ if (r)
+ return r;
+
+ r = nm_ip_route_get_prefix (route1) - nm_ip_route_get_prefix (route2);
+ if (r)
+ return r > 0 ? 1 : -1;
+
+ r = g_strcmp0 (nm_ip_route_get_next_hop (route1), nm_ip_route_get_next_hop (route2));
+ if (r)
+ return r;
+
+ metric1 = nm_ip_route_get_metric (route1) == -1 ? default_metric : nm_ip_route_get_metric (route1);
+ metric2 = nm_ip_route_get_metric (route2) == -1 ? default_metric : nm_ip_route_get_metric (route2);
+
+ r = metric1 - metric2;
+ if (r)
+ return r > 0 ? 1 : -1;
+
+ r = nm_ip_route_get_family (route1) - nm_ip_route_get_family (route2);
+ if (r)
+ return r > 0 ? 1 : -1;
+
+ return 0;
+}
+
+static int
+route_ptr_compare (const void *a, const void *b)
+{
+ return route_compare (*(NMIPRoute **) a, *(NMIPRoute **) b, -1);
+}
+
+static gboolean
+check_ip_routes (NMConnection *orig,
+ NMConnection *candidate,
+ GHashTable *settings,
+ gint64 default_metric,
+ gboolean v4)
+{
+ gs_free NMIPRoute **routes1 = NULL, **routes2 = NULL;
+ NMSettingIPConfig *s_ip1, *s_ip2;
+ const char *s_name;
+ GHashTable *props;
+ guint i, num;
+
+ s_name = v4 ? NM_SETTING_IP4_CONFIG_SETTING_NAME :
+ NM_SETTING_IP6_CONFIG_SETTING_NAME;
+
+ props = check_property_in_hash (settings,
+ s_name,
+ NM_SETTING_IP_CONFIG_ROUTES);
+ if (!props)
+ return TRUE;
+
+ s_ip1 = (NMSettingIPConfig *) nm_connection_get_setting_by_name (orig, s_name);
+ s_ip2 = (NMSettingIPConfig *) nm_connection_get_setting_by_name (candidate, s_name);
+
+ if (!s_ip1 || !s_ip2)
+ return FALSE;
+
+ num = nm_setting_ip_config_get_num_routes (s_ip1);
+ if (num != nm_setting_ip_config_get_num_routes (s_ip2))
+ return FALSE;
+
+ routes1 = g_new (NMIPRoute *, num);
+ routes2 = g_new (NMIPRoute *, num);
+
+ for (i = 0; i < num; i++) {
+ routes1[i] = nm_setting_ip_config_get_route (s_ip1, i);
+ routes2[i] = nm_setting_ip_config_get_route (s_ip2, i);
+ }
+
+ qsort (routes1, num, sizeof (NMIPRoute *), route_ptr_compare);
+ qsort (routes2, num, sizeof (NMIPRoute *), route_ptr_compare);
+
+ for (i = 0; i < num; i++) {
+ if (route_compare (routes1[i], routes2[i], default_metric))
+ return FALSE;
+ }
+
+ remove_from_hash (settings, props, s_name, NM_SETTING_IP_CONFIG_ROUTES);
+ return TRUE;
+}
+
static gboolean
check_ip4_method (NMConnection *orig,
NMConnection *candidate,
check_possible_match (NMConnection *orig,
NMConnection *candidate,
GHashTable *settings,
- gboolean device_has_carrier)
+ gboolean device_has_carrier,
+ gint64 default_v4_metric,
+ gint64 default_v6_metric)
{
g_return_val_if_fail (settings != NULL, NULL);
if (!check_ip4_method (orig, candidate, settings, device_has_carrier))
return NULL;
+ if (!check_ip_routes (orig, candidate, settings, default_v4_metric, TRUE))
+ return NULL;
+
+ if (!check_ip_routes (orig, candidate, settings, default_v6_metric, FALSE))
+ return NULL;
+
if (!check_connection_interface_name (orig, candidate, settings))
return NULL;
nm_utils_match_connection (GSList *connections,
NMConnection *original,
gboolean device_has_carrier,
+ gint64 default_v4_metric,
+ gint64 default_v6_metric,
NMUtilsMatchFilterFunc match_filter_func,
gpointer match_filter_data)
{
}
if (!nm_connection_diff (original, candidate, NM_SETTING_COMPARE_FLAG_INFERRABLE, &diffs)) {
- if (!best_match)
- best_match = check_possible_match (original, candidate, diffs, device_has_carrier);
+ if (!best_match) {
+ best_match = check_possible_match (original, candidate, diffs, device_has_carrier,
+ default_v4_metric, default_v6_metric);
+ }
if (!best_match && nm_logging_enabled (LOGL_DEBUG, LOGD_CORE)) {
GString *diff_string;
copy = nm_simple_connection_new_clone (orig);
connections = g_slist_append (connections, copy);
- matched = nm_utils_match_connection (connections, orig, TRUE, NULL, NULL);
+ matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL);
g_assert (matched == copy);
/* Now change a material property like IPv4 method and ensure matching fails */
g_object_set (G_OBJECT (s_ip4),
NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL,
NULL);
- matched = nm_utils_match_connection (connections, orig, TRUE, NULL, NULL);
+ matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL);
g_assert (matched == NULL);
g_slist_free (connections);
NM_SETTING_IP_CONFIG_MAY_FAIL, TRUE,
NULL);
- matched = nm_utils_match_connection (connections, orig, TRUE, NULL, NULL);
+ matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL);
g_assert (matched == copy);
g_slist_free (connections);
NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
NULL);
- matched = nm_utils_match_connection (connections, orig, TRUE, NULL, NULL);
+ matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL);
g_assert (matched == copy);
g_slist_free (connections);
NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
NULL);
- matched = nm_utils_match_connection (connections, orig, TRUE, NULL, NULL);
+ matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL);
g_assert (matched == copy);
g_slist_free (connections);
g_object_unref (copy);
}
-
static void
test_connection_match_ip4_method (void)
{
NM_SETTING_IP_CONFIG_MAY_FAIL, TRUE,
NULL);
- matched = nm_utils_match_connection (connections, orig, FALSE, NULL, NULL);
+ matched = nm_utils_match_connection (connections, orig, FALSE, 0, 0, NULL, NULL);
g_assert (matched == copy);
/* Ensure when carrier=true matching fails */
- matched = nm_utils_match_connection (connections, orig, TRUE, NULL, NULL);
+ matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL);
g_assert (matched == NULL);
g_slist_free (connections);
NM_SETTING_CONNECTION_INTERFACE_NAME, NULL,
NULL);
- matched = nm_utils_match_connection (connections, orig, TRUE, NULL, NULL);
+ matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL);
g_assert (matched == copy);
g_slist_free (connections);
NM_SETTING_WIRED_S390_NETTYPE, "qeth",
NULL);
- matched = nm_utils_match_connection (connections, orig, TRUE, NULL, NULL);
+ matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL);
g_assert (matched == copy);
g_slist_free (connections);
* the connections match. It can happen if assuming VLAN devices. */
nm_connection_remove_setting (orig, NM_TYPE_SETTING_WIRED);
- matched = nm_utils_match_connection (connections, orig, TRUE, NULL, NULL);
+ matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL);
g_assert (matched == copy);
g_slist_free (connections);
NM_SETTING_WIRED_CLONED_MAC_ADDRESS, "52:54:00:ab:db:23",
NULL);
- matched = nm_utils_match_connection (connections, orig, TRUE, NULL, NULL);
+ matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL);
g_assert (matched == fuzzy);
exact = nm_simple_connection_new_clone (orig);
NM_SETTING_WIRED_CLONED_MAC_ADDRESS, "52:54:00:ab:db:23",
NULL);
- matched = nm_utils_match_connection (connections, orig, TRUE, NULL, NULL);
+ matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL);
g_assert (matched == exact);
g_object_set (G_OBJECT (s_wired),
NM_SETTING_WIRED_CLONED_MAC_ADDRESS, "52:54:00:ab:db:24",
NULL);
- matched = nm_utils_match_connection (connections, orig, TRUE, NULL, NULL);
+ matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL);
g_assert (matched == fuzzy);
g_slist_free (connections);
nm_setting_ip_config_add_address (s_ip4, nm_addr);
nm_ip_address_unref (nm_addr);
- matched = nm_utils_match_connection (connections, orig, TRUE, NULL, NULL);
+ matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL);
g_assert (matched != copy);
g_slist_free (connections);
NM_SETTING_VLAN_FLAGS, 0,
NULL);
- matched = nm_utils_match_connection (connections, orig, TRUE, NULL, NULL);
+ matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL);
g_assert (matched != copy);
/* Check that the connections do not match if VLAN priorities differ */
g_object_set (G_OBJECT (s_vlan_copy), NM_SETTING_VLAN_FLAGS, 0, NULL);
nm_setting_vlan_add_priority_str (s_vlan_copy, NM_VLAN_INGRESS_MAP, "4:2");
- matched = nm_utils_match_connection (connections, orig, TRUE, NULL, NULL);
+ matched = nm_utils_match_connection (connections, orig, TRUE, 0, 0, NULL, NULL);
g_assert (matched != copy);
g_slist_free (connections);
g_object_unref (copy);
}
+static void
+test_connection_match_ip4_routes1 (void)
+{
+ gs_unref_object NMConnection *orig = NULL, *copy = NULL;
+ NMConnection *matched;
+ gs_free_slist GSList *connections = NULL;
+ NMSettingIPConfig *s_ip4;
+
+ orig = _match_connection_new ();
+
+ s_ip4 = nm_connection_get_setting_ip4_config (orig);
+ g_assert (s_ip4);
+ g_object_set (G_OBJECT (s_ip4),
+ NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
+ NULL);
+
+ nmtst_setting_ip_config_add_address (s_ip4, "10.0.0.1", 8);
+
+ /* Clone connection */
+ copy = nm_simple_connection_new_clone (orig);
+ connections = g_slist_append (connections, copy);
+
+ /* Set routes on original connection */
+ nmtst_setting_ip_config_add_route (s_ip4, "172.25.16.0", 24, "10.0.0.2", -1);
+ nmtst_setting_ip_config_add_route (s_ip4, "172.25.17.0", 24, "10.0.0.3", 20);
+
+ /* Set single route on cloned connection */
+ s_ip4 = nm_connection_get_setting_ip4_config (copy);
+ g_assert (s_ip4);
+ nmtst_setting_ip_config_add_route (s_ip4, "172.25.17.0", 24, "10.0.0.3", 20);
+
+ /* Try to match the connections */
+ matched = nm_utils_match_connection (connections, orig, FALSE, 100, 0, NULL, NULL);
+ g_assert (matched == NULL);
+}
+
+static void
+test_connection_match_ip4_routes2 (void)
+{
+ gs_unref_object NMConnection *orig = NULL, *copy = NULL;
+ NMConnection *matched;
+ gs_free_slist GSList *connections = NULL;
+ NMSettingIPConfig *s_ip4;
+
+ orig = _match_connection_new ();
+
+ s_ip4 = nm_connection_get_setting_ip4_config (orig);
+ g_assert (s_ip4);
+ g_object_set (G_OBJECT (s_ip4),
+ NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
+ NULL);
+
+ nmtst_setting_ip_config_add_address (s_ip4, "10.0.0.1", 8);
+
+ /* Clone connection */
+ copy = nm_simple_connection_new_clone (orig);
+ connections = g_slist_append (connections, copy);
+
+ /* Set routes on original connection */
+ nmtst_setting_ip_config_add_route (s_ip4, "172.25.16.0", 24, "10.0.0.2", -1);
+ nmtst_setting_ip_config_add_route (s_ip4, "172.25.17.0", 24, "10.0.0.3", 20);
+
+ /* Set routes on cloned connection, changing order and using explicit metrics */
+ s_ip4 = nm_connection_get_setting_ip4_config (copy);
+ g_assert (s_ip4);
+ nmtst_setting_ip_config_add_route (s_ip4, "172.25.17.0", 24, "10.0.0.3", 20);
+ nmtst_setting_ip_config_add_route (s_ip4, "172.25.16.0", 24, "10.0.0.2", 100);
+
+ /* Try to match the connections using different default metrics */
+ matched = nm_utils_match_connection (connections, orig, FALSE, 100, 0, NULL, NULL);
+ g_assert (matched == copy);
+ matched = nm_utils_match_connection (connections, orig, FALSE, 500, 0, NULL, NULL);
+ g_assert (matched == NULL);
+}
+
+static void
+test_connection_match_ip6_routes (void)
+{
+ gs_unref_object NMConnection *orig = NULL, *copy = NULL;
+ NMConnection *matched;
+ gs_free_slist GSList *connections = NULL;
+ NMSettingIPConfig *s_ip6;
+
+ orig = _match_connection_new ();
+
+ s_ip6 = nm_connection_get_setting_ip6_config (orig);
+ g_assert (s_ip6);
+ g_object_set (G_OBJECT (s_ip6),
+ NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_MANUAL,
+ NULL);
+
+ nmtst_setting_ip_config_add_address (s_ip6, "fd01::15", 64);
+
+ /* Clone connection */
+ copy = nm_simple_connection_new_clone (orig);
+ connections = g_slist_append (connections, copy);
+
+ /* Set routes on original connection */
+ nmtst_setting_ip_config_add_route (s_ip6, "2001:db8:a:b:0:0:0:0", 64, "fd01::16", -1);
+
+ /* Set routes on cloned connection */
+ s_ip6 = nm_connection_get_setting_ip6_config (copy);
+ g_assert (s_ip6);
+ nmtst_setting_ip_config_add_route (s_ip6, "2001:db8:a:b:0:0:0:0", 64, "fd01::16", 50);
+
+ /* Try to match the connections */
+ matched = nm_utils_match_connection (connections, orig, FALSE, 0, 100, NULL, NULL);
+ g_assert (matched == NULL);
+ matched = nm_utils_match_connection (connections, orig, FALSE, 0, 50, NULL, NULL);
+ g_assert (matched == copy);
+}
+
static NMConnection *
_create_connection_autoconnect (const char *id, gboolean autoconnect, int autoconnect_priority)
{
g_test_add_func ("/general/connection-match/cloned_mac", test_connection_match_cloned_mac);
g_test_add_func ("/general/connection-match/no-match-ip4-addr", test_connection_no_match_ip4_addr);
g_test_add_func ("/general/connection-match/no-match-vlan", test_connection_no_match_vlan);
+ g_test_add_func ("/general/connection-match/routes/ip4/1", test_connection_match_ip4_routes1);
+ g_test_add_func ("/general/connection-match/routes/ip4/2", test_connection_match_ip4_routes2);
+ g_test_add_func ("/general/connection-match/routes/ip6", test_connection_match_ip6_routes);
g_test_add_func ("/general/connection-sort/autoconnect-priority", test_connection_sort_autoconnect_priority);