platform: use correct scope for deleting IPv4 route

Refactor _nl_msg_new_route() to obtain the route scope (rtm_scope)
from the NMPObject, instead of a separate argument.

That way, when deleting an IPv4 route, we don't pick the first route
that matches (RT_SCOPE_NOWHERE), but use the actual scope of the route
that we want to delete. That matters, if there are more then one
otherwise identical routes that only differ by their scope.

For kernel, the scope of IPv6 routes is always global
(RT_SCOPE_UNIVERSE).

Also, during ip4_route_add() initialize the intermediate @obj to have
the values as we expect them after adding the route. That is necessary
to use it in _nl_msg_new_route(). But also nicer for consistency.

Also, move the scope_inv field in NMPlatformIP4Route to let the other
in_addr_t fields life side by side.
This commit is contained in:
Thomas Haller 2017-07-19 13:03:28 +02:00
parent 5a422af0d1
commit a041e431da
3 changed files with 20 additions and 9 deletions

View file

@ -2419,7 +2419,6 @@ static struct nl_msg *
_nl_msg_new_route (int nlmsg_type,
int nlmsg_flags,
const NMPObject *obj,
unsigned char scope,
gconstpointer gateway,
guint32 mss,
gconstpointer pref_src,
@ -2440,7 +2439,9 @@ _nl_msg_new_route (int nlmsg_type,
.rtm_tos = obj->ip_route.tos,
.rtm_table = RT_TABLE_MAIN, /* omit setting RTA_TABLE attribute */
.rtm_protocol = nmp_utils_ip_config_source_coerce_to_rtprot (obj->ip_route.rt_source),
.rtm_scope = scope,
.rtm_scope = is_v4
? nm_platform_route_scope_inv (obj->ip4_route.scope_inv)
: RT_SCOPE_NOWHERE,
.rtm_type = RTN_UNICAST,
.rtm_flags = 0,
.rtm_dst_len = obj->ip_route.plen,
@ -5695,11 +5696,12 @@ ip4_route_add (NMPlatform *platform, const NMPlatformIP4Route *route)
r = NMP_OBJECT_CAST_IP4_ROUTE (&obj);
r->network = nm_utils_ip4_address_clear_host_address (r->network, r->plen);
r->rt_source = nmp_utils_ip_config_source_round_trip_rtprot (r->rt_source),
r->scope_inv = nm_platform_route_scope_inv (!r->gateway
? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE);
nlmsg = _nl_msg_new_route (RTM_NEWROUTE,
NLM_F_CREATE | NLM_F_REPLACE,
&obj,
route->gateway ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK,
&route->gateway,
route->mss,
route->pref_src ? &route->pref_src : NULL,
@ -5729,7 +5731,6 @@ ip6_route_add (NMPlatform *platform, const NMPlatformIP6Route *route)
nlmsg = _nl_msg_new_route (RTM_NEWROUTE,
NLM_F_CREATE | NLM_F_REPLACE,
&obj,
IN6_IS_ADDR_UNSPECIFIED (&route->gateway) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE,
&route->gateway,
route->mss,
!IN6_IS_ADDR_UNSPECIFIED (&route->pref_src) ? &route->pref_src : NULL,
@ -5791,7 +5792,6 @@ ip_route_delete (NMPlatform *platform,
nlmsg = _nl_msg_new_route (RTM_DELROUTE,
0,
obj,
RT_SCOPE_NOWHERE,
NULL,
0,
NULL,

View file

@ -4752,6 +4752,7 @@ nm_platform_ip4_route_hash (const NMPlatformIP4Route *obj, NMPlatformIPRouteCmpT
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) {
h = NM_HASH_COMBINE (h, obj->ifindex);
h = NM_HASH_COMBINE (h, obj->rt_source);
h = NM_HASH_COMBINE (h, obj->scope_inv);
}
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
@ -4805,6 +4806,7 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) {
NM_CMP_FIELD (a, b, ifindex);
NM_CMP_FIELD (a, b, rt_source);
NM_CMP_FIELD (a, b, scope_inv);
}
break;
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:

View file

@ -379,13 +379,22 @@ struct _NMPlatformIP4Route {
in_addr_t network;
in_addr_t gateway;
/* The bitwise inverse of the route scope. It is inverted so that the
* default value (RT_SCOPE_NOWHERE) is nul. */
guint8 scope_inv;
/* RTA_PREFSRC/rtnl_route_get_pref_src(). A value of zero means that
* no pref-src is set. */
in_addr_t pref_src;
/* The bitwise inverse of the route scope rtm_scope. It is inverted so that the
* default value (RT_SCOPE_NOWHERE) is zero. Use nm_platform_route_scope_inv()
* to convert back and forth between the inverese representation and the
* real value.
*
* rtm_scope is part of the primary key for IPv4 routes. When deleting a route,
* the scope must match, unless it is left at RT_SCOPE_NOWHERE, in which case the first
* matching route is deleted.
*
* For IPv6 routes, the scope is ignored and kernel always assumes global scope.
* Hence, this field is only in NMPlatformIP4Route. */
guint8 scope_inv;
};
struct _NMPlatformIP6Route {