mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-09-06 17:14:02 +00:00
merge: brnach 'ff/platform_ecmp'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1466
This commit is contained in:
commit
fe7bea9685
|
@ -178,8 +178,9 @@ nmtst_platform_ip6_route_full(const char *network,
|
|||
static inline int
|
||||
_nmtst_platform_ip4_routes_equal_sort(gconstpointer a, gconstpointer b, gpointer user_data)
|
||||
{
|
||||
return nm_platform_ip4_route_cmp_full((const NMPlatformIP4Route *) a,
|
||||
(const NMPlatformIP4Route *) b);
|
||||
return nm_platform_ip4_route_cmp((const NMPlatformIP4Route *) a,
|
||||
(const NMPlatformIP4Route *) b,
|
||||
NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -210,7 +211,7 @@ nmtst_platform_ip4_routes_equal(const NMPlatformIP4Route *a,
|
|||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (nm_platform_ip4_route_cmp_full(&a[i], &b[i]) != 0) {
|
||||
if (nm_platform_ip4_route_cmp(&a[i], &b[i], NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL) != 0) {
|
||||
char buf1[NM_UTILS_TO_STRING_BUFFER_SIZE];
|
||||
char buf2[NM_UTILS_TO_STRING_BUFFER_SIZE];
|
||||
|
||||
|
@ -248,8 +249,9 @@ nmtst_platform_ip4_routes_equal_aptr(const NMPObject *const *a,
|
|||
static inline int
|
||||
_nmtst_platform_ip6_routes_equal_sort(gconstpointer a, gconstpointer b, gpointer user_data)
|
||||
{
|
||||
return nm_platform_ip6_route_cmp_full((const NMPlatformIP6Route *) a,
|
||||
(const NMPlatformIP6Route *) b);
|
||||
return nm_platform_ip6_route_cmp((const NMPlatformIP6Route *) a,
|
||||
(const NMPlatformIP6Route *) b,
|
||||
NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -280,7 +282,7 @@ nmtst_platform_ip6_routes_equal(const NMPlatformIP6Route *a,
|
|||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (nm_platform_ip6_route_cmp_full(&a[i], &b[i]) != 0) {
|
||||
if (nm_platform_ip6_route_cmp(&a[i], &b[i], NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL) != 0) {
|
||||
char buf1[NM_UTILS_TO_STRING_BUFFER_SIZE];
|
||||
char buf2[NM_UTILS_TO_STRING_BUFFER_SIZE];
|
||||
|
||||
|
|
|
@ -1092,10 +1092,7 @@ object_delete(NMPlatform *platform, const NMPObject *obj)
|
|||
}
|
||||
|
||||
static int
|
||||
ip_route_add(NMPlatform *platform,
|
||||
NMPNlmFlags flags,
|
||||
int addr_family,
|
||||
const NMPlatformIPRoute *route)
|
||||
ip_route_add(NMPlatform *platform, NMPNlmFlags flags, NMPObject *obj_stack)
|
||||
{
|
||||
NMDedupMultiIter iter;
|
||||
nm_auto_nmpobj NMPObject *obj = NULL;
|
||||
|
@ -1109,23 +1106,29 @@ ip_route_add(NMPlatform *platform,
|
|||
NMPlatformIPRoute *r = NULL;
|
||||
NMPlatformIP4Route *r4 = NULL;
|
||||
NMPlatformIP6Route *r6 = NULL;
|
||||
int addr_family;
|
||||
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(NMP_OBJECT_GET_TYPE(obj_stack),
|
||||
NMP_OBJECT_TYPE_IP4_ROUTE,
|
||||
NMP_OBJECT_TYPE_IP6_ROUTE));
|
||||
|
||||
addr_family = NMP_OBJECT_GET_ADDR_FAMILY(obj_stack);
|
||||
|
||||
flags = NM_FLAGS_UNSET(flags, NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE);
|
||||
|
||||
/* currently, only replace is implemented. */
|
||||
g_assert(flags == NMP_NLM_FLAG_REPLACE);
|
||||
|
||||
obj = nmp_object_new(addr_family == AF_INET ? NMP_OBJECT_TYPE_IP4_ROUTE
|
||||
: NMP_OBJECT_TYPE_IP6_ROUTE,
|
||||
(const NMPlatformObject *) route);
|
||||
r = NMP_OBJECT_CAST_IP_ROUTE(obj);
|
||||
if (NMP_OBJECT_GET_TYPE(obj_stack) == NMP_OBJECT_TYPE_IP4_ROUTE
|
||||
&& obj_stack->ip4_route.n_nexthops == 0 && obj_stack->ip4_route.ifindex > 0)
|
||||
obj_stack->ip4_route.n_nexthops = 1;
|
||||
|
||||
nm_platform_ip_route_normalize(addr_family, r);
|
||||
obj = nmp_object_clone(obj_stack, FALSE);
|
||||
|
||||
r = NMP_OBJECT_CAST_IP_ROUTE(obj);
|
||||
|
||||
switch (addr_family) {
|
||||
case AF_INET:
|
||||
|
|
|
@ -1250,8 +1250,8 @@ nmtstp_ip4_route_add(NMPlatform *platform,
|
|||
route.metric = metric;
|
||||
route.mss = mss;
|
||||
|
||||
g_assert(
|
||||
NMTST_NM_ERR_SUCCESS(nm_platform_ip4_route_add(platform, NMP_NLM_FLAG_REPLACE, &route)));
|
||||
g_assert(NMTST_NM_ERR_SUCCESS(
|
||||
nm_platform_ip4_route_add(platform, NMP_NLM_FLAG_REPLACE, &route, NULL)));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -333,30 +333,33 @@ test_ip4_route(void)
|
|||
/* Test route listing */
|
||||
routes = nmtstp_ip4_route_get_all(NM_PLATFORM_GET, ifindex);
|
||||
memset(rts, 0, sizeof(rts));
|
||||
rts[0].rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER);
|
||||
rts[0].network = gateway;
|
||||
rts[0].plen = 32;
|
||||
rts[0].ifindex = ifindex;
|
||||
rts[0].gateway = INADDR_ANY;
|
||||
rts[0].metric = metric;
|
||||
rts[0].mss = mss;
|
||||
rts[0].scope_inv = nm_platform_route_scope_inv(RT_SCOPE_LINK);
|
||||
rts[1].rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER);
|
||||
rts[1].network = network;
|
||||
rts[1].plen = plen;
|
||||
rts[1].ifindex = ifindex;
|
||||
rts[1].gateway = gateway;
|
||||
rts[1].metric = metric;
|
||||
rts[1].mss = mss;
|
||||
rts[1].scope_inv = nm_platform_route_scope_inv(RT_SCOPE_UNIVERSE);
|
||||
rts[2].rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER);
|
||||
rts[2].network = 0;
|
||||
rts[2].plen = 0;
|
||||
rts[2].ifindex = ifindex;
|
||||
rts[2].gateway = gateway;
|
||||
rts[2].metric = metric;
|
||||
rts[2].mss = mss;
|
||||
rts[2].scope_inv = nm_platform_route_scope_inv(RT_SCOPE_UNIVERSE);
|
||||
rts[0].rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER);
|
||||
rts[0].network = gateway;
|
||||
rts[0].plen = 32;
|
||||
rts[0].ifindex = ifindex;
|
||||
rts[0].gateway = INADDR_ANY;
|
||||
rts[0].metric = metric;
|
||||
rts[0].mss = mss;
|
||||
rts[0].scope_inv = nm_platform_route_scope_inv(RT_SCOPE_LINK);
|
||||
rts[0].n_nexthops = 1;
|
||||
rts[1].rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER);
|
||||
rts[1].network = network;
|
||||
rts[1].plen = plen;
|
||||
rts[1].ifindex = ifindex;
|
||||
rts[1].gateway = gateway;
|
||||
rts[1].metric = metric;
|
||||
rts[1].mss = mss;
|
||||
rts[1].scope_inv = nm_platform_route_scope_inv(RT_SCOPE_UNIVERSE);
|
||||
rts[1].n_nexthops = 1;
|
||||
rts[2].rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER);
|
||||
rts[2].network = 0;
|
||||
rts[2].plen = 0;
|
||||
rts[2].ifindex = ifindex;
|
||||
rts[2].gateway = gateway;
|
||||
rts[2].metric = metric;
|
||||
rts[2].mss = mss;
|
||||
rts[2].scope_inv = nm_platform_route_scope_inv(RT_SCOPE_UNIVERSE);
|
||||
rts[2].n_nexthops = 1;
|
||||
g_assert_cmpint(routes->len, ==, 3);
|
||||
nmtst_platform_ip4_routes_equal_aptr((const NMPObject *const *) routes->pdata,
|
||||
rts,
|
||||
|
@ -635,21 +638,22 @@ test_ip4_route_options(gconstpointer test_data)
|
|||
switch (TEST_IDX) {
|
||||
case 1:
|
||||
rts_add[rts_n++] = ((NMPlatformIP4Route){
|
||||
.ifindex = IFINDEX,
|
||||
.rt_source = NM_IP_CONFIG_SOURCE_USER,
|
||||
.network = nmtst_inet4_from_string("172.16.1.0"),
|
||||
.plen = 24,
|
||||
.metric = 20,
|
||||
.tos = 0x28,
|
||||
.window = 10000,
|
||||
.cwnd = 16,
|
||||
.initcwnd = 30,
|
||||
.initrwnd = 50,
|
||||
.mtu = 1350,
|
||||
.lock_cwnd = TRUE,
|
||||
.mss = 1300,
|
||||
.quickack = TRUE,
|
||||
.rto_min = 1000,
|
||||
.ifindex = IFINDEX,
|
||||
.rt_source = NM_IP_CONFIG_SOURCE_USER,
|
||||
.network = nmtst_inet4_from_string("172.16.1.0"),
|
||||
.plen = 24,
|
||||
.metric = 20,
|
||||
.tos = 0x28,
|
||||
.window = 10000,
|
||||
.cwnd = 16,
|
||||
.initcwnd = 30,
|
||||
.initrwnd = 50,
|
||||
.mtu = 1350,
|
||||
.lock_cwnd = TRUE,
|
||||
.mss = 1300,
|
||||
.quickack = TRUE,
|
||||
.rto_min = 1000,
|
||||
.n_nexthops = 1,
|
||||
});
|
||||
break;
|
||||
case 2:
|
||||
|
@ -663,12 +667,13 @@ test_ip4_route_options(gconstpointer test_data)
|
|||
.n_ifa_flags = 0,
|
||||
});
|
||||
rts_add[rts_n++] = ((NMPlatformIP4Route){
|
||||
.ifindex = IFINDEX,
|
||||
.rt_source = NM_IP_CONFIG_SOURCE_USER,
|
||||
.network = nmtst_inet4_from_string("172.17.1.0"),
|
||||
.gateway = nmtst_inet4_from_string("172.16.1.1"),
|
||||
.plen = 24,
|
||||
.metric = 20,
|
||||
.ifindex = IFINDEX,
|
||||
.rt_source = NM_IP_CONFIG_SOURCE_USER,
|
||||
.network = nmtst_inet4_from_string("172.17.1.0"),
|
||||
.gateway = nmtst_inet4_from_string("172.16.1.1"),
|
||||
.plen = 24,
|
||||
.metric = 20,
|
||||
.n_nexthops = 1,
|
||||
});
|
||||
rts_add[rts_n++] = ((NMPlatformIP4Route){
|
||||
.ifindex = IFINDEX,
|
||||
|
@ -678,6 +683,7 @@ test_ip4_route_options(gconstpointer test_data)
|
|||
.r_rtm_flags = RTNH_F_ONLINK,
|
||||
.plen = 24,
|
||||
.metric = 20,
|
||||
.n_nexthops = 1,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
|
@ -707,7 +713,7 @@ test_ip4_route_options(gconstpointer test_data)
|
|||
|
||||
for (i = 0; i < rts_n; i++)
|
||||
g_assert(NMTST_NM_ERR_SUCCESS(
|
||||
nm_platform_ip4_route_add(NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, &rts_add[i])));
|
||||
nm_platform_ip4_route_add(NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, &rts_add[i], NULL)));
|
||||
|
||||
for (i = 0; i < rts_n; i++) {
|
||||
rts_cmp[i] = rts_add[i];
|
||||
|
@ -982,8 +988,8 @@ again_find_idx:
|
|||
order_idx[order_len++] = idx;
|
||||
|
||||
r->ifindex = iface_data[idx].ifindex;
|
||||
g_assert(
|
||||
NMTST_NM_ERR_SUCCESS(nm_platform_ip4_route_add(platform, NMP_NLM_FLAG_APPEND, r)));
|
||||
g_assert(NMTST_NM_ERR_SUCCESS(
|
||||
nm_platform_ip4_route_add(platform, NMP_NLM_FLAG_APPEND, r, NULL)));
|
||||
} else {
|
||||
i = nmtst_get_rand_uint32() % order_len;
|
||||
idx = order_idx[i];
|
||||
|
@ -1930,7 +1936,7 @@ test_blackhole(gconstpointer test_data)
|
|||
nm_platform_ip_route_normalize(addr_family, &rr.rx);
|
||||
|
||||
if (IS_IPv4)
|
||||
r = nm_platform_ip4_route_add(NM_PLATFORM_GET, NMP_NLM_FLAG_APPEND, &rr.r4);
|
||||
r = nm_platform_ip4_route_add(NM_PLATFORM_GET, NMP_NLM_FLAG_APPEND, &rr.r4, NULL);
|
||||
else
|
||||
r = nm_platform_ip6_route_add(NM_PLATFORM_GET, NMP_NLM_FLAG_APPEND, &rr.r6);
|
||||
|
||||
|
|
|
@ -3640,21 +3640,27 @@ _new_from_nl_route(const struct nlmsghdr *nlh, gboolean id_only, ParseNlmsgIter
|
|||
struct {
|
||||
gboolean found;
|
||||
gboolean has_more;
|
||||
guint8 weight;
|
||||
int ifindex;
|
||||
NMIPAddr gateway;
|
||||
} nh = {
|
||||
.found = FALSE,
|
||||
.has_more = FALSE,
|
||||
};
|
||||
guint32 mss;
|
||||
guint32 window = 0;
|
||||
guint32 cwnd = 0;
|
||||
guint32 initcwnd = 0;
|
||||
guint32 initrwnd = 0;
|
||||
guint32 mtu = 0;
|
||||
guint32 rto_min = 0;
|
||||
guint32 lock = 0;
|
||||
gboolean quickack = FALSE;
|
||||
guint v4_n_nexthops = 0;
|
||||
NMPlatformIP4RtNextHop v4_nh_extra_nexthops_stack[10];
|
||||
gs_free NMPlatformIP4RtNextHop *v4_nh_extra_nexthops_heap = NULL;
|
||||
NMPlatformIP4RtNextHop *v4_nh_extra_nexthops = v4_nh_extra_nexthops_stack;
|
||||
guint v4_nh_extra_alloc = G_N_ELEMENTS(v4_nh_extra_nexthops_stack);
|
||||
guint32 mss;
|
||||
guint32 window = 0;
|
||||
guint32 cwnd = 0;
|
||||
guint32 initcwnd = 0;
|
||||
guint32 initrwnd = 0;
|
||||
guint32 mtu = 0;
|
||||
guint32 rto_min = 0;
|
||||
guint32 lock = 0;
|
||||
gboolean quickack = FALSE;
|
||||
|
||||
nm_assert((parse_nlmsg_iter->iter_more && parse_nlmsg_iter->ip6_route.next_multihop > 0)
|
||||
|| (!parse_nlmsg_iter->iter_more && parse_nlmsg_iter->ip6_route.next_multihop == 0));
|
||||
|
@ -3712,9 +3718,57 @@ _new_from_nl_route(const struct nlmsghdr *nlh, gboolean id_only, ParseNlmsgIter
|
|||
|
||||
idx = 0;
|
||||
while (TRUE) {
|
||||
if (idx == multihop_idx) {
|
||||
if (nh.found && IS_IPv4) {
|
||||
NMPlatformIP4RtNextHop *new_nexthop;
|
||||
|
||||
/* we parsed the first IPv4 nexthop in "nh", let's parse the following ones.
|
||||
*
|
||||
* At this point, v4_n_nexthops still counts how many hops we already added,
|
||||
* now we are about to add the (v4_n_nexthops+1) hop.
|
||||
*
|
||||
* Note that the first hop (of then v4_n_nexthops) is tracked in "nh".
|
||||
* v4_nh_extra_nexthops tracks the additional hops.
|
||||
*
|
||||
* v4_nh_extra_alloc is how many space is allocated for
|
||||
* v4_nh_extra_nexthops (note that in the end we will only add (v4_n_nexthops-1)
|
||||
* hops in this list). */
|
||||
nm_assert(v4_n_nexthops > 0u);
|
||||
if (v4_n_nexthops - 1u >= v4_nh_extra_alloc) {
|
||||
v4_nh_extra_alloc = NM_MAX(4, v4_nh_extra_alloc * 2u);
|
||||
if (!v4_nh_extra_nexthops_heap) {
|
||||
v4_nh_extra_nexthops_heap =
|
||||
g_new(NMPlatformIP4RtNextHop, v4_nh_extra_alloc);
|
||||
memcpy(v4_nh_extra_nexthops_heap,
|
||||
v4_nh_extra_nexthops_stack,
|
||||
G_N_ELEMENTS(v4_nh_extra_nexthops_stack));
|
||||
} else {
|
||||
v4_nh_extra_nexthops_heap = g_renew(NMPlatformIP4RtNextHop,
|
||||
v4_nh_extra_nexthops_heap,
|
||||
v4_nh_extra_alloc);
|
||||
}
|
||||
v4_nh_extra_nexthops = v4_nh_extra_nexthops_heap;
|
||||
}
|
||||
nm_assert(v4_n_nexthops - 1u < v4_nh_extra_alloc);
|
||||
new_nexthop = &v4_nh_extra_nexthops[v4_n_nexthops - 1u];
|
||||
new_nexthop->ifindex = rtnh->rtnh_ifindex;
|
||||
new_nexthop->weight = NM_MAX(rtnh->rtnh_hops, 1u);
|
||||
if (rtnh->rtnh_len > sizeof(*rtnh)) {
|
||||
struct nlattr *ntb[RTA_MAX + 1];
|
||||
|
||||
if (nla_parse_arr(ntb,
|
||||
(struct nlattr *) RTNH_DATA(rtnh),
|
||||
rtnh->rtnh_len - sizeof(*rtnh),
|
||||
NULL)
|
||||
< 0)
|
||||
return NULL;
|
||||
|
||||
if (_check_addr_or_return_null(ntb, RTA_GATEWAY, addr_len))
|
||||
memcpy(&new_nexthop->gateway, nla_data(ntb[RTA_GATEWAY]), addr_len);
|
||||
}
|
||||
} else if (IS_IPv4 || idx == multihop_idx) {
|
||||
nh.found = TRUE;
|
||||
nh.ifindex = rtnh->rtnh_ifindex;
|
||||
nh.weight = NM_MAX(rtnh->rtnh_hops, 1u);
|
||||
if (rtnh->rtnh_len > sizeof(*rtnh)) {
|
||||
struct nlattr *ntb[RTA_MAX + 1];
|
||||
|
||||
|
@ -3731,15 +3785,6 @@ _new_from_nl_route(const struct nlmsghdr *nlh, gboolean id_only, ParseNlmsgIter
|
|||
} else if (nh.found) {
|
||||
/* we just parsed a nexthop, but there is yet another hop afterwards. */
|
||||
nm_assert(idx == multihop_idx + 1);
|
||||
if (IS_IPv4) {
|
||||
/* for IPv4, multihop routes are currently not supported.
|
||||
*
|
||||
* If we ever support them, then the next-hop list is part of the NMPlatformIPRoute,
|
||||
* that is, for IPv4 we truly have multihop routes. Unlike for IPv6.
|
||||
*
|
||||
* For now, just error out. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* For IPv6 multihop routes, we need to remember to iterate again.
|
||||
* For each next-hop, we will create a distinct single-hop NMPlatformIP6Route. */
|
||||
|
@ -3747,6 +3792,9 @@ _new_from_nl_route(const struct nlmsghdr *nlh, gboolean id_only, ParseNlmsgIter
|
|||
break;
|
||||
}
|
||||
|
||||
if (IS_IPv4)
|
||||
v4_n_nexthops++;
|
||||
|
||||
if (tlen < RTNH_ALIGN(rtnh->rtnh_len) + sizeof(*rtnh))
|
||||
break;
|
||||
|
||||
|
@ -3780,6 +3828,9 @@ rta_multipath_done:
|
|||
nh.ifindex = ifindex;
|
||||
nh.gateway = gateway;
|
||||
nh.found = TRUE;
|
||||
nm_assert(v4_n_nexthops == 0);
|
||||
if (IS_IPv4)
|
||||
v4_n_nexthops = 1;
|
||||
} else {
|
||||
/* Kernel supports new style nexthop configuration,
|
||||
* verify that it is a duplicate and ignore old-style nexthop. */
|
||||
|
@ -3870,6 +3921,23 @@ rta_multipath_done:
|
|||
|
||||
obj->ip_route.ifindex = nh.ifindex;
|
||||
|
||||
if (IS_IPv4) {
|
||||
nm_assert((!!nh.found) == (v4_n_nexthops > 0u));
|
||||
obj->ip4_route.n_nexthops = v4_n_nexthops;
|
||||
if (v4_n_nexthops > 1) {
|
||||
/* We only set the weight for multihop routes. I think that corresponds to what kernel
|
||||
* does. The weight is mostly undefined for single-hop. */
|
||||
obj->ip4_route.weight = NM_MAX(nh.weight, 1u);
|
||||
|
||||
obj->_ip4_route.extra_nexthops =
|
||||
(v4_nh_extra_alloc == v4_n_nexthops - 1u
|
||||
&& v4_nh_extra_nexthops == v4_nh_extra_nexthops_heap)
|
||||
? g_steal_pointer(&v4_nh_extra_nexthops_heap)
|
||||
: nm_memdup(v4_nh_extra_nexthops,
|
||||
sizeof(v4_nh_extra_nexthops[0]) * (v4_n_nexthops - 1u));
|
||||
}
|
||||
}
|
||||
|
||||
if (_check_addr_or_return_null(tb, RTA_DST, addr_len))
|
||||
memcpy(obj->ip_route.network_ptr, nla_data(tb[RTA_DST]), addr_len);
|
||||
|
||||
|
@ -5180,6 +5248,39 @@ _nl_msg_new_route(uint16_t nlmsg_type, uint16_t nlmsg_flags, const NMPObject *ob
|
|||
NLA_PUT(msg, RTA_PREFSRC, addr_len, &obj->ip6_route.pref_src);
|
||||
}
|
||||
|
||||
if (IS_IPv4 && obj->ip4_route.n_nexthops > 1u) {
|
||||
struct nlattr *multipath;
|
||||
guint i;
|
||||
|
||||
if (!(multipath = nla_nest_start(msg, RTA_MULTIPATH)))
|
||||
goto nla_put_failure;
|
||||
|
||||
for (i = 0u; i < obj->ip4_route.n_nexthops; i++) {
|
||||
struct rtnexthop *rtnh;
|
||||
|
||||
rtnh = nlmsg_reserve(msg, sizeof(*rtnh), NLMSG_ALIGNTO);
|
||||
if (!rtnh)
|
||||
goto nla_put_failure;
|
||||
|
||||
if (i == 0u) {
|
||||
rtnh->rtnh_hops = NM_MAX(obj->ip4_route.weight, 1u);
|
||||
rtnh->rtnh_ifindex = obj->ip4_route.ifindex;
|
||||
NLA_PUT_U32(msg, RTA_GATEWAY, obj->ip4_route.gateway);
|
||||
} else {
|
||||
const NMPlatformIP4RtNextHop *n = &obj->_ip4_route.extra_nexthops[i - 1u];
|
||||
|
||||
rtnh->rtnh_hops = NM_MAX(n->weight, 1u);
|
||||
rtnh->rtnh_ifindex = n->ifindex;
|
||||
NLA_PUT_U32(msg, RTA_GATEWAY, n->gateway);
|
||||
}
|
||||
|
||||
rtnh->rtnh_flags = 0;
|
||||
rtnh->rtnh_len = (char *) nlmsg_tail(nlmsg_hdr(msg)) - (char *) rtnh;
|
||||
}
|
||||
|
||||
nla_nest_end(msg, multipath);
|
||||
}
|
||||
|
||||
if (obj->ip_route.mss || obj->ip_route.window || obj->ip_route.cwnd || obj->ip_route.initcwnd
|
||||
|| obj->ip_route.initrwnd || obj->ip_route.mtu || obj->ip_route.quickack
|
||||
|| obj->ip_route.rto_min || lock) {
|
||||
|
@ -9326,25 +9427,15 @@ ip6_address_delete(NMPlatform *platform, int ifindex, struct in6_addr addr, guin
|
|||
/*****************************************************************************/
|
||||
|
||||
static int
|
||||
ip_route_add(NMPlatform *platform,
|
||||
NMPNlmFlags flags,
|
||||
int addr_family,
|
||||
const NMPlatformIPRoute *route)
|
||||
ip_route_add(NMPlatform *platform, NMPNlmFlags flags, NMPObject *obj_stack)
|
||||
{
|
||||
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
|
||||
NMPObject obj;
|
||||
|
||||
nmp_object_stackinit(&obj,
|
||||
NMP_OBJECT_TYPE_IP_ROUTE(NM_IS_IPv4(addr_family)),
|
||||
(const NMPlatformObject *) route);
|
||||
|
||||
nm_platform_ip_route_normalize(addr_family, NMP_OBJECT_CAST_IP_ROUTE(&obj));
|
||||
|
||||
nlmsg = _nl_msg_new_route(RTM_NEWROUTE, flags & NMP_NLM_FLAG_FMASK, &obj);
|
||||
nlmsg = _nl_msg_new_route(RTM_NEWROUTE, flags & NMP_NLM_FLAG_FMASK, obj_stack);
|
||||
if (!nlmsg)
|
||||
g_return_val_if_reached(-NME_BUG);
|
||||
return do_add_addrroute(platform,
|
||||
&obj,
|
||||
obj_stack,
|
||||
nlmsg,
|
||||
NM_FLAGS_HAS(flags, NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE));
|
||||
}
|
||||
|
|
|
@ -5164,55 +5164,107 @@ nm_platform_ip_route_normalize(int addr_family, NMPlatformIPRoute *route)
|
|||
}
|
||||
|
||||
static int
|
||||
_ip_route_add(NMPlatform *self, NMPNlmFlags flags, int addr_family, gconstpointer route)
|
||||
_ip_route_add(NMPlatform *self, NMPNlmFlags flags, NMPObject *obj_stack)
|
||||
{
|
||||
char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE];
|
||||
int ifindex;
|
||||
|
||||
_CHECK_SELF(self, klass, FALSE);
|
||||
|
||||
nm_assert(route);
|
||||
nm_assert(NM_IN_SET(addr_family, AF_INET, AF_INET6));
|
||||
/* The caller already ensures that this is a stack allocated copy, that
|
||||
* - stays alive for the duration of the call.
|
||||
* - that the ip_route_add() implementation is allowed to modify.
|
||||
*/
|
||||
nm_assert(obj_stack);
|
||||
nm_assert(NMP_OBJECT_IS_STACKINIT(obj_stack));
|
||||
nm_assert(NM_IN_SET(NMP_OBJECT_GET_TYPE(obj_stack),
|
||||
NMP_OBJECT_TYPE_IP4_ROUTE,
|
||||
NMP_OBJECT_TYPE_IP6_ROUTE));
|
||||
|
||||
nm_assert(NMP_OBJECT_GET_TYPE(obj_stack) != NMP_OBJECT_TYPE_IP4_ROUTE
|
||||
|| obj_stack->ip4_route.n_nexthops <= 1u || obj_stack->_ip4_route.extra_nexthops);
|
||||
|
||||
nm_platform_ip_route_normalize(NMP_OBJECT_GET_ADDR_FAMILY((obj_stack)),
|
||||
NMP_OBJECT_CAST_IP_ROUTE(obj_stack));
|
||||
|
||||
ifindex = obj_stack->ip_route.ifindex;
|
||||
|
||||
ifindex = ((const NMPlatformIPRoute *) route)->ifindex;
|
||||
_LOG3D("route: %-10s IPv%c route: %s",
|
||||
_nmp_nlm_flag_to_string(flags & NMP_NLM_FLAG_FMASK),
|
||||
nm_utils_addr_family_to_char(addr_family),
|
||||
NM_IS_IPv4(addr_family) ? nm_platform_ip4_route_to_string(route, sbuf, sizeof(sbuf))
|
||||
: nm_platform_ip6_route_to_string(route, sbuf, sizeof(sbuf)));
|
||||
nm_utils_addr_family_to_char(NMP_OBJECT_GET_ADDR_FAMILY(obj_stack)),
|
||||
nmp_object_to_string(obj_stack, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf)));
|
||||
|
||||
return klass->ip_route_add(self, flags, addr_family, route);
|
||||
/* At this point, we pass "obj_stack" to the klass->ip_route_add() implementation.
|
||||
* The callee can rely on:
|
||||
* - the object being normalized and validated.
|
||||
* - staying fully alive until the function returns. In this case it
|
||||
* is stack allocated (and the potential "extra_nexthops" array is
|
||||
* guaranteed to stay alive too).
|
||||
*/
|
||||
return klass->ip_route_add(self, flags, obj_stack);
|
||||
}
|
||||
|
||||
int
|
||||
nm_platform_ip_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPObject *route)
|
||||
nm_platform_ip_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPObject *obj)
|
||||
{
|
||||
int addr_family;
|
||||
nm_auto_nmpobj const NMPObject *obj_keep_alive = NULL;
|
||||
NMPObject obj_stack;
|
||||
|
||||
switch (NMP_OBJECT_GET_TYPE(route)) {
|
||||
case NMP_OBJECT_TYPE_IP4_ROUTE:
|
||||
addr_family = AF_INET;
|
||||
break;
|
||||
case NMP_OBJECT_TYPE_IP6_ROUTE:
|
||||
addr_family = AF_INET6;
|
||||
break;
|
||||
default:
|
||||
g_return_val_if_reached(FALSE);
|
||||
nm_assert(
|
||||
NM_IN_SET(NMP_OBJECT_GET_TYPE(obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE));
|
||||
|
||||
nmp_object_stackinit(&obj_stack, NMP_OBJECT_GET_TYPE(obj), &obj->ip_route);
|
||||
|
||||
if (NMP_OBJECT_GET_TYPE(obj) == NMP_OBJECT_TYPE_IP4_ROUTE && obj->ip4_route.n_nexthops > 1u) {
|
||||
/* Ensure @obj stays alive, so we can alias extra_nexthops from the stackallocated
|
||||
* @obj_stack. */
|
||||
nm_assert(obj->_ip4_route.extra_nexthops);
|
||||
obj_keep_alive = nmp_object_ref(obj);
|
||||
obj_stack._ip4_route.extra_nexthops = obj->_ip4_route.extra_nexthops;
|
||||
}
|
||||
|
||||
return _ip_route_add(self, flags, addr_family, NMP_OBJECT_CAST_IP_ROUTE(route));
|
||||
return _ip_route_add(self, flags, &obj_stack);
|
||||
}
|
||||
|
||||
int
|
||||
nm_platform_ip4_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP4Route *route)
|
||||
nm_platform_ip4_route_add(NMPlatform *self,
|
||||
NMPNlmFlags flags,
|
||||
const NMPlatformIP4Route *route,
|
||||
const NMPlatformIP4RtNextHop *extra_nexthops)
|
||||
{
|
||||
return _ip_route_add(self, flags, AF_INET, route);
|
||||
gs_free NMPlatformIP4RtNextHop *extra_nexthops_free = NULL;
|
||||
NMPObject obj;
|
||||
|
||||
nm_assert(route);
|
||||
nm_assert(route->n_nexthops <= 1u || extra_nexthops);
|
||||
|
||||
nmp_object_stackinit(&obj, NMP_OBJECT_TYPE_IP4_ROUTE, (const NMPlatformObject *) route);
|
||||
|
||||
if (route->n_nexthops > 1u) {
|
||||
nm_assert(extra_nexthops);
|
||||
/* we need to ensure that @extra_nexthops stays alive until the function returns.
|
||||
* Copy the buffer.
|
||||
*
|
||||
* This is probably not necessary, because likely the caller will somehow ensure that
|
||||
* the extra_nexthops stay alive. Still do it, because it is a very unusual case and
|
||||
* likely cheap. */
|
||||
obj._ip4_route.extra_nexthops =
|
||||
nm_memdup_maybe_a(500u,
|
||||
extra_nexthops,
|
||||
sizeof(extra_nexthops[0]) * (route->n_nexthops - 1u),
|
||||
&extra_nexthops_free);
|
||||
}
|
||||
|
||||
return _ip_route_add(self, flags, &obj);
|
||||
}
|
||||
|
||||
int
|
||||
nm_platform_ip6_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP6Route *route)
|
||||
{
|
||||
return _ip_route_add(self, flags, AF_INET6, route);
|
||||
NMPObject obj;
|
||||
|
||||
nmp_object_stackinit(&obj, NMP_OBJECT_TYPE_IP6_ROUTE, (const NMPlatformObject *) route);
|
||||
return _ip_route_add(self, flags, &obj);
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
@ -6606,6 +6658,10 @@ _rtm_flags_to_string_full(char *buf, gsize buf_size, unsigned rtm_flags)
|
|||
/**
|
||||
* nm_platform_ip4_route_to_string:
|
||||
* @route: pointer to NMPlatformIP4Route route structure
|
||||
* @extra_nexthops: (allow-none): the route might be a ECMP multihop route
|
||||
* (with n_nexthops > 1). In that case, provide the list of extra hops
|
||||
* to print too. It is allowed for a multihop route to omit the extra hops
|
||||
* by passing NULL.
|
||||
* @buf: (allow-none): an optional buffer. If %NULL, a static buffer is used.
|
||||
* @len: the size of the @buf. If @buf is %NULL, this argument is ignored.
|
||||
*
|
||||
|
@ -6616,30 +6672,40 @@ _rtm_flags_to_string_full(char *buf, gsize buf_size, unsigned rtm_flags)
|
|||
* Returns: a string representation of the route.
|
||||
*/
|
||||
const char *
|
||||
nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsize len)
|
||||
nm_platform_ip4_route_to_string_full(const NMPlatformIP4Route *route,
|
||||
const NMPlatformIP4RtNextHop *extra_nexthops,
|
||||
char *buf,
|
||||
gsize len)
|
||||
{
|
||||
char s_network[INET_ADDRSTRLEN];
|
||||
char s_gateway[INET_ADDRSTRLEN];
|
||||
char s_pref_src[INET_ADDRSTRLEN];
|
||||
char str_dev[30];
|
||||
char str_mss[32];
|
||||
char str_table[30];
|
||||
char str_scope[30];
|
||||
char s_source[50];
|
||||
char str_tos[32];
|
||||
char str_window[32];
|
||||
char str_cwnd[32];
|
||||
char str_initcwnd[32];
|
||||
char str_initrwnd[32];
|
||||
char str_rto_min[32];
|
||||
char str_mtu[32];
|
||||
char str_rtm_flags[_RTM_FLAGS_TO_STRING_MAXLEN];
|
||||
char str_type[30];
|
||||
char str_metric[30];
|
||||
char *buf0;
|
||||
char s_network[INET_ADDRSTRLEN];
|
||||
char s_gateway[INET_ADDRSTRLEN];
|
||||
char s_pref_src[INET_ADDRSTRLEN];
|
||||
char str_dev[30];
|
||||
char str_mss[32];
|
||||
char str_table[30];
|
||||
char str_scope[30];
|
||||
char s_source[50];
|
||||
char str_tos[32];
|
||||
char str_window[32];
|
||||
char str_cwnd[32];
|
||||
char str_initcwnd[32];
|
||||
char str_initrwnd[32];
|
||||
char str_rto_min[32];
|
||||
char str_mtu[32];
|
||||
char str_rtm_flags[_RTM_FLAGS_TO_STRING_MAXLEN];
|
||||
char str_type[30];
|
||||
char str_metric[30];
|
||||
char weight_str[20];
|
||||
guint n_nexthops;
|
||||
|
||||
if (!nm_utils_to_string_buffer_init_null(route, &buf, &len))
|
||||
return buf;
|
||||
|
||||
buf0 = buf;
|
||||
|
||||
n_nexthops = nm_platform_ip4_route_get_n_nexthops(route);
|
||||
|
||||
inet_ntop(AF_INET, &route->network, s_network, sizeof(s_network));
|
||||
|
||||
if (route->gateway == 0)
|
||||
|
@ -6647,14 +6713,15 @@ nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsiz
|
|||
else
|
||||
inet_ntop(AF_INET, &route->gateway, s_gateway, sizeof(s_gateway));
|
||||
|
||||
g_snprintf(
|
||||
buf,
|
||||
len,
|
||||
nm_strbuf_append(
|
||||
&buf,
|
||||
&len,
|
||||
"type %s " /* type */
|
||||
"%s" /* table */
|
||||
"%s/%d"
|
||||
"%s%s" /* gateway */
|
||||
"%s"
|
||||
"%s%s" /* weight */
|
||||
"%s" /* dev/ifindex */
|
||||
" metric %s"
|
||||
"%s" /* mss */
|
||||
" rt-src %s" /* protocol */
|
||||
|
@ -6682,9 +6749,13 @@ nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsiz
|
|||
: ""),
|
||||
s_network,
|
||||
route->plen,
|
||||
s_gateway[0] ? " via " : "",
|
||||
s_gateway,
|
||||
_to_string_dev(str_dev, route->ifindex),
|
||||
n_nexthops <= 1 && s_gateway[0] ? " via " : "",
|
||||
n_nexthops <= 1 ? s_gateway : "",
|
||||
NM_PRINT_FMT_QUOTED2(n_nexthops <= 1 && route->weight != 0,
|
||||
" weight ",
|
||||
nm_sprintf_buf(weight_str, "%u", route->weight),
|
||||
""),
|
||||
n_nexthops <= 1 ? _to_string_dev(str_dev, route->ifindex) : "",
|
||||
route->metric_any
|
||||
? (route->metric ? nm_sprintf_buf(str_metric, "??+%u", route->metric) : "??")
|
||||
: nm_sprintf_buf(str_metric, "%u", route->metric),
|
||||
|
@ -6734,7 +6805,56 @@ nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsiz
|
|||
route->mtu)
|
||||
: "",
|
||||
route->r_force_commit ? " force-commit" : "");
|
||||
return buf;
|
||||
|
||||
if ((n_nexthops == 1 && route->ifindex > 0) || n_nexthops == 0) {
|
||||
/* A plain single hop route. Nothing extra to remark. */
|
||||
} else {
|
||||
nm_strbuf_append(&buf, &len, " n_nexthops %u", n_nexthops);
|
||||
if (n_nexthops > 1) {
|
||||
nm_strbuf_append(&buf,
|
||||
&len,
|
||||
" nexthop"
|
||||
"%s%s" /* gateway */
|
||||
"%s%s" /* weight */
|
||||
"%s" /* dev/ifindex */
|
||||
"",
|
||||
s_gateway[0] ? " via " : "",
|
||||
s_gateway,
|
||||
NM_PRINT_FMT_QUOTED2(route->weight != 1,
|
||||
" weight ",
|
||||
nm_sprintf_buf(weight_str, "%u", route->weight),
|
||||
""),
|
||||
_to_string_dev(str_dev, route->ifindex));
|
||||
if (!extra_nexthops)
|
||||
nm_strbuf_append_str(&buf, &len, " nexthops [...]");
|
||||
else {
|
||||
guint i;
|
||||
|
||||
for (i = 1; i < n_nexthops; i++) {
|
||||
const NMPlatformIP4RtNextHop *nexthop = &extra_nexthops[i - 1];
|
||||
|
||||
nm_strbuf_append(
|
||||
&buf,
|
||||
&len,
|
||||
" nexthop"
|
||||
"%s" /* ifindex */
|
||||
"%s%s" /* gateway */
|
||||
"%s%s" /* weight */
|
||||
"",
|
||||
NM_PRINT_FMT_QUOTED2(nexthop->gateway != 0 || nexthop->ifindex <= 0,
|
||||
" via ",
|
||||
nm_inet4_ntop(nexthop->gateway, s_gateway),
|
||||
""),
|
||||
_to_string_dev(str_dev, nexthop->ifindex),
|
||||
NM_PRINT_FMT_QUOTED2(nexthop->weight != 1,
|
||||
" weight ",
|
||||
nm_sprintf_buf(weight_str, "%u", nexthop->weight),
|
||||
""));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return buf0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7196,9 +7316,7 @@ nm_platform_qdisc_hash_update(const NMPlatformQdisc *obj, NMHashState *h)
|
|||
}
|
||||
|
||||
int
|
||||
nm_platform_qdisc_cmp_full(const NMPlatformQdisc *a,
|
||||
const NMPlatformQdisc *b,
|
||||
gboolean compare_handle)
|
||||
nm_platform_qdisc_cmp(const NMPlatformQdisc *a, const NMPlatformQdisc *b, gboolean compare_handle)
|
||||
{
|
||||
NM_CMP_SELF(a, b);
|
||||
NM_CMP_FIELD(a, b, ifindex);
|
||||
|
@ -7235,12 +7353,6 @@ nm_platform_qdisc_cmp_full(const NMPlatformQdisc *a,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nm_platform_qdisc_cmp(const NMPlatformQdisc *a, const NMPlatformQdisc *b)
|
||||
{
|
||||
return nm_platform_qdisc_cmp_full(a, b, TRUE);
|
||||
}
|
||||
|
||||
const char *
|
||||
nm_platform_tfilter_to_string(const NMPlatformTfilter *tfilter, char *buf, gsize len)
|
||||
{
|
||||
|
@ -8072,6 +8184,20 @@ nm_platform_lnk_wireguard_cmp(const NMPlatformLnkWireGuard *a, const NMPlatformL
|
|||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nm_platform_ip4_rt_nexthop_hash_update(const NMPlatformIP4RtNextHop *obj,
|
||||
gboolean for_id,
|
||||
NMHashState *h)
|
||||
{
|
||||
guint8 w;
|
||||
|
||||
nm_assert(obj);
|
||||
|
||||
w = for_id ? NM_MAX(obj->weight, 1u) : obj->weight;
|
||||
|
||||
nm_hash_update_vals(h, obj->ifindex, obj->gateway, w);
|
||||
}
|
||||
|
||||
void
|
||||
nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
|
||||
NMPlatformIPRouteCmpType cmp_type,
|
||||
|
@ -8079,6 +8205,8 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
|
|||
{
|
||||
switch (cmp_type) {
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ECMP_ID:
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
|
||||
nm_hash_update_vals(
|
||||
h,
|
||||
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)),
|
||||
|
@ -8087,40 +8215,38 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
|
|||
obj->metric,
|
||||
obj->tos,
|
||||
NM_HASH_COMBINE_BOOLS(guint8, obj->metric_any, obj->table_any));
|
||||
break;
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
|
||||
nm_hash_update_vals(
|
||||
h,
|
||||
obj->type_coerced,
|
||||
nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)),
|
||||
nm_ip4_addr_clear_host_address(obj->network, obj->plen),
|
||||
obj->plen,
|
||||
obj->metric,
|
||||
obj->tos,
|
||||
/* on top of WEAK_ID: */
|
||||
obj->ifindex,
|
||||
nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
|
||||
_ip_route_scope_inv_get_normalized(obj),
|
||||
obj->gateway,
|
||||
obj->mss,
|
||||
obj->pref_src,
|
||||
obj->window,
|
||||
obj->cwnd,
|
||||
obj->initcwnd,
|
||||
obj->initrwnd,
|
||||
obj->mtu,
|
||||
obj->rto_min,
|
||||
obj->r_rtm_flags & RTNH_F_ONLINK,
|
||||
NM_HASH_COMBINE_BOOLS(guint16,
|
||||
obj->metric_any,
|
||||
obj->table_any,
|
||||
obj->quickack,
|
||||
obj->lock_window,
|
||||
obj->lock_cwnd,
|
||||
obj->lock_initcwnd,
|
||||
obj->lock_initrwnd,
|
||||
obj->lock_mtu,
|
||||
obj->lock_mss));
|
||||
if (NM_IN_SET(cmp_type,
|
||||
NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID,
|
||||
NM_PLATFORM_IP_ROUTE_CMP_TYPE_ECMP_ID)) {
|
||||
nm_hash_update_vals(h,
|
||||
obj->type_coerced,
|
||||
nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
|
||||
_ip_route_scope_inv_get_normalized(obj),
|
||||
obj->mss,
|
||||
obj->pref_src,
|
||||
obj->window,
|
||||
obj->cwnd,
|
||||
obj->initcwnd,
|
||||
obj->initrwnd,
|
||||
obj->mtu,
|
||||
obj->rto_min,
|
||||
obj->r_rtm_flags & RTNH_F_ONLINK,
|
||||
NM_HASH_COMBINE_BOOLS(guint16,
|
||||
obj->quickack,
|
||||
obj->lock_window,
|
||||
obj->lock_cwnd,
|
||||
obj->lock_initcwnd,
|
||||
obj->lock_initrwnd,
|
||||
obj->lock_mtu,
|
||||
obj->lock_mss));
|
||||
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) {
|
||||
nm_hash_update_vals(h,
|
||||
obj->ifindex,
|
||||
nm_platform_ip4_route_get_n_nexthops(obj),
|
||||
obj->gateway,
|
||||
(guint8) NM_MAX(obj->weight, 1u));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
|
||||
nm_hash_update_vals(
|
||||
|
@ -8131,7 +8257,9 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
|
|||
nm_ip4_addr_clear_host_address(obj->network, obj->plen),
|
||||
obj->plen,
|
||||
obj->metric,
|
||||
nm_platform_ip4_route_get_n_nexthops(obj),
|
||||
obj->gateway,
|
||||
(guint8) NM_MAX(obj->weight, 1u),
|
||||
nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source),
|
||||
_ip_route_scope_inv_get_normalized(obj),
|
||||
obj->tos,
|
||||
|
@ -8164,6 +8292,8 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
|
|||
obj->plen,
|
||||
obj->metric,
|
||||
obj->gateway,
|
||||
obj->n_nexthops,
|
||||
obj->weight,
|
||||
obj->rt_source,
|
||||
obj->scope_inv,
|
||||
obj->tos,
|
||||
|
@ -8191,6 +8321,30 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
|
|||
}
|
||||
}
|
||||
|
||||
int
|
||||
nm_platform_ip4_rt_nexthop_cmp(const NMPlatformIP4RtNextHop *a,
|
||||
const NMPlatformIP4RtNextHop *b,
|
||||
gboolean for_id)
|
||||
{
|
||||
guint8 w_a;
|
||||
guint8 w_b;
|
||||
|
||||
/* Note that weight zero is not valid (in kernel). We thus treat
|
||||
* weight zero usually the same as 1.
|
||||
*
|
||||
* Not here for cmp/hash_update functions. These functions check for the exact
|
||||
* bit-pattern, and not the it means at other places. */
|
||||
NM_CMP_SELF(a, b);
|
||||
NM_CMP_FIELD(a, b, ifindex);
|
||||
NM_CMP_FIELD(a, b, gateway);
|
||||
|
||||
w_a = for_id ? NM_MAX(a->weight, 1u) : a->weight;
|
||||
w_b = for_id ? NM_MAX(b->weight, 1u) : b->weight;
|
||||
NM_CMP_DIRECT(w_a, w_b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
|
||||
const NMPlatformIP4Route *b,
|
||||
|
@ -8198,6 +8352,7 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
|
|||
{
|
||||
NM_CMP_SELF(a, b);
|
||||
switch (cmp_type) {
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ECMP_ID:
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
|
||||
NM_CMP_FIELD_UNSAFE(a, b, table_any);
|
||||
|
@ -8208,14 +8363,14 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
|
|||
NM_CMP_FIELD_UNSAFE(a, b, metric_any);
|
||||
NM_CMP_FIELD(a, b, metric);
|
||||
NM_CMP_FIELD(a, b, tos);
|
||||
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) {
|
||||
NM_CMP_FIELD(a, b, ifindex);
|
||||
if (NM_IN_SET(cmp_type,
|
||||
NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID,
|
||||
NM_PLATFORM_IP_ROUTE_CMP_TYPE_ECMP_ID)) {
|
||||
NM_CMP_FIELD(a, b, type_coerced);
|
||||
NM_CMP_DIRECT(nmp_utils_ip_config_source_round_trip_rtprot(a->rt_source),
|
||||
nmp_utils_ip_config_source_round_trip_rtprot(b->rt_source));
|
||||
NM_CMP_DIRECT(_ip_route_scope_inv_get_normalized(a),
|
||||
_ip_route_scope_inv_get_normalized(b));
|
||||
NM_CMP_FIELD(a, b, gateway);
|
||||
NM_CMP_FIELD(a, b, mss);
|
||||
NM_CMP_FIELD(a, b, pref_src);
|
||||
NM_CMP_FIELD(a, b, window);
|
||||
|
@ -8232,6 +8387,13 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
|
|||
NM_CMP_FIELD_UNSAFE(a, b, lock_initrwnd);
|
||||
NM_CMP_FIELD_UNSAFE(a, b, lock_mtu);
|
||||
NM_CMP_FIELD_UNSAFE(a, b, lock_mss);
|
||||
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) {
|
||||
NM_CMP_FIELD(a, b, ifindex);
|
||||
NM_CMP_FIELD(a, b, gateway);
|
||||
NM_CMP_DIRECT(NM_MAX(a->weight, 1u), NM_MAX(b->weight, 1u));
|
||||
NM_CMP_DIRECT(nm_platform_ip4_route_get_n_nexthops(a),
|
||||
nm_platform_ip4_route_get_n_nexthops(b));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY:
|
||||
|
@ -8251,7 +8413,16 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
|
|||
NM_CMP_FIELD(a, b, plen);
|
||||
NM_CMP_FIELD_UNSAFE(a, b, metric_any);
|
||||
NM_CMP_FIELD(a, b, metric);
|
||||
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) {
|
||||
NM_CMP_DIRECT(nm_platform_ip4_route_get_n_nexthops(a),
|
||||
nm_platform_ip4_route_get_n_nexthops(b));
|
||||
} else
|
||||
NM_CMP_FIELD(a, b, n_nexthops);
|
||||
NM_CMP_FIELD(a, b, gateway);
|
||||
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
|
||||
NM_CMP_DIRECT(NM_MAX(a->weight, 1u), NM_MAX(b->weight, 1u));
|
||||
else
|
||||
NM_CMP_FIELD(a, b, weight);
|
||||
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) {
|
||||
NM_CMP_DIRECT(nmp_utils_ip_config_source_round_trip_rtprot(a->rt_source),
|
||||
nmp_utils_ip_config_source_round_trip_rtprot(b->rt_source));
|
||||
|
@ -8308,6 +8479,9 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj,
|
|||
obj->src_plen,
|
||||
NM_HASH_COMBINE_BOOLS(guint8, obj->metric_any, obj->table_any));
|
||||
break;
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ECMP_ID:
|
||||
nm_assert_not_reached();
|
||||
/* fall-through */
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
|
||||
nm_hash_update_vals(
|
||||
h,
|
||||
|
@ -8400,6 +8574,9 @@ nm_platform_ip6_route_cmp(const NMPlatformIP6Route *a,
|
|||
{
|
||||
NM_CMP_SELF(a, b);
|
||||
switch (cmp_type) {
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ECMP_ID:
|
||||
nm_assert_not_reached();
|
||||
/* fall-through */
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
|
||||
case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID:
|
||||
NM_CMP_FIELD_UNSAFE(a, b, table_any);
|
||||
|
@ -8913,7 +9090,10 @@ log_ip4_route(NMPlatform *self,
|
|||
|
||||
_LOG3D("signal: route 4 %7s: %s",
|
||||
nm_platform_signal_change_type_to_string(change_type),
|
||||
nm_platform_ip4_route_to_string(route, sbuf, sizeof(sbuf)));
|
||||
nmp_object_to_string(NMP_OBJECT_UP_CAST(route),
|
||||
NMP_OBJECT_TO_STRING_PUBLIC,
|
||||
sbuf,
|
||||
sizeof(sbuf)));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -8928,7 +9108,10 @@ log_ip6_route(NMPlatform *self,
|
|||
|
||||
_LOG3D("signal: route 6 %7s: %s",
|
||||
nm_platform_signal_change_type_to_string(change_type),
|
||||
nm_platform_ip6_route_to_string(route, sbuf, sizeof(sbuf)));
|
||||
nmp_object_to_string(NMP_OBJECT_UP_CAST(route),
|
||||
NMP_OBJECT_TO_STRING_PUBLIC,
|
||||
sbuf,
|
||||
sizeof(sbuf)));
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -102,6 +102,11 @@ typedef enum {
|
|||
*/
|
||||
NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID,
|
||||
|
||||
/* IPv4 route can have multiple hops. This is the ID, by which multiple
|
||||
* routes are merged according to the next hop. This is basically NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID
|
||||
* which ignores the next hops. */
|
||||
NM_PLATFORM_IP_ROUTE_CMP_TYPE_ECMP_ID,
|
||||
|
||||
/* compare all fields as they make sense for kernel. For example,
|
||||
* a route destination 192.168.1.5/24 is not accepted by kernel and
|
||||
* we treat it identical to 192.168.1.0/24. Semantically these
|
||||
|
@ -382,9 +387,27 @@ typedef struct {
|
|||
|
||||
struct _NMPlatformIP4Route {
|
||||
__NMPlatformIPRoute_COMMON;
|
||||
|
||||
in_addr_t network;
|
||||
|
||||
/* RTA_GATEWAY. The gateway is part of the primary key for a route */
|
||||
/* If n_nexthops is zero, the the address has no next hops. That applies
|
||||
* to certain route types like blackhole.
|
||||
* If n_nexthops is 1, then the fields "ifindex", "gateway" and "weight"
|
||||
* are the first next-hop. There are no further nexthops.
|
||||
* If n_nexthops is greater than 1, the first next hop is in the fields
|
||||
* "ifindex", "gateway", "weight", and the (n_nexthops-1) hops are in
|
||||
* NMPObjectIP4Route.extra_nexthops field (outside the NMPlatformIP4Route
|
||||
* struct).
|
||||
*
|
||||
* For convenience, if ifindex > 0 and n_nexthops == 0, we assume that n_nexthops
|
||||
* is in fact 1. If ifindex is <= 0, n_nexthops must be zero.
|
||||
* See nm_platform_ip4_route_get_n_nexthops(). */
|
||||
guint n_nexthops;
|
||||
|
||||
/* RTA_GATEWAY. The gateway is part of the primary key for a route.
|
||||
* If n_nexthops is zero, this value is undefined (should be zero).
|
||||
* If n_nexthops is greater or equal to one, this is the gateway of
|
||||
* the first hop. */
|
||||
in_addr_t gateway;
|
||||
|
||||
/* RTA_PREFSRC (called "src" by iproute2).
|
||||
|
@ -412,6 +435,21 @@ struct _NMPlatformIP4Route {
|
|||
* For IPv6 routes, the scope is ignored and kernel always assumes global scope.
|
||||
* Hence, this field is only in NMPlatformIP4Route. */
|
||||
guint8 scope_inv;
|
||||
|
||||
/* This is the weight of for the first next-hop, in case of n_nexthops > 1.
|
||||
*
|
||||
* If n_nexthops is zero, this value is undefined (should be zero).
|
||||
* If n_nexthops is 1, this also doesn't matter, but it's usually set to
|
||||
* zero.
|
||||
* If n_nexthops is greater or equal to one, this is the weight of
|
||||
* the first hop.
|
||||
*
|
||||
* Note that upper layers use this flag to indicate whether this is a multihop route.
|
||||
* Single-hop, non-ECMP routes will have a weight of zero.
|
||||
*
|
||||
* The valid range for weight is 1-255. For convenience, we treat 0 the same
|
||||
* as 1 for multihop routes. */
|
||||
guint8 weight;
|
||||
};
|
||||
|
||||
struct _NMPlatformIP6Route {
|
||||
|
@ -636,6 +674,14 @@ typedef struct {
|
|||
bool proto_ad : 1;
|
||||
} NMPlatformVFVlan;
|
||||
|
||||
typedef struct {
|
||||
int ifindex;
|
||||
in_addr_t gateway;
|
||||
/* The valid range for weight is 1-255. For convenience, we treat 0 the same
|
||||
* as 1 for multihop routes. */
|
||||
guint8 weight;
|
||||
} NMPlatformIP4RtNextHop;
|
||||
|
||||
typedef struct {
|
||||
guint num_vlans;
|
||||
guint32 index;
|
||||
|
@ -1165,10 +1211,7 @@ typedef struct {
|
|||
struct in6_addr address,
|
||||
guint8 plen);
|
||||
|
||||
int (*ip_route_add)(NMPlatform *self,
|
||||
NMPNlmFlags flags,
|
||||
int addr_family,
|
||||
const NMPlatformIPRoute *route);
|
||||
int (*ip_route_add)(NMPlatform *self, NMPNlmFlags flags, NMPObject *obj_stack);
|
||||
int (*ip_route_get)(NMPlatform *self,
|
||||
int addr_family,
|
||||
gconstpointer address,
|
||||
|
@ -2129,6 +2172,23 @@ nm_platform_ip4_route_get_effective_metric(const NMPlatformIP4Route *r)
|
|||
: r->metric;
|
||||
}
|
||||
|
||||
static inline guint
|
||||
nm_platform_ip4_route_get_n_nexthops(const NMPlatformIP4Route *r)
|
||||
{
|
||||
/* The first hop of the "n_nexthops" is in NMPlatformIP4Route
|
||||
* itself. Thus, if the caller only sets ifindex and leaves
|
||||
* n_nexthops at zero, the number of next hops is still 1
|
||||
* (for convenience of the user who wants to initialize a
|
||||
* single hop route). */
|
||||
if (r->n_nexthops >= 1) {
|
||||
nm_assert(r->ifindex > 0);
|
||||
return r->n_nexthops;
|
||||
}
|
||||
if (r->ifindex > 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline guint32
|
||||
nm_platform_ip6_route_get_effective_metric(const NMPlatformIP6Route *r)
|
||||
{
|
||||
|
@ -2162,7 +2222,10 @@ nm_platform_ip_route_get_gateway(int addr_family, const NMPlatformIPRoute *route
|
|||
}
|
||||
|
||||
int nm_platform_ip_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPObject *route);
|
||||
int nm_platform_ip4_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP4Route *route);
|
||||
int nm_platform_ip4_route_add(NMPlatform *self,
|
||||
NMPNlmFlags flags,
|
||||
const NMPlatformIP4Route *route,
|
||||
const NMPlatformIP4RtNextHop *extra_nexthops);
|
||||
int nm_platform_ip6_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP6Route *route);
|
||||
|
||||
GPtrArray *nm_platform_ip_route_get_prune_list(NMPlatform *self,
|
||||
|
@ -2216,7 +2279,18 @@ const char *nm_platform_lnk_vrf_to_string(const NMPlatformLnkVrf *lnk, char *buf
|
|||
const char *nm_platform_lnk_vxlan_to_string(const NMPlatformLnkVxlan *lnk, char *buf, gsize len);
|
||||
const char *
|
||||
nm_platform_lnk_wireguard_to_string(const NMPlatformLnkWireGuard *lnk, char *buf, gsize len);
|
||||
const char *nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsize len);
|
||||
|
||||
const char *nm_platform_ip4_route_to_string_full(const NMPlatformIP4Route *route,
|
||||
const NMPlatformIP4RtNextHop *extra_nexthops,
|
||||
char *buf,
|
||||
gsize len);
|
||||
|
||||
static inline const char *
|
||||
nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsize len)
|
||||
{
|
||||
return nm_platform_ip4_route_to_string_full(route, NULL, buf, len);
|
||||
}
|
||||
|
||||
const char *nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsize len);
|
||||
const char *
|
||||
nm_platform_routing_rule_to_string(const NMPlatformRoutingRule *routing_rule, char *buf, gsize len);
|
||||
|
@ -2260,36 +2334,20 @@ GHashTable *nm_platform_ip4_address_addr_to_hash(NMPlatform *self, int ifindex);
|
|||
int nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
|
||||
const NMPlatformIP4Route *b,
|
||||
NMPlatformIPRouteCmpType cmp_type);
|
||||
int nm_platform_ip4_rt_nexthop_cmp(const NMPlatformIP4RtNextHop *a,
|
||||
const NMPlatformIP4RtNextHop *b,
|
||||
gboolean for_id);
|
||||
int nm_platform_ip6_route_cmp(const NMPlatformIP6Route *a,
|
||||
const NMPlatformIP6Route *b,
|
||||
NMPlatformIPRouteCmpType cmp_type);
|
||||
|
||||
static inline int
|
||||
nm_platform_ip4_route_cmp_full(const NMPlatformIP4Route *a, const NMPlatformIP4Route *b)
|
||||
{
|
||||
return nm_platform_ip4_route_cmp(a, b, NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL);
|
||||
}
|
||||
|
||||
static inline int
|
||||
nm_platform_ip6_route_cmp_full(const NMPlatformIP6Route *a, const NMPlatformIP6Route *b)
|
||||
{
|
||||
return nm_platform_ip6_route_cmp(a, b, NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL);
|
||||
}
|
||||
|
||||
int nm_platform_routing_rule_cmp(const NMPlatformRoutingRule *a,
|
||||
const NMPlatformRoutingRule *b,
|
||||
NMPlatformRoutingRuleCmpType cmp_type);
|
||||
|
||||
static inline int
|
||||
nm_platform_routing_rule_cmp_full(const NMPlatformRoutingRule *a, const NMPlatformRoutingRule *b)
|
||||
{
|
||||
return nm_platform_routing_rule_cmp(a, b, NM_PLATFORM_ROUTING_RULE_CMP_TYPE_FULL);
|
||||
}
|
||||
int
|
||||
nm_platform_qdisc_cmp(const NMPlatformQdisc *a, const NMPlatformQdisc *b, gboolean compare_handle);
|
||||
|
||||
int nm_platform_qdisc_cmp(const NMPlatformQdisc *a, const NMPlatformQdisc *b);
|
||||
int nm_platform_qdisc_cmp_full(const NMPlatformQdisc *a,
|
||||
const NMPlatformQdisc *b,
|
||||
gboolean compare_handle);
|
||||
int nm_platform_tfilter_cmp(const NMPlatformTfilter *a, const NMPlatformTfilter *b);
|
||||
|
||||
int nm_platform_mptcp_addr_cmp(const NMPlatformMptcpAddr *a, const NMPlatformMptcpAddr *b);
|
||||
|
@ -2298,6 +2356,20 @@ void nm_platform_link_hash_update(const NMPlatformLink *obj, NMHashState *h);
|
|||
void nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
|
||||
NMPlatformIPRouteCmpType cmp_type,
|
||||
NMHashState *h);
|
||||
|
||||
static inline guint
|
||||
nm_platform_ip4_route_hash(const NMPlatformIP4Route *obj, NMPlatformIPRouteCmpType cmp_type)
|
||||
{
|
||||
NMHashState h;
|
||||
|
||||
nm_hash_init(&h, 1118769853u);
|
||||
nm_platform_ip4_route_hash_update(obj, cmp_type, &h);
|
||||
return nm_hash_complete(&h);
|
||||
}
|
||||
|
||||
void nm_platform_ip4_rt_nexthop_hash_update(const NMPlatformIP4RtNextHop *obj,
|
||||
gboolean for_id,
|
||||
NMHashState *h);
|
||||
void nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj,
|
||||
NMPlatformIPRouteCmpType cmp_type,
|
||||
NMHashState *h);
|
||||
|
|
|
@ -734,6 +734,12 @@ _vt_cmd_obj_dispose_link(NMPObject *obj)
|
|||
nmp_object_unref(obj->_link.netlink.lnk);
|
||||
}
|
||||
|
||||
static void
|
||||
_vt_cmd_obj_dispose_ip4_route(NMPObject *obj)
|
||||
{
|
||||
nm_clear_g_free((gpointer *) &obj->_ip4_route.extra_nexthops);
|
||||
}
|
||||
|
||||
static void
|
||||
_vt_cmd_obj_dispose_lnk_vlan(NMPObject *obj)
|
||||
{
|
||||
|
@ -848,14 +854,12 @@ nmp_object_stackinit_id(NMPObject *obj, const NMPObject *src)
|
|||
if (klass->cmd_plobj_id_copy)
|
||||
klass->cmd_plobj_id_copy(&obj->object, &src->object);
|
||||
else {
|
||||
/* This object must not implement cmd_obj_copy().
|
||||
* If it would, it would mean that we require a deep copy
|
||||
* of the data. As @obj is stack-allocated, it cannot track
|
||||
* ownership. The caller must not use nmp_object_stackinit_id()
|
||||
* with an object of such a type. */
|
||||
nm_assert(!klass->cmd_obj_copy);
|
||||
|
||||
/* plain memcpy of the public part suffices. */
|
||||
/* plain memcpy.
|
||||
*
|
||||
* Note that for NMPObjectIP4Route this also copies extra_nexthops
|
||||
* pointer, aliasing it without taking ownership. That is potentially
|
||||
* dangerous, but when using a stack allocated instance, you must
|
||||
* always take care of ownership. */
|
||||
memcpy(&obj->object, &src->object, klass->sizeof_data);
|
||||
}
|
||||
return obj;
|
||||
|
@ -992,6 +996,41 @@ _vt_cmd_obj_to_string_link(const NMPObject *obj,
|
|||
}
|
||||
}
|
||||
|
||||
static const char *
|
||||
_vt_cmd_obj_to_string_ip4_route(const NMPObject *obj,
|
||||
NMPObjectToStringMode to_string_mode,
|
||||
char *buf,
|
||||
gsize buf_size)
|
||||
{
|
||||
const NMPClass *klass;
|
||||
char buf2[NM_UTILS_TO_STRING_BUFFER_SIZE];
|
||||
|
||||
klass = NMP_OBJECT_GET_CLASS(obj);
|
||||
|
||||
switch (to_string_mode) {
|
||||
case NMP_OBJECT_TO_STRING_PUBLIC:
|
||||
case NMP_OBJECT_TO_STRING_ID:
|
||||
nm_platform_ip4_route_to_string_full(&obj->ip4_route,
|
||||
obj->_ip4_route.extra_nexthops,
|
||||
buf,
|
||||
buf_size);
|
||||
return buf;
|
||||
case NMP_OBJECT_TO_STRING_ALL:
|
||||
g_snprintf(buf,
|
||||
buf_size,
|
||||
"[%s," NM_HASH_OBFUSCATE_PTR_FMT ",%u,%calive,%cvisible; %s]",
|
||||
klass->obj_type_name,
|
||||
NM_HASH_OBFUSCATE_PTR(obj),
|
||||
obj->parent._ref_count,
|
||||
nmp_object_is_alive(obj) ? '+' : '-',
|
||||
nmp_object_is_visible(obj) ? '+' : '-',
|
||||
nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, buf2, sizeof(buf2)));
|
||||
return buf;
|
||||
default:
|
||||
g_return_val_if_reached("ERROR");
|
||||
}
|
||||
}
|
||||
|
||||
static const char *
|
||||
_vt_cmd_obj_to_string_lnk_vlan(const NMPObject *obj,
|
||||
NMPObjectToStringMode to_string_mode,
|
||||
|
@ -1197,6 +1236,21 @@ _vt_cmd_obj_hash_update_link(const NMPObject *obj, gboolean for_id, NMHashState
|
|||
nmp_object_hash_update(obj->_link.netlink.lnk, h);
|
||||
}
|
||||
|
||||
static void
|
||||
_vt_cmd_obj_hash_update_ip4_route(const NMPObject *obj, gboolean for_id, NMHashState *h)
|
||||
{
|
||||
guint i;
|
||||
|
||||
nm_assert(NMP_OBJECT_GET_TYPE(obj) == NMP_OBJECT_TYPE_IP4_ROUTE);
|
||||
|
||||
nm_platform_ip4_route_hash_update(&obj->ip4_route,
|
||||
for_id ? NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID
|
||||
: NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL,
|
||||
h);
|
||||
for (i = 1u; i < obj->ip4_route.n_nexthops; i++)
|
||||
nm_platform_ip4_rt_nexthop_hash_update(&obj->_ip4_route.extra_nexthops[i - 1u], for_id, h);
|
||||
}
|
||||
|
||||
static void
|
||||
_vt_cmd_obj_hash_update_lnk_vlan(const NMPObject *obj, gboolean for_id, NMHashState *h)
|
||||
{
|
||||
|
@ -1298,7 +1352,9 @@ nmp_object_cmp_full(const NMPObject *obj1, const NMPObject *obj2, NMPObjectCmpFl
|
|||
} else if (obj1->obj_with_ifindex.ifindex != obj2->obj_with_ifindex.ifindex) {
|
||||
nmp_object_stackinit(&obj_stackcopy, klass->obj_type, &obj2->obj_with_ifindex);
|
||||
obj_stackcopy.obj_with_ifindex.ifindex = obj1->obj_with_ifindex.ifindex;
|
||||
obj2 = &obj_stackcopy;
|
||||
if (klass->obj_type == NMP_OBJECT_TYPE_IP4_ROUTE)
|
||||
obj_stackcopy._ip4_route.extra_nexthops = obj2->_ip4_route.extra_nexthops;
|
||||
obj2 = &obj_stackcopy;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1335,6 +1391,28 @@ _vt_cmd_obj_cmp_link(const NMPObject *obj1, const NMPObject *obj2, gboolean for_
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_vt_cmd_obj_cmp_ip4_route(const NMPObject *obj1, const NMPObject *obj2, gboolean for_id)
|
||||
{
|
||||
int c;
|
||||
guint i;
|
||||
|
||||
c = nm_platform_ip4_route_cmp(&obj1->ip4_route,
|
||||
&obj2->ip4_route,
|
||||
for_id ? NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID
|
||||
: NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL);
|
||||
NM_CMP_RETURN_DIRECT(c);
|
||||
|
||||
for (i = 1u; i < obj1->ip4_route.n_nexthops; i++) {
|
||||
c = nm_platform_ip4_rt_nexthop_cmp(&obj1->_ip4_route.extra_nexthops[i - 1u],
|
||||
&obj2->_ip4_route.extra_nexthops[i - 1u],
|
||||
for_id);
|
||||
NM_CMP_RETURN_DIRECT(c);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_vt_cmd_obj_cmp_lnk_vlan(const NMPObject *obj1, const NMPObject *obj2, gboolean for_id)
|
||||
{
|
||||
|
@ -1438,6 +1516,28 @@ _vt_cmd_obj_copy_link(NMPObject *dst, const NMPObject *src)
|
|||
dst->_link = src->_link;
|
||||
}
|
||||
|
||||
static void
|
||||
_vt_cmd_obj_copy_ip4_route(NMPObject *dst, const NMPObject *src)
|
||||
{
|
||||
nm_assert(dst != src);
|
||||
|
||||
if (src->ip4_route.n_nexthops <= 1) {
|
||||
nm_clear_g_free((gpointer *) &dst->_ip4_route.extra_nexthops);
|
||||
} else if (src->ip4_route.n_nexthops != dst->ip4_route.n_nexthops
|
||||
|| !nm_memeq_n(src->_ip4_route.extra_nexthops,
|
||||
src->ip4_route.n_nexthops - 1u,
|
||||
dst->_ip4_route.extra_nexthops,
|
||||
dst->ip4_route.n_nexthops - 1u,
|
||||
sizeof(NMPlatformIP4RtNextHop))) {
|
||||
nm_clear_g_free((gpointer *) &dst->_ip4_route.extra_nexthops);
|
||||
dst->_ip4_route.extra_nexthops =
|
||||
nm_memdup(src->_ip4_route.extra_nexthops,
|
||||
sizeof(NMPlatformIP4RtNextHop) * (src->ip4_route.n_nexthops - 1u));
|
||||
}
|
||||
|
||||
dst->ip4_route = src->ip4_route;
|
||||
}
|
||||
|
||||
static void
|
||||
_vt_cmd_obj_copy_lnk_vlan(NMPObject *dst, const NMPObject *src)
|
||||
{
|
||||
|
@ -1577,14 +1677,6 @@ _vt_cmd_plobj_id_cmp(tfilter, NMPlatformTfilter, {
|
|||
NM_CMP_FIELD(obj1, obj2, handle);
|
||||
});
|
||||
|
||||
static int
|
||||
_vt_cmd_plobj_id_cmp_ip4_route(const NMPlatformObject *obj1, const NMPlatformObject *obj2)
|
||||
{
|
||||
return nm_platform_ip4_route_cmp((const NMPlatformIP4Route *) obj1,
|
||||
(const NMPlatformIP4Route *) obj2,
|
||||
NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID);
|
||||
}
|
||||
|
||||
static int
|
||||
_vt_cmd_plobj_id_cmp_ip6_route(const NMPlatformObject *obj1, const NMPlatformObject *obj2)
|
||||
{
|
||||
|
@ -1673,10 +1765,6 @@ _vt_cmd_plobj_id_hash_update(ip6_address, NMPlatformIP6Address, {
|
|||
obj->address);
|
||||
});
|
||||
|
||||
_vt_cmd_plobj_id_hash_update(ip4_route, NMPlatformIP4Route, {
|
||||
nm_platform_ip4_route_hash_update(obj, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID, h);
|
||||
});
|
||||
|
||||
_vt_cmd_plobj_id_hash_update(ip6_route, NMPlatformIP6Route, {
|
||||
nm_platform_ip6_route_hash_update(obj, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID, h);
|
||||
});
|
||||
|
@ -1699,14 +1787,6 @@ _vt_cmd_plobj_id_hash_update(mptcp_addr, NMPlatformMptcpAddr, {
|
|||
nm_hash_update(h, &obj->addr, nm_utils_addr_family_to_size_untrusted(obj->addr_family));
|
||||
});
|
||||
|
||||
static void
|
||||
_vt_cmd_plobj_hash_update_ip4_route(const NMPlatformObject *obj, NMHashState *h)
|
||||
{
|
||||
return nm_platform_ip4_route_hash_update((const NMPlatformIP4Route *) obj,
|
||||
NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL,
|
||||
h);
|
||||
}
|
||||
|
||||
static void
|
||||
_vt_cmd_plobj_hash_update_ip6_route(const NMPlatformObject *obj, NMHashState *h)
|
||||
{
|
||||
|
@ -1715,6 +1795,14 @@ _vt_cmd_plobj_hash_update_ip6_route(const NMPlatformObject *obj, NMHashState *h)
|
|||
h);
|
||||
}
|
||||
|
||||
static int
|
||||
_vt_cmd_plobj_cmp_ip6_route(const NMPlatformObject *obj1, const NMPlatformObject *obj2)
|
||||
{
|
||||
return nm_platform_ip6_route_cmp((const NMPlatformIP6Route *) obj1,
|
||||
(const NMPlatformIP6Route *) obj2,
|
||||
NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL);
|
||||
}
|
||||
|
||||
static void
|
||||
_vt_cmd_plobj_hash_update_routing_rule(const NMPlatformObject *obj, NMHashState *h)
|
||||
{
|
||||
|
@ -1723,6 +1811,24 @@ _vt_cmd_plobj_hash_update_routing_rule(const NMPlatformObject *obj, NMHashState
|
|||
h);
|
||||
}
|
||||
|
||||
static inline int
|
||||
_vt_cmd_plobj_cmp_routing_rule(const NMPlatformObject *obj1, const NMPlatformObject *obj2)
|
||||
{
|
||||
return nm_platform_routing_rule_cmp((const NMPlatformRoutingRule *) obj1,
|
||||
(const NMPlatformRoutingRule *) obj2,
|
||||
NM_PLATFORM_ROUTING_RULE_CMP_TYPE_FULL);
|
||||
}
|
||||
|
||||
static int
|
||||
_vt_cmd_plobj_cmp_qdisc(const NMPlatformObject *obj1, const NMPlatformObject *obj2)
|
||||
{
|
||||
return nm_platform_qdisc_cmp((const NMPlatformQdisc *) obj1,
|
||||
(const NMPlatformQdisc *) obj2,
|
||||
TRUE);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
guint
|
||||
nmp_object_indirect_id_hash(gconstpointer a)
|
||||
{
|
||||
|
@ -3218,23 +3324,22 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
|
|||
},
|
||||
[NMP_OBJECT_TYPE_IP4_ROUTE - 1] =
|
||||
{
|
||||
.parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
|
||||
.obj_type = NMP_OBJECT_TYPE_IP4_ROUTE,
|
||||
.sizeof_data = sizeof(NMPObjectIP4Route),
|
||||
.sizeof_public = sizeof(NMPlatformIP4Route),
|
||||
.obj_type_name = "ip4-route",
|
||||
.addr_family = AF_INET,
|
||||
.rtm_gettype = RTM_GETROUTE,
|
||||
.signal_type_id = NM_PLATFORM_SIGNAL_ID_IP4_ROUTE,
|
||||
.signal_type = NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED,
|
||||
.supported_cache_ids = _supported_cache_ids_ipx_route,
|
||||
.cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_route,
|
||||
.cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_ip4_route,
|
||||
.cmd_plobj_id_hash_update = _vt_cmd_plobj_id_hash_update_ip4_route,
|
||||
.cmd_plobj_to_string_id = (CmdPlobjToStringIdFunc) nm_platform_ip4_route_to_string,
|
||||
.cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_ip4_route_to_string,
|
||||
.cmd_plobj_hash_update = _vt_cmd_plobj_hash_update_ip4_route,
|
||||
.cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_ip4_route_cmp_full,
|
||||
.parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
|
||||
.obj_type = NMP_OBJECT_TYPE_IP4_ROUTE,
|
||||
.sizeof_data = sizeof(NMPObjectIP4Route),
|
||||
.sizeof_public = sizeof(NMPlatformIP4Route),
|
||||
.obj_type_name = "ip4-route",
|
||||
.addr_family = AF_INET,
|
||||
.rtm_gettype = RTM_GETROUTE,
|
||||
.signal_type_id = NM_PLATFORM_SIGNAL_ID_IP4_ROUTE,
|
||||
.signal_type = NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED,
|
||||
.supported_cache_ids = _supported_cache_ids_ipx_route,
|
||||
.cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_route,
|
||||
.cmd_obj_hash_update = _vt_cmd_obj_hash_update_ip4_route,
|
||||
.cmd_obj_cmp = _vt_cmd_obj_cmp_ip4_route,
|
||||
.cmd_obj_copy = _vt_cmd_obj_copy_ip4_route,
|
||||
.cmd_obj_dispose = _vt_cmd_obj_dispose_ip4_route,
|
||||
.cmd_obj_to_string = _vt_cmd_obj_to_string_ip4_route,
|
||||
},
|
||||
[NMP_OBJECT_TYPE_IP6_ROUTE - 1] =
|
||||
{
|
||||
|
@ -3254,7 +3359,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
|
|||
.cmd_plobj_to_string_id = (CmdPlobjToStringIdFunc) nm_platform_ip6_route_to_string,
|
||||
.cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_ip6_route_to_string,
|
||||
.cmd_plobj_hash_update = _vt_cmd_plobj_hash_update_ip6_route,
|
||||
.cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_ip6_route_cmp_full,
|
||||
.cmd_plobj_cmp = _vt_cmd_plobj_cmp_ip6_route,
|
||||
},
|
||||
[NMP_OBJECT_TYPE_ROUTING_RULE - 1] =
|
||||
{
|
||||
|
@ -3273,7 +3378,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
|
|||
.cmd_plobj_to_string_id = (CmdPlobjToStringIdFunc) nm_platform_routing_rule_to_string,
|
||||
.cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_routing_rule_to_string,
|
||||
.cmd_plobj_hash_update = _vt_cmd_plobj_hash_update_routing_rule,
|
||||
.cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_routing_rule_cmp_full,
|
||||
.cmd_plobj_cmp = _vt_cmd_plobj_cmp_routing_rule,
|
||||
},
|
||||
[NMP_OBJECT_TYPE_QDISC - 1] =
|
||||
{
|
||||
|
@ -3292,7 +3397,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
|
|||
.cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_qdisc,
|
||||
.cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_qdisc_to_string,
|
||||
.cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_qdisc_hash_update,
|
||||
.cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_qdisc_cmp,
|
||||
.cmd_plobj_cmp = _vt_cmd_plobj_cmp_qdisc,
|
||||
},
|
||||
[NMP_OBJECT_TYPE_TFILTER - 1] =
|
||||
{
|
||||
|
|
|
@ -314,6 +314,13 @@ typedef struct {
|
|||
|
||||
typedef struct {
|
||||
NMPlatformIP4Route _public;
|
||||
|
||||
/* The first hop is embedded in _public (in the
|
||||
* ifindex, gateway and weight fields).
|
||||
* Only if _public.n_nexthops is greater than 1, then
|
||||
* this contains the remaining(!!) (_public.n_nexthops - 1)
|
||||
* extra hops for ECMP multihop routes. */
|
||||
const NMPlatformIP4RtNextHop *extra_nexthops;
|
||||
} NMPObjectIP4Route;
|
||||
|
||||
typedef struct {
|
||||
|
|
Loading…
Reference in a new issue