platform: fix ip4_check_reinstall_device_route() implementation

We must check if a conflicting route/address is configured on
*any* interface, not only on the target ifindex.

This at least restores the previous behavior. Note that this whole
check_reinstall_device_route() still has problems and it might
be better to move it all to NMRouteManager.

Fixes: 470bcefa5f
This commit is contained in:
Thomas Haller
2015-06-19 16:58:28 +02:00
parent 518cf76de7
commit 1bfade833a

View File

@@ -814,6 +814,14 @@ process_events (NMPlatform *platform)
delayed_action_handle_all (platform, TRUE); delayed_action_handle_all (platform, TRUE);
} }
/******************************************************************/
#define cache_lookup_all_objects(type, platform, obj_type, visible_only) \
((const type *const*) nmp_cache_lookup_multi (NM_LINUX_PLATFORM_GET_PRIVATE ((platform))->cache, \
nmp_cache_id_init_object_type (NMP_CACHE_ID_STATIC, (obj_type), (visible_only)), \
NULL))
/******************************************************************/ /******************************************************************/
#define DEVTYPE_PREFIX "DEVTYPE=" #define DEVTYPE_PREFIX "DEVTYPE="
@@ -4255,26 +4263,53 @@ ip4_check_reinstall_device_route (NMPlatform *platform, int ifindex, const NMPla
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
guint32 device_network; guint32 device_network;
NMPObject obj_needle; NMPObject obj_needle;
const NMPlatformIP4Address *const *addresses;
if (nmp_cache_lookup_obj (priv->cache, const NMPlatformIP4Route *const *routes;
nmp_object_stackinit_id_ip4_address (&obj_needle, ifindex, address->address, address->plen))) {
/* If we already have the same address installed on any interface,
* we back off. */
return FALSE;
}
device_network = nm_utils_ip4_address_clear_host_address (address->address, address->plen); device_network = nm_utils_ip4_address_clear_host_address (address->address, address->plen);
check_for_route: /* in many cases we expect the route to already exist. So first do an exact lookup
* to save the O(n) access below. */
nmp_object_stackinit_id_ip4_route (&obj_needle, ifindex, device_network, address->plen, device_route_metric); nmp_object_stackinit_id_ip4_route (&obj_needle, ifindex, device_network, address->plen, device_route_metric);
if (nmp_cache_lookup_obj (priv->cache, &obj_needle)) { if (nmp_cache_lookup_obj (priv->cache, &obj_needle)) {
/* There is already a route with metric 0 or the metric we want to install /* There is already a route with metric 0 or the metric we want to install
* for the same subnet. */ * for the same subnet. */
return FALSE; return FALSE;
} }
if (device_route_metric != 0) { if (obj_needle.ip4_route.metric != 0) {
device_route_metric = 0; obj_needle.ip4_route.metric = 0;
goto check_for_route; if (nmp_cache_lookup_obj (priv->cache, &obj_needle))
return FALSE;
}
/* also check whether we already have the same address configured on *any* device. */
addresses = cache_lookup_all_objects (NMPlatformIP4Address, platform, NMP_OBJECT_TYPE_IP4_ADDRESS, FALSE);
if (addresses) {
for (; *addresses; addresses++) {
const NMPlatformIP4Address *addr_candidate = *addresses;
if ( addr_candidate->plen == address->plen
&& addr_candidate->address == device_network) {
/* If we already have the same address installed on any interface,
* we back off. */
return FALSE;
}
}
}
routes = cache_lookup_all_objects (NMPlatformIP4Route, platform, NMP_OBJECT_TYPE_IP4_ROUTE, FALSE);
if (routes) {
for (; *routes; routes++) {
const NMPlatformIP4Route *route_candidate = *routes;
if ( route_candidate->network == device_network
&& route_candidate->plen == address->plen
&& (route_candidate->metric == 0 || route_candidate->metric == device_route_metric)) {
/* If we already have the same address installed on any interface,
* we back off. */
return FALSE;
}
}
} }
return TRUE; return TRUE;