diff options
Diffstat (limited to 'src/nm-ip4-config.c')
-rw-r--r-- | src/nm-ip4-config.c | 183 |
1 files changed, 150 insertions, 33 deletions
diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index db8c4b43e..5918f3dcb 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -35,6 +35,7 @@ #include "nm-core-internal.h" #include "nm-route-manager.h" #include "gsystem-local-alloc.h" +#include "nm-macros-internal.h" G_DEFINE_TYPE (NMIP4Config, nm_ip4_config, G_TYPE_OBJECT) @@ -45,6 +46,7 @@ typedef struct { gboolean never_default; guint32 gateway; + gboolean has_gateway; GArray *addresses; GArray *routes; GArray *nameservers; @@ -56,6 +58,8 @@ typedef struct { GArray *wins; guint32 mtu; NMIPConfigSource mtu_source; + gint64 route_metric; + gboolean metered; } NMIP4ConfigPrivate; /* internal guint32 are assigned to gobject properties of type uint. Ensure, that uint is large enough */ @@ -185,7 +189,7 @@ nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf) guint i; guint32 lowest_metric = G_MAXUINT32; guint32 old_gateway = 0; - gboolean has_gateway = FALSE; + gboolean old_has_gateway = FALSE; /* Slaves have no IP configuration */ if (nm_platform_link_get_master (NM_PLATFORM_GET, ifindex) > 0) @@ -202,6 +206,7 @@ nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf) /* Extract gateway from default route */ old_gateway = priv->gateway; + old_has_gateway = priv->has_gateway; for (i = 0; i < priv->routes->len; ) { const NMPlatformIP4Route *route = &g_array_index (priv->routes, NMPlatformIP4Route, i); @@ -210,7 +215,7 @@ nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf) priv->gateway = route->gateway; lowest_metric = route->metric; } - has_gateway = TRUE; + priv->has_gateway = TRUE; /* Remove the default route from the list */ g_array_remove_index_fast (priv->routes, i); continue; @@ -218,10 +223,14 @@ nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf) i++; } + /* we detect the route metric based on the default route. All non-default + * routes have their route metrics explicitly set. */ + priv->route_metric = priv->has_gateway ? (gint64) lowest_metric : (gint64) -1; + /* If there is a host route to the gateway, ignore that route. It is * automatically added by NetworkManager when needed. */ - if (has_gateway) { + if (priv->has_gateway) { for (i = 0; i < priv->routes->len; i++) { const NMPlatformIP4Route *route = &g_array_index (priv->routes, NMPlatformIP4Route, i); @@ -237,7 +246,7 @@ nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf) /* If the interface has the default route, and has IPv4 addresses, capture * nameservers from /etc/resolv.conf. */ - if (priv->addresses->len && has_gateway && capture_resolv_conf) { + if (priv->addresses->len && priv->has_gateway && capture_resolv_conf) { if (nm_ip4_config_capture_resolv_conf (priv->nameservers, NULL)) _NOTIFY (config, PROP_NAMESERVERS); } @@ -247,7 +256,8 @@ nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf) _NOTIFY (config, PROP_ROUTE_DATA); _NOTIFY (config, PROP_ADDRESSES); _NOTIFY (config, PROP_ROUTES); - if (priv->gateway != old_gateway) + if ( priv->gateway != old_gateway + || priv->has_gateway != old_has_gateway) _NOTIFY (config, PROP_GATEWAY); return config; @@ -335,6 +345,7 @@ nm_ip4_config_commit (const NMIP4Config *config, int ifindex, gboolean routes_fu void nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, guint32 default_route_metric) { + NMIP4ConfigPrivate *priv; guint naddresses, nroutes, nnameservers, nsearches; int i; @@ -343,6 +354,8 @@ nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, gu g_return_if_fail (NM_IS_SETTING_IP4_CONFIG (setting)); + priv = NM_IP4_CONFIG_GET_PRIVATE (config); + g_object_freeze_notify (G_OBJECT (config)); naddresses = nm_setting_ip_config_get_num_addresses (setting); @@ -362,6 +375,9 @@ nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, gu nm_ip4_config_set_gateway (config, gateway); } + if (priv->route_metric == -1) + priv->route_metric = nm_setting_ip_config_get_route_metric (setting); + /* Addresses */ for (i = 0; i < naddresses; i++) { NMIPAddress *s_addr = nm_setting_ip_config_get_address (setting, i); @@ -430,6 +446,7 @@ nm_ip4_config_create_setting (const NMIP4Config *config) guint naddresses, nroutes, nnameservers, nsearches; const char *method = NULL; int i; + gint64 route_metric; s_ip4 = NM_SETTING_IP_CONFIG (nm_setting_ip4_config_new ()); @@ -445,6 +462,7 @@ nm_ip4_config_create_setting (const NMIP4Config *config) nroutes = nm_ip4_config_get_num_routes (config); nnameservers = nm_ip4_config_get_num_nameservers (config); nsearches = nm_ip4_config_get_num_searches (config); + route_metric = nm_ip4_config_get_route_metric (config); /* Addresses */ for (i = 0; i < naddresses; i++) { @@ -470,7 +488,7 @@ nm_ip4_config_create_setting (const NMIP4Config *config) } /* Gateway */ - if ( gateway + if ( nm_ip4_config_has_gateway (config) && nm_setting_ip_config_get_num_addresses (s_ip4) > 0) { g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, nm_utils_inet4_ntop (gateway, NULL), @@ -480,7 +498,11 @@ nm_ip4_config_create_setting (const NMIP4Config *config) /* Use 'disabled' if the method wasn't previously set */ if (!method) method = NM_SETTING_IP4_CONFIG_METHOD_DISABLED; - g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, method, NULL); + + g_object_set (s_ip4, + NM_SETTING_IP_CONFIG_METHOD, method, + NM_SETTING_IP_CONFIG_ROUTE_METRIC, (gint64) route_metric, + NULL); /* Routes */ for (i = 0; i < nroutes; i++) { @@ -521,13 +543,17 @@ nm_ip4_config_create_setting (const NMIP4Config *config) /******************************************************************/ void -nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src) +nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src, NMIPConfigMergeFlags merge_flags) { + NMIP4ConfigPrivate *dst_priv, *src_priv; guint32 i; g_return_if_fail (src != NULL); g_return_if_fail (dst != NULL); + dst_priv = NM_IP4_CONFIG_GET_PRIVATE (dst); + src_priv = NM_IP4_CONFIG_GET_PRIVATE (src); + g_object_freeze_notify (G_OBJECT (dst)); /* addresses */ @@ -535,24 +561,37 @@ nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src) nm_ip4_config_add_address (dst, nm_ip4_config_get_address (src, i)); /* nameservers */ - for (i = 0; i < nm_ip4_config_get_num_nameservers (src); i++) - nm_ip4_config_add_nameserver (dst, nm_ip4_config_get_nameserver (src, i)); + if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_DNS)) { + for (i = 0; i < nm_ip4_config_get_num_nameservers (src); i++) + nm_ip4_config_add_nameserver (dst, nm_ip4_config_get_nameserver (src, i)); + } /* default gateway */ - if (nm_ip4_config_get_gateway (src)) + if (nm_ip4_config_has_gateway (src)) nm_ip4_config_set_gateway (dst, nm_ip4_config_get_gateway (src)); /* routes */ - for (i = 0; i < nm_ip4_config_get_num_routes (src); i++) - nm_ip4_config_add_route (dst, nm_ip4_config_get_route (src, i)); + if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_ROUTES)) { + for (i = 0; i < nm_ip4_config_get_num_routes (src); i++) + nm_ip4_config_add_route (dst, nm_ip4_config_get_route (src, i)); + } + + if (dst_priv->route_metric == -1) + dst_priv->route_metric = src_priv->route_metric; + else if (src_priv->route_metric != -1) + dst_priv->route_metric = MIN (dst_priv->route_metric, src_priv->route_metric); /* domains */ - for (i = 0; i < nm_ip4_config_get_num_domains (src); i++) - nm_ip4_config_add_domain (dst, nm_ip4_config_get_domain (src, i)); + if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_DNS)) { + for (i = 0; i < nm_ip4_config_get_num_domains (src); i++) + nm_ip4_config_add_domain (dst, nm_ip4_config_get_domain (src, i)); + } /* dns searches */ - for (i = 0; i < nm_ip4_config_get_num_searches (src); i++) - nm_ip4_config_add_search (dst, nm_ip4_config_get_search (src, i)); + if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_DNS)) { + for (i = 0; i < nm_ip4_config_get_num_searches (src); i++) + nm_ip4_config_add_search (dst, nm_ip4_config_get_search (src, i)); + } /* MSS */ if (nm_ip4_config_get_mss (src)) @@ -564,15 +603,23 @@ nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src) nm_ip4_config_get_mtu_source (src)); /* NIS */ - for (i = 0; i < nm_ip4_config_get_num_nis_servers (src); i++) - nm_ip4_config_add_nis_server (dst, nm_ip4_config_get_nis_server (src, i)); + if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_DNS)) { + for (i = 0; i < nm_ip4_config_get_num_nis_servers (src); i++) + nm_ip4_config_add_nis_server (dst, nm_ip4_config_get_nis_server (src, i)); - if (nm_ip4_config_get_nis_domain (src)) - nm_ip4_config_set_nis_domain (dst, nm_ip4_config_get_nis_domain (src)); + if (nm_ip4_config_get_nis_domain (src)) + nm_ip4_config_set_nis_domain (dst, nm_ip4_config_get_nis_domain (src)); + } /* WINS */ - for (i = 0; i < nm_ip4_config_get_num_wins (src); i++) - nm_ip4_config_add_wins (dst, nm_ip4_config_get_wins (src, i)); + if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_DNS)) { + for (i = 0; i < nm_ip4_config_get_num_wins (src); i++) + nm_ip4_config_add_wins (dst, nm_ip4_config_get_wins (src, i)); + } + + /* metered flag */ + nm_ip4_config_set_metered (dst, nm_ip4_config_get_metered (dst) || + nm_ip4_config_get_metered (src)); g_object_thaw_notify (G_OBJECT (dst)); } @@ -721,11 +768,14 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src) } /* default gateway */ - if (nm_ip4_config_get_gateway (src) == nm_ip4_config_get_gateway (dst)) - nm_ip4_config_set_gateway (dst, 0); + if ( (nm_ip4_config_has_gateway (src) == nm_ip4_config_has_gateway (dst)) + && (nm_ip4_config_get_gateway (src) == nm_ip4_config_get_gateway (dst))) + nm_ip4_config_unset_gateway (dst); if (!nm_ip4_config_get_num_addresses (dst)) - nm_ip4_config_set_gateway (dst, 0); + nm_ip4_config_unset_gateway (dst); + + /* ignore route_metric */ /* routes */ for (i = 0; i < nm_ip4_config_get_num_routes (src); i++) { @@ -796,12 +846,15 @@ nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src) i++; } + /* ignore route_metric */ /* ignore nameservers */ /* default gateway */ if ( !nm_ip4_config_get_num_addresses (dst) - || (nm_ip4_config_get_gateway (src) != nm_ip4_config_get_gateway (dst))) - nm_ip4_config_set_gateway (dst, 0); + || (nm_ip4_config_has_gateway (src) != nm_ip4_config_has_gateway (dst)) + || (nm_ip4_config_get_gateway (src) != nm_ip4_config_get_gateway (dst))) { + nm_ip4_config_unset_gateway (dst); + } /* routes */ for (i = 0; i < nm_ip4_config_get_num_routes (dst); ) { @@ -867,11 +920,17 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev } /* default gateway */ - if (src_priv->gateway != dst_priv->gateway) { + if ( src_priv->gateway != dst_priv->gateway + || src_priv->has_gateway != dst_priv->has_gateway) { nm_ip4_config_set_gateway (dst, src_priv->gateway); has_relevant_changes = TRUE; } + if (src_priv->route_metric != dst_priv->route_metric) { + dst_priv->route_metric = src_priv->route_metric; + has_minor_changes = TRUE; + } + /* addresses */ num = nm_ip4_config_get_num_addresses (src); are_equal = num == nm_ip4_config_get_num_addresses (dst); @@ -1028,6 +1087,12 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev has_minor_changes = TRUE; } + /* metered */ + if (src_priv->metered != dst_priv->metered) { + dst_priv->metered = src_priv->metered; + has_minor_changes = TRUE; + } + /* config_equal does not compare *all* the fields, therefore, we might have has_minor_changes * regardless of config_equal. But config_equal must correspond to has_relevant_changes. */ g_assert (config_equal == !has_relevant_changes); @@ -1059,8 +1124,10 @@ nm_ip4_config_dump (const NMIP4Config *config, const char *detail) g_message (" a: %s", nm_platform_ip4_address_to_string (nm_ip4_config_get_address (config, i))); /* default gateway */ - tmp = nm_ip4_config_get_gateway (config); - g_message (" gw: %s", nm_utils_inet4_ntop (tmp, NULL)); + if (nm_ip4_config_has_gateway (config)) { + tmp = nm_ip4_config_get_gateway (config); + g_message (" gw: %s", nm_utils_inet4_ntop (tmp, NULL)); + } /* nameservers */ for (i = 0; i < nm_ip4_config_get_num_nameservers (config); i++) { @@ -1098,6 +1165,7 @@ nm_ip4_config_dump (const NMIP4Config *config, const char *detail) } g_message (" n-dflt: %d", nm_ip4_config_get_never_default (config)); + g_message (" mtrd: %d", (int) nm_ip4_config_get_metered (config)); } gboolean @@ -1139,12 +1207,33 @@ nm_ip4_config_set_gateway (NMIP4Config *config, guint32 gateway) { NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - if (priv->gateway != gateway) { + if (priv->gateway != gateway || !priv->has_gateway) { priv->gateway = gateway; + priv->has_gateway = TRUE; _NOTIFY (config, PROP_GATEWAY); } } +void +nm_ip4_config_unset_gateway (NMIP4Config *config) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + + if (priv->has_gateway) { + priv->gateway = 0; + priv->has_gateway = FALSE; + _NOTIFY (config, PROP_GATEWAY); + } +} + +gboolean +nm_ip4_config_has_gateway (const NMIP4Config *config) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + + return priv->has_gateway; +} + guint32 nm_ip4_config_get_gateway (const NMIP4Config *config) { @@ -1153,6 +1242,14 @@ nm_ip4_config_get_gateway (const NMIP4Config *config) return priv->gateway; } +gint64 +nm_ip4_config_get_route_metric (const NMIP4Config *config) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + + return priv->route_metric; +} + /******************************************************************/ void @@ -1744,6 +1841,24 @@ nm_ip4_config_get_mtu_source (const NMIP4Config *config) /******************************************************************/ +void +nm_ip4_config_set_metered (NMIP4Config *config, gboolean metered) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + + priv->metered = !!metered; +} + +gboolean +nm_ip4_config_get_metered (const NMIP4Config *config) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + + return priv->metered; +} + +/******************************************************************/ + static inline void hash_u32 (GChecksum *sum, guint32 n) { @@ -1760,6 +1875,7 @@ nm_ip4_config_hash (const NMIP4Config *config, GChecksum *sum, gboolean dns_only g_return_if_fail (sum); if (!dns_only) { + hash_u32 (sum, nm_ip4_config_has_gateway (config)); hash_u32 (sum, nm_ip4_config_get_gateway (config)); for (i = 0; i < nm_ip4_config_get_num_addresses (config); i++) { @@ -1856,6 +1972,7 @@ nm_ip4_config_init (NMIP4Config *config) priv->searches = g_ptr_array_new_with_free_func (g_free); priv->nis = g_array_new (FALSE, TRUE, sizeof (guint32)); priv->wins = g_array_new (FALSE, TRUE, sizeof (guint32)); + priv->route_metric = -1; } static void @@ -2020,7 +2137,7 @@ get_property (GObject *object, guint prop_id, } break; case PROP_GATEWAY: - if (priv->gateway) + if (priv->has_gateway) g_value_set_string (value, nm_utils_inet4_ntop (priv->gateway, NULL)); else g_value_set_string (value, NULL); |