platform: fix cache to use kernel's notion for equality of routes
Until now, NetworkManager's platform cache for routes used the quadruple network/plen,metric,ifindex for equaliy. That is not kernel's understanding of how routes behave. For example, with `ip route append` you can add two IPv4 routes that only differ by their gateway. To the previous form of platform cache, these two routes would wrongly look identical, as the cache could not contain both routes. This also easily leads to cache-inconsistencies. Now that we have NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID, fix the route's compare operator to match kernel's. Well, not entirely. Kernel understands more properties for routes then NetworkManager. Some of these properties may also be part of the ID according to kernel. To NetworkManager such routes would still look identical as they only differ in a property that is not understood. This can still cause cache-inconsistencies. The only fix here is to add support for all these properties in NetworkManager as well. However, it's less serious, because with this commit we support several of the more important properties. See also the related bug rh#1337855 for kernel. Another difficulty is that `ip route replace` and `ip route change` changes an existing route. The replaced route has the same NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID, but differ in the actual NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID: # ip -d -4 route show dev v # ip monitor route & # ip route add 192.168.5.0/24 dev v 192.168.5.0/24 dev v scope link # ip route change 192.168.5.0/24 dev v scope 10 192.168.5.0/24 dev v scope 10 # ip -d -4 route show dev v unicast 192.168.5.0/24 proto boot scope 10 Note that we only got one RTM_NEWROUTE message, although from NMPCache's point of view, a new route (with a particular ID) was added and another route (with a different ID) was deleted. The cumbersome workaround is, to keep an ordered list of the routes, and figure out which route was replaced in response to an RTM_NEWROUTE. In absence of bugs, this should work fine. However, as we only rely on events, we might wrongly introduce a cache-inconsistancy as well. See the related bug rh#1337860. Also drop nm_platform_ip4_route_get() and the like. The ID of routes is complex, so it makes little sense to look up a route directly.
This commit is contained in:
@@ -370,6 +370,30 @@ GPtrArray *nm_dedup_multi_objs_to_ptr_array_head (const NMDedupMultiHeadEntry *h
|
|||||||
NMDedupMultiFcnSelectPredicate predicate,
|
NMDedupMultiFcnSelectPredicate predicate,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
|
||||||
|
static inline const NMDedupMultiEntry *
|
||||||
|
nm_dedup_multi_head_entry_get_idx (const NMDedupMultiHeadEntry *head_entry,
|
||||||
|
int idx)
|
||||||
|
{
|
||||||
|
CList *iter;
|
||||||
|
|
||||||
|
if (head_entry) {
|
||||||
|
if (idx >= 0) {
|
||||||
|
c_list_for_each (iter, &head_entry->lst_entries_head) {
|
||||||
|
if (idx-- == 0)
|
||||||
|
return c_list_entry (iter, NMDedupMultiEntry, lst_entries);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (iter = head_entry->lst_entries_head.prev;
|
||||||
|
iter != &head_entry->lst_entries_head;
|
||||||
|
iter = iter->prev) {
|
||||||
|
if (++idx == 0)
|
||||||
|
return c_list_entry (iter, NMDedupMultiEntry, lst_entries);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
nm_dedup_multi_head_entry_sort (const NMDedupMultiHeadEntry *head_entry,
|
nm_dedup_multi_head_entry_sort (const NMDedupMultiHeadEntry *head_entry,
|
||||||
CListSortCmp cmp,
|
CListSortCmp cmp,
|
||||||
|
@@ -394,6 +394,7 @@ link_delete (NMPlatform *platform, int ifindex)
|
|||||||
cache_op = nmp_cache_remove (nm_platform_get_cache (platform),
|
cache_op = nmp_cache_remove (nm_platform_get_cache (platform),
|
||||||
obj_old,
|
obj_old,
|
||||||
FALSE,
|
FALSE,
|
||||||
|
FALSE,
|
||||||
&obj_old2);
|
&obj_old2);
|
||||||
g_assert (cache_op == NMP_CACHE_OPS_REMOVED);
|
g_assert (cache_op == NMP_CACHE_OPS_REMOVED);
|
||||||
g_assert (obj_old2);
|
g_assert (obj_old2);
|
||||||
@@ -1085,6 +1086,7 @@ ipx_address_delete (NMPlatform *platform,
|
|||||||
if (nmp_cache_remove (nm_platform_get_cache (platform),
|
if (nmp_cache_remove (nm_platform_get_cache (platform),
|
||||||
o,
|
o,
|
||||||
TRUE,
|
TRUE,
|
||||||
|
FALSE,
|
||||||
&obj_old) != NMP_CACHE_OPS_REMOVED)
|
&obj_old) != NMP_CACHE_OPS_REMOVED)
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
g_assert (obj_old);
|
g_assert (obj_old);
|
||||||
@@ -1171,6 +1173,7 @@ ipx_route_delete (NMPlatform *platform,
|
|||||||
if (nmp_cache_remove (nm_platform_get_cache (platform),
|
if (nmp_cache_remove (nm_platform_get_cache (platform),
|
||||||
o,
|
o,
|
||||||
TRUE,
|
TRUE,
|
||||||
|
FALSE,
|
||||||
&obj_old) != NMP_CACHE_OPS_REMOVED)
|
&obj_old) != NMP_CACHE_OPS_REMOVED)
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
g_assert (obj_old);
|
g_assert (obj_old);
|
||||||
@@ -1204,15 +1207,19 @@ ip_route_add (NMPlatform *platform,
|
|||||||
{
|
{
|
||||||
NMDedupMultiIter iter;
|
NMDedupMultiIter iter;
|
||||||
nm_auto_nmpobj NMPObject *obj = NULL;
|
nm_auto_nmpobj NMPObject *obj = NULL;
|
||||||
NMPlatformIPRoute *rt;
|
|
||||||
NMPCacheOpsType cache_op;
|
NMPCacheOpsType cache_op;
|
||||||
const NMPObject *o = NULL;
|
const NMPObject *o = NULL;
|
||||||
nm_auto_nmpobj const NMPObject *obj_old = NULL;
|
nm_auto_nmpobj const NMPObject *obj_old = NULL;
|
||||||
nm_auto_nmpobj const NMPObject *obj_new = NULL;
|
nm_auto_nmpobj const NMPObject *obj_new = NULL;
|
||||||
|
nm_auto_nmpobj const NMPObject *obj_replace = NULL;
|
||||||
NMPCache *cache = nm_platform_get_cache (platform);
|
NMPCache *cache = nm_platform_get_cache (platform);
|
||||||
gboolean has_gateway = FALSE;
|
gboolean has_gateway = FALSE;
|
||||||
NMPlatformIP4Route *rt4 = NULL;
|
NMPlatformIPRoute *r = NULL;
|
||||||
NMPlatformIP6Route *rt6 = NULL;
|
NMPlatformIP4Route *r4 = NULL;
|
||||||
|
NMPlatformIP6Route *r6 = NULL;
|
||||||
|
gboolean has_same_weak_id;
|
||||||
|
gboolean only_dirty;
|
||||||
|
guint16 nlmsgflags;
|
||||||
|
|
||||||
g_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
|
g_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
|
||||||
|
|
||||||
@@ -1223,21 +1230,29 @@ ip_route_add (NMPlatform *platform,
|
|||||||
? NMP_OBJECT_TYPE_IP4_ROUTE
|
? NMP_OBJECT_TYPE_IP4_ROUTE
|
||||||
: NMP_OBJECT_TYPE_IP6_ROUTE,
|
: NMP_OBJECT_TYPE_IP6_ROUTE,
|
||||||
(const NMPlatformObject *) route);
|
(const NMPlatformObject *) route);
|
||||||
rt = &obj->ip_route;
|
r = &obj->ip_route;
|
||||||
rt->rt_source = nmp_utils_ip_config_source_round_trip_rtprot (rt->rt_source);
|
|
||||||
|
|
||||||
if (addr_family == AF_INET) {
|
switch (addr_family) {
|
||||||
rt4 = NMP_OBJECT_CAST_IP4_ROUTE (obj);
|
case AF_INET:
|
||||||
rt4->scope_inv = nm_platform_route_scope_inv (rt4->gateway ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK);
|
r4 = NMP_OBJECT_CAST_IP4_ROUTE (obj);
|
||||||
rt4->network = nm_utils_ip4_address_clear_host_address (rt4->network, rt4->plen);
|
r4->network = nm_utils_ip4_address_clear_host_address (r4->network, r4->plen);
|
||||||
if (rt4->gateway)
|
r4->rt_source = nmp_utils_ip_config_source_round_trip_rtprot (r4->rt_source),
|
||||||
|
r4->scope_inv = nm_platform_route_scope_inv (!r4->gateway
|
||||||
|
? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE);
|
||||||
|
if (r4->gateway)
|
||||||
has_gateway = TRUE;
|
has_gateway = TRUE;
|
||||||
} else {
|
break;
|
||||||
rt6 = NMP_OBJECT_CAST_IP6_ROUTE (obj);
|
case AF_INET6:
|
||||||
rt->metric = nm_utils_ip6_route_metric_normalize (rt->metric);
|
r6 = NMP_OBJECT_CAST_IP6_ROUTE (obj);
|
||||||
nm_utils_ip6_address_clear_host_address (&rt6->network, &rt6->network, rt->plen);
|
nm_utils_ip6_address_clear_host_address (&r6->network, &r6->network, r6->plen);
|
||||||
if (!IN6_IS_ADDR_UNSPECIFIED (&rt6->gateway))
|
r6->rt_source = nmp_utils_ip_config_source_round_trip_rtprot (r6->rt_source),
|
||||||
|
r6->metric = nm_utils_ip6_route_metric_normalize (r6->metric);
|
||||||
|
nm_utils_ip6_address_clear_host_address (&r6->src, &r6->src, r6->src_plen);
|
||||||
|
if (!IN6_IS_ADDR_UNSPECIFIED (&r6->gateway))
|
||||||
has_gateway = TRUE;
|
has_gateway = TRUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
nm_assert_not_reached ();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_gateway) {
|
if (has_gateway) {
|
||||||
@@ -1251,9 +1266,9 @@ ip_route_add (NMPlatform *platform,
|
|||||||
if (addr_family == AF_INET) {
|
if (addr_family == AF_INET) {
|
||||||
const NMPlatformIP4Route *item = NMP_OBJECT_CAST_IP4_ROUTE (o);
|
const NMPlatformIP4Route *item = NMP_OBJECT_CAST_IP4_ROUTE (o);
|
||||||
guint32 n = nm_utils_ip4_address_clear_host_address (item->network, item->plen);
|
guint32 n = nm_utils_ip4_address_clear_host_address (item->network, item->plen);
|
||||||
guint32 g = nm_utils_ip4_address_clear_host_address (rt4->gateway, item->plen);
|
guint32 g = nm_utils_ip4_address_clear_host_address (r4->gateway, item->plen);
|
||||||
|
|
||||||
if ( rt->ifindex == item->ifindex
|
if ( r->ifindex == item->ifindex
|
||||||
&& n == g) {
|
&& n == g) {
|
||||||
has_route_to_gw = TRUE;
|
has_route_to_gw = TRUE;
|
||||||
break;
|
break;
|
||||||
@@ -1261,8 +1276,8 @@ ip_route_add (NMPlatform *platform,
|
|||||||
} else {
|
} else {
|
||||||
const NMPlatformIP6Route *item = NMP_OBJECT_CAST_IP6_ROUTE (o);
|
const NMPlatformIP6Route *item = NMP_OBJECT_CAST_IP6_ROUTE (o);
|
||||||
|
|
||||||
if ( rt->ifindex == item->ifindex
|
if ( r->ifindex == item->ifindex
|
||||||
&& nm_utils_ip6_address_same_prefix (&rt6->gateway, &item->network, item->plen)) {
|
&& nm_utils_ip6_address_same_prefix (&r6->gateway, &item->network, item->plen)) {
|
||||||
has_route_to_gw = TRUE;
|
has_route_to_gw = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1271,17 +1286,73 @@ ip_route_add (NMPlatform *platform,
|
|||||||
if (!has_route_to_gw) {
|
if (!has_route_to_gw) {
|
||||||
if (addr_family == AF_INET) {
|
if (addr_family == AF_INET) {
|
||||||
nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip4-route '%d: %s/%d %d': Network Unreachable",
|
nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip4-route '%d: %s/%d %d': Network Unreachable",
|
||||||
rt->ifindex, nm_utils_inet4_ntop (rt4->network, NULL), rt->plen, rt->metric);
|
r->ifindex, nm_utils_inet4_ntop (r4->network, NULL), r->plen, r->metric);
|
||||||
} else {
|
} else {
|
||||||
nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip6-route '%d: %s/%d %d': Network Unreachable",
|
nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip6-route '%d: %s/%d %d': Network Unreachable",
|
||||||
rt->ifindex, nm_utils_inet6_ntop (&rt6->network, NULL), rt->plen, rt->metric);
|
r->ifindex, nm_utils_inet6_ntop (&r6->network, NULL), r->plen, r->metric);
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cache_op = nmp_cache_update_netlink (cache, obj, FALSE, &obj_old, &obj_new);
|
has_same_weak_id = FALSE;
|
||||||
nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new);
|
nmp_cache_iter_for_each (&iter,
|
||||||
|
nm_platform_lookup_all (platform,
|
||||||
|
NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID,
|
||||||
|
obj),
|
||||||
|
&o) {
|
||||||
|
if (addr_family == AF_INET) {
|
||||||
|
if (nm_platform_ip4_route_cmp (NMP_OBJECT_CAST_IP4_ROUTE (o), r4, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) == 0)
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
if (nm_platform_ip6_route_cmp (NMP_OBJECT_CAST_IP6_ROUTE (o), r6, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) == 0)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
has_same_weak_id = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlmsgflags = 0;
|
||||||
|
if (has_same_weak_id) {
|
||||||
|
switch (flags) {
|
||||||
|
case NMP_NLM_FLAG_REPLACE:
|
||||||
|
nlmsgflags = NLM_F_REPLACE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we manipulate the cache the same was as NMLinuxPlatform does it. */
|
||||||
|
cache_op = nmp_cache_update_netlink_route (cache,
|
||||||
|
obj,
|
||||||
|
FALSE,
|
||||||
|
nlmsgflags,
|
||||||
|
&obj_old,
|
||||||
|
&obj_new,
|
||||||
|
&obj_replace,
|
||||||
|
NULL);
|
||||||
|
only_dirty = FALSE;
|
||||||
|
if (cache_op != NMP_CACHE_OPS_UNCHANGED) {
|
||||||
|
if (obj_replace) {
|
||||||
|
const NMDedupMultiEntry *entry_replace;
|
||||||
|
|
||||||
|
entry_replace = nmp_cache_lookup_entry (cache, obj_replace);
|
||||||
|
nm_assert (entry_replace && entry_replace->obj == obj_replace);
|
||||||
|
nm_dedup_multi_entry_set_dirty (entry_replace, TRUE);
|
||||||
|
only_dirty = TRUE;
|
||||||
|
}
|
||||||
|
nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj_replace) {
|
||||||
|
cache_op = nmp_cache_remove (cache, obj_replace, TRUE, only_dirty, NULL);
|
||||||
|
if (cache_op != NMP_CACHE_OPS_UNCHANGED) {
|
||||||
|
nm_assert (cache_op == NMP_CACHE_OPS_REMOVED);
|
||||||
|
nm_platform_cache_update_emit_signal (platform, cache_op, obj_replace, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3392,7 +3392,7 @@ cache_prune_one_type (NMPlatform *platform, NMPObjectType obj_type)
|
|||||||
|
|
||||||
obj = iter.current->obj;
|
obj = iter.current->obj;
|
||||||
_LOGt ("cache-prune: prune %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ALL, NULL, 0));
|
_LOGt ("cache-prune: prune %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ALL, NULL, 0));
|
||||||
cache_op = nmp_cache_remove (cache, obj, TRUE, &obj_old);
|
cache_op = nmp_cache_remove (cache, obj, TRUE, TRUE, &obj_old);
|
||||||
nm_assert (cache_op == NMP_CACHE_OPS_REMOVED);
|
nm_assert (cache_op == NMP_CACHE_OPS_REMOVED);
|
||||||
cache_on_change (platform, cache_op, obj_old, NULL);
|
cache_on_change (platform, cache_op, obj_old, NULL);
|
||||||
nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, NULL);
|
nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, NULL);
|
||||||
@@ -3645,39 +3645,6 @@ cache_on_change (NMPlatform *platform,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
cache_post (NMPlatform *platform,
|
|
||||||
struct nlmsghdr *msghdr,
|
|
||||||
NMPCacheOpsType cache_op,
|
|
||||||
const NMPObject *obj,
|
|
||||||
const NMPObject *obj_old,
|
|
||||||
const NMPObject *obj_new)
|
|
||||||
{
|
|
||||||
if (msghdr->nlmsg_type == RTM_NEWROUTE) {
|
|
||||||
DelayedActionType action_type;
|
|
||||||
|
|
||||||
action_type = NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_IP4_ROUTE
|
|
||||||
? DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES
|
|
||||||
: DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES;
|
|
||||||
if ( !delayed_action_refresh_all_in_progress (platform, action_type)
|
|
||||||
&& nmp_cache_find_other_route_for_same_destination (nm_platform_get_cache (platform), obj)) {
|
|
||||||
/* via `iproute route change` the user can update an existing route which effectively
|
|
||||||
* means that a new object (with a different ID) comes into existance, replacing the
|
|
||||||
* old on. In other words, as the ID of the object changes, we really see a new
|
|
||||||
* object with the old one deleted.
|
|
||||||
* However, kernel decides not to send a RTM_DELROUTE event for that.
|
|
||||||
*
|
|
||||||
* To hack around that, check if the update leaves us with multiple routes for the
|
|
||||||
* same network/plen,metric part. In that case, we cannot do better then requesting
|
|
||||||
* all routes anew, which sucks.
|
|
||||||
*
|
|
||||||
* One mitigation to avoid a dump is only to request a new dump, if we are not in
|
|
||||||
* the middle of an ongoing dump (delayed_action_refresh_all_in_progress). */
|
|
||||||
delayed_action_schedule (platform, action_type, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -3939,16 +3906,73 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event
|
|||||||
|
|
||||||
case RTM_NEWLINK:
|
case RTM_NEWLINK:
|
||||||
case RTM_NEWADDR:
|
case RTM_NEWADDR:
|
||||||
case RTM_NEWROUTE:
|
|
||||||
case RTM_GETLINK:
|
case RTM_GETLINK:
|
||||||
cache_op = nmp_cache_update_netlink (cache, obj, is_dump, &obj_old, &obj_new);
|
cache_op = nmp_cache_update_netlink (cache, obj, is_dump, &obj_old, &obj_new);
|
||||||
if (cache_op != NMP_CACHE_OPS_UNCHANGED) {
|
if (cache_op != NMP_CACHE_OPS_UNCHANGED) {
|
||||||
cache_on_change (platform, cache_op, obj_old, obj_new);
|
cache_on_change (platform, cache_op, obj_old, obj_new);
|
||||||
cache_post (platform, msghdr, cache_op, obj, obj_old, obj_new);
|
|
||||||
nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new);
|
nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case RTM_NEWROUTE: {
|
||||||
|
nm_auto_nmpobj const NMPObject *obj_replace = NULL;
|
||||||
|
gboolean resync_required = FALSE;
|
||||||
|
gboolean only_dirty = FALSE;
|
||||||
|
|
||||||
|
cache_op = nmp_cache_update_netlink_route (cache,
|
||||||
|
obj,
|
||||||
|
is_dump,
|
||||||
|
msghdr->nlmsg_flags,
|
||||||
|
&obj_old,
|
||||||
|
&obj_new,
|
||||||
|
&obj_replace,
|
||||||
|
&resync_required);
|
||||||
|
if (cache_op != NMP_CACHE_OPS_UNCHANGED) {
|
||||||
|
if (obj_replace) {
|
||||||
|
const NMDedupMultiEntry *entry_replace;
|
||||||
|
|
||||||
|
/* we found an object that is to be replaced by the RTM_NEWROUTE message.
|
||||||
|
* While we invoke the signal, the platform cache might change and invalidate
|
||||||
|
* the findings. Mitigate that (for the most part), by marking the entry as
|
||||||
|
* dirty and only delete @obj_replace if it is still dirty afterwards.
|
||||||
|
*
|
||||||
|
* Yes, there is a tiny tiny chance for still getting it wrong. But in practice,
|
||||||
|
* the signal handlers do not cause to call the platform again, so the cache
|
||||||
|
* is not really changing. -- if they would, it would anyway be dangerous to overflow
|
||||||
|
* the stack and it's not ensured that the processing of netlink messages is
|
||||||
|
* reentrant (maybe it is).
|
||||||
|
*/
|
||||||
|
entry_replace = nmp_cache_lookup_entry (cache, obj_replace);
|
||||||
|
nm_assert (entry_replace && entry_replace->obj == obj_replace);
|
||||||
|
nm_dedup_multi_entry_set_dirty (entry_replace, TRUE);
|
||||||
|
only_dirty = TRUE;
|
||||||
|
}
|
||||||
|
cache_on_change (platform, cache_op, obj_old, obj_new);
|
||||||
|
nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj_replace) {
|
||||||
|
/* the RTM_NEWROUTE message indicates that another route was replaced.
|
||||||
|
* Remove it now. */
|
||||||
|
cache_op = nmp_cache_remove (cache, obj_replace, TRUE, only_dirty, NULL);
|
||||||
|
if (cache_op != NMP_CACHE_OPS_UNCHANGED) {
|
||||||
|
nm_assert (cache_op == NMP_CACHE_OPS_REMOVED);
|
||||||
|
cache_on_change (platform, cache_op, obj_replace, NULL);
|
||||||
|
nm_platform_cache_update_emit_signal (platform, cache_op, obj_replace, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resync_required) {
|
||||||
|
/* we'd like to avoid such resyncs as they are expensive and we should only rely on the
|
||||||
|
* netlink events. This needs investigation. */
|
||||||
|
_LOGT ("schedule resync of routes after RTM_NEWROUTE");
|
||||||
|
delayed_action_schedule (platform,
|
||||||
|
delayed_action_refresh_from_object_type (NMP_OBJECT_GET_TYPE (obj)),
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case RTM_DELLINK:
|
case RTM_DELLINK:
|
||||||
case RTM_DELADDR:
|
case RTM_DELADDR:
|
||||||
case RTM_DELROUTE:
|
case RTM_DELROUTE:
|
||||||
@@ -5829,6 +5853,7 @@ ip_route_add (NMPlatform *platform,
|
|||||||
r6 = NMP_OBJECT_CAST_IP6_ROUTE (&obj);
|
r6 = NMP_OBJECT_CAST_IP6_ROUTE (&obj);
|
||||||
nm_utils_ip6_address_clear_host_address (&r6->network, &r6->network, r6->plen);
|
nm_utils_ip6_address_clear_host_address (&r6->network, &r6->network, r6->plen);
|
||||||
r6->rt_source = nmp_utils_ip_config_source_round_trip_rtprot (r6->rt_source),
|
r6->rt_source = nmp_utils_ip_config_source_round_trip_rtprot (r6->rt_source),
|
||||||
|
r6->metric = nm_utils_ip6_route_metric_normalize (r6->metric);
|
||||||
nm_utils_ip6_address_clear_host_address (&r6->src, &r6->src, r6->src_plen);
|
nm_utils_ip6_address_clear_host_address (&r6->src, &r6->src, r6->src_plen);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@@ -2803,6 +2803,26 @@ nm_platform_ethtool_get_link_settings (NMPlatform *self, int ifindex, gboolean *
|
|||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
const NMDedupMultiHeadEntry *
|
||||||
|
nm_platform_lookup_all (NMPlatform *platform,
|
||||||
|
NMPCacheIdType cache_id_type,
|
||||||
|
NMPObject *obj)
|
||||||
|
{
|
||||||
|
return nmp_cache_lookup_all (nm_platform_get_cache (platform),
|
||||||
|
cache_id_type,
|
||||||
|
obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
const NMDedupMultiEntry *
|
||||||
|
nm_platform_lookup_entry (NMPlatform *platform,
|
||||||
|
NMPCacheIdType cache_id_type,
|
||||||
|
NMPObject *obj)
|
||||||
|
{
|
||||||
|
return nmp_cache_lookup_entry_with_idx_type (nm_platform_get_cache (platform),
|
||||||
|
cache_id_type,
|
||||||
|
obj);
|
||||||
|
}
|
||||||
|
|
||||||
const NMDedupMultiHeadEntry *
|
const NMDedupMultiHeadEntry *
|
||||||
nm_platform_lookup (NMPlatform *self,
|
nm_platform_lookup (NMPlatform *self,
|
||||||
const NMPLookup *lookup)
|
const NMPLookup *lookup)
|
||||||
@@ -3505,38 +3525,6 @@ nm_platform_ip_route_delete (NMPlatform *self,
|
|||||||
return klass->ip_route_delete (self, obj);
|
return klass->ip_route_delete (self, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
const NMPlatformIP4Route *
|
|
||||||
nm_platform_ip4_route_get (NMPlatform *self, int ifindex, in_addr_t network, guint8 plen, guint32 metric)
|
|
||||||
{
|
|
||||||
NMPObject obj_id;
|
|
||||||
const NMPObject *obj;
|
|
||||||
|
|
||||||
_CHECK_SELF (self, klass, FALSE);
|
|
||||||
|
|
||||||
nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric);
|
|
||||||
obj = nmp_cache_lookup_obj (nm_platform_get_cache (self), &obj_id);
|
|
||||||
if (nmp_object_is_visible (obj))
|
|
||||||
return &obj->ip4_route;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
const NMPlatformIP6Route *
|
|
||||||
nm_platform_ip6_route_get (NMPlatform *self, int ifindex, struct in6_addr network, guint8 plen, guint32 metric)
|
|
||||||
{
|
|
||||||
NMPObject obj_id;
|
|
||||||
const NMPObject *obj;
|
|
||||||
|
|
||||||
_CHECK_SELF (self, klass, FALSE);
|
|
||||||
|
|
||||||
metric = nm_utils_ip6_route_metric_normalize (metric);
|
|
||||||
|
|
||||||
nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric);
|
|
||||||
obj = nmp_cache_lookup_obj (nm_platform_get_cache (self), &obj_id);
|
|
||||||
if (nmp_object_is_visible (obj))
|
|
||||||
return &obj->ip6_route;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
@@ -4747,12 +4735,6 @@ nm_platform_ip4_route_hash (const NMPlatformIP4Route *obj, NMPlatformIPRouteCmpT
|
|||||||
h = NM_HASH_COMBINE (h, nm_utils_ip4_address_clear_host_address (obj->network, obj->plen));
|
h = NM_HASH_COMBINE (h, nm_utils_ip4_address_clear_host_address (obj->network, obj->plen));
|
||||||
h = NM_HASH_COMBINE (h, obj->plen);
|
h = NM_HASH_COMBINE (h, obj->plen);
|
||||||
break;
|
break;
|
||||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID_CACHE:
|
|
||||||
h = NM_HASH_COMBINE (h, nm_utils_ip4_address_clear_host_address (obj->network, obj->plen));
|
|
||||||
h = NM_HASH_COMBINE (h, obj->plen);
|
|
||||||
h = NM_HASH_COMBINE (h, obj->metric);
|
|
||||||
h = NM_HASH_COMBINE (h, obj->ifindex);
|
|
||||||
break;
|
|
||||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
|
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
|
||||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
|
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
|
||||||
h = NM_HASH_COMBINE (h, nm_utils_ip4_address_clear_host_address (obj->network, obj->plen));
|
h = NM_HASH_COMBINE (h, nm_utils_ip4_address_clear_host_address (obj->network, obj->plen));
|
||||||
@@ -4819,12 +4801,6 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route
|
|||||||
NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX (a->network, b->network, MIN (a->plen, b->plen));
|
NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX (a->network, b->network, MIN (a->plen, b->plen));
|
||||||
NM_CMP_FIELD (a, b, plen);
|
NM_CMP_FIELD (a, b, plen);
|
||||||
break;
|
break;
|
||||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID_CACHE:
|
|
||||||
NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX (a->network, b->network, MIN (a->plen, b->plen));
|
|
||||||
NM_CMP_FIELD (a, b, plen);
|
|
||||||
NM_CMP_FIELD (a, b, metric);
|
|
||||||
NM_CMP_FIELD (a, b, ifindex);
|
|
||||||
break;
|
|
||||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
|
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
|
||||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
|
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
|
||||||
NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX (a->network, b->network, MIN (a->plen, b->plen));
|
NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX (a->network, b->network, MIN (a->plen, b->plen));
|
||||||
@@ -4892,12 +4868,6 @@ nm_platform_ip6_route_hash (const NMPlatformIP6Route *obj, NMPlatformIPRouteCmpT
|
|||||||
h = NM_HASH_COMBINE_IN6ADDR_PREFIX (h, &obj->network, obj->plen);
|
h = NM_HASH_COMBINE_IN6ADDR_PREFIX (h, &obj->network, obj->plen);
|
||||||
h = NM_HASH_COMBINE (h, obj->plen);
|
h = NM_HASH_COMBINE (h, obj->plen);
|
||||||
break;
|
break;
|
||||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID_CACHE:
|
|
||||||
h = NM_HASH_COMBINE_IN6ADDR_PREFIX (h, &obj->network, obj->plen);
|
|
||||||
h = NM_HASH_COMBINE (h, obj->plen);
|
|
||||||
h = NM_HASH_COMBINE (h, obj->metric);
|
|
||||||
h = NM_HASH_COMBINE (h, obj->ifindex);
|
|
||||||
break;
|
|
||||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
|
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
|
||||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
|
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
|
||||||
h = NM_HASH_COMBINE_IN6ADDR_PREFIX (h, &obj->network, obj->plen);
|
h = NM_HASH_COMBINE_IN6ADDR_PREFIX (h, &obj->network, obj->plen);
|
||||||
@@ -4956,12 +4926,6 @@ nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route
|
|||||||
NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX (&a->network, &b->network, MIN (a->plen, b->plen));
|
NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX (&a->network, &b->network, MIN (a->plen, b->plen));
|
||||||
NM_CMP_FIELD (a, b, plen);
|
NM_CMP_FIELD (a, b, plen);
|
||||||
break;
|
break;
|
||||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID_CACHE:
|
|
||||||
NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX (&a->network, &b->network, MIN (a->plen, b->plen));
|
|
||||||
NM_CMP_FIELD (a, b, plen);
|
|
||||||
NM_CMP_FIELD (a, b, metric);
|
|
||||||
NM_CMP_FIELD (a, b, ifindex);
|
|
||||||
break;
|
|
||||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
|
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
|
||||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
|
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
|
||||||
NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX (&a->network, &b->network, MIN (a->plen, b->plen));
|
NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX (&a->network, &b->network, MIN (a->plen, b->plen));
|
||||||
|
@@ -115,11 +115,6 @@ typedef enum {
|
|||||||
*/
|
*/
|
||||||
NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID,
|
NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID,
|
||||||
|
|
||||||
/* FIXME: this type is what NMPCache currently uses for object identity.
|
|
||||||
* Eventually, we want to use NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID,
|
|
||||||
* which is the same what kernel does. */
|
|
||||||
NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID_CACHE,
|
|
||||||
|
|
||||||
/* NMIP4Config and NMIP6Config also track a list of routes. They have their
|
/* NMIP4Config and NMIP6Config also track a list of routes. They have their
|
||||||
* own notion of what equality means. Basically, they consider network/plen
|
* own notion of what equality means. Basically, they consider network/plen
|
||||||
* for IPv4 and IPv6. */
|
* for IPv4 and IPv6. */
|
||||||
@@ -1102,9 +1097,6 @@ gboolean nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, GPtrArray
|
|||||||
gboolean nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, const GPtrArray *known_addresses, gboolean keep_link_local);
|
gboolean nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, const GPtrArray *known_addresses, gboolean keep_link_local);
|
||||||
gboolean nm_platform_address_flush (NMPlatform *self, int ifindex);
|
gboolean nm_platform_address_flush (NMPlatform *self, int ifindex);
|
||||||
|
|
||||||
const NMPlatformIP4Route *nm_platform_ip4_route_get (NMPlatform *self, int ifindex, in_addr_t network, guint8 plen, guint32 metric);
|
|
||||||
const NMPlatformIP6Route *nm_platform_ip6_route_get (NMPlatform *self, int ifindex, struct in6_addr network, guint8 plen, guint32 metric);
|
|
||||||
|
|
||||||
gboolean nm_platform_ip4_route_add (NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP4Route *route);
|
gboolean nm_platform_ip4_route_add (NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP4Route *route);
|
||||||
gboolean nm_platform_ip6_route_add (NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP6Route *route);
|
gboolean nm_platform_ip6_route_add (NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP6Route *route);
|
||||||
|
|
||||||
|
@@ -216,7 +216,7 @@ _idx_obj_part (const DedupMultiIdxType *idx_type,
|
|||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
case NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION:
|
case NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID:
|
||||||
obj_type = NMP_OBJECT_GET_TYPE (obj_a);
|
obj_type = NMP_OBJECT_GET_TYPE (obj_a);
|
||||||
if ( !NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ROUTE,
|
if ( !NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ROUTE,
|
||||||
NMP_OBJECT_TYPE_IP6_ROUTE)
|
NMP_OBJECT_TYPE_IP6_ROUTE)
|
||||||
@@ -589,29 +589,6 @@ nmp_object_stackinit_id_ip6_address (NMPObject *obj, int ifindex, const struct i
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
const NMPObject *
|
|
||||||
nmp_object_stackinit_id_ip4_route (NMPObject *obj, int ifindex, guint32 network, guint8 plen, guint32 metric)
|
|
||||||
{
|
|
||||||
_nmp_object_stackinit_from_type (obj, NMP_OBJECT_TYPE_IP4_ROUTE);
|
|
||||||
obj->ip4_route.ifindex = ifindex;
|
|
||||||
obj->ip4_route.network = network;
|
|
||||||
obj->ip4_route.plen = plen;
|
|
||||||
obj->ip4_route.metric = metric;
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
const NMPObject *
|
|
||||||
nmp_object_stackinit_id_ip6_route (NMPObject *obj, int ifindex, const struct in6_addr *network, guint8 plen, guint32 metric)
|
|
||||||
{
|
|
||||||
_nmp_object_stackinit_from_type (obj, NMP_OBJECT_TYPE_IP6_ROUTE);
|
|
||||||
obj->ip6_route.ifindex = ifindex;
|
|
||||||
if (network)
|
|
||||||
obj->ip6_route.network = *network;
|
|
||||||
obj->ip6_route.plen = plen;
|
|
||||||
obj->ip6_route.metric = metric;
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
@@ -765,8 +742,6 @@ _vt_cmd_plobj_to_string_id (ip4_address, NMPlatformIP4Address, "%d: %s/%d%s%s",
|
|||||||
obj->peer_address != obj->address ? "," : "",
|
obj->peer_address != obj->address ? "," : "",
|
||||||
obj->peer_address != obj->address ? nm_utils_inet4_ntop (obj->peer_address & nm_utils_ip4_prefix_to_netmask (obj->plen), buf2) : "");
|
obj->peer_address != obj->address ? nm_utils_inet4_ntop (obj->peer_address & nm_utils_ip4_prefix_to_netmask (obj->plen), buf2) : "");
|
||||||
_vt_cmd_plobj_to_string_id (ip6_address, NMPlatformIP6Address, "%d: %s", obj->ifindex, nm_utils_inet6_ntop (&obj->address, buf1));
|
_vt_cmd_plobj_to_string_id (ip6_address, NMPlatformIP6Address, "%d: %s", obj->ifindex, nm_utils_inet6_ntop (&obj->address, buf1));
|
||||||
_vt_cmd_plobj_to_string_id (ip4_route, NMPlatformIP4Route, "%d: %s/%d %d", obj->ifindex, nm_utils_inet4_ntop ( obj->network, buf1), obj->plen, obj->metric);
|
|
||||||
_vt_cmd_plobj_to_string_id (ip6_route, NMPlatformIP6Route, "%d: %s/%d %d", obj->ifindex, nm_utils_inet6_ntop (&obj->network, buf1), obj->plen, obj->metric);
|
|
||||||
|
|
||||||
guint
|
guint
|
||||||
nmp_object_hash (const NMPObject *obj)
|
nmp_object_hash (const NMPObject *obj)
|
||||||
@@ -984,18 +959,12 @@ _vt_cmd_plobj_id_copy (ip6_address, NMPlatformIP6Address, {
|
|||||||
dst->address = src->address;
|
dst->address = src->address;
|
||||||
});
|
});
|
||||||
_vt_cmd_plobj_id_copy (ip4_route, NMPlatformIP4Route, {
|
_vt_cmd_plobj_id_copy (ip4_route, NMPlatformIP4Route, {
|
||||||
dst->ifindex = src->ifindex;
|
*dst = *src;
|
||||||
dst->plen = src->plen;
|
nm_assert (nm_platform_ip4_route_cmp (dst, src, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) == 0);
|
||||||
dst->metric = src->metric;
|
|
||||||
dst->network = src->network;
|
|
||||||
nm_assert (nm_platform_ip4_route_cmp (dst, src, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID_CACHE) == 0);
|
|
||||||
});
|
});
|
||||||
_vt_cmd_plobj_id_copy (ip6_route, NMPlatformIP6Route, {
|
_vt_cmd_plobj_id_copy (ip6_route, NMPlatformIP6Route, {
|
||||||
dst->ifindex = src->ifindex;
|
*dst = *src;
|
||||||
dst->plen = src->plen;
|
nm_assert (nm_platform_ip6_route_cmp (dst, src, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) == 0);
|
||||||
dst->metric = src->metric;
|
|
||||||
dst->network = src->network;
|
|
||||||
nm_assert (nm_platform_ip6_route_cmp (dst, src, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID_CACHE) == 0);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Uses internally nmp_object_copy(), hence it also violates the const
|
/* Uses internally nmp_object_copy(), hence it also violates the const
|
||||||
@@ -1080,13 +1049,13 @@ _vt_cmd_plobj_id_cmp (ip6_address, NMPlatformIP6Address,
|
|||||||
static int
|
static int
|
||||||
_vt_cmd_plobj_id_cmp_ip4_route (const NMPlatformObject *obj1, const NMPlatformObject *obj2)
|
_vt_cmd_plobj_id_cmp_ip4_route (const NMPlatformObject *obj1, const NMPlatformObject *obj2)
|
||||||
{
|
{
|
||||||
return nm_platform_ip4_route_cmp ((NMPlatformIP4Route *) obj1, (NMPlatformIP4Route *) obj2, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID_CACHE);
|
return nm_platform_ip4_route_cmp ((NMPlatformIP4Route *) obj1, (NMPlatformIP4Route *) obj2, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_vt_cmd_plobj_id_cmp_ip6_route (const NMPlatformObject *obj1, const NMPlatformObject *obj2)
|
_vt_cmd_plobj_id_cmp_ip6_route (const NMPlatformObject *obj1, const NMPlatformObject *obj2)
|
||||||
{
|
{
|
||||||
return nm_platform_ip6_route_cmp ((NMPlatformIP6Route *) obj1, (NMPlatformIP6Route *) obj2, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID_CACHE);
|
return nm_platform_ip6_route_cmp ((NMPlatformIP6Route *) obj1, (NMPlatformIP6Route *) obj2, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
guint
|
guint
|
||||||
@@ -1140,10 +1109,10 @@ _vt_cmd_plobj_id_hash (ip6_address, NMPlatformIP6Address, {
|
|||||||
hash = NM_HASH_COMBINE (hash, nm_utils_in6_addr_hash (&obj->address));
|
hash = NM_HASH_COMBINE (hash, nm_utils_in6_addr_hash (&obj->address));
|
||||||
})
|
})
|
||||||
_vt_cmd_plobj_id_hash (ip4_route, NMPlatformIP4Route, {
|
_vt_cmd_plobj_id_hash (ip4_route, NMPlatformIP4Route, {
|
||||||
hash = nm_platform_ip4_route_hash (obj, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID_CACHE);
|
hash = nm_platform_ip4_route_hash (obj, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID);
|
||||||
})
|
})
|
||||||
_vt_cmd_plobj_id_hash (ip6_route, NMPlatformIP6Route, {
|
_vt_cmd_plobj_id_hash (ip6_route, NMPlatformIP6Route, {
|
||||||
hash = nm_platform_ip6_route_hash (obj, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID_CACHE);
|
hash = nm_platform_ip6_route_hash (obj, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID);
|
||||||
})
|
})
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
@@ -1238,7 +1207,7 @@ static const guint8 _supported_cache_ids_ipx_route[] = {
|
|||||||
NMP_CACHE_ID_TYPE_OBJECT_TYPE,
|
NMP_CACHE_ID_TYPE_OBJECT_TYPE,
|
||||||
NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX,
|
NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX,
|
||||||
NMP_CACHE_ID_TYPE_DEFAULT_ROUTES,
|
NMP_CACHE_ID_TYPE_DEFAULT_ROUTES,
|
||||||
NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION,
|
NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID,
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1617,39 +1586,80 @@ nmp_lookup_init_route_visible (NMPLookup *lookup,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const NMPLookup *
|
const NMPLookup *
|
||||||
nmp_lookup_init_route_by_dest (NMPLookup *lookup,
|
nmp_lookup_init_route_by_weak_id (NMPLookup *lookup,
|
||||||
int addr_family,
|
const NMPObject *obj)
|
||||||
gconstpointer network,
|
{
|
||||||
guint plen,
|
const NMPlatformIP4Route *r4;
|
||||||
guint32 metric)
|
const NMPlatformIP6Route *r6;
|
||||||
|
|
||||||
|
nm_assert (lookup);
|
||||||
|
|
||||||
|
switch (NMP_OBJECT_GET_TYPE (obj)) {
|
||||||
|
case NMP_OBJECT_TYPE_IP4_ROUTE:
|
||||||
|
r4 = NMP_OBJECT_CAST_IP4_ROUTE (obj);
|
||||||
|
return nmp_lookup_init_ip4_route_by_weak_id (lookup,
|
||||||
|
r4->network,
|
||||||
|
r4->plen,
|
||||||
|
r4->metric,
|
||||||
|
r4->tos);
|
||||||
|
case NMP_OBJECT_TYPE_IP6_ROUTE:
|
||||||
|
r6 = NMP_OBJECT_CAST_IP6_ROUTE (obj);
|
||||||
|
return nmp_lookup_init_ip6_route_by_weak_id (lookup,
|
||||||
|
&r6->network,
|
||||||
|
r6->plen,
|
||||||
|
r6->metric,
|
||||||
|
&r6->src,
|
||||||
|
r6->src_plen);
|
||||||
|
default:
|
||||||
|
nm_assert_not_reached ();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const NMPLookup *
|
||||||
|
nmp_lookup_init_ip4_route_by_weak_id (NMPLookup *lookup,
|
||||||
|
in_addr_t network,
|
||||||
|
guint plen,
|
||||||
|
guint32 metric,
|
||||||
|
guint8 tos)
|
||||||
{
|
{
|
||||||
NMPObject *o;
|
NMPObject *o;
|
||||||
|
|
||||||
nm_assert (lookup);
|
nm_assert (lookup);
|
||||||
|
|
||||||
switch (addr_family) {
|
o = _nmp_object_stackinit_from_type (&lookup->selector_obj, NMP_OBJECT_TYPE_IP4_ROUTE);
|
||||||
case AF_INET:
|
o->object.ifindex = 1;
|
||||||
o = _nmp_object_stackinit_from_type (&lookup->selector_obj, NMP_OBJECT_TYPE_IP4_ROUTE);
|
o->ip_route.plen = plen;
|
||||||
o->object.ifindex = 1;
|
o->ip_route.metric = metric;
|
||||||
o->ip_route.plen = plen;
|
if (network)
|
||||||
o->ip_route.metric = metric;
|
o->ip4_route.network = network;
|
||||||
if (network)
|
o->ip4_route.tos = tos;
|
||||||
o->ip4_route.network = *((in_addr_t *) network);
|
lookup->cache_id_type = NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID;
|
||||||
lookup->cache_id_type = NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION;
|
return _L (lookup);
|
||||||
break;
|
}
|
||||||
case AF_INET6:
|
|
||||||
o = _nmp_object_stackinit_from_type (&lookup->selector_obj, NMP_OBJECT_TYPE_IP6_ROUTE);
|
const NMPLookup *
|
||||||
o->object.ifindex = 1;
|
nmp_lookup_init_ip6_route_by_weak_id (NMPLookup *lookup,
|
||||||
o->ip_route.plen = plen;
|
const struct in6_addr *network,
|
||||||
o->ip_route.metric = metric;
|
guint plen,
|
||||||
if (network)
|
guint32 metric,
|
||||||
o->ip6_route.network = *((struct in6_addr *) network);
|
const struct in6_addr *src,
|
||||||
lookup->cache_id_type = NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION;
|
guint8 src_plen)
|
||||||
break;
|
{
|
||||||
default:
|
NMPObject *o;
|
||||||
nm_assert_not_reached ();
|
|
||||||
return NULL;
|
nm_assert (lookup);
|
||||||
}
|
|
||||||
|
o = _nmp_object_stackinit_from_type (&lookup->selector_obj, NMP_OBJECT_TYPE_IP6_ROUTE);
|
||||||
|
o->object.ifindex = 1;
|
||||||
|
o->ip_route.plen = plen;
|
||||||
|
o->ip_route.metric = metric;
|
||||||
|
if (network)
|
||||||
|
o->ip6_route.network = *network;
|
||||||
|
if (src)
|
||||||
|
o->ip6_route.src = *src;
|
||||||
|
o->ip6_route.src_plen = src_plen;
|
||||||
|
lookup->cache_id_type = NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID;
|
||||||
return _L (lookup);
|
return _L (lookup);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1684,55 +1694,6 @@ nmp_cache_lookup_to_array (const NMDedupMultiHeadEntry *head_entry,
|
|||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
/**
|
|
||||||
* nmp_cache_find_other_route_for_same_destination:
|
|
||||||
* @cache:
|
|
||||||
* @route:
|
|
||||||
*
|
|
||||||
* Look into the cache whether there is a route to the same destination,
|
|
||||||
* in terms of network/plen,metric.
|
|
||||||
*
|
|
||||||
* Returns: (transfer none): the first found route object from the cache
|
|
||||||
* that has the same (network/plen,metric) values as @route, but has different
|
|
||||||
* ID. Or %NULL, if no such route exists.
|
|
||||||
*/
|
|
||||||
const NMPObject *
|
|
||||||
nmp_cache_find_other_route_for_same_destination (const NMPCache *cache, const NMPObject *route)
|
|
||||||
{
|
|
||||||
NMPLookup lookup;
|
|
||||||
NMDedupMultiIter iter;
|
|
||||||
const NMPObject *o = NULL;
|
|
||||||
|
|
||||||
nm_assert (cache);
|
|
||||||
|
|
||||||
switch (NMP_OBJECT_GET_TYPE (route)) {
|
|
||||||
case NMP_OBJECT_TYPE_IP4_ROUTE:
|
|
||||||
nmp_lookup_init_route_by_dest (&lookup,
|
|
||||||
AF_INET,
|
|
||||||
&route->ip4_route.network,
|
|
||||||
route->ip_route.plen,
|
|
||||||
route->ip_route.metric);
|
|
||||||
break;
|
|
||||||
case NMP_OBJECT_TYPE_IP6_ROUTE:
|
|
||||||
nmp_lookup_init_route_by_dest (&lookup,
|
|
||||||
AF_INET6,
|
|
||||||
&route->ip6_route.network,
|
|
||||||
route->ip_route.plen,
|
|
||||||
route->ip_route.metric);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
g_return_val_if_reached (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
nmp_cache_iter_for_each (&iter, nmp_cache_lookup (cache, &lookup), &o) {
|
|
||||||
nm_assert (NMP_OBJECT_GET_CLASS (route) == NMP_OBJECT_GET_CLASS (o));
|
|
||||||
|
|
||||||
if (!nmp_object_id_equal (route, o))
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
const NMPObject *
|
const NMPObject *
|
||||||
nmp_cache_lookup_link_full (const NMPCache *cache,
|
nmp_cache_lookup_link_full (const NMPCache *cache,
|
||||||
int ifindex,
|
int ifindex,
|
||||||
@@ -1961,6 +1922,7 @@ NMPCacheOpsType
|
|||||||
nmp_cache_remove (NMPCache *cache,
|
nmp_cache_remove (NMPCache *cache,
|
||||||
const NMPObject *obj_needle,
|
const NMPObject *obj_needle,
|
||||||
gboolean equals_by_ptr,
|
gboolean equals_by_ptr,
|
||||||
|
gboolean only_dirty,
|
||||||
const NMPObject **out_obj_old)
|
const NMPObject **out_obj_old)
|
||||||
{
|
{
|
||||||
const NMDedupMultiEntry *entry_old;
|
const NMDedupMultiEntry *entry_old;
|
||||||
@@ -1983,6 +1945,11 @@ nmp_cache_remove (NMPCache *cache,
|
|||||||
* @obj_needle. */
|
* @obj_needle. */
|
||||||
return NMP_CACHE_OPS_UNCHANGED;
|
return NMP_CACHE_OPS_UNCHANGED;
|
||||||
}
|
}
|
||||||
|
if ( only_dirty
|
||||||
|
&& !entry_old->dirty) {
|
||||||
|
/* the entry is not dirty. Skip. */
|
||||||
|
return NMP_CACHE_OPS_UNCHANGED;
|
||||||
|
}
|
||||||
_idxcache_update (cache, entry_old, NULL, FALSE, NULL);
|
_idxcache_update (cache, entry_old, NULL, FALSE, NULL);
|
||||||
return NMP_CACHE_OPS_REMOVED;
|
return NMP_CACHE_OPS_REMOVED;
|
||||||
}
|
}
|
||||||
@@ -2193,6 +2160,164 @@ nmp_cache_update_netlink (NMPCache *cache,
|
|||||||
return NMP_CACHE_OPS_UPDATED;
|
return NMP_CACHE_OPS_UPDATED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NMPCacheOpsType
|
||||||
|
nmp_cache_update_netlink_route (NMPCache *cache,
|
||||||
|
NMPObject *obj_hand_over,
|
||||||
|
gboolean is_dump,
|
||||||
|
guint16 nlmsgflags,
|
||||||
|
const NMPObject **out_obj_old,
|
||||||
|
const NMPObject **out_obj_new,
|
||||||
|
const NMPObject **out_obj_replace,
|
||||||
|
gboolean *out_resync_required)
|
||||||
|
{
|
||||||
|
NMDedupMultiIter iter;
|
||||||
|
const NMDedupMultiEntry *entry_old;
|
||||||
|
const NMDedupMultiEntry *entry_new;
|
||||||
|
const NMDedupMultiEntry *entry_cur;
|
||||||
|
const NMDedupMultiEntry *entry_replace;
|
||||||
|
const NMDedupMultiHeadEntry *head_entry;
|
||||||
|
gboolean is_alive;
|
||||||
|
NMPCacheOpsType ops_type = NMP_CACHE_OPS_UNCHANGED;
|
||||||
|
gboolean resync_required;
|
||||||
|
|
||||||
|
nm_assert (cache);
|
||||||
|
nm_assert (NMP_OBJECT_IS_VALID (obj_hand_over));
|
||||||
|
nm_assert (!NMP_OBJECT_IS_STACKINIT (obj_hand_over));
|
||||||
|
/* A link object from netlink must have the udev related fields unset.
|
||||||
|
* We could implement to handle that, but there is no need to support such
|
||||||
|
* a use-case */
|
||||||
|
nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_hand_over), NMP_OBJECT_TYPE_IP4_ROUTE,
|
||||||
|
NMP_OBJECT_TYPE_IP6_ROUTE));
|
||||||
|
nm_assert (nm_dedup_multi_index_obj_find (cache->multi_idx, obj_hand_over) != obj_hand_over);
|
||||||
|
|
||||||
|
entry_old = _lookup_entry (cache, obj_hand_over);
|
||||||
|
entry_new = NULL;
|
||||||
|
|
||||||
|
if (!entry_old) {
|
||||||
|
|
||||||
|
if (!nmp_object_is_alive (obj_hand_over))
|
||||||
|
goto update_done;
|
||||||
|
|
||||||
|
_idxcache_update (cache,
|
||||||
|
entry_old,
|
||||||
|
obj_hand_over,
|
||||||
|
is_dump,
|
||||||
|
&entry_new);
|
||||||
|
ops_type = NMP_CACHE_OPS_ADDED;
|
||||||
|
goto update_done;
|
||||||
|
}
|
||||||
|
|
||||||
|
is_alive = nmp_object_is_alive (obj_hand_over);
|
||||||
|
|
||||||
|
if (!is_alive) {
|
||||||
|
/* the update would make @entry_old invalid. Remove it. */
|
||||||
|
_idxcache_update (cache, entry_old, NULL, FALSE, NULL);
|
||||||
|
ops_type = NMP_CACHE_OPS_REMOVED;
|
||||||
|
goto update_done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nmp_object_equal (entry_old->obj, obj_hand_over)) {
|
||||||
|
nm_dedup_multi_entry_set_dirty (entry_old, FALSE);
|
||||||
|
goto update_done;
|
||||||
|
}
|
||||||
|
|
||||||
|
_idxcache_update (cache,
|
||||||
|
entry_old,
|
||||||
|
obj_hand_over,
|
||||||
|
is_dump,
|
||||||
|
&entry_new);
|
||||||
|
ops_type = NMP_CACHE_OPS_UPDATED;
|
||||||
|
|
||||||
|
update_done:
|
||||||
|
NM_SET_OUT (out_obj_old, nmp_object_ref (nm_dedup_multi_entry_get_obj (entry_old)));
|
||||||
|
NM_SET_OUT (out_obj_new, nmp_object_ref (nm_dedup_multi_entry_get_obj (entry_new)));
|
||||||
|
|
||||||
|
/* a RTM_GETROUTE event may signal that another object was replaced.
|
||||||
|
* Find out whether that is the case and return it as @obj_replaced.
|
||||||
|
*
|
||||||
|
* Also, fixup the order of @entry_new within NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID
|
||||||
|
* index. For most parts, we don't care about the order of objects (including routes).
|
||||||
|
* But NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID we must keep in the correct order, to
|
||||||
|
* properly find @obj_replaced. */
|
||||||
|
resync_required = FALSE;
|
||||||
|
entry_replace = NULL;
|
||||||
|
if (is_dump) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entry_new) {
|
||||||
|
if ( NM_FLAGS_HAS (nlmsgflags, NLM_F_REPLACE)
|
||||||
|
&& nmp_cache_lookup_all (cache,
|
||||||
|
NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID,
|
||||||
|
obj_hand_over)) {
|
||||||
|
/* hm. @obj_hand_over was not added, meaning it was not alive.
|
||||||
|
* However, we track some other objects with the same weak-id.
|
||||||
|
* It's unclear what that means. To be sure, resync. */
|
||||||
|
resync_required = TRUE;
|
||||||
|
}
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry_cur = _lookup_entry_with_idx_type (cache,
|
||||||
|
NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID,
|
||||||
|
entry_new->obj);
|
||||||
|
if (!entry_cur) {
|
||||||
|
nm_assert_not_reached ();
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
nm_assert (entry_cur->obj == entry_new->obj);
|
||||||
|
|
||||||
|
head_entry = entry_cur->head;
|
||||||
|
nm_assert (head_entry == nmp_cache_lookup_all (cache,
|
||||||
|
NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID,
|
||||||
|
entry_cur->obj));
|
||||||
|
|
||||||
|
if (head_entry->len == 1) {
|
||||||
|
/* there is only one object, and we expect it to be @obj_new. */
|
||||||
|
nm_assert (nm_dedup_multi_head_entry_get_idx (head_entry, 0) == entry_cur);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (nlmsgflags & (NLM_F_REPLACE | NLM_F_EXCL | NLM_F_CREATE | NLM_F_APPEND)) {
|
||||||
|
case NLM_F_REPLACE:
|
||||||
|
/* ip route change */
|
||||||
|
|
||||||
|
/* get the first element (but skip @obj_new). */
|
||||||
|
nm_dedup_multi_iter_init (&iter, head_entry);
|
||||||
|
if (!nm_dedup_multi_iter_next (&iter))
|
||||||
|
nm_assert_not_reached ();
|
||||||
|
if (iter.current == entry_cur) {
|
||||||
|
if (!nm_dedup_multi_iter_next (&iter))
|
||||||
|
nm_assert_not_reached ();
|
||||||
|
}
|
||||||
|
entry_replace = iter.current;
|
||||||
|
|
||||||
|
nm_assert ( entry_replace
|
||||||
|
&& entry_cur != entry_replace);
|
||||||
|
|
||||||
|
nm_dedup_multi_entry_reorder (entry_cur, entry_replace, FALSE);
|
||||||
|
break;
|
||||||
|
case NLM_F_CREATE | NLM_F_APPEND:
|
||||||
|
/* ip route append */
|
||||||
|
nm_dedup_multi_entry_reorder (entry_cur, NULL, TRUE);
|
||||||
|
break;
|
||||||
|
case NLM_F_CREATE:
|
||||||
|
/* ip route prepend */
|
||||||
|
nm_dedup_multi_entry_reorder (entry_cur, NULL, FALSE);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* this is an unexecpted case, probably a bug that we need to handle better. */
|
||||||
|
resync_required = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
NM_SET_OUT (out_obj_replace, nmp_object_ref (nm_dedup_multi_entry_get_obj (entry_replace)));
|
||||||
|
NM_SET_OUT (out_resync_required, resync_required);
|
||||||
|
return ops_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
NMPCacheOpsType
|
NMPCacheOpsType
|
||||||
nmp_cache_update_link_udev (NMPCache *cache,
|
nmp_cache_update_link_udev (NMPCache *cache,
|
||||||
int ifindex,
|
int ifindex,
|
||||||
@@ -2436,7 +2561,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
|
|||||||
.cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip4_route,
|
.cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip4_route,
|
||||||
.cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_ip4_route,
|
.cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_ip4_route,
|
||||||
.cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_ip4_route,
|
.cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_ip4_route,
|
||||||
.cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_ip4_route,
|
.cmd_plobj_to_string_id = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_ip4_route_to_string,
|
||||||
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_ip4_route_to_string,
|
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_ip4_route_to_string,
|
||||||
.cmd_plobj_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_ip4_route_hash_full,
|
.cmd_plobj_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_ip4_route_hash_full,
|
||||||
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip4_route_cmp_full,
|
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip4_route_cmp_full,
|
||||||
@@ -2456,7 +2581,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
|
|||||||
.cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip6_route,
|
.cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip6_route,
|
||||||
.cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_ip6_route,
|
.cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_ip6_route,
|
||||||
.cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_ip6_route,
|
.cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_ip6_route,
|
||||||
.cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_ip6_route,
|
.cmd_plobj_to_string_id = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_ip6_route_to_string,
|
||||||
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_ip6_route_to_string,
|
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_ip6_route_to_string,
|
||||||
.cmd_plobj_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_ip6_route_hash_full,
|
.cmd_plobj_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_ip6_route_hash_full,
|
||||||
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip6_route_cmp_full,
|
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip6_route_cmp_full,
|
||||||
|
@@ -93,7 +93,7 @@ typedef enum { /*< skip >*/
|
|||||||
* sends one RTM_NEWADDR notification without notifying about the deletion. We detect
|
* sends one RTM_NEWADDR notification without notifying about the deletion. We detect
|
||||||
* that by having this index to contain overlapping routes which require special
|
* that by having this index to contain overlapping routes which require special
|
||||||
* cache-resync. */
|
* cache-resync. */
|
||||||
NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION,
|
NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID,
|
||||||
|
|
||||||
__NMP_CACHE_ID_TYPE_MAX,
|
__NMP_CACHE_ID_TYPE_MAX,
|
||||||
NMP_CACHE_ID_TYPE_MAX = __NMP_CACHE_ID_TYPE_MAX - 1,
|
NMP_CACHE_ID_TYPE_MAX = __NMP_CACHE_ID_TYPE_MAX - 1,
|
||||||
@@ -452,8 +452,6 @@ const NMPObject *nmp_object_stackinit_id (NMPObject *obj, const NMPObject *src)
|
|||||||
const NMPObject *nmp_object_stackinit_id_link (NMPObject *obj, int ifindex);
|
const NMPObject *nmp_object_stackinit_id_link (NMPObject *obj, int ifindex);
|
||||||
const NMPObject *nmp_object_stackinit_id_ip4_address (NMPObject *obj, int ifindex, guint32 address, guint8 plen, guint32 peer_address);
|
const NMPObject *nmp_object_stackinit_id_ip4_address (NMPObject *obj, int ifindex, guint32 address, guint8 plen, guint32 peer_address);
|
||||||
const NMPObject *nmp_object_stackinit_id_ip6_address (NMPObject *obj, int ifindex, const struct in6_addr *address);
|
const NMPObject *nmp_object_stackinit_id_ip6_address (NMPObject *obj, int ifindex, const struct in6_addr *address);
|
||||||
const NMPObject *nmp_object_stackinit_id_ip4_route (NMPObject *obj, int ifindex, guint32 network, guint8 plen, guint32 metric);
|
|
||||||
const NMPObject *nmp_object_stackinit_id_ip6_route (NMPObject *obj, int ifindex, const struct in6_addr *network, guint8 plen, guint32 metric);
|
|
||||||
|
|
||||||
const char *nmp_object_to_string (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size);
|
const char *nmp_object_to_string (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size);
|
||||||
guint nmp_object_hash (const NMPObject *obj);
|
guint nmp_object_hash (const NMPObject *obj);
|
||||||
@@ -529,11 +527,19 @@ const NMPLookup *nmp_lookup_init_route_visible (NMPLookup *lookup,
|
|||||||
NMPObjectType obj_type,
|
NMPObjectType obj_type,
|
||||||
int ifindex,
|
int ifindex,
|
||||||
gboolean only_default);
|
gboolean only_default);
|
||||||
const NMPLookup *nmp_lookup_init_route_by_dest (NMPLookup *lookup,
|
const NMPLookup *nmp_lookup_init_route_by_weak_id (NMPLookup *lookup,
|
||||||
int addr_family,
|
const NMPObject *obj);
|
||||||
gconstpointer network,
|
const NMPLookup *nmp_lookup_init_ip4_route_by_weak_id (NMPLookup *lookup,
|
||||||
guint plen,
|
in_addr_t network,
|
||||||
guint32 metric);
|
guint plen,
|
||||||
|
guint32 metric,
|
||||||
|
guint8 tos);
|
||||||
|
const NMPLookup *nmp_lookup_init_ip6_route_by_weak_id (NMPLookup *lookup,
|
||||||
|
const struct in6_addr *network,
|
||||||
|
guint plen,
|
||||||
|
guint32 metric,
|
||||||
|
const struct in6_addr *src,
|
||||||
|
guint8 src_plen);
|
||||||
|
|
||||||
GArray *nmp_cache_lookup_to_array (const NMDedupMultiHeadEntry *head_entry,
|
GArray *nmp_cache_lookup_to_array (const NMDedupMultiHeadEntry *head_entry,
|
||||||
NMPObjectType obj_type,
|
NMPObjectType obj_type,
|
||||||
@@ -577,8 +583,6 @@ nmp_cache_iter_next_link (NMDedupMultiIter *iter, const NMPlatformLink **out_obj
|
|||||||
nmp_cache_iter_next_link ((iter), (obj)); \
|
nmp_cache_iter_next_link ((iter), (obj)); \
|
||||||
)
|
)
|
||||||
|
|
||||||
const NMPObject *nmp_cache_find_other_route_for_same_destination (const NMPCache *cache, const NMPObject *route);
|
|
||||||
|
|
||||||
const NMPObject *nmp_cache_lookup_link_full (const NMPCache *cache,
|
const NMPObject *nmp_cache_lookup_link_full (const NMPCache *cache,
|
||||||
int ifindex,
|
int ifindex,
|
||||||
const char *ifname,
|
const char *ifname,
|
||||||
@@ -598,6 +602,7 @@ void ASSERT_nmp_cache_is_consistent (const NMPCache *cache);
|
|||||||
NMPCacheOpsType nmp_cache_remove (NMPCache *cache,
|
NMPCacheOpsType nmp_cache_remove (NMPCache *cache,
|
||||||
const NMPObject *obj_needle,
|
const NMPObject *obj_needle,
|
||||||
gboolean equals_by_ptr,
|
gboolean equals_by_ptr,
|
||||||
|
gboolean only_dirty,
|
||||||
const NMPObject **out_obj_old);
|
const NMPObject **out_obj_old);
|
||||||
NMPCacheOpsType nmp_cache_remove_netlink (NMPCache *cache,
|
NMPCacheOpsType nmp_cache_remove_netlink (NMPCache *cache,
|
||||||
const NMPObject *obj_needle,
|
const NMPObject *obj_needle,
|
||||||
@@ -608,6 +613,14 @@ NMPCacheOpsType nmp_cache_update_netlink (NMPCache *cache,
|
|||||||
gboolean is_dump,
|
gboolean is_dump,
|
||||||
const NMPObject **out_obj_old,
|
const NMPObject **out_obj_old,
|
||||||
const NMPObject **out_obj_new);
|
const NMPObject **out_obj_new);
|
||||||
|
NMPCacheOpsType nmp_cache_update_netlink_route (NMPCache *cache,
|
||||||
|
NMPObject *obj_hand_over,
|
||||||
|
gboolean is_dump,
|
||||||
|
guint16 nlmsgflags,
|
||||||
|
const NMPObject **out_obj_old,
|
||||||
|
const NMPObject **out_obj_new,
|
||||||
|
const NMPObject **out_obj_replace,
|
||||||
|
gboolean *out_resync_required);
|
||||||
NMPCacheOpsType nmp_cache_update_link_udev (NMPCache *cache,
|
NMPCacheOpsType nmp_cache_update_link_udev (NMPCache *cache,
|
||||||
int ifindex,
|
int ifindex,
|
||||||
struct udev_device *udevice,
|
struct udev_device *udevice,
|
||||||
@@ -663,6 +676,14 @@ ASSERT_nmp_cache_ops (const NMPCache *cache,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const NMDedupMultiHeadEntry *nm_platform_lookup_all (NMPlatform *platform,
|
||||||
|
NMPCacheIdType cache_id_type,
|
||||||
|
NMPObject *obj);
|
||||||
|
|
||||||
|
const NMDedupMultiEntry *nm_platform_lookup_entry (NMPlatform *platform,
|
||||||
|
NMPCacheIdType cache_id_type,
|
||||||
|
NMPObject *obj);
|
||||||
|
|
||||||
static inline const NMDedupMultiHeadEntry *
|
static inline const NMDedupMultiHeadEntry *
|
||||||
nm_platform_lookup_obj_type (NMPlatform *platform,
|
nm_platform_lookup_obj_type (NMPlatform *platform,
|
||||||
NMPObjectType obj_type)
|
NMPObjectType obj_type)
|
||||||
@@ -721,15 +742,29 @@ nm_platform_lookup_route_visible_clone (NMPlatform *platform,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline const NMDedupMultiHeadEntry *
|
static inline const NMDedupMultiHeadEntry *
|
||||||
nm_platform_lookup_route_by_dest (NMPlatform *platform,
|
nm_platform_lookup_ip4_route_by_weak_id (NMPlatform *platform,
|
||||||
int addr_family,
|
in_addr_t network,
|
||||||
gconstpointer network,
|
guint plen,
|
||||||
guint plen,
|
guint32 metric,
|
||||||
guint32 metric)
|
guint8 tos)
|
||||||
{
|
{
|
||||||
NMPLookup lookup;
|
NMPLookup lookup;
|
||||||
|
|
||||||
nmp_lookup_init_route_by_dest (&lookup, addr_family, network, plen, metric);
|
nmp_lookup_init_ip4_route_by_weak_id (&lookup, network, plen, metric, tos);
|
||||||
|
return nm_platform_lookup (platform, &lookup);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const NMDedupMultiHeadEntry *
|
||||||
|
nm_platform_lookup_ip6_route_by_weak_id (NMPlatform *platform,
|
||||||
|
const struct in6_addr *network,
|
||||||
|
guint plen,
|
||||||
|
guint32 metric,
|
||||||
|
const struct in6_addr *src,
|
||||||
|
guint8 src_plen)
|
||||||
|
{
|
||||||
|
NMPLookup lookup;
|
||||||
|
|
||||||
|
nmp_lookup_init_ip6_route_by_weak_id (&lookup, network, plen, metric, src, src_plen);
|
||||||
return nm_platform_lookup (platform, &lookup);
|
return nm_platform_lookup (platform, &lookup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -294,113 +294,219 @@ link_callback (NMPlatform *platform, int obj_type_i, int ifindex, NMPlatformLink
|
|||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
gboolean
|
static const NMPlatformIP4Route *
|
||||||
nmtstp_ip4_route_exists (const char *ifname, guint32 network, int plen, guint32 metric)
|
_ip4_route_get (NMPlatform *platform,
|
||||||
|
int ifindex,
|
||||||
|
guint32 network,
|
||||||
|
int plen,
|
||||||
|
guint32 metric,
|
||||||
|
guint8 tos,
|
||||||
|
guint *out_c_exists)
|
||||||
{
|
{
|
||||||
gs_free char *arg_network = NULL;
|
NMDedupMultiIter iter;
|
||||||
const char *argv[] = {
|
NMPLookup lookup;
|
||||||
NULL,
|
const NMPObject *o;
|
||||||
"route",
|
guint c;
|
||||||
"list",
|
const NMPlatformIP4Route *r = NULL;
|
||||||
"dev",
|
|
||||||
ifname,
|
|
||||||
"exact",
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
int exit_status;
|
|
||||||
gs_free char *std_out = NULL, *std_err = NULL;
|
|
||||||
char *out;
|
|
||||||
gboolean success;
|
|
||||||
gs_free_error GError *error = NULL;
|
|
||||||
gs_free char *metric_pattern = NULL;
|
|
||||||
|
|
||||||
g_assert (ifname && nm_utils_is_valid_iface_name (ifname, NULL));
|
|
||||||
g_assert (!strstr (ifname, " metric "));
|
|
||||||
g_assert (plen >= 0 && plen <= 32);
|
|
||||||
|
|
||||||
if (!nmtstp_is_root_test ()) {
|
|
||||||
/* If we don't test against linux-platform, we don't actually configure any
|
|
||||||
* routes in the system. */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
argv[0] = nm_utils_file_search_in_paths ("ip", NULL,
|
|
||||||
(const char *[]) { "/sbin", "/usr/sbin", NULL },
|
|
||||||
G_FILE_TEST_IS_EXECUTABLE, NULL, NULL, NULL);
|
|
||||||
argv[6] = arg_network = g_strdup_printf ("%s/%d", nm_utils_inet4_ntop (network, NULL), plen);
|
|
||||||
|
|
||||||
if (!argv[0]) {
|
|
||||||
/* Hm. There is no 'ip' binary. Return *unknown* */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
success = g_spawn_sync (NULL,
|
|
||||||
(char **) argv,
|
|
||||||
(char *[]) { NULL },
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
&std_out,
|
|
||||||
&std_err,
|
|
||||||
&exit_status,
|
|
||||||
&error);
|
|
||||||
g_assert_no_error (error);
|
|
||||||
g_assert (success);
|
|
||||||
g_assert_cmpstr (std_err, ==, "");
|
|
||||||
g_assert (std_out);
|
|
||||||
|
|
||||||
metric_pattern = g_strdup_printf (" metric %u", metric);
|
|
||||||
out = std_out;
|
|
||||||
while (out) {
|
|
||||||
char *eol = strchr (out, '\n');
|
|
||||||
gs_free char *line = eol ? g_strndup (out, eol - out) : g_strdup (out);
|
|
||||||
const char *p;
|
|
||||||
|
|
||||||
out = eol ? &eol[1] : NULL;
|
|
||||||
if (!line[0])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (metric == 0) {
|
|
||||||
if (!strstr (line, " metric "))
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
p = strstr (line, metric_pattern);
|
|
||||||
if (p && NM_IN_SET (p[strlen (metric_pattern)], ' ', '\0'))
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
_nmtstp_assert_ip4_route_exists (const char *file, guint line, const char *func, NMPlatform *platform, gboolean exists, const char *ifname, guint32 network, int plen, guint32 metric)
|
|
||||||
{
|
|
||||||
int ifindex;
|
|
||||||
gboolean exists_checked;
|
|
||||||
|
|
||||||
_init_platform (&platform, FALSE);
|
_init_platform (&platform, FALSE);
|
||||||
|
|
||||||
/* Check for existance of the route by spawning iproute2. Do this because platform
|
nmp_lookup_init_ip4_route_by_weak_id (&lookup,
|
||||||
* code might be entirely borked, but we expect ip-route to give a correct result.
|
network,
|
||||||
* If the ip command cannot be found, we accept this as success. */
|
plen,
|
||||||
exists_checked = nmtstp_ip4_route_exists (ifname, network, plen, metric);
|
metric,
|
||||||
if (exists_checked != -1 && !exists_checked != !exists) {
|
tos);
|
||||||
g_error ("[%s:%u] %s(): We expect the ip4 route %s/%d metric %u %s, but it %s",
|
|
||||||
file, line, func,
|
c = 0;
|
||||||
nm_utils_inet4_ntop (network, NULL), plen, metric,
|
nmp_cache_iter_for_each (&iter,
|
||||||
exists ? "to exist" : "not to exist",
|
nm_platform_lookup (platform, &lookup),
|
||||||
exists ? "doesn't" : "does");
|
&o) {
|
||||||
|
if ( NMP_OBJECT_CAST_IP4_ROUTE (o)->ifindex != ifindex
|
||||||
|
&& ifindex > 0)
|
||||||
|
continue;
|
||||||
|
if (!r)
|
||||||
|
r = NMP_OBJECT_CAST_IP4_ROUTE (o);
|
||||||
|
c++;
|
||||||
}
|
}
|
||||||
|
|
||||||
ifindex = nm_platform_link_get_ifindex (platform, ifname);
|
NM_SET_OUT (out_c_exists, c);
|
||||||
g_assert (ifindex > 0);
|
return r;
|
||||||
if (!nm_platform_ip4_route_get (platform, ifindex, network, plen, metric) != !exists) {
|
}
|
||||||
g_error ("[%s:%u] %s(): The ip4 route %s/%d metric %u %s, but platform thinks %s",
|
|
||||||
file, line, func,
|
const NMPlatformIP4Route *
|
||||||
nm_utils_inet4_ntop (network, NULL), plen, metric,
|
_nmtstp_assert_ip4_route_exists (const char *file,
|
||||||
exists ? "exists" : "does not exist",
|
guint line,
|
||||||
exists ? "it doesn't" : "it does");
|
const char *func,
|
||||||
|
NMPlatform *platform,
|
||||||
|
int c_exists,
|
||||||
|
const char *ifname,
|
||||||
|
guint32 network,
|
||||||
|
int plen,
|
||||||
|
guint32 metric,
|
||||||
|
guint8 tos)
|
||||||
|
{
|
||||||
|
int ifindex;
|
||||||
|
guint c;
|
||||||
|
const NMPlatformIP4Route *r = NULL;
|
||||||
|
|
||||||
|
_init_platform (&platform, FALSE);
|
||||||
|
|
||||||
|
ifindex = -1;
|
||||||
|
if (ifname) {
|
||||||
|
ifindex = nm_platform_link_get_ifindex (platform, ifname);
|
||||||
|
g_assert (ifindex > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r = _ip4_route_get (platform,
|
||||||
|
ifindex,
|
||||||
|
network,
|
||||||
|
plen,
|
||||||
|
metric,
|
||||||
|
tos,
|
||||||
|
&c);
|
||||||
|
|
||||||
|
if (c != c_exists && c_exists != -1) {
|
||||||
|
g_error ("[%s:%u] %s(): The ip4 route %s/%d metric %u tos %u shall exist %u times, but platform has it %u times",
|
||||||
|
file, line, func,
|
||||||
|
nm_utils_inet4_ntop (network, NULL), plen,
|
||||||
|
metric,
|
||||||
|
tos,
|
||||||
|
c_exists,
|
||||||
|
c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NMPlatformIP4Route *
|
||||||
|
nmtstp_ip4_route_get (NMPlatform *platform,
|
||||||
|
int ifindex,
|
||||||
|
guint32 network,
|
||||||
|
int plen,
|
||||||
|
guint32 metric,
|
||||||
|
guint8 tos)
|
||||||
|
{
|
||||||
|
return _ip4_route_get (platform,
|
||||||
|
ifindex,
|
||||||
|
network,
|
||||||
|
plen,
|
||||||
|
metric,
|
||||||
|
tos,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
static const NMPlatformIP6Route *
|
||||||
|
_ip6_route_get (NMPlatform *platform,
|
||||||
|
int ifindex,
|
||||||
|
const struct in6_addr *network,
|
||||||
|
guint plen,
|
||||||
|
guint32 metric,
|
||||||
|
const struct in6_addr *src,
|
||||||
|
guint8 src_plen,
|
||||||
|
guint *out_c_exists)
|
||||||
|
{
|
||||||
|
NMDedupMultiIter iter;
|
||||||
|
NMPLookup lookup;
|
||||||
|
const NMPObject *o;
|
||||||
|
guint c;
|
||||||
|
const NMPlatformIP6Route *r = NULL;
|
||||||
|
|
||||||
|
_init_platform (&platform, FALSE);
|
||||||
|
|
||||||
|
nmp_lookup_init_ip6_route_by_weak_id (&lookup,
|
||||||
|
network,
|
||||||
|
plen,
|
||||||
|
metric,
|
||||||
|
src,
|
||||||
|
src_plen);
|
||||||
|
|
||||||
|
c = 0;
|
||||||
|
nmp_cache_iter_for_each (&iter,
|
||||||
|
nm_platform_lookup (platform, &lookup),
|
||||||
|
&o) {
|
||||||
|
if ( NMP_OBJECT_CAST_IP6_ROUTE (o)->ifindex != ifindex
|
||||||
|
&& ifindex > 0)
|
||||||
|
continue;
|
||||||
|
if (!r)
|
||||||
|
r = NMP_OBJECT_CAST_IP6_ROUTE (o);
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
|
||||||
|
NM_SET_OUT (out_c_exists, c);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NMPlatformIP6Route *
|
||||||
|
_nmtstp_assert_ip6_route_exists (const char *file,
|
||||||
|
guint line,
|
||||||
|
const char *func,
|
||||||
|
NMPlatform *platform,
|
||||||
|
int c_exists,
|
||||||
|
const char *ifname,
|
||||||
|
const struct in6_addr *network,
|
||||||
|
guint plen,
|
||||||
|
guint32 metric,
|
||||||
|
const struct in6_addr *src,
|
||||||
|
guint8 src_plen)
|
||||||
|
{
|
||||||
|
int ifindex;
|
||||||
|
guint c;
|
||||||
|
const NMPlatformIP6Route *r = NULL;
|
||||||
|
|
||||||
|
_init_platform (&platform, FALSE);
|
||||||
|
|
||||||
|
ifindex = -1;
|
||||||
|
if (ifname) {
|
||||||
|
ifindex = nm_platform_link_get_ifindex (platform, ifname);
|
||||||
|
g_assert (ifindex > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = _ip6_route_get (platform,
|
||||||
|
ifindex,
|
||||||
|
network,
|
||||||
|
plen,
|
||||||
|
metric,
|
||||||
|
src,
|
||||||
|
src_plen,
|
||||||
|
&c);
|
||||||
|
|
||||||
|
if (c != c_exists && c_exists != -1) {
|
||||||
|
char s_src[NM_UTILS_INET_ADDRSTRLEN];
|
||||||
|
char s_network[NM_UTILS_INET_ADDRSTRLEN];
|
||||||
|
|
||||||
|
g_error ("[%s:%u] %s(): The ip6 route %s/%d metric %u src %s/%d shall exist %u times, but platform has it %u times",
|
||||||
|
file, line, func,
|
||||||
|
nm_utils_inet6_ntop (network, s_network),
|
||||||
|
plen,
|
||||||
|
metric,
|
||||||
|
nm_utils_inet6_ntop (src, s_src),
|
||||||
|
src_plen,
|
||||||
|
c_exists,
|
||||||
|
c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NMPlatformIP6Route *
|
||||||
|
nmtstp_ip6_route_get (NMPlatform *platform,
|
||||||
|
int ifindex,
|
||||||
|
const struct in6_addr *network,
|
||||||
|
guint plen,
|
||||||
|
guint32 metric,
|
||||||
|
const struct in6_addr *src,
|
||||||
|
guint8 src_plen)
|
||||||
|
{
|
||||||
|
return _ip6_route_get (platform,
|
||||||
|
ifindex,
|
||||||
|
network,
|
||||||
|
plen,
|
||||||
|
metric,
|
||||||
|
src,
|
||||||
|
src_plen,
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@@ -121,10 +121,45 @@ gboolean nmtstp_run_command_check_external (int external_command);
|
|||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
gboolean nmtstp_ip4_route_exists (const char *ifname, guint32 network, int plen, guint32 metric);
|
const NMPlatformIP4Route *_nmtstp_assert_ip4_route_exists (const char *file,
|
||||||
|
guint line,
|
||||||
|
const char *func,
|
||||||
|
NMPlatform *platform,
|
||||||
|
int c_exists,
|
||||||
|
const char *ifname,
|
||||||
|
guint32 network,
|
||||||
|
int plen,
|
||||||
|
guint32 metric,
|
||||||
|
guint8 tos);
|
||||||
|
#define nmtstp_assert_ip4_route_exists(platform, c_exists, ifname, network, plen, metric, tos) _nmtstp_assert_ip4_route_exists (__FILE__, __LINE__, G_STRFUNC, platform, c_exists, ifname, network, plen, metric, tos)
|
||||||
|
|
||||||
void _nmtstp_assert_ip4_route_exists (const char *file, guint line, const char *func, NMPlatform *platform, gboolean exists, const char *ifname, guint32 network, int plen, guint32 metric);
|
const NMPlatformIP4Route *nmtstp_ip4_route_get (NMPlatform *platform,
|
||||||
#define nmtstp_assert_ip4_route_exists(platform, exists, ifname, network, plen, metric) _nmtstp_assert_ip4_route_exists (__FILE__, __LINE__, G_STRFUNC, platform, exists, ifname, network, plen, metric)
|
int ifindex,
|
||||||
|
guint32 network,
|
||||||
|
int plen,
|
||||||
|
guint32 metric,
|
||||||
|
guint8 tos);
|
||||||
|
|
||||||
|
const NMPlatformIP6Route *_nmtstp_assert_ip6_route_exists (const char *file,
|
||||||
|
guint line,
|
||||||
|
const char *func,
|
||||||
|
NMPlatform *platform,
|
||||||
|
int c_exists,
|
||||||
|
const char *ifname,
|
||||||
|
const struct in6_addr *network,
|
||||||
|
guint plen,
|
||||||
|
guint32 metric,
|
||||||
|
const struct in6_addr *src,
|
||||||
|
guint8 src_plen);
|
||||||
|
#define nmtstp_assert_ip6_route_exists(platform, c_exists, ifname, network, plen, metric, src, src_plen) _nmtstp_assert_ip6_route_exists (__FILE__, __LINE__, G_STRFUNC, platform, c_exists, ifname, network, plen, metric, src, src_plen)
|
||||||
|
|
||||||
|
const NMPlatformIP6Route *nmtstp_ip6_route_get (NMPlatform *platform,
|
||||||
|
int ifindex,
|
||||||
|
const struct in6_addr *network,
|
||||||
|
guint plen,
|
||||||
|
guint32 metric,
|
||||||
|
const struct in6_addr *src,
|
||||||
|
guint8 src_plen);
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
@@ -139,50 +139,50 @@ test_ip4_route_metric0 (void)
|
|||||||
int mss = 1000;
|
int mss = 1000;
|
||||||
|
|
||||||
/* No routes initially */
|
/* No routes initially */
|
||||||
nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0);
|
nmtstp_assert_ip4_route_exists (NULL, 0, DEVICE_NAME, network, plen, 0, 0);
|
||||||
nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, metric);
|
nmtstp_assert_ip4_route_exists (NULL, 0, DEVICE_NAME, network, plen, metric, 0);
|
||||||
|
|
||||||
/* add the first route */
|
/* add the first route */
|
||||||
nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, metric, mss);
|
nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, metric, mss);
|
||||||
accept_signal (route_added);
|
accept_signal (route_added);
|
||||||
|
|
||||||
nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0);
|
nmtstp_assert_ip4_route_exists (NULL, 0, DEVICE_NAME, network, plen, 0, 0);
|
||||||
nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric);
|
nmtstp_assert_ip4_route_exists (NULL, 1, DEVICE_NAME, network, plen, metric, 0);
|
||||||
|
|
||||||
/* Deleting route with metric 0 does nothing */
|
/* Deleting route with metric 0 does nothing */
|
||||||
g_assert (nmtstp_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, 0));
|
g_assert (nmtstp_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, 0));
|
||||||
ensure_no_signal (route_removed);
|
ensure_no_signal (route_removed);
|
||||||
|
|
||||||
nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0);
|
nmtstp_assert_ip4_route_exists (NULL, 0, DEVICE_NAME, network, plen, 0, 0);
|
||||||
nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric);
|
nmtstp_assert_ip4_route_exists (NULL, 1, DEVICE_NAME, network, plen, metric, 0);
|
||||||
|
|
||||||
/* add the second route */
|
/* add the second route */
|
||||||
nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, 0, mss);
|
nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, 0, mss);
|
||||||
accept_signal (route_added);
|
accept_signal (route_added);
|
||||||
|
|
||||||
nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, 0);
|
nmtstp_assert_ip4_route_exists (NULL, 1, DEVICE_NAME, network, plen, 0, 0);
|
||||||
nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric);
|
nmtstp_assert_ip4_route_exists (NULL, 1, DEVICE_NAME, network, plen, metric, 0);
|
||||||
|
|
||||||
/* Delete route with metric 0 */
|
/* Delete route with metric 0 */
|
||||||
g_assert (nmtstp_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, 0));
|
g_assert (nmtstp_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, 0));
|
||||||
accept_signal (route_removed);
|
accept_signal (route_removed);
|
||||||
|
|
||||||
nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0);
|
nmtstp_assert_ip4_route_exists (NULL, 0, DEVICE_NAME, network, plen, 0, 0);
|
||||||
nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric);
|
nmtstp_assert_ip4_route_exists (NULL, 1, DEVICE_NAME, network, plen, metric, 0);
|
||||||
|
|
||||||
/* Delete route with metric 0 again (we expect nothing to happen) */
|
/* Delete route with metric 0 again (we expect nothing to happen) */
|
||||||
g_assert (nmtstp_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, 0));
|
g_assert (nmtstp_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, 0));
|
||||||
ensure_no_signal (route_removed);
|
ensure_no_signal (route_removed);
|
||||||
|
|
||||||
nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0);
|
nmtstp_assert_ip4_route_exists (NULL, 0, DEVICE_NAME, network, plen, 0, 0);
|
||||||
nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric);
|
nmtstp_assert_ip4_route_exists (NULL, 1, DEVICE_NAME, network, plen, metric, 0);
|
||||||
|
|
||||||
/* Delete the other route */
|
/* Delete the other route */
|
||||||
g_assert (nmtstp_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric));
|
g_assert (nmtstp_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric));
|
||||||
accept_signal (route_removed);
|
accept_signal (route_removed);
|
||||||
|
|
||||||
nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0);
|
nmtstp_assert_ip4_route_exists (NULL, 0, DEVICE_NAME, network, plen, 0, 0);
|
||||||
nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, metric);
|
nmtstp_assert_ip4_route_exists (NULL, 0, DEVICE_NAME, network, plen, metric, 0);
|
||||||
|
|
||||||
free_signal (route_added);
|
free_signal (route_added);
|
||||||
free_signal (route_changed);
|
free_signal (route_changed);
|
||||||
@@ -213,9 +213,9 @@ test_ip4_route (void)
|
|||||||
accept_signal (route_added);
|
accept_signal (route_added);
|
||||||
|
|
||||||
/* Add route */
|
/* Add route */
|
||||||
nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, metric);
|
nmtstp_assert_ip4_route_exists (NULL, 0, DEVICE_NAME, network, plen, metric, 0);
|
||||||
nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, 0, metric, mss);
|
nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, 0, metric, mss);
|
||||||
nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric);
|
nmtstp_assert_ip4_route_exists (NULL, 1, DEVICE_NAME, network, plen, metric, 0);
|
||||||
accept_signal (route_added);
|
accept_signal (route_added);
|
||||||
|
|
||||||
/* Add route again */
|
/* Add route again */
|
||||||
@@ -223,9 +223,9 @@ test_ip4_route (void)
|
|||||||
accept_signals (route_changed, 0, 1);
|
accept_signals (route_changed, 0, 1);
|
||||||
|
|
||||||
/* Add default route */
|
/* Add default route */
|
||||||
nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, 0, 0, metric);
|
nmtstp_assert_ip4_route_exists (NULL, 0, DEVICE_NAME, 0, 0, metric, 0);
|
||||||
nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway, 0, metric, mss);
|
nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway, 0, metric, mss);
|
||||||
nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, 0, 0, metric);
|
nmtstp_assert_ip4_route_exists (NULL, 1, DEVICE_NAME, 0, 0, metric, 0);
|
||||||
accept_signal (route_added);
|
accept_signal (route_added);
|
||||||
|
|
||||||
/* Add default route again */
|
/* Add default route again */
|
||||||
@@ -265,7 +265,7 @@ test_ip4_route (void)
|
|||||||
|
|
||||||
/* Remove route */
|
/* Remove route */
|
||||||
g_assert (nmtstp_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric));
|
g_assert (nmtstp_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric));
|
||||||
nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, metric);
|
nmtstp_assert_ip4_route_exists (NULL, 0, DEVICE_NAME, network, plen, metric, 0);
|
||||||
accept_signal (route_removed);
|
accept_signal (route_removed);
|
||||||
|
|
||||||
/* Remove route again */
|
/* Remove route again */
|
||||||
@@ -315,9 +315,9 @@ test_ip6_route (void)
|
|||||||
accept_signal (route_added);
|
accept_signal (route_added);
|
||||||
|
|
||||||
/* Add route */
|
/* Add route */
|
||||||
g_assert (!nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, network, plen, metric));
|
g_assert (!nmtstp_ip6_route_get (NM_PLATFORM_GET, ifindex, &network, plen, metric, NULL, 0));
|
||||||
nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, pref_src, metric, mss);
|
nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, pref_src, metric, mss);
|
||||||
g_assert (nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, network, plen, metric));
|
g_assert (nmtstp_ip6_route_get (NM_PLATFORM_GET, ifindex, &network, plen, metric, NULL, 0));
|
||||||
accept_signal (route_added);
|
accept_signal (route_added);
|
||||||
|
|
||||||
/* Add route again */
|
/* Add route again */
|
||||||
@@ -325,9 +325,9 @@ test_ip6_route (void)
|
|||||||
accept_signals (route_changed, 0, 1);
|
accept_signals (route_changed, 0, 1);
|
||||||
|
|
||||||
/* Add default route */
|
/* Add default route */
|
||||||
g_assert (!nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, in6addr_any, 0, metric));
|
g_assert (!nmtstp_ip6_route_get (NM_PLATFORM_GET, ifindex, &in6addr_any, 0, metric, NULL, 0));
|
||||||
nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, in6addr_any, metric, mss);
|
nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, in6addr_any, metric, mss);
|
||||||
g_assert (nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, in6addr_any, 0, metric));
|
g_assert (nmtstp_ip6_route_get (NM_PLATFORM_GET, ifindex, &in6addr_any, 0, metric, NULL, 0));
|
||||||
accept_signal (route_added);
|
accept_signal (route_added);
|
||||||
|
|
||||||
/* Add default route again */
|
/* Add default route again */
|
||||||
@@ -367,7 +367,7 @@ test_ip6_route (void)
|
|||||||
|
|
||||||
/* Remove route */
|
/* Remove route */
|
||||||
g_assert (nmtstp_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric));
|
g_assert (nmtstp_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric));
|
||||||
g_assert (!nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, network, plen, metric));
|
g_assert (!nmtstp_ip6_route_get (NM_PLATFORM_GET, ifindex, &network, plen, metric, NULL, 0));
|
||||||
accept_signal (route_removed);
|
accept_signal (route_removed);
|
||||||
|
|
||||||
/* Remove route again */
|
/* Remove route again */
|
||||||
@@ -398,8 +398,8 @@ test_ip4_zero_gateway (void)
|
|||||||
|
|
||||||
NMTST_WAIT_ASSERT (100, {
|
NMTST_WAIT_ASSERT (100, {
|
||||||
nmtstp_wait_for_signal (NM_PLATFORM_GET, 10);
|
nmtstp_wait_for_signal (NM_PLATFORM_GET, 10);
|
||||||
if ( nm_platform_ip4_route_get (NM_PLATFORM_GET, ifindex, nmtst_inet4_from_string ("1.2.3.1"), 32, 0)
|
if ( nmtstp_ip4_route_get (NM_PLATFORM_GET, ifindex, nmtst_inet4_from_string ("1.2.3.1"), 32, 0, 0)
|
||||||
&& nm_platform_ip4_route_get (NM_PLATFORM_GET, ifindex, nmtst_inet4_from_string ("1.2.3.2"), 32, 0))
|
&& nmtstp_ip4_route_get (NM_PLATFORM_GET, ifindex, nmtst_inet4_from_string ("1.2.3.2"), 32, 0, 0))
|
||||||
break;
|
break;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -466,7 +466,7 @@ test_ip6_route_options (gconstpointer test_data)
|
|||||||
const int TEST_IDX = GPOINTER_TO_INT (test_data);
|
const int TEST_IDX = GPOINTER_TO_INT (test_data);
|
||||||
const int IFINDEX = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
|
const int IFINDEX = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
|
||||||
GPtrArray *routes;
|
GPtrArray *routes;
|
||||||
#define RTS_MAX 1
|
#define RTS_MAX 3
|
||||||
NMPlatformIP6Route rts_add[RTS_MAX] = { };
|
NMPlatformIP6Route rts_add[RTS_MAX] = { };
|
||||||
NMPlatformIP6Route rts_cmp[RTS_MAX] = { };
|
NMPlatformIP6Route rts_cmp[RTS_MAX] = { };
|
||||||
NMPlatformIP6Address addr[1] = { };
|
NMPlatformIP6Address addr[1] = { };
|
||||||
@@ -512,6 +512,34 @@ test_ip6_route_options (gconstpointer test_data)
|
|||||||
.pref_src = *nmtst_inet6_from_string ("2000::2"),
|
.pref_src = *nmtst_inet6_from_string ("2000::2"),
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
case 3:
|
||||||
|
addr[addr_n++] = ((NMPlatformIP6Address) {
|
||||||
|
.ifindex = IFINDEX,
|
||||||
|
.address = *nmtst_inet6_from_string ("2001:db8:8086::5"),
|
||||||
|
.plen = 128,
|
||||||
|
.peer_address = in6addr_any,
|
||||||
|
.lifetime = NM_PLATFORM_LIFETIME_PERMANENT,
|
||||||
|
.preferred = NM_PLATFORM_LIFETIME_PERMANENT,
|
||||||
|
.n_ifa_flags = 0,
|
||||||
|
});
|
||||||
|
rts_add[rts_n++] = ((NMPlatformIP6Route) {
|
||||||
|
.ifindex = IFINDEX,
|
||||||
|
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
|
||||||
|
.network = *nmtst_inet6_from_string ("2001:db8:8086::"),
|
||||||
|
.plen = 110,
|
||||||
|
.metric = 10021,
|
||||||
|
.mss = 0,
|
||||||
|
});
|
||||||
|
rts_add[rts_n++] = ((NMPlatformIP6Route) {
|
||||||
|
.ifindex = IFINDEX,
|
||||||
|
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
|
||||||
|
.network = *nmtst_inet6_from_string ("2001:db8:abad:c0de::"),
|
||||||
|
.plen = 64,
|
||||||
|
.gateway = *nmtst_inet6_from_string ("2001:db8:8086::1"),
|
||||||
|
.metric = 21,
|
||||||
|
.mss = 0,
|
||||||
|
});
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
}
|
}
|
||||||
@@ -538,6 +566,7 @@ test_ip6_route_options (gconstpointer test_data)
|
|||||||
switch (TEST_IDX) {
|
switch (TEST_IDX) {
|
||||||
case 1:
|
case 1:
|
||||||
case 2:
|
case 2:
|
||||||
|
case 3:
|
||||||
for (i = 0; i < rts_n; i++) {
|
for (i = 0; i < rts_n; i++) {
|
||||||
rts_cmp[i] = rts_add[i];
|
rts_cmp[i] = rts_add[i];
|
||||||
rts_cmp[i].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
|
rts_cmp[i].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
|
||||||
@@ -567,6 +596,126 @@ test_ip6_route_options (gconstpointer test_data)
|
|||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_ip (gconstpointer test_data)
|
||||||
|
{
|
||||||
|
const int TEST_IDX = GPOINTER_TO_INT (test_data);
|
||||||
|
const int IFINDEX = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
|
||||||
|
guint i, j, k;
|
||||||
|
const NMPlatformLink *l;
|
||||||
|
char ifname[IFNAMSIZ];
|
||||||
|
char ifname2[IFNAMSIZ];
|
||||||
|
char s1[NM_UTILS_INET_ADDRSTRLEN];
|
||||||
|
NMPlatform *platform = NM_PLATFORM_GET;
|
||||||
|
const int EX_ = -1;
|
||||||
|
struct {
|
||||||
|
int ifindex;
|
||||||
|
} iface_data[10] = { 0 };
|
||||||
|
int order_idx[G_N_ELEMENTS (iface_data)] = { 0 };
|
||||||
|
guint order_len;
|
||||||
|
guint try;
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (iface_data); i++) {
|
||||||
|
nm_sprintf_buf (ifname, "v%02u", i);
|
||||||
|
nm_sprintf_buf (ifname2, "w%02u", i);
|
||||||
|
|
||||||
|
g_assert (!nm_platform_link_get_by_ifname (platform, ifname));
|
||||||
|
g_assert (!nm_platform_link_get_by_ifname (platform, ifname2));
|
||||||
|
l = nmtstp_link_veth_add (platform, EX_, ifname, ifname2);
|
||||||
|
iface_data[i].ifindex = l->ifindex;
|
||||||
|
|
||||||
|
nmtstp_link_set_updown (platform, EX_, iface_data[i].ifindex, TRUE);
|
||||||
|
nmtstp_link_set_updown (platform, EX_, nmtstp_link_get (platform, -1, ifname2)->ifindex, TRUE);
|
||||||
|
|
||||||
|
nm_sprintf_buf (s1, "192.168.7.%d", 100 + i);
|
||||||
|
nmtstp_ip4_address_add (platform,
|
||||||
|
EX_,
|
||||||
|
iface_data[i].ifindex,
|
||||||
|
nmtst_inet4_from_string (s1),
|
||||||
|
24,
|
||||||
|
nmtst_inet4_from_string (s1),
|
||||||
|
3600,
|
||||||
|
3600,
|
||||||
|
0,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
order_len = 0;
|
||||||
|
for (try = 0; try < 5 * G_N_ELEMENTS (order_idx); try++) {
|
||||||
|
NMPObject o;
|
||||||
|
NMPlatformIP4Route *r;
|
||||||
|
guint idx;
|
||||||
|
const NMDedupMultiHeadEntry *head_entry;
|
||||||
|
NMPLookup lookup;
|
||||||
|
|
||||||
|
nmp_object_stackinit (&o, NMP_OBJECT_TYPE_IP4_ROUTE, NULL);
|
||||||
|
r = NMP_OBJECT_CAST_IP4_ROUTE (&o);
|
||||||
|
r->network = nmtst_inet4_from_string ("192.168.9.0");
|
||||||
|
r->plen = 24;
|
||||||
|
r->metric = 109;
|
||||||
|
|
||||||
|
if ( order_len == 0
|
||||||
|
|| ( order_len < G_N_ELEMENTS (order_idx)
|
||||||
|
&& nmtst_get_rand_int () % 2)) {
|
||||||
|
again_find_idx:
|
||||||
|
idx = nmtst_get_rand_int () % G_N_ELEMENTS (iface_data);
|
||||||
|
for (i = 0; i < order_len; i++) {
|
||||||
|
if (order_idx[i] == idx)
|
||||||
|
goto again_find_idx;
|
||||||
|
}
|
||||||
|
order_idx[order_len++] = idx;
|
||||||
|
|
||||||
|
r->ifindex = iface_data[idx].ifindex;
|
||||||
|
g_assert (nm_platform_ip4_route_add (platform, NMP_NLM_FLAG_APPEND, r));
|
||||||
|
} else {
|
||||||
|
i = nmtst_get_rand_int () % order_len;
|
||||||
|
idx = order_idx[i];
|
||||||
|
for (i++; i < order_len; i++)
|
||||||
|
order_idx[i - 1] = order_idx[i];
|
||||||
|
order_len--;
|
||||||
|
|
||||||
|
r->ifindex = iface_data[idx].ifindex;
|
||||||
|
g_assert (nm_platform_ip_route_delete (platform, &o));
|
||||||
|
}
|
||||||
|
|
||||||
|
head_entry = nm_platform_lookup (platform,
|
||||||
|
nmp_lookup_init_obj_type (&lookup, NMP_OBJECT_TYPE_IP4_ROUTE));
|
||||||
|
for (j = 0; j < G_N_ELEMENTS (iface_data); j++) {
|
||||||
|
gboolean has;
|
||||||
|
NMDedupMultiIter iter;
|
||||||
|
const NMPObject *o_cached;
|
||||||
|
|
||||||
|
has = FALSE;
|
||||||
|
for (k = 0; k < order_len; k++) {
|
||||||
|
if (order_idx[k] == j) {
|
||||||
|
g_assert (!has);
|
||||||
|
has = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nmp_cache_iter_for_each (&iter, head_entry, &o_cached) {
|
||||||
|
const NMPlatformIP4Route *r_cached = NMP_OBJECT_CAST_IP4_ROUTE (o_cached);
|
||||||
|
|
||||||
|
if ( r_cached->ifindex != iface_data[j].ifindex
|
||||||
|
|| r_cached->metric != 109)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
g_assert (has);
|
||||||
|
has = FALSE;
|
||||||
|
}
|
||||||
|
g_assert (!has);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (iface_data); i++)
|
||||||
|
g_assert (nm_platform_link_delete (platform, iface_data[i].ifindex));
|
||||||
|
|
||||||
|
(void) TEST_IDX;
|
||||||
|
(void) IFINDEX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP;
|
NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP;
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -586,7 +735,10 @@ _nmtstp_setup_tests (void)
|
|||||||
add_test_func ("/route/ip4_options", test_ip4_route_options);
|
add_test_func ("/route/ip4_options", test_ip4_route_options);
|
||||||
add_test_func_data ("/route/ip6_options/1", test_ip6_route_options, GINT_TO_POINTER (1));
|
add_test_func_data ("/route/ip6_options/1", test_ip6_route_options, GINT_TO_POINTER (1));
|
||||||
add_test_func_data ("/route/ip6_options/2", test_ip6_route_options, GINT_TO_POINTER (2));
|
add_test_func_data ("/route/ip6_options/2", test_ip6_route_options, GINT_TO_POINTER (2));
|
||||||
|
add_test_func_data ("/route/ip6_options/3", test_ip6_route_options, GINT_TO_POINTER (3));
|
||||||
|
|
||||||
if (nmtstp_is_root_test ())
|
if (nmtstp_is_root_test ()) {
|
||||||
|
add_test_func_data ("/route/ip/1", test_ip, GINT_TO_POINTER (1));
|
||||||
add_test_func ("/route/ip4_zero_gateway", test_ip4_zero_gateway);
|
add_test_func ("/route/ip4_zero_gateway", test_ip4_zero_gateway);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -553,6 +553,7 @@ static void
|
|||||||
test_ip6 (test_fixture *fixture, gconstpointer user_data)
|
test_ip6 (test_fixture *fixture, gconstpointer user_data)
|
||||||
{
|
{
|
||||||
GArray *routes;
|
GArray *routes;
|
||||||
|
int i;
|
||||||
|
|
||||||
NMPlatformIP6Route state1[] = {
|
NMPlatformIP6Route state1[] = {
|
||||||
{
|
{
|
||||||
@@ -771,7 +772,37 @@ test_ip6 (test_fixture *fixture, gconstpointer user_data)
|
|||||||
|
|
||||||
/* 2001:db8:abad:c0de::/64 on dev0 was updated for gateway removal*/
|
/* 2001:db8:abad:c0de::/64 on dev0 was updated for gateway removal*/
|
||||||
routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP6_ROUTE);
|
routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP6_ROUTE);
|
||||||
g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state2));
|
if (routes->len != G_N_ELEMENTS (state2)) {
|
||||||
|
NMPlatformIP6Route rr;
|
||||||
|
|
||||||
|
/* hm, seems kernel may wrongly treat IPv6 gateway for `ip route replace`.
|
||||||
|
* See rh#1480427.
|
||||||
|
*
|
||||||
|
* We would expect that `ip route replace` replaces an existing route.
|
||||||
|
* However, kernel may not do so, and instead prepend it.
|
||||||
|
*
|
||||||
|
* Work around that, by checking if such a route exists and accept
|
||||||
|
* it. */
|
||||||
|
g_assert (nmtstp_is_root_test ());
|
||||||
|
g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state2) + 1);
|
||||||
|
rr = ((NMPlatformIP6Route) {
|
||||||
|
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
|
||||||
|
.network = *nmtst_inet6_from_string ("2001:db8:abad:c0de::"),
|
||||||
|
.plen = 64,
|
||||||
|
.ifindex = fixture->ifindex0,
|
||||||
|
.gateway = *nmtst_inet6_from_string ("2001:db8:8086::1"),
|
||||||
|
.metric = 21,
|
||||||
|
.mss = 0,
|
||||||
|
});
|
||||||
|
for (i = 0; i < routes->len; i++) {
|
||||||
|
if (nm_platform_ip6_route_cmp (&rr,
|
||||||
|
&g_array_index (routes, NMPlatformIP6Route, i),
|
||||||
|
NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL) != 0)
|
||||||
|
continue;
|
||||||
|
g_array_remove_index (routes, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, state2, routes->len, TRUE);
|
nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, state2, routes->len, TRUE);
|
||||||
g_array_free (routes, TRUE);
|
g_array_free (routes, TRUE);
|
||||||
|
|
||||||
@@ -806,9 +837,9 @@ _assert_route_check (const NMPlatformVTableRoute *vtable, gboolean has, const NM
|
|||||||
g_assert (route);
|
g_assert (route);
|
||||||
|
|
||||||
if (vtable->is_ip4)
|
if (vtable->is_ip4)
|
||||||
r = (const NMPlatformIPXRoute *) nm_platform_ip4_route_get (NM_PLATFORM_GET, route->rx.ifindex, route->r4.network, route->rx.plen, route->rx.metric);
|
r = (const NMPlatformIPXRoute *) nmtstp_ip4_route_get (NM_PLATFORM_GET, route->rx.ifindex, route->r4.network, route->rx.plen, route->rx.metric, route->r4.tos);
|
||||||
else
|
else
|
||||||
r = (const NMPlatformIPXRoute *) nm_platform_ip6_route_get (NM_PLATFORM_GET, route->rx.ifindex, route->r6.network, route->rx.plen, route->rx.metric);
|
r = (const NMPlatformIPXRoute *) nmtstp_ip6_route_get (NM_PLATFORM_GET, route->rx.ifindex, &route->r6.network, route->rx.plen, route->rx.metric, &route->r6.src, route->r6.src_plen);
|
||||||
|
|
||||||
if (!has) {
|
if (!has) {
|
||||||
g_assert (!r);
|
g_assert (!r);
|
||||||
@@ -940,6 +971,5 @@ _nmtstp_setup_tests (void)
|
|||||||
{
|
{
|
||||||
g_test_add ("/route-manager/ip4", test_fixture, NULL, fixture_setup, test_ip4, fixture_teardown);
|
g_test_add ("/route-manager/ip4", test_fixture, NULL, fixture_setup, test_ip4, fixture_teardown);
|
||||||
g_test_add ("/route-manager/ip6", test_fixture, NULL, fixture_setup, test_ip6, fixture_teardown);
|
g_test_add ("/route-manager/ip6", test_fixture, NULL, fixture_setup, test_ip6, fixture_teardown);
|
||||||
|
|
||||||
g_test_add ("/route-manager/ip4-full-sync", test_fixture, NULL, fixture_setup, test_ip4_full_sync, fixture_teardown);
|
g_test_add ("/route-manager/ip4-full-sync", test_fixture, NULL, fixture_setup, test_ip4_full_sync, fixture_teardown);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user