From 45dc2fededfe9db586b9f181263e72b769359a62 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Wed, 15 Feb 2017 14:00:44 +0100 Subject: [PATCH] platform: add support for some route options Add support for new route options: window, cwnd, initcwnd, initrwnd, mtu (and their related *-lock flag), tos and src (RTA_SRC). --- src/platform/nm-linux-platform.c | 145 ++++++++++++++++++++++++++----- src/platform/nm-platform.c | 89 ++++++++++++++++++- src/platform/nm-platform.h | 13 +++ src/platform/tests/test-route.c | 131 ++++++++++++++++++++++++++++ 4 files changed, 352 insertions(+), 26 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 38d7b63db5..921a70f2a2 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -1833,6 +1833,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) NMIPAddr gateway; } nh; guint32 mss; + guint32 window = 0, cwnd = 0, initcwnd = 0, initrwnd = 0, mtu = 0, lock = 0; guint32 table; if (!nlmsg_valid_hdr (nlh, sizeof (*rtm))) @@ -1846,8 +1847,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) if (!NM_IN_SET (rtm->rtm_family, AF_INET, AF_INET6)) goto errout; - if ( rtm->rtm_type != RTN_UNICAST - || rtm->rtm_tos != 0) + if (rtm->rtm_type != RTN_UNICAST) goto errout; err = nlmsg_parse (nlh, sizeof (struct rtmsg), tb, RTA_MAX, policy); @@ -1941,21 +1941,34 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) mss = 0; if (tb[RTA_METRICS]) { struct nlattr *mtb[RTAX_MAX + 1]; - int i; + static struct nla_policy rtax_policy[RTAX_MAX + 1] = { + [RTAX_LOCK] = { .type = NLA_U32 }, + [RTAX_ADVMSS] = { .type = NLA_U32 }, + [RTAX_WINDOW] = { .type = NLA_U32 }, + [RTAX_CWND] = { .type = NLA_U32 }, + [RTAX_INITCWND] = { .type = NLA_U32 }, + [RTAX_INITRWND] = { .type = NLA_U32 }, + [RTAX_MTU] = { .type = NLA_U32 }, + }; - err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL); + err = nla_parse_nested (mtb, RTAX_MAX, tb[RTA_METRICS], rtax_policy); if (err < 0) goto errout; - for (i = 1; i <= RTAX_MAX; i++) { - if (mtb[i]) { - if (i == RTAX_ADVMSS) { - if (nla_len (mtb[i]) >= sizeof (uint32_t)) - mss = nla_get_u32(mtb[i]); - break; - } - } - } + if (mtb[RTAX_LOCK]) + lock = nla_get_u32 (mtb[RTAX_LOCK]); + if (mtb[RTAX_ADVMSS]) + mss = nla_get_u32 (mtb[RTAX_ADVMSS]); + if (mtb[RTAX_WINDOW]) + window = nla_get_u32 (mtb[RTAX_WINDOW]); + if (mtb[RTAX_CWND]) + cwnd = nla_get_u32 (mtb[RTAX_CWND]); + if (mtb[RTAX_INITCWND]) + initcwnd = nla_get_u32 (mtb[RTAX_INITCWND]); + if (mtb[RTAX_INITRWND]) + initrwnd = nla_get_u32 (mtb[RTAX_INITRWND]); + if (mtb[RTAX_MTU]) + mtu = nla_get_u32 (mtb[RTAX_MTU]); } /*****************************************************************/ @@ -1987,7 +2000,24 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) memcpy (&obj->ip6_route.pref_src, nla_data (tb[RTA_PREFSRC]), addr_len); } + if (!is_v4 && tb[RTA_SRC]) { + _check_addr_or_errout (tb, RTA_SRC, addr_len); + memcpy (&obj->ip6_route.src, nla_data (tb[RTA_SRC]), addr_len); + obj->ip6_route.src_plen = rtm->rtm_src_len; + } + obj->ip_route.mss = mss; + obj->ip_route.window = window; + obj->ip_route.cwnd = cwnd; + obj->ip_route.initcwnd = initcwnd; + obj->ip_route.initrwnd = initrwnd; + obj->ip_route.mtu = mtu; + obj->ip_route.tos = rtm->rtm_tos; + obj->ip_route.lock_window = NM_FLAGS_HAS (lock, 1 << RTAX_WINDOW); + obj->ip_route.lock_cwnd = NM_FLAGS_HAS (lock, 1 << RTAX_CWND); + obj->ip_route.lock_initcwnd = NM_FLAGS_HAS (lock, 1 << RTAX_INITCWND); + obj->ip_route.lock_initrwnd = NM_FLAGS_HAS (lock, 1 << RTAX_INITRWND); + obj->ip_route.lock_mtu = NM_FLAGS_HAS (lock, 1 << RTAX_MTU); if (NM_FLAGS_HAS (rtm->rtm_flags, RTM_F_CLONED)) { /* we must not straight way reject cloned routes, because we might have cached @@ -2362,19 +2392,28 @@ _nl_msg_new_route (int nlmsg_type, gconstpointer gateway, guint32 metric, guint32 mss, - gconstpointer pref_src) + gconstpointer pref_src, + gconstpointer src, + guint8 src_plen, + guint8 tos, + guint32 window, + guint32 cwnd, + guint32 initcwnd, + guint32 initrwnd, + guint32 mtu, + guint32 lock) { struct nl_msg *msg; struct rtmsg rtmsg = { .rtm_family = family, - .rtm_tos = 0, + .rtm_tos = tos, .rtm_table = RT_TABLE_MAIN, /* omit setting RTA_TABLE attribute */ .rtm_protocol = nmp_utils_ip_config_source_coerce_to_rtprot (source), .rtm_scope = scope, .rtm_type = RTN_UNICAST, .rtm_flags = 0, .rtm_dst_len = plen, - .rtm_src_len = 0, + .rtm_src_len = src ? src_plen : 0, }; NMIPAddr network_clean; @@ -2396,19 +2435,35 @@ _nl_msg_new_route (int nlmsg_type, nm_utils_ipx_address_clear_host_address (family, &network_clean, network, plen); NLA_PUT (msg, RTA_DST, addr_len, &network_clean); + if (src) + NLA_PUT (msg, RTA_SRC, addr_len, src); + NLA_PUT_U32 (msg, RTA_PRIORITY, metric); if (pref_src) NLA_PUT (msg, RTA_PREFSRC, addr_len, pref_src); - if (mss > 0) { + if (mss || window || cwnd || initcwnd || initrwnd || mtu || lock) { struct nlattr *metrics; metrics = nla_nest_start (msg, RTA_METRICS); if (!metrics) goto nla_put_failure; - NLA_PUT_U32 (msg, RTAX_ADVMSS, mss); + if (mss) + NLA_PUT_U32 (msg, RTAX_ADVMSS, mss); + if (window) + NLA_PUT_U32 (msg, RTAX_WINDOW, window); + if (cwnd) + NLA_PUT_U32 (msg, RTAX_CWND, cwnd); + if (initcwnd) + NLA_PUT_U32 (msg, RTAX_INITCWND, initcwnd); + if (initrwnd) + NLA_PUT_U32 (msg, RTAX_INITRWND, initrwnd); + if (mtu) + NLA_PUT_U32 (msg, RTAX_MTU, mtu); + if (lock) + NLA_PUT_U32 (msg, RTAX_LOCK, lock); nla_nest_end(msg, metrics); } @@ -5903,6 +5958,16 @@ ip6_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags fl return ipx_route_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP6_ROUTE, flags); } +static guint32 +ip_route_get_lock_flag (NMPlatformIPRoute *route) +{ + return (((guint32) route->lock_window) << RTAX_WINDOW) + | (((guint32) route->lock_cwnd) << RTAX_CWND) + | (((guint32) route->lock_initcwnd) << RTAX_INITCWND) + | (((guint32) route->lock_initrwnd) << RTAX_INITRWND) + | (((guint32) route->lock_mtu) << RTAX_MTU); +} + static gboolean ip4_route_add (NMPlatform *platform, const NMPlatformIP4Route *route) { @@ -5924,7 +5989,16 @@ ip4_route_add (NMPlatform *platform, const NMPlatformIP4Route *route) &route->gateway, route->metric, route->mss, - route->pref_src ? &route->pref_src : NULL); + route->pref_src ? &route->pref_src : NULL, + NULL, + 0, + route->tos, + route->window, + route->cwnd, + route->initcwnd, + route->initrwnd, + route->mtu, + ip_route_get_lock_flag ((NMPlatformIPRoute *) route)); nmp_object_stackinit_id_ip4_route (&obj_id, route->ifindex, network, route->plen, route->metric); return do_add_addrroute (platform, &obj_id, nlmsg); @@ -5951,7 +6025,16 @@ ip6_route_add (NMPlatform *platform, const NMPlatformIP6Route *route) &route->gateway, route->metric, route->mss, - !IN6_IS_ADDR_UNSPECIFIED (&route->pref_src) ? &route->pref_src : NULL); + !IN6_IS_ADDR_UNSPECIFIED (&route->pref_src) ? &route->pref_src : NULL, + !IN6_IS_ADDR_UNSPECIFIED (&route->src) ? &route->src : NULL, + route->src_plen, + route->tos, + route->window, + route->cwnd, + route->initcwnd, + route->initrwnd, + route->mtu, + ip_route_get_lock_flag ((NMPlatformIPRoute *) route)); nmp_object_stackinit_id_ip6_route (&obj_id, route->ifindex, &network, route->plen, route->metric); return do_add_addrroute (platform, &obj_id, nlmsg); @@ -6006,7 +6089,16 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 p NULL, metric, 0, - NULL); + NULL, + NULL, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0); if (!nlmsg) return FALSE; @@ -6032,7 +6124,16 @@ ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, gu NULL, metric, 0, - NULL); + NULL, + NULL, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0); if (!nlmsg) return FALSE; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 5878231edc..e711f642d6 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -3865,6 +3865,7 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi char s_pref_src[INET_ADDRSTRLEN]; char str_dev[TO_STRING_DEV_BUF_SIZE]; char str_scope[30], s_source[50]; + char str_tos[32], str_window[32], str_cwnd[32], str_initcwnd[32], str_initrwnd[32], str_mtu[32]; if (!nm_utils_to_string_buffer_init_null (route, &buf, &len)) return buf; @@ -3874,16 +3875,35 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi _to_string_dev (NULL, route->ifindex, str_dev, sizeof (str_dev)); + if (route->tos) + nm_sprintf_buf (str_tos, " tos 0x%x", (unsigned) route->tos); + if (route->window) + nm_sprintf_buf (str_window, " window %s%"G_GUINT32_FORMAT, route->lock_window ? "lock " : "", route->window); + if (route->cwnd) + nm_sprintf_buf (str_cwnd, " cwnd %s%"G_GUINT32_FORMAT, route->lock_cwnd ? "lock " : "", route->cwnd); + if (route->initcwnd) + nm_sprintf_buf (str_initcwnd, " initcwnd %s%"G_GUINT32_FORMAT, route->lock_initcwnd ? "lock " : "", route->initcwnd); + if (route->initrwnd) + nm_sprintf_buf (str_initrwnd, " initrwnd %s%"G_GUINT32_FORMAT, route->lock_initrwnd ? "lock " : "", route->initrwnd); + if (route->mtu) + nm_sprintf_buf (str_mtu, " mtu %s%"G_GUINT32_FORMAT, route->lock_mtu ? "lock " : "", route->mtu); + g_snprintf (buf, len, "%s/%d" " via %s" "%s" " metric %"G_GUINT32_FORMAT " mss %"G_GUINT32_FORMAT - " src %s" /* source */ + " rt-src %s" /* protocol */ "%s" /* cloned */ "%s%s" /* scope */ "%s%s" /* pref-src */ + "%s" /* tos */ + "%s" /* window */ + "%s" /* cwnd */ + "%s" /* initcwnd */ + "%s" /* initrwnd */ + "%s" /* mtu */ "", s_network, route->plen, @@ -3896,7 +3916,13 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi route->scope_inv ? " scope " : "", route->scope_inv ? (nm_platform_route_scope2str (nm_platform_route_scope_inv (route->scope_inv), str_scope, sizeof (str_scope))) : "", route->pref_src ? " pref-src " : "", - route->pref_src ? inet_ntop (AF_INET, &route->pref_src, s_pref_src, sizeof(s_pref_src)) : ""); + route->pref_src ? inet_ntop (AF_INET, &route->pref_src, s_pref_src, sizeof(s_pref_src)) : "", + route->tos ? str_tos : "", + route->window ? str_window : "", + route->cwnd ? str_cwnd : "", + route->initcwnd ? str_initcwnd : "", + route->initrwnd ? str_initrwnd : "", + route->mtu ? str_mtu : ""); return buf; } @@ -3916,13 +3942,16 @@ const char * nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsize len) { char s_network[INET6_ADDRSTRLEN], s_gateway[INET6_ADDRSTRLEN], s_pref_src[INET6_ADDRSTRLEN]; + char s_src[INET6_ADDRSTRLEN]; char str_dev[TO_STRING_DEV_BUF_SIZE], s_source[50]; + char str_tos[32], str_window[32], str_cwnd[32], str_initcwnd[32], str_initrwnd[32], str_mtu[32]; if (!nm_utils_to_string_buffer_init_null (route, &buf, &len)) return buf; inet_ntop (AF_INET6, &route->network, s_network, sizeof (s_network)); inet_ntop (AF_INET6, &route->gateway, s_gateway, sizeof (s_gateway)); + inet_ntop (AF_INET6, &route->src, s_src, sizeof (s_src)); if (IN6_IS_ADDR_UNSPECIFIED (&route->pref_src)) s_pref_src[0] = 0; @@ -3931,15 +3960,35 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi _to_string_dev (NULL, route->ifindex, str_dev, sizeof (str_dev)); + if (route->tos) + nm_sprintf_buf (str_tos, " tos 0x%x", (unsigned) route->tos); + if (route->window) + nm_sprintf_buf (str_window, " window %s%"G_GUINT32_FORMAT, route->lock_window ? "lock " : "", route->window); + if (route->cwnd) + nm_sprintf_buf (str_cwnd, " cwnd %s%"G_GUINT32_FORMAT, route->lock_cwnd ? "lock " : "", route->cwnd); + if (route->initcwnd) + nm_sprintf_buf (str_initcwnd, " initcwnd %s%"G_GUINT32_FORMAT, route->lock_initcwnd ? "lock " : "", route->initcwnd); + if (route->initrwnd) + nm_sprintf_buf (str_initrwnd, " initrwnd %s%"G_GUINT32_FORMAT, route->lock_initrwnd ? "lock " : "", route->initrwnd); + if (route->mtu) + nm_sprintf_buf (str_mtu, " mtu %s%"G_GUINT32_FORMAT, route->lock_mtu ? "lock " : "", route->mtu); + g_snprintf (buf, len, "%s/%d" " via %s" "%s" " metric %"G_GUINT32_FORMAT " mss %"G_GUINT32_FORMAT - " src %s" /* source */ + " rt-src %s" /* protocol */ + " src %s/%u" /* source */ "%s" /* cloned */ "%s%s" /* pref-src */ + "%s" /* tos */ + "%s" /* window */ + "%s" /* cwnd */ + "%s" /* initcwnd */ + "%s" /* initrwnd */ + "%s" /* mtu */ "", s_network, route->plen, @@ -3948,9 +3997,17 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi route->metric, route->mss, nmp_utils_ip_config_source_to_string (route->rt_source, s_source, sizeof (s_source)), + s_src, route->src_plen, route->rt_cloned ? " cloned" : "", s_pref_src[0] ? " pref-src " : "", - s_pref_src[0] ? s_pref_src : ""); + s_pref_src[0] ? s_pref_src : "", + route->tos ? str_tos : "", + route->window ? str_window : "", + route->cwnd ? str_cwnd : "", + route->initcwnd ? str_initcwnd : "", + route->initrwnd ? str_initrwnd : "", + route->mtu ? str_mtu : ""); + return buf; } @@ -4239,6 +4296,17 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route _CMP_FIELD (a, b, scope_inv); _CMP_FIELD (a, b, pref_src); _CMP_FIELD (a, b, rt_cloned); + _CMP_FIELD (a, b, tos); + _CMP_FIELD (a, b, lock_window); + _CMP_FIELD (a, b, lock_cwnd); + _CMP_FIELD (a, b, lock_initcwnd); + _CMP_FIELD (a, b, lock_initrwnd); + _CMP_FIELD (a, b, lock_mtu); + _CMP_FIELD (a, b, window); + _CMP_FIELD (a, b, cwnd); + _CMP_FIELD (a, b, initcwnd); + _CMP_FIELD (a, b, initrwnd); + _CMP_FIELD (a, b, mtu); return 0; } @@ -4252,9 +4320,22 @@ nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route _CMP_FIELD (a, b, metric); _CMP_FIELD_MEMCMP (a, b, gateway); _CMP_FIELD_MEMCMP (a, b, pref_src); + _CMP_FIELD_MEMCMP (a, b, src); + _CMP_FIELD (a, b, src_plen); _CMP_FIELD (a, b, rt_source); _CMP_FIELD (a, b, mss); _CMP_FIELD (a, b, rt_cloned); + _CMP_FIELD (a, b, tos); + _CMP_FIELD (a, b, lock_window); + _CMP_FIELD (a, b, lock_cwnd); + _CMP_FIELD (a, b, lock_initcwnd); + _CMP_FIELD (a, b, lock_initrwnd); + _CMP_FIELD (a, b, lock_mtu); + _CMP_FIELD (a, b, window); + _CMP_FIELD (a, b, cwnd); + _CMP_FIELD (a, b, initcwnd); + _CMP_FIELD (a, b, initrwnd); + _CMP_FIELD (a, b, mtu); return 0; } diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 28dd650a89..a9d192f0dd 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -324,9 +324,20 @@ typedef union { * of platform users. This flag is internal to track those hidden * routes. Such a route is not alive, according to nmp_object_is_alive(). */ \ bool rt_cloned:1; \ + bool lock_window:1; \ + bool lock_cwnd:1; \ + bool lock_initcwnd:1; \ + bool lock_initrwnd:1; \ + bool lock_mtu:1; \ \ guint32 metric; \ guint32 mss; \ + guint32 tos; \ + guint32 window; \ + guint32 cwnd; \ + guint32 initcwnd; \ + guint32 initrwnd; \ + guint32 mtu; \ ; typedef struct { @@ -359,6 +370,8 @@ struct _NMPlatformIP6Route { struct in6_addr network; struct in6_addr gateway; struct in6_addr pref_src; + struct in6_addr src; + guint8 src_plen; }; typedef union { diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index ecc1e10643..ca5b847c9d 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -222,6 +222,14 @@ test_ip4_route (void) /* Remove route again */ g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric)); + /* Remove default route */ + g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, 0, 0, metric)); + accept_signal (route_removed); + + /* Remove route to gateway */ + g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, gateway, 32, metric)); + accept_signal (route_removed); + free_signal (route_added); free_signal (route_changed); free_signal (route_removed); @@ -314,6 +322,14 @@ test_ip6_route (void) /* Remove route again */ g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric)); + /* Remove default route */ + g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, in6addr_any, 0, metric)); + accept_signal (route_removed); + + /* Remove route to gateway */ + g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, gateway, 128, metric)); + accept_signal (route_removed); + free_signal (route_added); free_signal (route_changed); free_signal (route_removed); @@ -342,6 +358,119 @@ test_ip4_zero_gateway (void) nm_platform_process_events (NM_PLATFORM_GET); } +static void +test_ip4_route_options (void) +{ + int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); + NMPlatformIP4Route route = { }; + in_addr_t network; + GArray *routes; + NMPlatformIP4Route rts[1]; + + inet_pton (AF_INET, "172.16.1.0", &network); + + route.ifindex = ifindex; + route.rt_source = NM_IP_CONFIG_SOURCE_USER; + route.network = network; + route.plen = 24; + route.metric = 20; + route.tos = 0x28; + route.window = 10000; + route.cwnd = 16; + route.initcwnd = 30; + route.initrwnd = 50; + route.mtu = 1350; + route.lock_cwnd = TRUE; + + g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, &route)); + + /* Test route listing */ + routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, + NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | + NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); + memset (rts, 0, sizeof (rts)); + rts[0].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER); + rts[0].scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK); + rts[0].network = network; + rts[0].plen = 24; + rts[0].ifindex = ifindex; + rts[0].metric = 20; + rts[0].tos = 0x28; + rts[0].window = 10000; + rts[0].cwnd = 16; + rts[0].initcwnd = 30; + rts[0].initrwnd = 50; + rts[0].mtu = 1350; + rts[0].lock_cwnd = TRUE; + + g_assert_cmpint (routes->len, ==, 1); + nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, rts, routes->len, TRUE); + + /* Remove route */ + g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, 24, 20)); + + g_array_unref (routes); +} + + +static void +test_ip6_route_options (void) +{ + int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); + NMPlatformIP6Route route = { }; + struct in6_addr network, src; + GArray *routes; + NMPlatformIP6Route rts[3]; + + inet_pton (AF_INET6, "2001:db8:a:b:0:0:0:0", &network); + inet_pton (AF_INET6, "2001:db8:e:0:0:0:0:0", &src); + + route.ifindex = ifindex; + route.rt_source = NM_IP_CONFIG_SOURCE_USER; + route.network = network; + route.plen = 64; + route.gateway = in6addr_any; + route.src = src; + route.src_plen = 48; + route.metric = 1024; + route.window = 20000; + route.cwnd = 8; + route.initcwnd = 22; + route.initrwnd = 33; + route.mtu = 1300; + route.lock_mtu = TRUE; + + g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, &route)); + + /* Test route listing */ + routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, + NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | + NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); + 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 = network; + rts[0].plen = 64; + rts[0].ifindex = ifindex; + rts[0].gateway = in6addr_any; + rts[0].src = src; + rts[0].src_plen = 48; + rts[0].metric = 1024; + rts[0].window = 20000; + rts[0].cwnd = 8; + rts[0].initcwnd = 22; + rts[0].initrwnd = 33; + rts[0].mtu = 1300; + rts[0].lock_mtu = TRUE; + + g_assert_cmpint (routes->len, ==, 1); + nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, rts, routes->len, TRUE); + + /* Remove route */ + g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, 64, 1024)); + + g_array_unref (routes); +} + /*****************************************************************************/ NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP; @@ -368,6 +497,8 @@ _nmtstp_setup_tests (void) g_test_add_func ("/route/ip4", test_ip4_route); g_test_add_func ("/route/ip6", test_ip6_route); g_test_add_func ("/route/ip4_metric0", test_ip4_route_metric0); + g_test_add_func ("/route/ip4_options", test_ip4_route_options); + g_test_add_func ("/route/ip6_options", test_ip6_route_options); if (nmtstp_is_root_test ()) g_test_add_func ("/route/ip4_zero_gateway", test_ip4_zero_gateway);