From c55c6312330288c4b1b1afcbeef7ef99a7a95810 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 17 Feb 2017 09:27:11 +0100 Subject: [PATCH 01/11] shared: add test utilities for IP routes Add utility functions to check the value of a route attribute. --- shared/nm-utils/nm-test-utils.h | 45 +++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/shared/nm-utils/nm-test-utils.h b/shared/nm-utils/nm-test-utils.h index 579504dcb7..b7d45b262c 100644 --- a/shared/nm-utils/nm-test-utils.h +++ b/shared/nm-utils/nm-test-utils.h @@ -1291,6 +1291,50 @@ nmtst_setting_ip_config_add_route (NMSettingIPConfig *s_ip, g_assert (nm_setting_ip_config_add_route (s_ip, route)); nm_ip_route_unref (route); } + +inline static void +nmtst_assert_route_attribute_string (NMIPRoute *route, const char *name, const char *value) +{ + GVariant *variant; + + variant = nm_ip_route_get_attribute (route, name); + g_assert (variant); + g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)); + g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, value); +} + +inline static void +nmtst_assert_route_attribute_byte (NMIPRoute *route, const char *name, guchar value) +{ + GVariant *variant; + + variant = nm_ip_route_get_attribute (route, name); + g_assert (variant); + g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTE)); + g_assert_cmpint (g_variant_get_byte (variant), ==, value); +} + +inline static void +nmtst_assert_route_attribute_uint32 (NMIPRoute *route, const char *name, guint32 value) +{ + GVariant *variant; + + variant = nm_ip_route_get_attribute (route, name); + g_assert (variant); + g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32)); + g_assert_cmpint (g_variant_get_uint32 (variant), ==, value); +} + +inline static void +nmtst_assert_route_attribute_boolean (NMIPRoute *route, const char *name, gboolean value) +{ + GVariant *variant; + + variant = nm_ip_route_get_attribute (route, name); + g_assert (variant); + g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN)); + g_assert_cmpint (g_variant_get_boolean (variant), ==, value); +} #endif /* NM_SETTING_IP_CONFIG_H */ #if (defined(__NM_SIMPLE_CONNECTION_H__) && defined(__NM_SETTING_CONNECTION_H__)) || (defined(NM_CONNECTION_H)) @@ -1661,6 +1705,7 @@ nmtst_assert_hwaddr_equals (gconstpointer hwaddr1, gssize hwaddr1_len, const cha nmtst_assert_hwaddr_equals (hwaddr1, hwaddr1_len, expected, __FILE__, __LINE__) #endif + #if defined(__NM_SIMPLE_CONNECTION_H__) && defined(__NM_SETTING_CONNECTION_H__) && defined(__NM_KEYFILE_INTERNAL_H__) static inline NMConnection * From 36d9e252d2733f43765597d54bcdd9efa750531d Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 9 Feb 2017 17:26:04 +0100 Subject: [PATCH 02/11] platform: support preferred source option for IPv6 routes Extend the support for the preferred source route option (RTA_PREFSRC) to IPv6. --- src/nm-default-route-manager.c | 1 + src/nm-test-utils-core.h | 5 +++-- src/platform/nm-fake-platform.c | 3 ++- src/platform/nm-linux-platform.c | 10 ++++++---- src/platform/nm-platform.c | 23 +++++++++++++++++------ src/platform/nm-platform.h | 5 +++-- src/platform/tests/test-cleanup.c | 6 +++--- src/platform/tests/test-route.c | 20 ++++++++++++++------ src/tests/test-ip6-config.c | 10 +++++----- src/tests/test-route-manager.c | 1 + 10 files changed, 55 insertions(+), 29 deletions(-) diff --git a/src/nm-default-route-manager.c b/src/nm-default-route-manager.c index 5944654cff..428c343673 100644 --- a/src/nm-default-route-manager.c +++ b/src/nm-default-route-manager.c @@ -317,6 +317,7 @@ _platform_route_sync_add (const VTableIP *vtable, NMDefaultRouteManager *self, g in6addr_any, 0, entry->route.r6.gateway, + entry->route.r6.pref_src, entry->effective_metric, entry->route.rx.mss); } diff --git a/src/nm-test-utils-core.h b/src/nm-test-utils-core.h index 546e2361f2..7cd08ce57a 100644 --- a/src/nm-test-utils-core.h +++ b/src/nm-test-utils-core.h @@ -162,7 +162,7 @@ nmtst_platform_ip4_route_full (const char *network, guint plen, const char *gate } static inline NMPlatformIP6Route * -nmtst_platform_ip6_route (const char *network, guint plen, const char *gateway) +nmtst_platform_ip6_route (const char *network, guint plen, const char *gateway, const char *pref_src) { static NMPlatformIP6Route route; @@ -172,6 +172,7 @@ nmtst_platform_ip6_route (const char *network, guint plen, const char *gateway) route.network = *nmtst_inet6_from_string (network); route.plen = plen; route.gateway = *nmtst_inet6_from_string (gateway); + route.pref_src = *nmtst_inet6_from_string (pref_src); return &route; } @@ -181,7 +182,7 @@ nmtst_platform_ip6_route_full (const char *network, guint plen, const char *gate int ifindex, NMIPConfigSource source, guint metric, guint mss) { - NMPlatformIP6Route *route = nmtst_platform_ip6_route (network, plen, gateway); + NMPlatformIP6Route *route = nmtst_platform_ip6_route (network, plen, gateway, NULL); route->ifindex = ifindex; route->rt_source = source; diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index b92f56ce21..447188e631 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -1295,7 +1295,7 @@ ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, static gboolean ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, struct in6_addr network, guint8 plen, struct in6_addr gateway, - guint32 metric, guint32 mss) + struct in6_addr pref_src, guint32 metric, guint32 mss) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform); NMPlatformIP6Route route; @@ -1311,6 +1311,7 @@ ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, route.gateway = gateway; route.metric = metric; route.mss = mss; + route.pref_src = pref_src; if (!IN6_IS_ADDR_UNSPECIFIED(&gateway)) { for (i = 0; i < priv->ip6_routes->len; i++) { diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 3138b171bc..abc26e37f3 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -1980,9 +1980,11 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) if (is_v4) obj->ip4_route.scope_inv = nm_platform_route_scope_inv (rtm->rtm_scope); - if (is_v4) { - if (_check_addr_or_errout (tb, RTA_PREFSRC, addr_len)) + if (_check_addr_or_errout (tb, RTA_PREFSRC, addr_len)) { + if (is_v4) memcpy (&obj->ip4_route.pref_src, nla_data (tb[RTA_PREFSRC]), addr_len); + else + memcpy (&obj->ip6_route.pref_src, nla_data (tb[RTA_PREFSRC]), addr_len); } obj->ip_route.mss = mss; @@ -5929,7 +5931,7 @@ ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, static gboolean ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, struct in6_addr network, guint8 plen, struct in6_addr gateway, - guint32 metric, guint32 mss) + struct in6_addr pref_src, guint32 metric, guint32 mss) { NMPObject obj_id; nm_auto_nlmsg struct nl_msg *nlmsg = NULL; @@ -5945,7 +5947,7 @@ ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, &gateway, metric, mss, - NULL); + !IN6_IS_ADDR_UNSPECIFIED (&pref_src) ? &pref_src : NULL); nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric); return do_add_addrroute (platform, &obj_id, nlmsg); diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index b72534420e..713fccb32c 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -3168,7 +3168,7 @@ gboolean nm_platform_ip6_route_add (NMPlatform *self, int ifindex, NMIPConfigSource source, struct in6_addr network, guint8 plen, struct in6_addr gateway, - guint32 metric, guint32 mss) + struct in6_addr pref_src, guint32 metric, guint32 mss) { _CHECK_SELF (self, klass, FALSE); @@ -3182,12 +3182,13 @@ nm_platform_ip6_route_add (NMPlatform *self, route.network = network; route.plen = plen; route.gateway = gateway; + route.pref_src = pref_src; route.metric = metric; route.mss = mss; _LOGD ("route: adding or updating IPv6 route: %s", nm_platform_ip6_route_to_string (&route, NULL, 0)); } - return klass->ip6_route_add (self, ifindex, source, network, plen, gateway, metric, mss); + return klass->ip6_route_add (self, ifindex, source, network, plen, gateway, pref_src, metric, mss); } gboolean @@ -3950,14 +3951,19 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi const char * nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsize len) { - char s_network[INET6_ADDRSTRLEN], s_gateway[INET6_ADDRSTRLEN]; + char s_network[INET6_ADDRSTRLEN], s_gateway[INET6_ADDRSTRLEN], s_pref_src[INET6_ADDRSTRLEN]; char str_dev[TO_STRING_DEV_BUF_SIZE], s_source[50]; 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->network, s_network, sizeof (s_network)); + inet_ntop (AF_INET6, &route->gateway, s_gateway, sizeof (s_gateway)); + + if (IN6_IS_ADDR_UNSPECIFIED (&route->pref_src)) + s_pref_src[0] = 0; + else + inet_ntop (AF_INET6, &route->pref_src, s_pref_src, sizeof (s_pref_src)); _to_string_dev (NULL, route->ifindex, str_dev, sizeof (str_dev)); @@ -3969,6 +3975,7 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi " mss %"G_GUINT32_FORMAT " src %s" /* source */ "%s" /* cloned */ + "%s%s" /* pref-src */ "", s_network, route->plen, @@ -3977,7 +3984,9 @@ 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)), - route->rt_cloned ? " cloned" : ""); + route->rt_cloned ? " cloned" : "", + s_pref_src[0] ? " pref-src " : "", + s_pref_src[0] ? s_pref_src : ""); return buf; } @@ -4278,6 +4287,7 @@ nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route _CMP_FIELD (a, b, plen); _CMP_FIELD (a, b, metric); _CMP_FIELD_MEMCMP (a, b, gateway); + _CMP_FIELD_MEMCMP (a, b, pref_src); _CMP_FIELD (a, b, rt_source); _CMP_FIELD (a, b, mss); _CMP_FIELD (a, b, rt_cloned); @@ -4431,6 +4441,7 @@ _vtr_v6_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *rout route->r6.network, route->rx.plen, route->r6.gateway, + route->r6.pref_src, metric >= 0 ? (guint32) metric : route->rx.metric, route->rx.mss); } diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 63dbe5a07c..3cc96f3c05 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -358,6 +358,7 @@ struct _NMPlatformIP6Route { __NMPlatformIPRoute_COMMON; struct in6_addr network; struct in6_addr gateway; + struct in6_addr pref_src; }; typedef union { @@ -672,7 +673,7 @@ typedef struct { in_addr_t pref_src, guint32 metric, guint32 mss); gboolean (*ip6_route_add) (NMPlatform *, int ifindex, NMIPConfigSource source, struct in6_addr network, guint8 plen, struct in6_addr gateway, - guint32 metric, guint32 mss); + struct in6_addr pref_src, guint32 metric, guint32 mss); gboolean (*ip4_route_delete) (NMPlatform *, int ifindex, in_addr_t network, guint8 plen, guint32 metric); gboolean (*ip6_route_delete) (NMPlatform *, int ifindex, struct in6_addr network, guint8 plen, guint32 metric); const NMPlatformIP4Route *(*ip4_route_get) (NMPlatform *, int ifindex, in_addr_t network, guint8 plen, guint32 metric); @@ -974,7 +975,7 @@ gboolean nm_platform_ip4_route_add (NMPlatform *self, int ifindex, NMIPConfigSou in_addr_t pref_src, guint32 metric, guint32 mss); gboolean nm_platform_ip6_route_add (NMPlatform *self, int ifindex, NMIPConfigSource source, struct in6_addr network, guint8 plen, struct in6_addr gateway, - guint32 metric, guint32 mss); + struct in6_addr pref_src, guint32 metric, guint32 mss); gboolean nm_platform_ip4_route_delete (NMPlatform *self, int ifindex, in_addr_t network, guint8 plen, guint32 metric); gboolean nm_platform_ip6_route_delete (NMPlatform *self, int ifindex, struct in6_addr network, guint8 plen, guint32 metric); diff --git a/src/platform/tests/test-cleanup.c b/src/platform/tests/test-cleanup.c index 4ac4929895..41f59d07aa 100644 --- a/src/platform/tests/test-cleanup.c +++ b/src/platform/tests/test-cleanup.c @@ -68,9 +68,9 @@ test_cleanup_internal (void) g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway4, 32, INADDR_ANY, 0, metric, mss)); g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network4, plen4, gateway4, 0, metric, mss)); g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway4, 0, metric, mss)); - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway6, 128, in6addr_any, metric, mss)); - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network6, plen6, gateway6, metric, mss)); - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway6, metric, mss)); + g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway6, 128, in6addr_any, in6addr_any, metric, mss)); + g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network6, plen6, gateway6, in6addr_any, metric, mss)); + g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway6, in6addr_any, metric, mss)); addresses4 = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex); addresses6 = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex); diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index 59a05bd492..df0e748a90 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -238,36 +238,41 @@ test_ip6_route (void) NMPlatformIP6Route rts[3]; struct in6_addr network; guint8 plen = 64; - struct in6_addr gateway; + struct in6_addr gateway, pref_src; /* Choose a high metric so that we hopefully don't conflict. */ int metric = 22987; int mss = 1000; inet_pton (AF_INET6, "2001:db8:a:b:0:0:0:0", &network); inet_pton (AF_INET6, "2001:db8:c:d:1:2:3:4", &gateway); + inet_pton (AF_INET6, "::42", &pref_src); + + g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, pref_src, 128, in6addr_any, + NM_PLATFORM_LIFETIME_PERMANENT, NM_PLATFORM_LIFETIME_PERMANENT, 0)); + accept_signals (route_added, 0, 1); /* Add route to gateway */ - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 128, in6addr_any, metric, mss)); + g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 128, in6addr_any, in6addr_any, metric, mss)); accept_signal (route_added); /* Add route */ g_assert (!nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, network, plen, metric)); - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, metric, mss)); + g_assert (nm_platform_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)); accept_signal (route_added); /* Add route again */ - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, metric, mss)); + g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, pref_src, metric, mss)); accept_signals (route_changed, 0, 1); /* Add default route */ g_assert (!nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, in6addr_any, 0, metric)); - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, metric, mss)); + g_assert (nm_platform_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)); accept_signal (route_added); /* Add default route again */ - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, metric, mss)); + g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, in6addr_any, metric, mss)); accept_signals (route_changed, 0, 1); /* Test route listing */ @@ -278,6 +283,7 @@ test_ip6_route (void) rts[0].plen = 128; rts[0].ifindex = ifindex; rts[0].gateway = in6addr_any; + rts[0].pref_src = in6addr_any; rts[0].metric = nm_utils_ip6_route_metric_normalize (metric); rts[0].mss = mss; rts[1].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER); @@ -285,6 +291,7 @@ test_ip6_route (void) rts[1].plen = plen; rts[1].ifindex = ifindex; rts[1].gateway = gateway; + rts[1].pref_src = pref_src; rts[1].metric = nm_utils_ip6_route_metric_normalize (metric); rts[1].mss = mss; rts[2].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER); @@ -292,6 +299,7 @@ test_ip6_route (void) rts[2].plen = 0; rts[2].ifindex = ifindex; rts[2].gateway = gateway; + rts[2].pref_src = in6addr_any; rts[2].metric = nm_utils_ip6_route_metric_normalize (metric); rts[2].mss = mss; g_assert_cmpint (routes->len, ==, 3); diff --git a/src/tests/test-ip6-config.c b/src/tests/test-ip6-config.c index 505f9a5d19..7e83625c5b 100644 --- a/src/tests/test-ip6-config.c +++ b/src/tests/test-ip6-config.c @@ -37,8 +37,8 @@ build_test_config (void) config = nm_ip6_config_new (1); nm_ip6_config_add_address (config, nmtst_platform_ip6_address ("abcd:1234:4321::cdde", "1:2:3:4::5", 64)); - nm_ip6_config_add_route (config, nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2")); - nm_ip6_config_add_route (config, nmtst_platform_ip6_route ("2001:abba::", 16, "2001:abba::2234")); + nm_ip6_config_add_route (config, nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2", NULL)); + nm_ip6_config_add_route (config, nmtst_platform_ip6_route ("2001:abba::", 16, "2001:abba::2234", NULL)); nm_ip6_config_set_gateway (config, nmtst_inet6_from_string ("3001:abba::3234")); @@ -74,7 +74,7 @@ test_subtract (void) /* add a couple more things to the test config */ dst = build_test_config (); nm_ip6_config_add_address (dst, nmtst_platform_ip6_address (expected_addr, NULL, expected_addr_plen)); - nm_ip6_config_add_route (dst, nmtst_platform_ip6_route (expected_route_dest, expected_route_plen, expected_route_next_hop)); + nm_ip6_config_add_route (dst, nmtst_platform_ip6_route (expected_route_dest, expected_route_plen, expected_route_next_hop, NULL)); expected_ns1 = *nmtst_inet6_from_string ("2222:3333:4444::5555"); nm_ip6_config_add_nameserver (dst, &expected_ns1); @@ -139,7 +139,7 @@ test_compare_with_source (void) nm_ip6_config_add_address (b, &addr); /* Route */ - route = *nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2"); + route = *nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2", NULL); route.rt_source = NM_IP_CONFIG_SOURCE_USER; nm_ip6_config_add_route (a, &route); @@ -203,7 +203,7 @@ test_add_route_with_source (void) a = nm_ip6_config_new (1); /* Test that a higher priority source is not overwritten */ - route = *nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2"); + route = *nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2", NULL); route.rt_source = NM_IP_CONFIG_SOURCE_USER; nm_ip6_config_add_route (a, &route); diff --git a/src/tests/test-route-manager.c b/src/tests/test-route-manager.c index df43dd987a..38e945ce4c 100644 --- a/src/tests/test-route-manager.c +++ b/src/tests/test-route-manager.c @@ -427,6 +427,7 @@ setup_dev1_ip6 (int ifindex) *nmtst_inet6_from_string ("2001:db8:8088::"), 48, in6addr_any, + in6addr_any, 10, 0)) g_assert_not_reached (); From 63951cad7f660cad26310ce271c502b01badabb5 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 9 Feb 2017 23:22:25 +0100 Subject: [PATCH 03/11] platform: change signature of nm_platform_ip{4,6}_route_add() Change the functions to accept a platform route as argument. This will make it easier to add new route options. --- src/nm-default-route-manager.c | 32 +++++----- src/platform/nm-fake-platform.c | 97 +++++++++++++------------------ src/platform/nm-linux-platform.c | 52 +++++++++-------- src/platform/nm-platform.c | 92 +++++++++-------------------- src/platform/nm-platform.h | 16 ++--- src/platform/tests/test-cleanup.c | 12 ++-- src/platform/tests/test-common.c | 48 +++++++++++++++ src/platform/tests/test-common.h | 20 +++++++ src/platform/tests/test-route.c | 24 ++++---- src/tests/test-route-manager.c | 38 ++++++------ 10 files changed, 216 insertions(+), 215 deletions(-) diff --git a/src/nm-default-route-manager.c b/src/nm-default-route-manager.c index 428c343673..71ca919ec6 100644 --- a/src/nm-default-route-manager.c +++ b/src/nm-default-route-manager.c @@ -301,25 +301,21 @@ _platform_route_sync_add (const VTableIP *vtable, NMDefaultRouteManager *self, g return FALSE; if (vtable->vt->is_ip4) { - success = nm_platform_ip4_route_add (priv->platform, - entry->route.rx.ifindex, - entry->route.rx.rt_source, - 0, - 0, - entry->route.r4.gateway, - 0, - entry->effective_metric, - entry->route.rx.mss); + NMPlatformIP4Route rt = entry->route.r4; + + rt.network = 0; + rt.plen = 0; + rt.metric = entry->effective_metric; + + success = nm_platform_ip4_route_add (priv->platform, &rt); } else { - success = nm_platform_ip6_route_add (priv->platform, - entry->route.rx.ifindex, - entry->route.rx.rt_source, - in6addr_any, - 0, - entry->route.r6.gateway, - entry->route.r6.pref_src, - entry->effective_metric, - entry->route.rx.mss); + NMPlatformIP6Route rt = entry->route.r6; + + rt.network = in6addr_any; + rt.plen = 0; + rt.metric = entry->effective_metric; + + success = nm_platform_ip6_route_add (priv->platform, &rt); } if (!success) { _LOGW (vtable->vt->addr_family, "failed to add default route %s with effective metric %u", diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 447188e631..276ebe85e7 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -1225,42 +1225,29 @@ ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, gu } static gboolean -ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, - in_addr_t network, guint8 plen, in_addr_t gateway, - in_addr_t pref_src, guint32 metric, guint32 mss) +ip4_route_add (NMPlatform *platform, const NMPlatformIP4Route *route) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform); - NMPlatformIP4Route route; + NMPlatformIP4Route rt = *route; guint i; - guint8 scope; - g_assert (plen <= 32); + rt.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (rt.rt_source); + rt.network = nm_utils_ip4_address_clear_host_address (rt.network, rt.plen); + rt.scope_inv = nm_platform_route_scope_inv (rt.gateway ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK); - scope = gateway == 0 ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE; - - memset (&route, 0, sizeof (route)); - route.ifindex = ifindex; - route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (source); - route.network = nm_utils_ip4_address_clear_host_address (network, plen); - route.plen = plen; - route.gateway = gateway; - route.metric = metric; - route.mss = mss; - route.scope_inv = nm_platform_route_scope_inv (scope); - - if (gateway) { + if (rt.gateway) { for (i = 0; i < priv->ip4_routes->len; i++) { NMPlatformIP4Route *item = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i); guint32 gate = ntohl (item->network) >> (32 - item->plen); - guint32 host = ntohl (gateway) >> (32 - item->plen); + guint32 host = ntohl (rt.gateway) >> (32 - item->plen); - if (ifindex == item->ifindex && gate == host) + if (rt.ifindex == item->ifindex && gate == host) break; } if (i == priv->ip4_routes->len) { nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip4-route '%d: %s/%d %d': Network Unreachable", - route.ifindex, nm_utils_inet4_ntop (route.network, NULL), route.plen, route.metric); + rt.ifindex, nm_utils_inet4_ntop (rt.network, NULL), rt.plen, rt.metric); return FALSE; } } @@ -1268,66 +1255,58 @@ ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, for (i = 0; i < priv->ip4_routes->len; i++) { NMPlatformIP4Route *item = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i); - if (item->network != route.network) + if (item->network != rt.network) continue; - if (item->plen != route.plen) + if (item->plen != rt.plen) continue; - if (item->metric != metric) + if (item->metric != rt.metric) continue; - if (item->ifindex != route.ifindex) { + if (item->ifindex != rt.ifindex) { ip4_route_delete (platform, item->ifindex, item->network, item->plen, item->metric); i--; continue; } - memcpy (item, &route, sizeof (route)); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP4_ROUTE, ifindex, &route, (int) NM_PLATFORM_SIGNAL_CHANGED); + memcpy (item, &rt, sizeof (rt)); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP4_ROUTE, + rt.ifindex, &rt, (int) NM_PLATFORM_SIGNAL_CHANGED); return TRUE; } - g_array_append_val (priv->ip4_routes, route); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP4_ROUTE, ifindex, &route, (int) NM_PLATFORM_SIGNAL_ADDED); + g_array_append_val (priv->ip4_routes, rt); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP4_ROUTE, + rt.ifindex, &rt, (int) NM_PLATFORM_SIGNAL_ADDED); return TRUE; } static gboolean -ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, - struct in6_addr network, guint8 plen, struct in6_addr gateway, - struct in6_addr pref_src, guint32 metric, guint32 mss) +ip6_route_add (NMPlatform *platform, const NMPlatformIP6Route *route) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform); - NMPlatformIP6Route route; + NMPlatformIP6Route rt = *route; guint i; - metric = nm_utils_ip6_route_metric_normalize (metric); + rt.metric = nm_utils_ip6_route_metric_normalize (rt.metric); + rt.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (rt.rt_source); + nm_utils_ip6_address_clear_host_address (&rt.network, &rt.network, rt.plen); - memset (&route, 0, sizeof (route)); - route.ifindex = ifindex; - route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (source); - nm_utils_ip6_address_clear_host_address (&route.network, &network, plen); - route.plen = plen; - route.gateway = gateway; - route.metric = metric; - route.mss = mss; - route.pref_src = pref_src; - - if (!IN6_IS_ADDR_UNSPECIFIED(&gateway)) { + if (!IN6_IS_ADDR_UNSPECIFIED (&rt.gateway)) { for (i = 0; i < priv->ip6_routes->len; i++) { NMPlatformIP6Route *item = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i); - guint8 gate_bits = gateway.s6_addr[item->plen / 8] >> (8 - item->plen % 8); + guint8 gate_bits = rt.gateway.s6_addr[item->plen / 8] >> (8 - item->plen % 8); guint8 host_bits = item->network.s6_addr[item->plen / 8] >> (8 - item->plen % 8); - if ( ifindex == item->ifindex - && memcmp (&gateway, &item->network, item->plen / 8) == 0 + if ( rt.ifindex == item->ifindex + && memcmp (&rt.gateway, &item->network, item->plen / 8) == 0 && gate_bits == host_bits) break; } if (i == priv->ip6_routes->len) { nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip6-route '%d: %s/%d %d': Network Unreachable", - route.ifindex, nm_utils_inet6_ntop (&route.network, NULL), route.plen, route.metric); + rt.ifindex, nm_utils_inet6_ntop (&rt.network, NULL), rt.plen, rt.metric); return FALSE; } } @@ -1335,26 +1314,28 @@ ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, for (i = 0; i < priv->ip6_routes->len; i++) { NMPlatformIP6Route *item = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i); - if (!IN6_ARE_ADDR_EQUAL (&item->network, &route.network)) + if (!IN6_ARE_ADDR_EQUAL (&item->network, &rt.network)) continue; - if (item->plen != route.plen) + if (item->plen != rt.plen) continue; - if (item->metric != metric) + if (item->metric != rt.metric) continue; - if (item->ifindex != route.ifindex) { + if (item->ifindex != rt.ifindex) { ip6_route_delete (platform, item->ifindex, item->network, item->plen, item->metric); i--; continue; } - memcpy (item, &route, sizeof (route)); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP6_ROUTE, ifindex, &route, (int) NM_PLATFORM_SIGNAL_CHANGED); + memcpy (item, &rt, sizeof (rt)); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP6_ROUTE, + rt.ifindex, &rt, (int) NM_PLATFORM_SIGNAL_CHANGED); return TRUE; } - g_array_append_val (priv->ip6_routes, route); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP6_ROUTE, ifindex, &route, (int) NM_PLATFORM_SIGNAL_ADDED); + g_array_append_val (priv->ip6_routes, rt); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP6_ROUTE, + rt.ifindex, &rt, (int) NM_PLATFORM_SIGNAL_ADDED); return TRUE; } diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index abc26e37f3..38d7b63db5 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -5904,52 +5904,56 @@ ip6_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags fl } static gboolean -ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, - in_addr_t network, guint8 plen, in_addr_t gateway, - in_addr_t pref_src, guint32 metric, guint32 mss) +ip4_route_add (NMPlatform *platform, const NMPlatformIP4Route *route) { NMPObject obj_id; nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + in_addr_t network; + network = nm_utils_ip4_address_clear_host_address (route->network, route->plen); + + /* FIXME: take the scope from route into account */ nlmsg = _nl_msg_new_route (RTM_NEWROUTE, NLM_F_CREATE | NLM_F_REPLACE, AF_INET, - ifindex, - source, - gateway ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK, + route->ifindex, + route->rt_source, + route->gateway ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK, &network, - plen, - &gateway, - metric, - mss, - pref_src ? &pref_src : NULL); + route->plen, + &route->gateway, + route->metric, + route->mss, + route->pref_src ? &route->pref_src : NULL); - nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric); + nmp_object_stackinit_id_ip4_route (&obj_id, route->ifindex, network, route->plen, route->metric); return do_add_addrroute (platform, &obj_id, nlmsg); } static gboolean -ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, - struct in6_addr network, guint8 plen, struct in6_addr gateway, - struct in6_addr pref_src, guint32 metric, guint32 mss) +ip6_route_add (NMPlatform *platform, const NMPlatformIP6Route *route) { NMPObject obj_id; nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + struct in6_addr network; + nm_utils_ip6_address_clear_host_address (&network, &route->network, route->plen); + + /* FIXME: take the scope from route into account */ nlmsg = _nl_msg_new_route (RTM_NEWROUTE, NLM_F_CREATE | NLM_F_REPLACE, AF_INET6, - ifindex, - source, - !IN6_IS_ADDR_UNSPECIFIED (&gateway) ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK, + route->ifindex, + route->rt_source, + IN6_IS_ADDR_UNSPECIFIED (&route->gateway) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE, &network, - plen, - &gateway, - metric, - mss, - !IN6_IS_ADDR_UNSPECIFIED (&pref_src) ? &pref_src : NULL); + route->plen, + &route->gateway, + route->metric, + route->mss, + !IN6_IS_ADDR_UNSPECIFIED (&route->pref_src) ? &route->pref_src : NULL); - nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric); + nmp_object_stackinit_id_ip6_route (&obj_id, route->ifindex, &network, route->plen, route->metric); return do_add_addrroute (platform, &obj_id, nlmsg); } diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 713fccb32c..5878231edc 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -3109,14 +3109,7 @@ nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRoute /** * nm_platform_ip4_route_add: * @self: - * @ifindex: - * @source: - * network: - * plen: - * gateway: - * pref_src: - * metric: - * mss: + * @route: * * For kernel, a gateway can be either explicitly set or left * at zero (0.0.0.0). In addition, there is the scope of the IPv4 @@ -3137,58 +3130,29 @@ nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRoute * Returns: %TRUE in case of success. */ gboolean -nm_platform_ip4_route_add (NMPlatform *self, - int ifindex, NMIPConfigSource source, - in_addr_t network, guint8 plen, - in_addr_t gateway, in_addr_t pref_src, - guint32 metric, guint32 mss) +nm_platform_ip4_route_add (NMPlatform *self, const NMPlatformIP4Route *route) { _CHECK_SELF (self, klass, FALSE); - g_return_val_if_fail (plen <= 32, FALSE); + g_return_val_if_fail (route, FALSE); + g_return_val_if_fail (route->plen <= 32, FALSE); - if (_LOGD_ENABLED ()) { - NMPlatformIP4Route route = { 0 }; + _LOGD ("route: adding or updating IPv4 route: %s", nm_platform_ip4_route_to_string (route, NULL, 0)); - route.ifindex = ifindex; - route.rt_source = source; - route.network = network; - route.plen = plen; - route.gateway = gateway; - route.metric = metric; - route.mss = mss; - route.pref_src = pref_src; - - _LOGD ("route: adding or updating IPv4 route: %s", nm_platform_ip4_route_to_string (&route, NULL, 0)); - } - return klass->ip4_route_add (self, ifindex, source, network, plen, gateway, pref_src, metric, mss); + return klass->ip4_route_add (self, route); } gboolean -nm_platform_ip6_route_add (NMPlatform *self, - int ifindex, NMIPConfigSource source, - struct in6_addr network, guint8 plen, struct in6_addr gateway, - struct in6_addr pref_src, guint32 metric, guint32 mss) +nm_platform_ip6_route_add (NMPlatform *self, const NMPlatformIP6Route *route) { _CHECK_SELF (self, klass, FALSE); - g_return_val_if_fail (plen <= 128, FALSE); + g_return_val_if_fail (route, FALSE); + g_return_val_if_fail (route->plen <= 128, FALSE); - if (_LOGD_ENABLED ()) { - NMPlatformIP6Route route = { 0 }; + _LOGD ("route: adding or updating IPv6 route: %s", nm_platform_ip6_route_to_string (route, NULL, 0)); - route.ifindex = ifindex; - route.rt_source = source; - route.network = network; - route.plen = plen; - route.gateway = gateway; - route.pref_src = pref_src; - route.metric = metric; - route.mss = mss; - - _LOGD ("route: adding or updating IPv6 route: %s", nm_platform_ip6_route_to_string (&route, NULL, 0)); - } - return klass->ip6_route_add (self, ifindex, source, network, plen, gateway, pref_src, metric, mss); + return klass->ip6_route_add (self, route); } gboolean @@ -4421,29 +4385,27 @@ nm_platform_netns_push (NMPlatform *platform, NMPNetns **netns) static gboolean _vtr_v4_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, gint64 metric) { - return nm_platform_ip4_route_add (self, - ifindex > 0 ? ifindex : route->rx.ifindex, - route->rx.rt_source, - route->r4.network, - route->rx.plen, - route->r4.gateway, - route->r4.pref_src, - metric >= 0 ? (guint32) metric : route->rx.metric, - route->rx.mss); + NMPlatformIP4Route rt = route->r4; + + if (ifindex > 0) + rt.ifindex = ifindex; + if (metric >= 0) + rt.metric = metric; + + return nm_platform_ip4_route_add (self, &rt); } static gboolean _vtr_v6_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, gint64 metric) { - return nm_platform_ip6_route_add (self, - ifindex > 0 ? ifindex : route->rx.ifindex, - route->rx.rt_source, - route->r6.network, - route->rx.plen, - route->r6.gateway, - route->r6.pref_src, - metric >= 0 ? (guint32) metric : route->rx.metric, - route->rx.mss); + NMPlatformIP6Route rt = route->r6; + + if (ifindex > 0) + rt.ifindex = ifindex; + if (metric >= 0) + rt.metric = metric; + + return nm_platform_ip6_route_add (self, &rt); } static gboolean diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 3cc96f3c05..28dd650a89 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -668,12 +668,8 @@ typedef struct { GArray * (*ip4_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteFlags flags); GArray * (*ip6_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteFlags flags); - gboolean (*ip4_route_add) (NMPlatform *, int ifindex, NMIPConfigSource source, - in_addr_t network, guint8 plen, in_addr_t gateway, - in_addr_t pref_src, guint32 metric, guint32 mss); - gboolean (*ip6_route_add) (NMPlatform *, int ifindex, NMIPConfigSource source, - struct in6_addr network, guint8 plen, struct in6_addr gateway, - struct in6_addr pref_src, guint32 metric, guint32 mss); + gboolean (*ip4_route_add) (NMPlatform *, const NMPlatformIP4Route *route); + gboolean (*ip6_route_add) (NMPlatform *, const NMPlatformIP6Route *route); gboolean (*ip4_route_delete) (NMPlatform *, int ifindex, in_addr_t network, guint8 plen, guint32 metric); gboolean (*ip6_route_delete) (NMPlatform *, int ifindex, struct in6_addr network, guint8 plen, guint32 metric); const NMPlatformIP4Route *(*ip4_route_get) (NMPlatform *, int ifindex, in_addr_t network, guint8 plen, guint32 metric); @@ -970,12 +966,8 @@ const NMPlatformIP4Route *nm_platform_ip4_route_get (NMPlatform *self, int ifind const NMPlatformIP6Route *nm_platform_ip6_route_get (NMPlatform *self, int ifindex, struct in6_addr network, guint8 plen, guint32 metric); GArray *nm_platform_ip4_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags); GArray *nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags); -gboolean nm_platform_ip4_route_add (NMPlatform *self, int ifindex, NMIPConfigSource source, - in_addr_t network, guint8 plen, in_addr_t gateway, - in_addr_t pref_src, guint32 metric, guint32 mss); -gboolean nm_platform_ip6_route_add (NMPlatform *self, int ifindex, NMIPConfigSource source, - struct in6_addr network, guint8 plen, struct in6_addr gateway, - struct in6_addr pref_src, guint32 metric, guint32 mss); +gboolean nm_platform_ip4_route_add (NMPlatform *self, const NMPlatformIP4Route *route); +gboolean nm_platform_ip6_route_add (NMPlatform *self, const NMPlatformIP6Route *route); gboolean nm_platform_ip4_route_delete (NMPlatform *self, int ifindex, in_addr_t network, guint8 plen, guint32 metric); gboolean nm_platform_ip6_route_delete (NMPlatform *self, int ifindex, struct in6_addr network, guint8 plen, guint32 metric); diff --git a/src/platform/tests/test-cleanup.c b/src/platform/tests/test-cleanup.c index 41f59d07aa..71a92cbfae 100644 --- a/src/platform/tests/test-cleanup.c +++ b/src/platform/tests/test-cleanup.c @@ -65,12 +65,12 @@ test_cleanup_internal (void) /* Add routes and addresses */ g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr4, plen4, addr4, lifetime, preferred, 0, NULL)); g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr6, plen6, in6addr_any, lifetime, preferred, flags)); - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway4, 32, INADDR_ANY, 0, metric, mss)); - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network4, plen4, gateway4, 0, metric, mss)); - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway4, 0, metric, mss)); - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway6, 128, in6addr_any, in6addr_any, metric, mss)); - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network6, plen6, gateway6, in6addr_any, metric, mss)); - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway6, in6addr_any, metric, mss)); + nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway4, 32, INADDR_ANY, 0, metric, mss); + nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network4, plen4, gateway4, 0, metric, mss); + nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway4, 0, metric, mss); + nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway6, 128, in6addr_any, in6addr_any, metric, mss); + nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network6, plen6, gateway6, in6addr_any, metric, mss); + nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway6, in6addr_any, metric, mss); addresses4 = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex); addresses6 = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex); diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c index 0e42a727d7..d09fa3bae9 100644 --- a/src/platform/tests/test-common.c +++ b/src/platform/tests/test-common.c @@ -783,6 +783,54 @@ nmtstp_ip6_address_add (NMPlatform *platform, NULL); } +void nmtstp_ip4_route_add (NMPlatform *platform, + int ifindex, + NMIPConfigSource source, + in_addr_t network, + guint8 plen, + in_addr_t gateway, + in_addr_t pref_src, + guint32 metric, + guint32 mss) +{ + NMPlatformIP4Route route = { }; + + route.ifindex = ifindex; + route.rt_source = source; + route.network = network; + route.plen = plen; + route.gateway = gateway; + route.pref_src = pref_src; + route.metric = metric; + route.mss = mss; + + g_assert (nm_platform_ip4_route_add (platform, &route)); +} + +void nmtstp_ip6_route_add (NMPlatform *platform, + int ifindex, + NMIPConfigSource source, + struct in6_addr network, + guint8 plen, + struct in6_addr gateway, + struct in6_addr pref_src, + guint32 metric, + guint32 mss) +{ + NMPlatformIP6Route route = { }; + + route.ifindex = ifindex; + route.rt_source = source; + route.network = network; + route.plen = plen; + route.gateway = gateway; + route.pref_src = pref_src; + route.metric = metric; + route.mss = mss; + + g_assert (nm_platform_ip6_route_add (platform, &route)); +} + /*****************************************************************************/ static void diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h index 48a41de63a..e13afe43a7 100644 --- a/src/platform/tests/test-common.h +++ b/src/platform/tests/test-common.h @@ -167,6 +167,26 @@ void nmtstp_ip6_address_del (NMPlatform *platform, struct in6_addr address, int plen); +void nmtstp_ip4_route_add (NMPlatform *platform, + int ifindex, + NMIPConfigSource source, + in_addr_t network, + guint8 plen, + in_addr_t gateway, + in_addr_t pref_src, + guint32 metric, + guint32 mss); + +void nmtstp_ip6_route_add (NMPlatform *platform, + int ifindex, + NMIPConfigSource source, + struct in6_addr network, + guint8 plen, + struct in6_addr gateway, + struct in6_addr pref_src, + guint32 metric, + guint32 mss); + /*****************************************************************************/ const NMPlatformLink *nmtstp_link_get_typed (NMPlatform *platform, int ifindex, const char *name, NMLinkType link_type); diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index df0e748a90..ecc1e10643 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -94,7 +94,7 @@ test_ip4_route_metric0 (void) nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, metric); /* add the first route */ - g_assert (nm_platform_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); nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0); @@ -108,7 +108,7 @@ test_ip4_route_metric0 (void) nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric); /* add the second route */ - g_assert (nm_platform_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); nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, 0); @@ -160,27 +160,27 @@ test_ip4_route (void) inet_pton (AF_INET, "198.51.100.1", &gateway); /* Add route to gateway */ - g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 32, INADDR_ANY, 0, metric, mss)); + nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 32, INADDR_ANY, 0, metric, mss); accept_signal (route_added); /* Add route */ nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, metric); - g_assert (nm_platform_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); accept_signal (route_added); /* Add route again */ - g_assert (nm_platform_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); accept_signals (route_changed, 0, 1); /* Add default route */ nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, 0, 0, metric); - g_assert (nm_platform_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); accept_signal (route_added); /* Add default route again */ - g_assert (nm_platform_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); accept_signals (route_changed, 0, 1); /* Test route listing */ @@ -252,27 +252,27 @@ test_ip6_route (void) accept_signals (route_added, 0, 1); /* Add route to gateway */ - g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 128, in6addr_any, in6addr_any, metric, mss)); + nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 128, in6addr_any, in6addr_any, metric, mss); accept_signal (route_added); /* Add route */ g_assert (!nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, network, plen, metric)); - g_assert (nm_platform_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)); accept_signal (route_added); /* Add route again */ - g_assert (nm_platform_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); accept_signals (route_changed, 0, 1); /* Add default route */ g_assert (!nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, in6addr_any, 0, metric)); - g_assert (nm_platform_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)); accept_signal (route_added); /* Add default route again */ - g_assert (nm_platform_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); accept_signals (route_changed, 0, 1); /* Test route listing */ diff --git a/src/tests/test-route-manager.c b/src/tests/test-route-manager.c index 38e945ce4c..ba7834e9ea 100644 --- a/src/tests/test-route-manager.c +++ b/src/tests/test-route-manager.c @@ -75,16 +75,15 @@ setup_dev1_ip4 (int ifindex) /* Add some route outside of route manager. The route manager * should get rid of it upon sync. */ - if (!nm_platform_ip4_route_add (NM_PLATFORM_GET, - route.ifindex, - NM_IP_CONFIG_SOURCE_USER, - nmtst_inet4_from_string ("9.0.0.0"), - 8, - INADDR_ANY, - 0, - 10, - route.mss)) - g_assert_not_reached (); + nmtstp_ip4_route_add (NM_PLATFORM_GET, + route.ifindex, + NM_IP_CONFIG_SOURCE_USER, + nmtst_inet4_from_string ("9.0.0.0"), + 8, + INADDR_ANY, + 0, + 10, + route.mss); route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER); inet_pton (AF_INET, "6.6.6.0", &route.network); @@ -421,16 +420,15 @@ setup_dev1_ip6 (int ifindex) /* Add some route outside of route manager. The route manager * should get rid of it upon sync. */ - if (!nm_platform_ip6_route_add (NM_PLATFORM_GET, - ifindex, - NM_IP_CONFIG_SOURCE_USER, - *nmtst_inet6_from_string ("2001:db8:8088::"), - 48, - in6addr_any, - in6addr_any, - 10, - 0)) - g_assert_not_reached (); + nmtstp_ip6_route_add (NM_PLATFORM_GET, + ifindex, + NM_IP_CONFIG_SOURCE_USER, + *nmtst_inet6_from_string ("2001:db8:8088::"), + 48, + in6addr_any, + in6addr_any, + 10, + 0); route = nmtst_platform_ip6_route_full ("2001:db8:8086::", 48, From 45dc2fededfe9db586b9f181263e72b769359a62 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Wed, 15 Feb 2017 14:00:44 +0100 Subject: [PATCH 04/11] 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); From 93b3a478bb5236f37be3d6d3414755ae17cbec04 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 2 Mar 2017 11:08:34 +0100 Subject: [PATCH 05/11] libnm-core: add attribute parsing/format helpers Various libnm objects (addresses, routes) carry an hash table of attributes represented as GVariants indexed by name. Add common routines to convert to and from a string representation. To parse a string, a knowledge of the supported attributes (and their types) is needed: we represent it as an opaque type NMVariantAttributeSpec that callers must query to the library for the specific object type and pass to the parse function. --- libnm-core/nm-utils-private.h | 5 + libnm-core/nm-utils.c | 255 ++++++++++++++++++++++++++++++++++ libnm-core/nm-utils.h | 15 ++ libnm/libnm.ver | 2 + 4 files changed, 277 insertions(+) diff --git a/libnm-core/nm-utils-private.h b/libnm-core/nm-utils-private.h index fab3803808..ee425593d6 100644 --- a/libnm-core/nm-utils-private.h +++ b/libnm-core/nm-utils-private.h @@ -28,6 +28,11 @@ #include "nm-setting-private.h" #include "nm-setting-ip-config.h" +struct _NMVariantAttributeSpec { + char *name; + const GVariantType *type; +}; + gboolean _nm_utils_string_slist_validate (GSList *list, const char **valid_values); diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index 9fc66c8753..f57e2bb154 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -4697,6 +4697,261 @@ _nm_utils_team_config_equal (const char *conf1, } #endif +static char * +attribute_escape (const char *src, char c1, char c2) +{ + char *ret, *dest; + + dest = ret = malloc (strlen (src) * 2 + 1); + + while (*src) { + if (*src == c1 || *src == c2 || *src == '\\') + *dest++ = '\\'; + *dest++ = *src++; + } + *dest++ = '\0'; + + return ret; +} + +static char * +attribute_unescape (const char *start, const char *end) +{ + char *ret, *dest; + + nm_assert (start <= end); + dest = ret = g_malloc (end - start + 1); + + for (; start < end && *start; start++) { + if (*start == '\\') { + start++; + if (!*start) + break; + } + *dest++ = *start; + } + *dest = '\0'; + + return ret; +} + +/** + * nm_utils_parse_variant_attributes: + * @string: the input string + * @attr_separator: the attribute separator character + * @key_value_separator: character separating key and values + * @ignore_unknown: whether unknown attributes should be ignored + * @spec: the attribute format specifiers + * @error: (out) (allow-none): location to store the error on failure + * + * Parse attributes from a string. + * + * Returns: (transfer full): a #GHashTable mapping attribute names to #GVariant values. + * + * Since: 1.8 + */ +GHashTable * +nm_utils_parse_variant_attributes (const char *string, + char attr_separator, + char key_value_separator, + gboolean ignore_unknown, + const NMVariantAttributeSpec *const *spec, + GError **error) +{ + gs_unref_hashtable GHashTable *ht = NULL; + const char *ptr = string, *start = NULL, *sep; + GVariant *variant; + const NMVariantAttributeSpec * const *s; + + g_return_val_if_fail (string, NULL); + g_return_val_if_fail (attr_separator, NULL); + g_return_val_if_fail (key_value_separator, NULL); + g_return_val_if_fail (!error || !*error, NULL); + + ht = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref); + + while (TRUE) { + gs_free char *name = NULL, *value = NULL; + + if (!start) + start = ptr; + if (*ptr == '\\') { + ptr++; + if (!*ptr) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("unterminated escape sequence")); + return NULL; + } + goto next; + } + if (*ptr == attr_separator || *ptr == '\0') { + if (ptr == start) { + /* multiple separators */ + start = NULL; + goto next; + } + + /* Find the key-value separator */ + for (sep = start; sep != ptr; sep++) { + if (*sep == '\\') { + sep++; + if (!*sep) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("unterminated escape sequence")); + return NULL; + } + } + if (*sep == key_value_separator) + break; + } + + if (*sep != key_value_separator) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("missing key-value separator '%c'"), key_value_separator); + return NULL; + } + + name = attribute_unescape (start, sep); + value = attribute_unescape (sep + 1, ptr); + + for (s = spec; *s; s++) { + if (nm_streq (name, (*s)->name)) + break; + } + + if (!*s) { + if (ignore_unknown) + goto next; + else { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("unknown attribute '%s'"), name); + return NULL; + } + } + + if (g_variant_type_equal ((*s)->type, G_VARIANT_TYPE_UINT32)) { + gint64 num = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT32, -1); + + if (num == -1) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("invalid uint32 value '%s' for attribute '%s'"), value, name); + return NULL; + } + variant = g_variant_new_uint32 (num); + } else if (g_variant_type_equal ((*s)->type, G_VARIANT_TYPE_BYTE)) { + gint64 num = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT8, -1); + + if (num == -1) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("invalid uint8 value '%s' for attribute '%s'"), value, name); + return NULL; + } + variant = g_variant_new_byte ((guchar) num); + } else if (g_variant_type_equal ((*s)->type, G_VARIANT_TYPE_BOOLEAN)) { + gboolean b; + + if (nm_streq (value, "true")) + b = TRUE; + else if (nm_streq (value, "false")) + b = FALSE; + else { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("invalid boolean value '%s' for attribute '%s'"), value, name); + return NULL; + } + variant = g_variant_new_boolean (b); + } else if (g_variant_type_equal ((*s)->type, G_VARIANT_TYPE_STRING)) { + variant = g_variant_new_take_string (g_steal_pointer (&value)); + } else { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("unsupported attribute '%s' of type '%s'"), name, + (char *) (*s)->type); + return NULL; + } + + g_hash_table_insert (ht, g_steal_pointer (&name), variant); + start = NULL; + } +next: + if (*ptr == '\0') + break; + ptr++; + } + + return g_steal_pointer (&ht); +} + +/* + * nm_utils_format_variant_attributes: + * @attributes: a #GHashTable mapping attribute names to #GVariant values + * @attr_separator: the attribute separator character + * @key_value_separator: character separating key and values + * + * Format attributes to a string. + * + * Returns: (transfer full): the string representing attributes, or %NULL + * in case there are no attributes + * + * Since: 1.8 + */ +char * +nm_utils_format_variant_attributes (GHashTable *attributes, + char attr_separator, + char key_value_separator) +{ + GString *str = NULL; + GVariant *variant; + char sep = 0; + const char *name, *value; + char *escaped; + char buf[64]; + gs_free_list GList *keys = NULL; + GList *iter; + + g_return_val_if_fail (attr_separator, NULL); + g_return_val_if_fail (key_value_separator, NULL); + + if (!attributes || !g_hash_table_size (attributes)) + return NULL; + + keys = g_list_sort (g_hash_table_get_keys (attributes), (GCompareFunc) g_strcmp0); + str = g_string_new (""); + + for (iter = keys; iter; iter = g_list_next (iter)) { + name = iter->data; + variant = g_hash_table_lookup (attributes, name); + value = NULL; + + if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32)) + value = nm_sprintf_buf (buf, "%u", g_variant_get_uint32 (variant)); + else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTE)) + value = nm_sprintf_buf (buf, "%hhu", g_variant_get_byte (variant)); + else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN)) + value = g_variant_get_boolean (variant) ? "true" : "false"; + else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) + value = g_variant_get_string (variant, NULL); + else + continue; + + if (sep) + g_string_append_c (str, sep); + + escaped = attribute_escape (name, attr_separator, key_value_separator); + g_string_append (str, escaped); + g_free (escaped); + + g_string_append_c (str, key_value_separator); + + escaped = attribute_escape (value, attr_separator, key_value_separator); + g_string_append (str, escaped); + g_free (escaped); + + sep = attr_separator; + } + + return g_string_free (str, FALSE); +} + /*****************************************************************************/ /** diff --git a/libnm-core/nm-utils.h b/libnm-core/nm-utils.h index caf2e62e02..77fe18a906 100644 --- a/libnm-core/nm-utils.h +++ b/libnm-core/nm-utils.h @@ -38,6 +38,8 @@ G_BEGIN_DECLS +typedef struct _NMVariantAttributeSpec NMVariantAttributeSpec; + /* SSID helpers */ gboolean nm_utils_is_empty_ssid (const guint8 *ssid, gsize len); const char *nm_utils_escape_ssid (const guint8 *ssid, gsize len); @@ -215,6 +217,19 @@ const char **nm_utils_enum_get_values (GType type, gint from, gint to); NM_AVAILABLE_IN_1_6 guint nm_utils_version (void); +NM_AVAILABLE_IN_1_8 +GHashTable * nm_utils_parse_variant_attributes (const char *string, + char attr_separator, + char key_value_separator, + gboolean ignore_unknown, + const NMVariantAttributeSpec *const *spec, + GError **error); + +NM_AVAILABLE_IN_1_8 +char * nm_utils_format_variant_attributes (GHashTable *attributes, + char attr_separator, + char key_value_separator); + G_END_DECLS #endif /* __NM_UTILS_H__ */ diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 2d6f739e6e..3e8087b652 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1163,4 +1163,6 @@ global: nm_setting_dummy_get_type; nm_setting_dummy_new; nm_setting_gsm_get_mtu; + nm_utils_format_variant_attributes; + nm_utils_parse_variant_attributes; } libnm_1_6_0; From 54e58eb96bbfcd26d31ddba2e98ff2c59335a02a Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Wed, 15 Feb 2017 15:06:24 +0100 Subject: [PATCH 06/11] libnm-core: define known route attribute names and validation function This adds definition of a set of known route option attributes to libnm-core and helper functions. nm_ip_route_attribute_validate() performs the validation of the attribute type and, in case of a formatted string attribute, of its content. nm_ip_route_get_variant_attribute_spec() returns the attribute format specifier to be passed to nm_utils_parse_variant_attributes(). Since at the moment NMIPRoute is the only user of NMVariantAttributeSpec and the type is opaque to users of the library, the struct is extended to carry some other data useful for validation. --- libnm-core/nm-setting-ip-config.c | 151 ++++++++++++++++++++++++++++++ libnm-core/nm-setting-ip-config.h | 22 +++++ libnm-core/nm-utils-private.h | 3 + libnm-core/tests/test-general.c | 135 ++++++++++++++++++++++++++ libnm/libnm.ver | 2 + 5 files changed, 313 insertions(+) diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c index 09c5798a25..6a42133c1e 100644 --- a/libnm-core/nm-setting-ip-config.c +++ b/libnm-core/nm-setting-ip-config.c @@ -1182,6 +1182,157 @@ nm_ip_route_set_attribute (NMIPRoute *route, const char *name, GVariant *value) g_hash_table_remove (route->attributes, name); } +#define ATTR_SPEC_PTR(name, type, v4, v6, str_type) \ + &(NMVariantAttributeSpec) { name, type, v4, v6, str_type } + +static const NMVariantAttributeSpec * const ip_route_attribute_spec[] = { + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_PREF_SRC, G_VARIANT_TYPE_STRING, TRUE, TRUE, 'a'), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_SRC, G_VARIANT_TYPE_STRING, FALSE, TRUE, 'p'), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_TOS, G_VARIANT_TYPE_BYTE, TRUE, TRUE, 0 ), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_CWND, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_INITCWND, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_INITRWND, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_MTU, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, G_VARIANT_TYPE_BOOLEAN, TRUE, TRUE, 0 ), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, G_VARIANT_TYPE_BOOLEAN, TRUE, TRUE, 0 ), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, G_VARIANT_TYPE_BOOLEAN, TRUE, TRUE, 0 ), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND, G_VARIANT_TYPE_BOOLEAN, TRUE, TRUE, 0 ), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, G_VARIANT_TYPE_BOOLEAN, TRUE, TRUE, 0 ), + NULL, +}; + +/** + * nm_ip_route_get_variant_attribute_spec: + * + * Returns: the specifiers for route attributes + * + * Since: 1.8 + */ +const NMVariantAttributeSpec *const * +nm_ip_route_get_variant_attribute_spec (void) +{ + return ip_route_attribute_spec; +} + +/** + * nm_ip_route_attribute_validate: + * @name: the attribute name + * @value: the attribute value + * @family: IP address family of the route + * @known: (out): on return, whether the attribute name is a known one + * @error: (allow-none): return location for a #GError, or %NULL + * + * Validates a route attribute, i.e. checks that the attribute is a known one + * and the value is of the correct type and well-formed. + * + * Returns: %TRUE if the attribute is valid, %FALSE otherwise + * + * Since: 1.8 + */ +gboolean +nm_ip_route_attribute_validate (const char *name, + GVariant *value, + int family, + gboolean *known, + GError **error) +{ + const NMVariantAttributeSpec *const *iter; + const NMVariantAttributeSpec *spec = NULL; + + g_return_val_if_fail (name, FALSE); + g_return_val_if_fail (value, FALSE); + g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); + + for (iter = ip_route_attribute_spec; *iter; iter++) { + if (nm_streq (name, (*iter)->name)) { + spec = *iter; + break; + } + } + + if (!spec) { + NM_SET_OUT (known, FALSE); + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + _("unknown attribute")); + return FALSE; + } + + NM_SET_OUT (known, TRUE); + + if (!g_variant_is_of_type (value, spec->type)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + _("invalid attribute type'%s'"), + g_variant_get_type_string (value)); + return FALSE; + } + + if ( (family == AF_INET && !spec->v4) + || (family == AF_INET6 && !spec->v6)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + family == AF_INET ? + _("attribute is not valid for a IPv4 route") : + _("attribute is not valid for a IPv6 route")); + return FALSE; + } + + if (spec->type == G_VARIANT_TYPE_STRING) { + const char *string = g_variant_get_string (value, NULL); + gs_free char *string_free = NULL; + char *sep; + + switch (spec->str_type) { + case 'a': /* IP address */ + if (!nm_utils_ipaddr_valid (family, string)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + family == AF_INET ? + _("'%s' is not a valid IPv4 address") : + _("'%s' is not a valid IPv6 address"), + string); + return FALSE; + } + break; + case 'p': /* IP address + optional prefix */ + string_free = g_strdup (string); + sep = strchr (string_free, '/'); + if (sep) { + *sep = 0; + if (_nm_utils_ascii_str_to_int64 (sep + 1, 10, 1, family == AF_INET ? 32 : 128, -1) < 0) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + _("invalid prefix %s"), sep + 1); + return FALSE; + } + } + if (!nm_utils_ipaddr_valid (family, string_free)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + family == AF_INET ? + _("'%s' is not a valid IPv4 address") : + _("'%s' is not a valid IPv6 address"), + string_free); + return FALSE; + } + break; + default: + break; + } + } + + return TRUE; +} + /*****************************************************************************/ G_DEFINE_ABSTRACT_TYPE (NMSettingIPConfig, nm_setting_ip_config, NM_TYPE_SETTING) diff --git a/libnm-core/nm-setting-ip-config.h b/libnm-core/nm-setting-ip-config.h index b18d6a9439..a4ebdc3268 100644 --- a/libnm-core/nm-setting-ip-config.h +++ b/libnm-core/nm-setting-ip-config.h @@ -28,6 +28,7 @@ #endif #include "nm-setting.h" +#include "nm-utils.h" G_BEGIN_DECLS @@ -121,7 +122,28 @@ GVariant *nm_ip_route_get_attribute (NMIPRoute *route, void nm_ip_route_set_attribute (NMIPRoute *route, const char *name, GVariant *value); +NM_AVAILABLE_IN_1_8 +const NMVariantAttributeSpec *const *nm_ip_route_get_variant_attribute_spec (void); +NM_AVAILABLE_IN_1_8 +gboolean nm_ip_route_attribute_validate (const char *name, + GVariant *value, + int family, + gboolean *known, + GError **error); +#define NM_IP_ROUTE_ATTRIBUTE_PREF_SRC "pref-src" +#define NM_IP_ROUTE_ATTRIBUTE_SRC "src" +#define NM_IP_ROUTE_ATTRIBUTE_TOS "tos" +#define NM_IP_ROUTE_ATTRIBUTE_WINDOW "window" +#define NM_IP_ROUTE_ATTRIBUTE_CWND "cwnd" +#define NM_IP_ROUTE_ATTRIBUTE_INITCWND "initcwnd" +#define NM_IP_ROUTE_ATTRIBUTE_INITRWND "initrwnd" +#define NM_IP_ROUTE_ATTRIBUTE_MTU "mtu" +#define NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW "lock-window" +#define NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND "lock-cwnd" +#define NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND "lock-initcwnd" +#define NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND "lock-initrwnd" +#define NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU "lock-mtu" #define NM_TYPE_SETTING_IP_CONFIG (nm_setting_ip_config_get_type ()) #define NM_SETTING_IP_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_IP_CONFIG, NMSettingIPConfig)) diff --git a/libnm-core/nm-utils-private.h b/libnm-core/nm-utils-private.h index ee425593d6..03c8790764 100644 --- a/libnm-core/nm-utils-private.h +++ b/libnm-core/nm-utils-private.h @@ -31,6 +31,9 @@ struct _NMVariantAttributeSpec { char *name; const GVariantType *type; + bool v4:1; + bool v6:1; + char str_type; }; gboolean _nm_utils_string_slist_validate (GSList *list, diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index 073850b4e5..9cdbf2626a 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -642,6 +642,47 @@ test_setting_ip4_config_address_data (void) g_object_unref (conn); } +static void +test_setting_ip_route_attributes (void) +{ + GVariant *variant; + gboolean res, known; + +#define TEST_ATTR(name, type, value, family, exp_res, exp_known) \ + variant = g_variant_new_ ## type (value); \ + res = nm_ip_route_attribute_validate (name, variant, family, &known, NULL); \ + g_assert (res == exp_res); \ + g_assert (known == exp_known); \ + g_variant_unref (variant); + + TEST_ATTR ("foo", uint32, 12, AF_INET, FALSE, FALSE); + + TEST_ATTR ("tos", byte, 127, AF_INET, TRUE, TRUE); + TEST_ATTR ("tos", string, "0x28", AF_INET, FALSE, TRUE); + + TEST_ATTR ("cwnd", uint32, 10, AF_INET, TRUE, TRUE); + TEST_ATTR ("cwnd", string, "11", AF_INET, FALSE, TRUE); + + TEST_ATTR ("lock-mtu", boolean, TRUE, AF_INET, TRUE, TRUE); + TEST_ATTR ("lock-mtu", uint32, 1, AF_INET, FALSE, TRUE); + + TEST_ATTR ("src", string, "fd01::1", AF_INET6, TRUE, TRUE); + TEST_ATTR ("src", string, "fd01::1/64", AF_INET6, TRUE, TRUE); + TEST_ATTR ("src", string, "fd01::1/128", AF_INET6, TRUE, TRUE); + TEST_ATTR ("src", string, "fd01::1/129", AF_INET6, FALSE, TRUE); + TEST_ATTR ("src", string, "fd01::1/a", AF_INET6, FALSE, TRUE); + TEST_ATTR ("src", string, "abc/64", AF_INET6, FALSE, TRUE); + TEST_ATTR ("src", string, "1.2.3.4", AF_INET, FALSE, TRUE); + TEST_ATTR ("src", string, "1.2.3.4", AF_INET6, FALSE, TRUE); + + TEST_ATTR ("pref-src", string, "1.2.3.4", AF_INET, TRUE, TRUE); + TEST_ATTR ("pref-src", string, "1.2.3.4", AF_INET6, FALSE, TRUE); + TEST_ATTR ("pref-src", string, "1.2.3.0/24", AF_INET, FALSE, TRUE); + TEST_ATTR ("pref-src", string, "fd01::12", AF_INET6, TRUE, TRUE); + +#undef TEST_ATTR +} + static void test_setting_gsm_apn_spaces (void) { @@ -5412,6 +5453,97 @@ test_nm_in_strset (void) #undef _ASSERT } +static void +test_route_attributes_parse (void) +{ + GHashTable *ht; + GError *error = NULL; + GVariant *variant; + + ht = nm_utils_parse_variant_attributes ("mtu=1400 pref-src=1.2.3.4 cwnd=14", + ' ', '=', FALSE, + nm_ip_route_get_variant_attribute_spec (), + &error); + g_assert_no_error (error); + g_assert (ht); + g_hash_table_unref (ht); + + ht = nm_utils_parse_variant_attributes ("mtu=1400 pref-src=1.2.3.4 cwnd=14 \\", + ' ', '=', FALSE, + nm_ip_route_get_variant_attribute_spec (), + &error); + g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED); + g_assert (!ht); + g_clear_error (&error); + + ht = nm_utils_parse_variant_attributes ("mtu.1400 pref-src.1\\.2\\.3\\.4 ", + ' ', '.', FALSE, + nm_ip_route_get_variant_attribute_spec (), + &error); + g_assert (ht); + g_assert_no_error (error); + variant = g_hash_table_lookup (ht, NM_IP_ROUTE_ATTRIBUTE_MTU); + g_assert (variant); + g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32)); + g_assert_cmpuint (g_variant_get_uint32 (variant), ==, 1400); + + variant = g_hash_table_lookup (ht, NM_IP_ROUTE_ATTRIBUTE_PREF_SRC); + g_assert (variant); + g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)); + g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "1.2.3.4"); + g_hash_table_unref (ht); + + ht = nm_utils_parse_variant_attributes ("src:fd01\\:\\:42\\/64/initrwnd:21", + '/', ':', FALSE, + nm_ip_route_get_variant_attribute_spec (), + &error); + g_assert (ht); + g_assert_no_error (error); + variant = g_hash_table_lookup (ht, NM_IP_ROUTE_ATTRIBUTE_INITRWND); + g_assert (variant); + g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32)); + g_assert_cmpuint (g_variant_get_uint32 (variant), ==, 21); + + variant = g_hash_table_lookup (ht, NM_IP_ROUTE_ATTRIBUTE_SRC); + g_assert (variant); + g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)); + g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "fd01::42/64"); + g_hash_table_unref (ht); +} + +static void +test_route_attributes_format (void) +{ + gs_unref_hashtable GHashTable *ht = NULL; + char *str; + + ht = g_hash_table_new_full (g_str_hash, g_str_equal, + NULL, (GDestroyNotify) g_variant_unref); + + str = nm_utils_format_variant_attributes (NULL, ' ', '='); + g_assert_cmpstr (str, ==, NULL); + + str = nm_utils_format_variant_attributes (ht, ' ', '='); + g_assert_cmpstr (str, ==, NULL); + + g_hash_table_insert (ht, NM_IP_ROUTE_ATTRIBUTE_MTU, g_variant_new_uint32 (5000)); + g_hash_table_insert (ht, NM_IP_ROUTE_ATTRIBUTE_INITRWND, g_variant_new_uint32 (20)); + g_hash_table_insert (ht, NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, g_variant_new_boolean (TRUE)); + g_hash_table_insert (ht, NM_IP_ROUTE_ATTRIBUTE_PREF_SRC, g_variant_new_string ("aaaa:bbbb::1")); + str = nm_utils_format_variant_attributes (ht, ' ', '='); + g_assert_cmpstr (str, ==, "initrwnd=20 lock-mtu=true mtu=5000 pref-src=aaaa:bbbb::1"); + g_hash_table_remove_all (ht); + g_free (str); + + g_hash_table_insert (ht, NM_IP_ROUTE_ATTRIBUTE_WINDOW, g_variant_new_uint32 (30000)); + g_hash_table_insert (ht, NM_IP_ROUTE_ATTRIBUTE_INITCWND, g_variant_new_uint32 (21)); + g_hash_table_insert (ht, NM_IP_ROUTE_ATTRIBUTE_SRC, g_variant_new_string ("aaaa:bbbb:cccc:dddd::/64")); + str = nm_utils_format_variant_attributes (ht, '/', ':'); + g_assert_cmpstr (str, ==, "initcwnd:21/src:aaaa\\:bbbb\\:cccc\\:dddd\\:\\:\\/64/window:30000"); + g_hash_table_remove_all (ht); + g_free (str); +} + /*****************************************************************************/ static gboolean @@ -5467,6 +5599,7 @@ int main (int argc, char **argv) g_test_add_func ("/core/general/test_setting_vpn_modify_during_foreach", test_setting_vpn_modify_during_foreach); g_test_add_func ("/core/general/test_setting_ip4_config_labels", test_setting_ip4_config_labels); g_test_add_func ("/core/general/test_setting_ip4_config_address_data", test_setting_ip4_config_address_data); + g_test_add_func ("/core/general/test_setting_ip_route_attributes", test_setting_ip_route_attributes); g_test_add_func ("/core/general/test_setting_gsm_apn_spaces", test_setting_gsm_apn_spaces); g_test_add_func ("/core/general/test_setting_gsm_apn_bad_chars", test_setting_gsm_apn_bad_chars); g_test_add_func ("/core/general/test_setting_gsm_apn_underscore", test_setting_gsm_apn_underscore); @@ -5576,6 +5709,8 @@ int main (int argc, char **argv) g_test_add_func ("/core/general/_nm_utils_team_config_equal", test_nm_utils_team_config_equal); g_test_add_func ("/core/general/test_nm_utils_enum", test_nm_utils_enum); g_test_add_func ("/core/general/nm-set-out", test_nm_set_out); + g_test_add_func ("/core/general/route_attributes/parse", test_route_attributes_parse); + g_test_add_func ("/core/general/route_attributes/format", test_route_attributes_format); return g_test_run (); } diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 3e8087b652..4b3d02fdfa 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1148,6 +1148,8 @@ libnm_1_8_0 { global: nm_connection_get_setting_dummy; nm_device_dummy_get_type; + nm_ip_route_get_variant_attribute_spec; + nm_ip_route_attribute_validate; nm_setting_802_1x_auth_flags_get_type; nm_setting_802_1x_get_auth_timeout; nm_setting_802_1x_get_ca_cert_password; From dad1071374640a71a4a87026064e5c30cabbd948 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Wed, 15 Feb 2017 15:41:04 +0100 Subject: [PATCH 07/11] core: apply route options from configuration --- src/nm-ip4-config.c | 33 ++++++++++++++++++++++++++++ src/nm-ip6-config.c | 52 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 7497ab914c..b3d8ee478d 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -412,6 +412,38 @@ nm_ip4_config_commit (const NMIP4Config *config, int ifindex, gboolean routes_fu return TRUE; } +static void +merge_route_attributes (NMIPRoute *s_route, NMPlatformIP4Route *r) +{ + GVariant *variant; + in_addr_t addr; + +#define GET_ATTR(name, field, variant_type, type) \ + variant = nm_ip_route_get_attribute (s_route, name); \ + if (variant && g_variant_is_of_type (variant, G_VARIANT_TYPE_ ## variant_type)) \ + r->field = g_variant_get_ ## type (variant); + + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TOS, tos, BYTE, byte); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW, window, UINT32, uint32); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_CWND, cwnd, UINT32, uint32); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITCWND, initcwnd, UINT32, uint32); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITRWND, initrwnd, UINT32, uint32); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_MTU, mtu, UINT32, uint32); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, lock_window, BOOLEAN, boolean); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, lock_cwnd, BOOLEAN, boolean); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, lock_initcwnd, BOOLEAN, boolean); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND, lock_initrwnd, BOOLEAN, boolean); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, lock_mtu, BOOLEAN, boolean); + + if ( (variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_PREF_SRC)) + && g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) { + if (inet_pton (AF_INET, g_variant_get_string (variant, NULL), &addr) == 1) + r->pref_src = addr; + } + +#undef GET_ATTR +} + void nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, guint32 default_route_metric) { @@ -492,6 +524,7 @@ nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, gu route.metric = nm_ip_route_get_metric (s_route); route.rt_source = NM_IP_CONFIG_SOURCE_USER; + merge_route_attributes (s_route, &route); nm_ip4_config_add_route (config, &route); } diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index e83e30a131..070ce06937 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -416,6 +416,57 @@ nm_ip6_config_commit (const NMIP6Config *config, int ifindex, gboolean routes_fu return success; } +static void +merge_route_attributes (NMIPRoute *s_route, NMPlatformIP6Route *r) +{ + GVariant *variant; + struct in6_addr addr; + +#define GET_ATTR(name, field, variant_type, type) \ + variant = nm_ip_route_get_attribute (s_route, name); \ + if (variant && g_variant_is_of_type (variant, G_VARIANT_TYPE_ ## variant_type)) \ + r->field = g_variant_get_ ## type (variant); + + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TOS, tos, BYTE, byte); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW, window, UINT32, uint32); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_CWND, cwnd, UINT32, uint32); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITCWND, initcwnd, UINT32, uint32); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITRWND, initrwnd, UINT32, uint32); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_MTU, mtu, UINT32, uint32); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, lock_window, BOOLEAN, boolean); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, lock_cwnd, BOOLEAN, boolean); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, lock_initcwnd, BOOLEAN, boolean); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND, lock_initrwnd, BOOLEAN, boolean); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, lock_mtu, BOOLEAN, boolean); + + + if ( (variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_PREF_SRC)) + && g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) { + if (inet_pton (AF_INET6, g_variant_get_string (variant, NULL), &addr) == 1) + r->pref_src = addr; + } + + if ( (variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_SRC)) + && g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) { + gs_free char *string = NULL; + guint8 plen = 128; + char *sep; + + string = g_variant_dup_string (variant, NULL); + sep = strchr (string, '/'); + if (sep) { + *sep = 0; + plen = _nm_utils_ascii_str_to_int64 (sep + 1, 10, 1, 128, 255); + } + if ( plen <= 128 + && inet_pton (AF_INET6, string, &addr) == 1) { + r->src = addr; + r->src_plen = plen; + } + } +#undef GET_ATTR +} + void nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIPConfig *setting, guint32 default_route_metric) { @@ -492,6 +543,7 @@ nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIPConfig *setting, gu route.metric = nm_ip_route_get_metric (s_route); route.rt_source = NM_IP_CONFIG_SOURCE_USER; + merge_route_attributes (s_route, &route); nm_ip6_config_add_route (config, &route); } From cdfa6251021b097f4dfa1e723c546dd83fd9c44d Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 16 Feb 2017 00:14:25 +0100 Subject: [PATCH 08/11] keyfile: support route options --- libnm-core/nm-keyfile-reader.c | 31 +++++++++++++++++++ libnm-core/nm-keyfile-writer.c | 19 +++++++++++- .../tests/keyfiles/Test_Wired_Connection | 2 ++ .../plugins/keyfile/tests/test-keyfile.c | 26 +++++++++++++++- 4 files changed, 76 insertions(+), 2 deletions(-) diff --git a/libnm-core/nm-keyfile-reader.c b/libnm-core/nm-keyfile-reader.c index c071264d32..b955dbf617 100644 --- a/libnm-core/nm-keyfile-reader.c +++ b/libnm-core/nm-keyfile-reader.c @@ -428,6 +428,31 @@ read_one_ip_address_or_route (KeyfileReaderInfo *info, return result; } +static void +fill_route_attributes (GKeyFile *kf, NMIPRoute *route, const char *setting, const char *key, int family) +{ + gs_free char *value = NULL; + gs_unref_hashtable GHashTable *hash = NULL; + GHashTableIter iter; + char *name; + GVariant *variant; + + value = nm_keyfile_plugin_kf_get_string (kf, setting, key, NULL); + if (!value || !value[0]) + return; + + hash = nm_utils_parse_variant_attributes (value, ',', '=', TRUE, + nm_ip_route_get_variant_attribute_spec (), + NULL); + if (hash) { + g_hash_table_iter_init (&iter, hash); + while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &variant)) { + if (nm_ip_route_attribute_validate (name, variant, family, NULL, NULL)) + nm_ip_route_set_attribute (route, name, g_variant_ref (variant)); + } + } +} + static void ip_address_or_route_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key) { @@ -454,6 +479,7 @@ ip_address_or_route_parser (KeyfileReaderInfo *info, NMSetting *setting, const c for (key_basename = key_names; *key_basename; key_basename++) { char *key_name; gpointer item; + char options_key[128]; /* -1 means no suffix */ if (i >= 0) @@ -463,6 +489,11 @@ ip_address_or_route_parser (KeyfileReaderInfo *info, NMSetting *setting, const c item = read_one_ip_address_or_route (info, key, setting_name, key_name, ipv6, routes, gateway ? NULL : &gateway, setting); + if (item && routes) { + nm_sprintf_buf (options_key, "%s_options", key_name); + fill_route_attributes (info->keyfile, item, setting_name, options_key, ipv6 ? AF_INET6 : AF_INET); + } + g_free (key_name); if (info->error) { diff --git a/libnm-core/nm-keyfile-writer.c b/libnm-core/nm-keyfile-writer.c index 21aeca2fa8..13a29ccdcc 100644 --- a/libnm-core/nm-keyfile-writer.c +++ b/libnm-core/nm-keyfile-writer.c @@ -138,7 +138,7 @@ write_ip_values (GKeyFile *file, int family, i; const char *addr, *gw; guint32 plen, metric; - char key_name[30], *key_name_idx; + char key_name[64], *key_name_idx; if (!array->len) return; @@ -188,6 +188,23 @@ write_ip_values (GKeyFile *file, sprintf (key_name_idx, "%d", i + 1); nm_keyfile_plugin_kf_set_string (file, setting_name, key_name, output->str); + + if (is_route) { + gs_free char *attributes = NULL; + gs_strfreev char **names = NULL; + gs_unref_hashtable GHashTable *hash = g_hash_table_new (g_str_hash, g_str_equal); + int j; + + names = nm_ip_route_get_attribute_names (array->pdata[i]); + for (j = 0; names && names[j]; j++) + g_hash_table_insert (hash, names[j], nm_ip_route_get_attribute (array->pdata[i], names[j])); + + attributes = nm_utils_format_variant_attributes (hash, ',', '='); + if (attributes) { + g_strlcat (key_name, "_options", sizeof (key_name)); + nm_keyfile_plugin_kf_set_string (file, setting_name, key_name, attributes); + } + } } g_string_free (output, TRUE); } diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection b/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection index de8373bef2..e55e229306 100644 --- a/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection +++ b/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection @@ -34,6 +34,7 @@ routes8=1.1.1.8/18,0.0.0.0, routes9=1.1.1.9/19,0.0.0.0,0 routes10=1.1.1.10/20,,0 routes11=1.1.1.11/21,,21 +routes11_options=cwnd=10,lock-cwnd=true,mtu=1430,pref-src=7.7.7.7 ignore-auto-routes=false ignore-auto-dns=false @@ -58,5 +59,6 @@ route3=6:7:8:9:0:1:2:3/126,,1 route4=7:8:9:0:1:2:3:4/125/::,5 route5=8:9:0:1:2:3:4:5/124,6 route6=8:9:0:1:2:3:4:6/123,, +route6_options=src=abce::/63 ignore-auto-routes=false ignore-auto-dns=false diff --git a/src/settings/plugins/keyfile/tests/test-keyfile.c b/src/settings/plugins/keyfile/tests/test-keyfile.c index 1d1f5d8ccb..f43300f2c8 100644 --- a/src/settings/plugins/keyfile/tests/test-keyfile.c +++ b/src/settings/plugins/keyfile/tests/test-keyfile.c @@ -224,6 +224,7 @@ test_read_valid_wired_connection (void) NMSettingWired *s_wired; NMSettingIPConfig *s_ip4; NMSettingIPConfig *s_ip6; + NMIPRoute *route; gs_free_error GError *error = NULL; const char *mac; char expected_mac_address[ETH_ALEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }; @@ -318,6 +319,15 @@ test_read_valid_wired_connection (void) check_ip_route (s_ip4, 10, "1.1.1.10", 20, NULL, -1); check_ip_route (s_ip4, 11, "1.1.1.11", 21, NULL, 21); + /* Route attributes */ + route = nm_setting_ip_config_get_route (s_ip4, 11); + g_assert (route); + + nmtst_assert_route_attribute_uint32 (route, NM_IP_ROUTE_ATTRIBUTE_CWND, 10); + nmtst_assert_route_attribute_uint32 (route, NM_IP_ROUTE_ATTRIBUTE_MTU, 1430); + nmtst_assert_route_attribute_boolean (route, NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, TRUE); + nmtst_assert_route_attribute_string (route, NM_IP_ROUTE_ATTRIBUTE_PREF_SRC, "7.7.7.7"); + /* ===== IPv6 SETTING ===== */ s_ip6 = nm_connection_get_setting_ip6_config (connection); g_assert (s_ip6); @@ -357,6 +367,11 @@ test_read_valid_wired_connection (void) check_ip_route (s_ip6, 4, "7:8:9:0:1:2:3:4", 125, NULL, 5); check_ip_route (s_ip6, 5, "8:9:0:1:2:3:4:5", 124, NULL, 6); check_ip_route (s_ip6, 6, "8:9:0:1:2:3:4:6", 123, NULL, -1); + + /* Route attributes */ + route = nm_setting_ip_config_get_route (s_ip6, 6); + g_assert (route); + nmtst_assert_route_attribute_string (route, NM_IP_ROUTE_ATTRIBUTE_SRC, "abce::/63"); } static void @@ -402,6 +417,7 @@ test_write_wired_connection (void) NMSettingWired *s_wired; NMSettingIPConfig *s_ip4; NMSettingIPConfig *s_ip6; + NMIPRoute *rt; const char *mac = "99:88:77:66:55:44"; const char *dns1 = "4.2.2.1"; const char *dns2 = "4.2.2.2"; @@ -429,6 +445,7 @@ test_write_wired_connection (void) const char *route6_4 = "5:6:7:8:9:0:1:2"; const char *route6_4_nh = "::"; guint64 timestamp = 0x12345678L; + GError *error = NULL; connection = nm_simple_connection_new (); @@ -473,7 +490,14 @@ test_write_wired_connection (void) add_one_ip_route (s_ip4, route1, route1_nh, 24, 3); add_one_ip_route (s_ip4, route2, route2_nh, 8, 1); add_one_ip_route (s_ip4, route3, route3_nh, 7, -1); - add_one_ip_route (s_ip4, route4, route4_nh, 6, 4); + + rt = nm_ip_route_new (AF_INET, route4, 6, route4_nh, 4, &error); + g_assert_no_error (error); + nm_ip_route_set_attribute (rt, NM_IP_ROUTE_ATTRIBUTE_CWND, g_variant_new_uint32 (10)); + nm_ip_route_set_attribute (rt, NM_IP_ROUTE_ATTRIBUTE_MTU, g_variant_new_uint32 (1492)); + nm_ip_route_set_attribute (rt, NM_IP_ROUTE_ATTRIBUTE_PREF_SRC, g_variant_new_string ("1.2.3.4")); + g_assert (nm_setting_ip_config_add_route (s_ip4, rt)); + nm_ip_route_unref (rt); /* DNS servers */ nm_setting_ip_config_add_dns (s_ip4, dns1); From 40e1fd9531119318dfc05b6fdab0c326b60f9bdd Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 16 Feb 2017 14:30:16 +0100 Subject: [PATCH 09/11] ifcfg-rh: support route options For IPv4 we support both the legacy and the new route file format. In the legacy format, option are appended to the "ip route" command arguments: 203.0.113.0/24 metric 3 via 198.51.100.1 dev eth2 cwnd 14 mtu lock 1500 This is backwards compatible with initscripts. In the new format, a OPTIONSx= variable is added to represent the options in the same format understood by iproute2: ADDRESS0=203.0.113.0 NETMASK0=255.255.255.0 GATEWAY0=198.51.100.1 METRIC0=3 OPTIONS0="cwnd 14 mtu lock 1500" initscripts do not support this variable at the moment (but the changes needed to support it are trivial). By default the new format is used, unless the route file is already in the legacy format. For IPv6 only the legacy format is supported, as before. --- libnm-core/nm-setting-ip4-config.c | 2 +- .../plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 164 ++++++++++++++++-- .../plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 124 ++++++++++--- .../route-test-wired-static-routes | 1 + .../route-test-wired-static-routes-legacy | 2 +- .../route6-test-wired-ipv6-manual | 2 + .../plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 36 +++- 7 files changed, 295 insertions(+), 36 deletions(-) diff --git a/libnm-core/nm-setting-ip4-config.c b/libnm-core/nm-setting-ip4-config.c index 91a4a3f50c..3a3661613f 100644 --- a/libnm-core/nm-setting-ip4-config.c +++ b/libnm-core/nm-setting-ip4-config.c @@ -615,7 +615,7 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *ip4_class) * ---end--- * ---ifcfg-rh--- * property: routes - * variable: ADDRESS1, NETMASK1, GATEWAY1, METRIC1, ... + * variable: ADDRESS1, NETMASK1, GATEWAY1, METRIC1, OPTIONS1, ... * description: List of static routes. They are not stored in ifcfg-* file, * but in route-* file instead. * ---end--- diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 4a128024c7..e29a204a08 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -435,6 +435,134 @@ read_full_ip4_address (shvarFile *ifcfg, return FALSE; } +/* + * Use looser syntax to comprise all the possibilities. + * The validity must be checked after the match. + */ +#define IPV4_ADDR_REGEX "(?:[0-9]{1,3}\\.){3}[0-9]{1,3}" +#define IPV6_ADDR_REGEX "[0-9A-Fa-f:.]+" + +/* + * NOTE: The regexes below don't describe all variants allowed by 'ip route add', + * namely destination IP without 'to' keyword is recognized just at line start. + */ + +static gboolean +parse_route_options (NMIPRoute *route, int family, const char *line, GError **error) +{ + GRegex *regex = NULL; + GMatchInfo *match_info = NULL; + gboolean success = FALSE; + char *metrics[] = { NM_IP_ROUTE_ATTRIBUTE_WINDOW, NM_IP_ROUTE_ATTRIBUTE_CWND, + NM_IP_ROUTE_ATTRIBUTE_INITCWND , NM_IP_ROUTE_ATTRIBUTE_INITRWND, + NM_IP_ROUTE_ATTRIBUTE_MTU , NULL }; + char buffer[1024]; + int i; + + g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE); + + for (i = 0; metrics[i]; i++) { + nm_sprintf_buf (buffer, "(?:\\s|^)%s\\s+(lock\\s+)?(\\d+)(?:$|\\s)", metrics[i]); + regex = g_regex_new (buffer, 0, 0, NULL); + g_regex_match (regex, line, 0, &match_info); + if (g_match_info_matches (match_info)) { + gs_free char *lock = g_match_info_fetch (match_info, 1); + gs_free char *str = g_match_info_fetch (match_info, 2); + gint64 num = _nm_utils_ascii_str_to_int64 (str, 10, 0, G_MAXUINT32, -1); + + if (num == -1) { + g_match_info_free (match_info); + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid route %s '%s'", metrics[i], str); + goto out; + } + + nm_ip_route_set_attribute (route, metrics[i], + g_variant_new_uint32 (num)); + if (lock && lock[0]) { + nm_sprintf_buf (buffer, "lock-%s", metrics[i]); + nm_ip_route_set_attribute (route, buffer, + g_variant_new_boolean (TRUE)); + } + } + g_clear_pointer (®ex, g_regex_unref); + g_clear_pointer (&match_info, g_match_info_free); + } + + /* tos */ + regex = g_regex_new ("(?:\\s|^)tos\\s+(\\S+)(?:$|\\s)", 0, 0, NULL); + g_regex_match (regex, line, 0, &match_info); + if (g_match_info_matches (match_info)) { + gs_free char *str = g_match_info_fetch (match_info, 1); + gs_free_error GError *local_error = NULL; + gint64 num = _nm_utils_ascii_str_to_int64 (str, 0, 0, G_MAXUINT8, -1); + + if (num == -1) { + g_match_info_free (match_info); + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid route %s '%s'", "tos", str); + goto out; + } + nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_TOS, + g_variant_new_byte ((guchar) num)); + } + g_clear_pointer (®ex, g_regex_unref); + g_clear_pointer (&match_info, g_match_info_free); + + /* from */ + if (family == AF_INET6) { + regex = g_regex_new ("(?:\\s|^)from\\s+(" IPV6_ADDR_REGEX "(?:/\\d{1,3})?)(?:$|\\s)", 0, 0, NULL); + g_regex_match (regex, line, 0, &match_info); + if (g_match_info_matches (match_info)) { + gs_free char *str = g_match_info_fetch (match_info, 1); + gs_free_error GError *local_error = NULL; + GVariant *variant = g_variant_new_string (str); + + if (!nm_ip_route_attribute_validate (NM_IP_ROUTE_ATTRIBUTE_SRC, variant, family, NULL, &local_error)) { + g_match_info_free (match_info); + g_variant_unref (variant); + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid route from '%s': %s", str, local_error->message); + goto out; + } + nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_SRC, variant); + } + g_clear_pointer (®ex, g_regex_unref); + g_clear_pointer (&match_info, g_match_info_free); + } + + if (family == AF_INET) + regex = g_regex_new ("(?:\\s|^)src\\s+(" IPV4_ADDR_REGEX ")(?:$|\\s)", 0, 0, NULL); + else + regex = g_regex_new ("(?:\\s|^)src\\s+(" IPV6_ADDR_REGEX ")(?:$|\\s)", 0, 0, NULL); + g_regex_match (regex, line, 0, &match_info); + if (g_match_info_matches (match_info)) { + gs_free char *str = g_match_info_fetch (match_info, 1); + gs_free_error GError *local_error = NULL; + GVariant *variant = g_variant_new_string (str); + + if (!nm_ip_route_attribute_validate (NM_IP_ROUTE_ATTRIBUTE_PREF_SRC, variant, family, + NULL, &local_error)) { + g_match_info_free (match_info); + g_variant_unref (variant); + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid route src '%s': %s", str, local_error->message); + goto out; + } + + nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_PREF_SRC, variant); + } + success = TRUE; + +out: + if (regex) + g_regex_unref (regex); + if (match_info) + g_match_info_free (match_info); + + return success; +} + /* Returns TRUE on missing route or valid route */ static gboolean read_one_ip4_route (shvarFile *ifcfg, @@ -507,10 +635,20 @@ read_one_ip4_route (shvarFile *ifcfg, metric = -1; *out_route = nm_ip_route_new_binary (AF_INET, &dest, prefix, &next_hop, metric, error); - if (*out_route) - return TRUE; + if (!*out_route) + return FALSE; - return FALSE; + /* Options */ + nm_clear_g_free (&value); + value = svGetValueStr_cp (ifcfg, numbered_tag (tag, "OPTIONS", which)); + if (value) { + if (!parse_route_options (*out_route, AF_INET, value, error)) { + g_clear_pointer (out_route, nm_ip_route_unref); + return FALSE; + } + } + + return TRUE; } static gboolean @@ -636,6 +774,12 @@ read_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError * route = nm_ip_route_new (AF_INET, dest, prefix_int, next_hop, metric_int, error); if (!route) goto error; + + if (!parse_route_options (route, AF_INET, *iter, error)) { + nm_ip_route_unref (route); + goto error; + } + if (!nm_setting_ip_config_add_route (s_ip4, route)) PARSE_WARNING ("duplicate IP4 route"); nm_ip_route_unref (route); @@ -729,13 +873,6 @@ error: return success; } -/* IPv6 address is very complex to describe completely by a regular expression, - * so don't try to, rather use looser syntax to comprise all possibilities - * NOTE: The regexes below don't describe all variants allowed by 'ip route add', - * namely destination IP without 'to' keyword is recognized just at line start. - */ -#define IPV6_ADDR_REGEX "[0-9A-Fa-f:.]+" - static gboolean read_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error) { @@ -757,6 +894,7 @@ read_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error const char *pattern_via = "via\\s+(" IPV6_ADDR_REGEX ")"; /* IPv6 of gateway */ const char *pattern_metric = "metric\\s+(\\d+)"; /* metric */ + g_return_val_if_fail (filename != NULL, FALSE); g_return_val_if_fail (s_ip6 != NULL, FALSE); g_return_val_if_fail (!error || !*error, FALSE); @@ -862,6 +1000,12 @@ read_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error g_free (next_hop); if (!route) goto error; + + if (!parse_route_options (route, AF_INET6, *iter, error)) { + nm_ip_route_unref (route); + goto error; + } + if (!nm_setting_ip_config_add_route (s_ip6, route)) PARSE_WARNING ("duplicate IP6 route"); nm_ip_route_unref (route); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index 620e89e4ba..ce72237a72 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -1867,6 +1867,61 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) } } +static char * +get_route_attributes_string (NMIPRoute *route, int family) +{ + gs_strfreev char **names = NULL; + GVariant *attr, *lock; + GString *str; + int i; + + names = nm_ip_route_get_attribute_names (route); + if (!names || !names[0]) + return NULL; + + str = g_string_new (""); + + for (i = 0; names[i]; i++) { + attr = nm_ip_route_get_attribute (route, names[i]); + + if (!nm_ip_route_attribute_validate (names[i], attr, family, NULL, NULL)) + continue; + + if (NM_IN_STRSET (names[i], NM_IP_ROUTE_ATTRIBUTE_WINDOW, + NM_IP_ROUTE_ATTRIBUTE_CWND, + NM_IP_ROUTE_ATTRIBUTE_INITCWND, + NM_IP_ROUTE_ATTRIBUTE_INITRWND, + NM_IP_ROUTE_ATTRIBUTE_MTU)) { + char lock_name[256]; + + nm_sprintf_buf (lock_name, "lock-%s", names[i]); + lock = nm_ip_route_get_attribute (route, lock_name); + + g_string_append_printf (str, + "%s %s%u", + names[i], + (lock && g_variant_get_boolean (lock)) ? "lock " : "", + g_variant_get_uint32 (attr)); + } else if (strstr (names[i], "lock-")) { + /* handled above */ + } else if (nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_TOS)) { + g_string_append_printf (str, "%s %u", names[i], (unsigned) g_variant_get_byte (attr)); + } else if ( nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_PREF_SRC) + || nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_SRC)) { + char *arg = nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_PREF_SRC) ? "src" : "from"; + + g_string_append_printf (str, "%s %s", arg, g_variant_get_string (attr, NULL)); + } else { + _LOGW ("unknown route option '%s'", names[i]); + continue; + } + if (names[i + 1]) + g_string_append_c (str, ' '); + } + + return g_string_free (str, FALSE); +} + static gboolean write_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError **error) { @@ -1891,6 +1946,8 @@ write_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError route_items = g_malloc0 (sizeof (char*) * (num + 1)); for (i = 0; i < num; i++) { + gs_free char *options = NULL; + route = nm_setting_ip_config_get_route (s_ip4, i); dest = nm_ip_route_get_dest (route); @@ -1898,10 +1955,19 @@ write_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError next_hop = nm_ip_route_get_next_hop (route); metric = nm_ip_route_get_metric (route); - if (metric == -1) - route_items[i] = g_strdup_printf ("%s/%u via %s\n", dest, prefix, next_hop); - else - route_items[i] = g_strdup_printf ("%s/%u via %s metric %u\n", dest, prefix, next_hop, (guint32) metric); + options = get_route_attributes_string (route, AF_INET); + + if (metric == -1) { + route_items[i] = g_strdup_printf ("%s/%u via %s%s%s\n", + dest, prefix, next_hop, + options ? " " : "", + options ?: ""); + } else { + route_items[i] = g_strdup_printf ("%s/%u via %s metric %u%s%s\n", + dest, prefix, next_hop, (guint32) metric, + options ? " " : "", + options ?: ""); + } } route_items[num] = NULL; route_contents = g_strjoinv (NULL, route_items); @@ -1960,7 +2026,7 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) { NMSettingIPConfig *s_ip4; const char *value; - char *addr_key, *prefix_key, *netmask_key, *gw_key, *metric_key, *tmp; + char *addr_key, *prefix_key, *netmask_key, *gw_key, *metric_key, *options_key, *tmp; char *route_path = NULL; gint32 j; guint32 i, n, num; @@ -2217,13 +2283,17 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) netmask_key = g_strdup_printf ("NETMASK%d", i); gw_key = g_strdup_printf ("GATEWAY%d", i); metric_key = g_strdup_printf ("METRIC%d", i); + options_key = g_strdup_printf ("OPTIONS%d", i); if (i >= num) { svUnsetValue (routefile, addr_key); svUnsetValue (routefile, netmask_key); svUnsetValue (routefile, gw_key); svUnsetValue (routefile, metric_key); + svUnsetValue (routefile, options_key); } else { + gs_free char *options = NULL; + route = nm_setting_ip_config_get_route (s_ip4, i); svSetValueStr (routefile, addr_key, nm_ip_route_get_dest (route)); @@ -2244,12 +2314,17 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) svSetValueStr (routefile, metric_key, tmp); g_free (tmp); } + + options = get_route_attributes_string (route, AF_INET); + if (options) + svSetValueStr (routefile, options_key, options); } g_free (addr_key); g_free (netmask_key); g_free (gw_key); g_free (metric_key); + g_free (options_key); } if (!svWriteFile (routefile, 0644, error)) { svCloseFile (routefile); @@ -2371,15 +2446,13 @@ write_ip4_aliases (NMConnection *connection, char *base_ifcfg_path) static gboolean write_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error) { - char **route_items; - gs_free char *route_contents = NULL; + nm_auto_free_gstring GString *contents = NULL; NMIPRoute *route; guint32 i, num; - g_return_val_if_fail (filename != NULL, FALSE); - g_return_val_if_fail (s_ip6 != NULL, FALSE); - g_return_val_if_fail (error != NULL, FALSE); - g_return_val_if_fail (*error == NULL, FALSE); + g_return_val_if_fail (filename, FALSE); + g_return_val_if_fail (s_ip6, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); num = nm_setting_ip_config_get_num_routes (s_ip6); if (num == 0) { @@ -2387,28 +2460,33 @@ write_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **erro return TRUE; } - route_items = g_malloc0 (sizeof (char*) * (num + 1)); + contents = g_string_new (""); for (i = 0; i < num; i++) { + gs_free char *options = NULL; + route = nm_setting_ip_config_get_route (s_ip6, i); + options = get_route_attributes_string (route, AF_INET6); if (nm_ip_route_get_metric (route) == -1) { - route_items[i] = g_strdup_printf ("%s/%u via %s\n", - nm_ip_route_get_dest (route), - nm_ip_route_get_prefix (route), - nm_ip_route_get_next_hop (route)); - } else { - route_items[i] = g_strdup_printf ("%s/%u via %s metric %u\n", + g_string_append_printf (contents, "%s/%u via %s%s%s", nm_ip_route_get_dest (route), nm_ip_route_get_prefix (route), nm_ip_route_get_next_hop (route), - (guint32) nm_ip_route_get_metric (route)); + options ? " " : "", + options ?: ""); + } else { + g_string_append_printf (contents, "%s/%u via %s metric %u%s%s", + nm_ip_route_get_dest (route), + nm_ip_route_get_prefix (route), + nm_ip_route_get_next_hop (route), + (unsigned) nm_ip_route_get_metric (route), + options ? " " : "", + options ?: ""); } + g_string_append (contents, "\n"); } - route_items[num] = NULL; - route_contents = g_strjoinv (NULL, route_items); - g_strfreev (route_items); - if (!g_file_set_contents (filename, route_contents, -1, NULL)) { + if (!g_file_set_contents (filename, contents->str, -1, NULL)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Writing route6 file '%s' failed", filename); return FALSE; diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes index ee2a32d8e2..10a63b674f 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes @@ -6,3 +6,4 @@ ADDRESS1=44.55.66.77 NETMASK1=255.255.255.255 GATEWAY1=192.168.1.7 METRIC1=3 +OPTIONS1="mtu lock 9000 cwnd 12 src 1.1.1.1 tos 0x28 window 30000 initcwnd lock 13 initrwnd 14" diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes-legacy b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes-legacy index cb7d42bde2..3f02032ad7 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes-legacy +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes-legacy @@ -3,5 +3,5 @@ 21.31.41.0/24 via 9.9.9.9 metric 1 via 8.8.8.8 to 32.42.52.62 - 43.53.0.0/16 metric 3 via 7.7.7.7 dev eth2 + 43.53.0.0/16 metric 3 via 7.7.7.7 dev eth2 cwnd 14 mtu lock 9000 initrwnd 20 window lock 10000 initcwnd lock 42 src 1.2.3.4 diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route6-test-wired-ipv6-manual b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route6-test-wired-ipv6-manual index b3259ab7ff..8bdf0acf5c 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route6-test-wired-ipv6-manual +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route6-test-wired-ipv6-manual @@ -5,3 +5,5 @@ default via dead::beaf # routes without "via" are valid abbe::cafe/64 metric 777 + +aaaa::cccc/64 from 1111::2222/48 via 3333::4444 src 5555::6666 mtu lock 1450 cwnd 13 diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index bd6068ce15..2058b6209a 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -1127,6 +1127,15 @@ test_read_wired_static_routes (void) g_assert_cmpint (nm_ip_route_get_prefix (ip4_route), ==, 32); g_assert_cmpstr (nm_ip_route_get_next_hop (ip4_route), ==, "192.168.1.7"); g_assert_cmpint (nm_ip_route_get_metric (ip4_route), ==, 3); + nmtst_assert_route_attribute_byte (ip4_route, NM_IP_ROUTE_ATTRIBUTE_TOS, 0x28); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_WINDOW, 30000); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_CWND, 12); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITCWND, 13); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITRWND, 14); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_MTU, 9000); + nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, TRUE); + nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, TRUE); + nmtst_assert_route_attribute_string (ip4_route, NM_IP_ROUTE_ATTRIBUTE_PREF_SRC, "1.1.1.1"); g_object_unref (connection); } @@ -1188,6 +1197,14 @@ test_read_wired_static_routes_legacy (void) g_assert_cmpint (nm_ip_route_get_prefix (ip4_route), ==, 16); g_assert_cmpstr (nm_ip_route_get_next_hop (ip4_route), ==, "7.7.7.7"); g_assert_cmpint (nm_ip_route_get_metric (ip4_route), ==, 3); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_WINDOW, 10000); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_CWND, 14); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITCWND, 42); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITRWND, 20); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_MTU, 9000); + nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, TRUE); + nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, TRUE); + nmtst_assert_route_attribute_string (ip4_route, NM_IP_ROUTE_ATTRIBUTE_PREF_SRC, "1.2.3.4"); g_object_unref (connection); } @@ -1328,7 +1345,7 @@ test_read_wired_ipv6_manual (void) g_assert_cmpint (nm_ip_address_get_prefix (ip6_addr), ==, 96); /* Routes */ - g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip6), ==, 2); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip6), ==, 3); /* Route #1 */ ip6_route = nm_setting_ip_config_get_route (s_ip6, 0); g_assert (ip6_route); @@ -1343,6 +1360,17 @@ test_read_wired_ipv6_manual (void) g_assert_cmpint (nm_ip_route_get_prefix (ip6_route), ==, 64); g_assert_cmpstr (nm_ip_route_get_next_hop (ip6_route), ==, NULL); g_assert_cmpint (nm_ip_route_get_metric (ip6_route), ==, 777); + /* Route #3 */ + ip6_route = nm_setting_ip_config_get_route (s_ip6, 2); + g_assert (ip6_route); + g_assert_cmpstr (nm_ip_route_get_dest (ip6_route), ==, "aaaa::cccc"); + g_assert_cmpint (nm_ip_route_get_prefix (ip6_route), ==, 64); + g_assert_cmpstr (nm_ip_route_get_next_hop (ip6_route), ==, "3333::4444"); + nmtst_assert_route_attribute_uint32 (ip6_route, NM_IP_ROUTE_ATTRIBUTE_CWND, 13); + nmtst_assert_route_attribute_uint32 (ip6_route, NM_IP_ROUTE_ATTRIBUTE_MTU, 1450); + nmtst_assert_route_attribute_boolean (ip6_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, TRUE); + nmtst_assert_route_attribute_string (ip6_route, NM_IP_ROUTE_ATTRIBUTE_SRC, "1111::2222/48"); + nmtst_assert_route_attribute_string (ip6_route, NM_IP_ROUTE_ATTRIBUTE_PREF_SRC, "5555::6666"); /* DNS Addresses */ g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip6), ==, 2); @@ -3867,6 +3895,12 @@ test_write_wired_static (void) route6 = nm_ip_route_new (AF_INET6, "::", 128, "2222:aaaa::9999", 1, &error); g_assert_no_error (error); + nm_ip_route_set_attribute (route6, NM_IP_ROUTE_ATTRIBUTE_TOS, g_variant_new_byte (0xb8)); + nm_ip_route_set_attribute (route6, NM_IP_ROUTE_ATTRIBUTE_CWND, g_variant_new_uint32 (100)); + nm_ip_route_set_attribute (route6, NM_IP_ROUTE_ATTRIBUTE_MTU, g_variant_new_uint32 (1280)); + nm_ip_route_set_attribute (route6, NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, g_variant_new_boolean (TRUE)); + nm_ip_route_set_attribute (route6, NM_IP_ROUTE_ATTRIBUTE_SRC, g_variant_new_string ("2222::bbbb/32")); + nm_ip_route_set_attribute (route6, NM_IP_ROUTE_ATTRIBUTE_PREF_SRC, g_variant_new_string ("::42")); nm_setting_ip_config_add_route (s_ip6, route6); nm_ip_route_unref (route6); From d0949141203f6a546317277ed788ea114d401dd8 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 16 Feb 2017 10:16:45 +0100 Subject: [PATCH 10/11] cli: support route options --- clients/cli/common.c | 99 +++++++++++++++++++++++++++++------------- clients/cli/common.h | 2 +- clients/cli/settings.c | 45 +++++++++---------- 3 files changed, 91 insertions(+), 55 deletions(-) diff --git a/clients/cli/common.c b/clients/cli/common.c index 56f28ad7f1..c46f6c27e6 100644 --- a/clients/cli/common.c +++ b/clients/cli/common.c @@ -395,26 +395,20 @@ finish: /* * nmc_parse_and_build_route: * @family: AF_INET or AF_INET6 - * @first: the route destination in the form of "address/prefix" - (/prefix is optional) - * @second: (allow-none): next hop address, if third is not NULL. Otherwise it could be - either next hop address or metric. (It can be NULL when @third is NULL). - * @third: (allow-none): route metric + * @str: route string to be parsed * @error: location to store GError * - * Parse route from strings and return an #NMIPRoute + * Parse route from string and return an #NMIPRoute * - * Returns: %TRUE on success, %FALSE on failure + * Returns: a new #NMIPRoute or %NULL on error */ NMIPRoute * nmc_parse_and_build_route (int family, - const char *first, - const char *second, - const char *third, + const char *str, GError **error) { int max_prefix = (family == AF_INET) ? 32 : 128; - char *dest = NULL, *plen = NULL; + char *plen = NULL; const char *next_hop = NULL; const char *canon_dest; long int prefix = max_prefix; @@ -423,13 +417,27 @@ nmc_parse_and_build_route (int family, gboolean success = FALSE; GError *local = NULL; gint64 metric = -1; + guint i, len; + gs_strfreev char **routev = NULL; + gs_free char *value = NULL; + gs_free char *dest = NULL; + gs_unref_hashtable GHashTable *attrs = NULL; + GHashTable *tmp_attrs; g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE); - g_return_val_if_fail (first != NULL, FALSE); - g_return_val_if_fail (second || !third, FALSE); + g_return_val_if_fail (str, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - dest = g_strdup (first); + value = g_strdup (str); + routev = nmc_strsplit_set (g_strstrip (value), " \t", 0); + len = g_strv_length (routev); + if (len < 1) { + g_set_error (error, 1, 0, _("'%s' is not valid (the format is: ip[/prefix] [next-hop] [metric] [attr=val] [attr=val])"), + str); + goto finish; + } + + dest = g_strdup (routev[0]); plen = strchr (dest, '/'); /* prefix delimiter */ if (plen) *plen++ = '\0'; @@ -443,26 +451,50 @@ nmc_parse_and_build_route (int family, } } - if (second) { - if (third || nm_utils_ipaddr_valid (family, second)) - next_hop = second; - else { - /* 'second' can be a metric */ - if (!nmc_string_to_uint (second, TRUE, 0, G_MAXUINT32, &tmp_ulong)) { - g_set_error (error, 1, 0, _("the second component of route ('%s') is neither " - "a next hop address nor a metric"), second); + for (i = 1; i < len; i++) { + if (nm_utils_ipaddr_valid (family, routev[i])) { + if (metric != -1 || attrs) { + g_set_error (error, 1, 0, _("the next hop ('%s') must be first"), routev[i]); + goto finish; + } + next_hop = routev[i]; + } else if (nmc_string_to_uint (routev[i], TRUE, 0, G_MAXUINT32, &tmp_ulong)) { + if (attrs) { + g_set_error (error, 1, 0, _("the metric ('%s') must be before attributes"), routev[i]); goto finish; } metric = tmp_ulong; - } - } + } else if (strchr (routev[i], '=')) { + GHashTableIter iter; + char *iter_key; + GVariant *iter_value; - if (third) { - if (!nmc_string_to_uint (third, TRUE, 0, G_MAXUINT32, &tmp_ulong)) { - g_set_error (error, 1, 0, _("invalid metric '%s'"), third); + tmp_attrs = nm_utils_parse_variant_attributes (routev[i], ' ', '=', FALSE, + nm_ip_route_get_variant_attribute_spec(), + error); + if (!tmp_attrs) { + g_prefix_error (error, "invalid option '%s': ", routev[i]); + goto finish; + } + + if (!attrs) + attrs = g_hash_table_new (g_str_hash, g_str_equal); + + g_hash_table_iter_init (&iter, tmp_attrs); + while (g_hash_table_iter_next (&iter, (gpointer *) &iter_key, (gpointer *) &iter_value)) { + if (!nm_ip_route_attribute_validate (iter_key, iter_value, family, NULL, error)) { + g_prefix_error (error, "%s: ", iter_key); + g_hash_table_unref (tmp_attrs); + goto finish; + } + g_hash_table_insert (attrs, iter_key, iter_value); + g_hash_table_iter_steal (&iter); + } + g_hash_table_unref (tmp_attrs); + } else { + g_set_error (error, 1, 0, _("unrecognized option '%s'"), routev[i]); goto finish; } - metric = tmp_ulong; } route = nm_ip_route_new (family, dest, prefix, next_hop, metric, &local); @@ -485,10 +517,19 @@ nmc_parse_and_build_route (int family, goto finish; } + if (attrs) { + GHashTableIter iter; + char *name; + GVariant *variant; + + g_hash_table_iter_init (&iter, attrs); + while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &variant)) + nm_ip_route_set_attribute (route, name, variant); + } + success = TRUE; finish: - g_free (dest); return route; } diff --git a/clients/cli/common.h b/clients/cli/common.h index 4209136350..3a598f631c 100644 --- a/clients/cli/common.h +++ b/clients/cli/common.h @@ -31,7 +31,7 @@ gboolean print_dhcp4_config (NMDhcpConfig *dhcp4, NmCli *nmc, const char *group_ gboolean print_dhcp6_config (NMDhcpConfig *dhcp6, NmCli *nmc, const char *group_prefix, const char *one_field); NMIPAddress *nmc_parse_and_build_address (int family, const char *ip_str, GError **error); -NMIPRoute *nmc_parse_and_build_route (int family, const char *first, const char *second, const char *third, GError **error); +NMIPRoute *nmc_parse_and_build_route (int family, const char *str, GError **error); const char * nmc_device_state_to_string (NMDeviceState state); const char * nmc_device_reason_to_string (NMDeviceStateReason reason); diff --git a/clients/cli/settings.c b/clients/cli/settings.c index 047e50f616..ffa3e89c20 100644 --- a/clients/cli/settings.c +++ b/clients/cli/settings.c @@ -3470,29 +3470,6 @@ _parse_ip_address (int family, const char *address, GError **error) return ipaddr; } -static NMIPRoute * -_parse_ip_route (int family, const char *route, GError **error) -{ - char *value = g_strdup (route); - char **routev; - guint len; - NMIPRoute *iproute = NULL; - - routev = nmc_strsplit_set (g_strstrip (value), " \t", 0); - len = g_strv_length (routev); - if (len < 1 || len > 3) { - g_set_error (error, 1, 0, _("'%s' is not valid (the format is: ip[/prefix] [next-hop] [metric])"), - route); - goto finish; - } - iproute = nmc_parse_and_build_route (family, routev[0], routev[1], len >= 2 ? routev[2] : NULL, error); - -finish: - g_free (value); - g_strfreev (routev); - return iproute; -} - DEFINE_GETTER (nmc_property_ipv4_get_method, NM_SETTING_IP_CONFIG_METHOD) DEFINE_GETTER (nmc_property_ipv4_get_dns, NM_SETTING_IP_CONFIG_DNS) DEFINE_GETTER (nmc_property_ipv4_get_dns_search, NM_SETTING_IP_CONFIG_DNS_SEARCH) @@ -3536,8 +3513,21 @@ nmc_property_ipvx_get_routes (NMSetting *setting, NmcPropertyGetType get_type) num_routes = nm_setting_ip_config_get_num_routes (s_ip); for (i = 0; i < num_routes; i++) { + gs_free char *attr_str = NULL; + gs_strfreev char **attr_names = NULL; + gs_unref_hashtable GHashTable *hash = g_hash_table_new (g_str_hash, g_str_equal); + int j; + route = nm_setting_ip_config_get_route (s_ip, i); + attr_names = nm_ip_route_get_attribute_names (route); + for (j = 0; attr_names && attr_names[j]; j++) { + g_hash_table_insert (hash, attr_names[j], + nm_ip_route_get_attribute (route, attr_names[j])); + } + + attr_str = nm_utils_format_variant_attributes (hash, ' ', '='); + if (get_type == NMC_PROPERTY_GET_PARSABLE) { if (printable->len > 0) g_string_append (printable, ", "); @@ -3550,7 +3540,10 @@ nmc_property_ipvx_get_routes (NMSetting *setting, NmcPropertyGetType get_type) g_string_append_printf (printable, " %s", nm_ip_route_get_next_hop (route)); if (nm_ip_route_get_metric (route) != -1) g_string_append_printf (printable, " %u", (guint32) nm_ip_route_get_metric (route)); + if (attr_str) + g_string_append_printf (printable, " %s", attr_str); } else { + if (printable->len > 0) g_string_append (printable, "; "); @@ -3567,6 +3560,8 @@ nmc_property_ipvx_get_routes (NMSetting *setting, NmcPropertyGetType get_type) if (nm_ip_route_get_metric (route) != -1) g_string_append_printf (printable, ", mt = %u", (guint32) nm_ip_route_get_metric (route)); + if (attr_str) + g_string_append_printf (printable, " %s", attr_str); g_string_append (printable, " }"); } @@ -3858,7 +3853,7 @@ nmc_property_ipv4_set_gateway (NMSetting *setting, const char *prop, const char static NMIPRoute * _parse_ipv4_route (const char *route, GError **error) { - return _parse_ip_route (AF_INET, route, error); + return nmc_parse_and_build_route (AF_INET, route, error); } static gboolean @@ -4201,7 +4196,7 @@ nmc_property_ipv6_set_gateway (NMSetting *setting, const char *prop, const char static NMIPRoute * _parse_ipv6_route (const char *route, GError **error) { - return _parse_ip_route (AF_INET6, route, error); + return nmc_parse_and_build_route (AF_INET6, route, error); } static gboolean From 10f58f2bd36e1d74ab174b3f81817a78bde66dda Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 4 Mar 2017 14:47:28 +0100 Subject: [PATCH 11/11] ifcg-rh/writer: stack allocate keys in write_ip4_setting() And make the types of the integer count variables consistent. --- .../plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 97 ++++++++----------- 1 file changed, 40 insertions(+), 57 deletions(-) diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index ce72237a72..2484799cb6 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -2026,10 +2026,14 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) { NMSettingIPConfig *s_ip4; const char *value; - char *addr_key, *prefix_key, *netmask_key, *gw_key, *metric_key, *options_key, *tmp; + char *tmp; + char addr_key[64]; + char prefix_key[64]; + char netmask_key[64]; + char gw_key[64]; char *route_path = NULL; - gint32 j; - guint32 i, n, num; + gint j; + guint i, num, n; gint64 route_metric; gint priority; int timeout; @@ -2069,26 +2073,21 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) svUnsetValue (ifcfg, "BOOTPROTO"); for (j = -1; j < 256; j++) { if (j == -1) { - addr_key = g_strdup ("IPADDR"); - prefix_key = g_strdup ("PREFIX"); - netmask_key = g_strdup ("NETMASK"); - gw_key = g_strdup ("GATEWAY"); + nm_sprintf_buf (addr_key, "IPADDR"); + nm_sprintf_buf (prefix_key, "PREFIX"); + nm_sprintf_buf (netmask_key, "NETMASK"); + nm_sprintf_buf (gw_key, "GATEWAY"); } else { - addr_key = g_strdup_printf ("IPADDR%d", j); - prefix_key = g_strdup_printf ("PREFIX%d", j); - netmask_key = g_strdup_printf ("NETMASK%d", j); - gw_key = g_strdup_printf ("GATEWAY%d", j); + nm_sprintf_buf (addr_key, "IPADDR%d", (guint) j); + nm_sprintf_buf (prefix_key, "PREFIX%u", (guint) j); + nm_sprintf_buf (netmask_key, "NETMASK%u", (guint) j); + nm_sprintf_buf (gw_key, "GATEWAY%u", (guint) j); } svUnsetValue (ifcfg, addr_key); svUnsetValue (ifcfg, prefix_key); svUnsetValue (ifcfg, netmask_key); svUnsetValue (ifcfg, gw_key); - - g_free (addr_key); - g_free (prefix_key); - g_free (netmask_key); - g_free (gw_key); } route_path = utils_get_route_path (svFileGetName (ifcfg)); @@ -2140,15 +2139,15 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) * See https://bugzilla.redhat.com/show_bug.cgi?id=771673 * and https://bugzilla.redhat.com/show_bug.cgi?id=1105770 */ - addr_key = g_strdup ("IPADDR"); - prefix_key = g_strdup ("PREFIX"); - netmask_key = g_strdup ("NETMASK"); - gw_key = g_strdup ("GATEWAY"); + nm_sprintf_buf (addr_key, "IPADDR"); + nm_sprintf_buf (prefix_key, "PREFIX"); + nm_sprintf_buf (netmask_key, "NETMASK"); + nm_sprintf_buf (gw_key, "GATEWAY"); } else { - addr_key = g_strdup_printf ("IPADDR%d", n); - prefix_key = g_strdup_printf ("PREFIX%d", n); - netmask_key = g_strdup_printf ("NETMASK%d", n); - gw_key = g_strdup_printf ("GATEWAY%d", n); + nm_sprintf_buf (addr_key, "IPADDR%u", n); + nm_sprintf_buf (prefix_key, "PREFIX%u", n); + nm_sprintf_buf (netmask_key, "NETMASK%u", n); + nm_sprintf_buf (gw_key, "GATEWAY%u", n); } svSetValueStr (ifcfg, addr_key, nm_ip_address_get_address (addr)); @@ -2159,30 +2158,20 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) svUnsetValue (ifcfg, netmask_key); svUnsetValue (ifcfg, gw_key); - - g_free (addr_key); - g_free (prefix_key); - g_free (netmask_key); - g_free (gw_key); n++; } /* Clear remaining IPADDR, etc */ - for (; n < 256; n++) { - addr_key = g_strdup_printf ("IPADDR%d", n); - prefix_key = g_strdup_printf ("PREFIX%d", n); - netmask_key = g_strdup_printf ("NETMASK%d", n); - gw_key = g_strdup_printf ("GATEWAY%d", n); + for (i = n; i < 256; i++) { + nm_sprintf_buf (addr_key, "IPADDR%u", i); + nm_sprintf_buf (prefix_key, "PREFIX%u", i); + nm_sprintf_buf (netmask_key, "NETMASK%u", i); + nm_sprintf_buf (gw_key, "GATEWAY%u", i); svUnsetValue (ifcfg, addr_key); svUnsetValue (ifcfg, prefix_key); svUnsetValue (ifcfg, netmask_key); svUnsetValue (ifcfg, gw_key); - - g_free (addr_key); - g_free (prefix_key); - g_free (netmask_key); - g_free (gw_key); } svSetValueStr (ifcfg, "GATEWAY", nm_setting_ip_config_get_gateway (s_ip4)); @@ -2191,15 +2180,13 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) for (i = 0; i < 254; i++) { const char *dns; - addr_key = g_strdup_printf ("DNS%d", i + 1); - + nm_sprintf_buf (addr_key, "DNS%u", i + 1); if (i >= num) svUnsetValue (ifcfg, addr_key); else { dns = nm_setting_ip_config_get_dns (s_ip4, i); svSetValueStr (ifcfg, addr_key, dns); } - g_free (addr_key); } num = nm_setting_ip_config_get_num_dns_searches (s_ip4); @@ -2278,12 +2265,14 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) NMIPRoute *route; guint32 netmask; gint64 metric; + char metric_key[64]; + char options_key[64]; - addr_key = g_strdup_printf ("ADDRESS%d", i); - netmask_key = g_strdup_printf ("NETMASK%d", i); - gw_key = g_strdup_printf ("GATEWAY%d", i); - metric_key = g_strdup_printf ("METRIC%d", i); - options_key = g_strdup_printf ("OPTIONS%d", i); + nm_sprintf_buf (addr_key, "ADDRESS%u", i); + nm_sprintf_buf (netmask_key, "NETMASK%u", i); + nm_sprintf_buf (gw_key, "GATEWAY%u", i); + nm_sprintf_buf (metric_key, "METRIC%u", i); + nm_sprintf_buf (options_key, "OPTIONS%u", i); if (i >= num) { svUnsetValue (routefile, addr_key); @@ -2319,12 +2308,6 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) if (options) svSetValueStr (routefile, options_key, options); } - - g_free (addr_key); - g_free (netmask_key); - g_free (gw_key); - g_free (metric_key); - g_free (options_key); } if (!svWriteFile (routefile, 0644, error)) { svCloseFile (routefile); @@ -2518,9 +2501,8 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) NMSettingIPConfig *s_ip6; NMSettingIPConfig *s_ip4; const char *value; - char *addr_key; char *tmp; - guint32 i, num, num4; + guint i, num, num4; gint priority; NMIPAddress *addr; const char *dns; @@ -2608,7 +2590,9 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) num4 = s_ip4 ? nm_setting_ip_config_get_num_dns (s_ip4) : 0; /* from where to start with IPv6 entries */ num = nm_setting_ip_config_get_num_dns (s_ip6); for (i = 0; i < 254; i++) { - addr_key = g_strdup_printf ("DNS%d", i + num4 + 1); + char addr_key[64]; + + nm_sprintf_buf (addr_key, "DNS%u", i + num4 + 1); if (i >= num) svUnsetValue (ifcfg, addr_key); @@ -2616,7 +2600,6 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) dns = nm_setting_ip_config_get_dns (s_ip6, i); svSetValueStr (ifcfg, addr_key, dns); } - g_free (addr_key); } /* Write out DNS domains - 'DOMAIN' key is shared for both IPv4 and IPv6 domains */