diff options
author | Thomas Haller <thaller@redhat.com> | 2015-01-24 18:18:16 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2015-01-24 18:27:35 +0100 |
commit | 0c136c1e2cee1e8ec00d18f071562cc846a766a5 (patch) | |
tree | 9b3783d729e97b8cb9bda518907130923a18b175 | |
parent | 091daaa60ed940e0bc303e8bdfc8811ceb998941 (diff) | |
parent | da708059dabb2854d11eed1a403398327b31535b (diff) | |
download | NetworkManager-0c136c1e2cee1e8ec00d18f071562cc846a766a5.tar.gz |
core: merge branch 'th/bgo740443_device_ip_changes'
This branch brings three major changes:
- when routes or addresses are removed externally,
remove those entiries also from what we want to configure
on the interface. That way, on the next commit, we will
not re-add those externally removed entries.
-- at least not unless the entries reappear due to an
event such as a new DHCP lease.
- the combined NMIPConfig object of a device which is also
exposed via DBUS, will no longer contain those externally
removed entries. The IP config really shows what is actually
configured.
- for default-routes, no longer enforce the default route even
on managed devices. Only during commit phases, we might re-add/
remove a default route from a device, otherwise, pickup the
default route (or its absence) as actually configured.
https://bugzilla.gnome.org/show_bug.cgi?id=740443
-rw-r--r-- | src/devices/nm-device.c | 373 | ||||
-rw-r--r-- | src/nm-default-route-manager.c | 6 | ||||
-rw-r--r-- | src/nm-ip4-config.c | 284 | ||||
-rw-r--r-- | src/nm-ip4-config.h | 1 | ||||
-rw-r--r-- | src/nm-ip6-config.c | 217 | ||||
-rw-r--r-- | src/nm-ip6-config.h | 1 |
6 files changed, 627 insertions, 255 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 607ff3785f..caed116f51 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -239,9 +239,9 @@ typedef struct { /* IP4 configuration info */ NMIP4Config * ip4_config; /* Combined config from VPN, settings, and device */ IpState ip4_state; + NMIP4Config * con_ip4_config; /* config from the setting */ NMIP4Config * dev_ip4_config; /* Config from DHCP, PPP, LLv4, etc */ NMIP4Config * ext_ip4_config; /* Stuff added outside NM */ - gboolean ext_ip4_config_had_any_addresses; NMIP4Config * wwan_ip4_config; /* WWAN configuration */ struct { gboolean v4_has; @@ -276,10 +276,10 @@ typedef struct { /* IP6 configuration info */ NMIP6Config * ip6_config; IpState ip6_state; + NMIP6Config * con_ip6_config; /* config from the setting */ NMIP6Config * vpn6_config; /* routes added by a VPN which uses this device */ NMIP6Config * wwan_ip6_config; NMIP6Config * ext_ip6_config; /* Stuff added outside NM */ - gboolean ext_ip6_config_had_any_addresses; gboolean nm_ipv6ll; /* TRUE if NM handles the device's IPv6LL address */ NMRDisc * rdisc; @@ -2836,6 +2836,43 @@ _device_get_default_route_from_platform (NMDevice *self, int addr_family, NMPlat } /*********************************************/ + +static void +ensure_con_ipx_config (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMConnection *connection; + + g_assert (!!priv->con_ip4_config == !!priv->con_ip6_config); + + if (priv->con_ip4_config) + return; + + connection = nm_device_get_connection (self); + if (!connection) + return; + + priv->con_ip4_config = nm_ip4_config_new (); + priv->con_ip6_config = nm_ip6_config_new (); + + nm_ip4_config_merge_setting (priv->con_ip4_config, + nm_connection_get_setting_ip4_config (connection), + nm_device_get_ip4_route_metric (self)); + nm_ip6_config_merge_setting (priv->con_ip6_config, + nm_connection_get_setting_ip6_config (connection), + nm_device_get_ip6_route_metric (self)); + + if (nm_device_uses_assumed_connection (self)) { + /* For assumed connections ignore all addresses and routes. */ + nm_ip4_config_reset_addresses (priv->con_ip4_config); + nm_ip4_config_reset_routes (priv->con_ip4_config); + + nm_ip6_config_reset_addresses (priv->con_ip6_config); + nm_ip6_config_reset_routes (priv->con_ip6_config); + } +} + +/*********************************************/ /* DHCPv4 stuff */ static void @@ -2874,7 +2911,9 @@ ip4_config_merge_and_apply (NMDevice *self, NMConnection *connection; gboolean success; NMIP4Config *composite; + gboolean has_direct_route; const guint32 default_route_metric = nm_device_get_ip4_route_metric (self); + guint32 gateway; /* Merge all the configs into the composite config */ if (config) { @@ -2883,6 +2922,9 @@ ip4_config_merge_and_apply (NMDevice *self, } composite = nm_ip4_config_new (); + + ensure_con_ipx_config (self); + if (priv->dev_ip4_config) nm_ip4_config_merge (composite, priv->dev_ip4_config); if (priv->vpn4_config) @@ -2896,73 +2938,87 @@ ip4_config_merge_and_apply (NMDevice *self, if (priv->wwan_ip4_config) nm_ip4_config_merge (composite, priv->wwan_ip4_config); - /* Merge user overrides into the composite config. Generated+assumed - * connections come from the system not the user and merging them would - * be redundant, so don't bother. - */ + /* Merge user overrides into the composite config. For assumed connection, + * con_ip4_config is empty. */ + if (priv->con_ip4_config) + nm_ip4_config_merge (composite, priv->con_ip4_config); + connection = nm_device_get_connection (self); + + /* Add the default route. + * + * We keep track of the default route of a device in a private field. + * NMDevice needs to know the default route at this point, because the gateway + * might require a direct route (see below). + * + * But also, we don't want to add the default route to priv->ip4_config, + * because the default route from the setting might not be the same that + * NMDefaultRouteManager eventually configures (because the it might + * tweak the effective metric). + */ + + /* unless we come to a different conclusion below, we have no default route and + * the route is assumed. */ priv->default_route.v4_has = FALSE; priv->default_route.v4_is_assumed = TRUE; - if (connection) { - gboolean assumed = nm_device_uses_assumed_connection (self); - NMPlatformIP4Route *route = &priv->default_route.v4; - if (!nm_settings_connection_get_nm_generated_assumed (NM_SETTINGS_CONNECTION (connection))) { - nm_ip4_config_merge_setting (composite, - nm_connection_get_setting_ip4_config (connection), - default_route_metric); - } + if (!commit) { + /* during a non-commit event, we always pickup whatever is configured. */ + goto END_ADD_DEFAULT_ROUTE; + } + + if (nm_device_uses_assumed_connection (self)) + goto END_ADD_DEFAULT_ROUTE; + + + /* we are about to commit (for a non-assumed connection). Enforce whatever we have + * configured. */ + priv->default_route.v4_is_assumed = FALSE; + + if ( !connection + || !nm_default_route_manager_ip4_connection_has_default_route (nm_default_route_manager_get (), connection)) + goto END_ADD_DEFAULT_ROUTE; + + if (!nm_ip4_config_get_num_addresses (composite)) { + /* without addresses we can have no default route. */ + goto END_ADD_DEFAULT_ROUTE; + } + + gateway = nm_ip4_config_get_gateway (composite); + if ( !gateway + && nm_device_get_device_type (self) != NM_DEVICE_TYPE_MODEM) + goto END_ADD_DEFAULT_ROUTE; + + has_direct_route = ( gateway == 0 + || nm_ip4_config_get_subnet_for_host (composite, gateway) + || nm_ip4_config_get_direct_route_for_host (composite, gateway)); + + priv->default_route.v4_has = TRUE; + memset (&priv->default_route.v4, 0, sizeof (priv->default_route.v4)); + priv->default_route.v4.source = NM_IP_CONFIG_SOURCE_USER; + priv->default_route.v4.gateway = gateway; + priv->default_route.v4.metric = default_route_metric; + priv->default_route.v4.mss = nm_ip4_config_get_mss (composite); + + if (!has_direct_route) { + NMPlatformIP4Route r = priv->default_route.v4; + + /* add a direct route to the gateway */ + r.network = gateway; + r.plen = 32; + r.gateway = 0; + nm_ip4_config_add_route (composite, &r); + } + +END_ADD_DEFAULT_ROUTE: - /* Add the default route. - * - * We keep track of the default route of a device in a private field. - * NMDevice needs to know the default route at this point, because the gateway - * might require a direct route (see below). - * - * But also, we don't want to add the default route to priv->ip4_config, - * because the default route from the setting might not be the same that - * NMDefaultRouteManager eventually configures (because the it might - * tweak the effective metric). + if (priv->default_route.v4_is_assumed) { + /* If above does not explicitly assign a default route, we always pick up the + * default route based on what is currently configured. + * That means that even managed connections with never-default, can + * get a default route (if configured externally). */ - if ( !assumed - && nm_default_route_manager_ip4_connection_has_default_route (nm_default_route_manager_get (), connection)) { - guint32 gateway = 0; - - priv->default_route.v4_is_assumed = FALSE; - if ( (!commit && priv->ext_ip4_config_had_any_addresses) - || ( commit && nm_ip4_config_get_num_addresses (composite))) { - /* For managed interfaces, we can only configure a gateway, if either the external config indicates - * that we already have addresses, or if we are about to commit any addresses. - * Otherwise adding a default route will fail, because NMDefaultRouteManager does not add any - * addresses for the route. */ - gateway = nm_ip4_config_get_gateway (composite); - if ( gateway - || nm_device_get_device_type (self) == NM_DEVICE_TYPE_MODEM) { - memset (route, 0, sizeof (*route)); - route->source = NM_IP_CONFIG_SOURCE_USER; - route->gateway = gateway; - route->metric = default_route_metric; - route->mss = nm_ip4_config_get_mss (composite); - priv->default_route.v4_has = TRUE; - - if ( gateway - && !nm_ip4_config_get_subnet_for_host (composite, gateway) - && !nm_ip4_config_get_direct_route_for_host (composite, gateway)) { - /* add a direct route to the gateway */ - NMPlatformIP4Route r = *route; - - r.network = gateway; - r.plen = 32; - r.gateway = 0; - nm_ip4_config_add_route (composite, &r); - } - } - } - } else { - /* For interfaces that are assumed and that have no default-route by configuration, we assume - * the default connection and pick up whatever is configured. */ - priv->default_route.v4_has = _device_get_default_route_from_platform (self, AF_INET, (NMPlatformIPRoute *) route); - } + priv->default_route.v4_has = _device_get_default_route_from_platform (self, AF_INET, (NMPlatformIPRoute *) &priv->default_route.v4); } /* Allow setting MTU etc */ @@ -3438,10 +3494,13 @@ ip6_config_merge_and_apply (NMDevice *self, NMConnection *connection; gboolean success; NMIP6Config *composite; + gboolean has_direct_route; + const struct in6_addr *gateway; /* If no config was passed in, create a new one */ composite = nm_ip6_config_new (); - g_assert (composite); + + ensure_con_ipx_config (self); /* Merge all the IP configs into the composite config */ if (priv->ac_ip6_config) @@ -3459,72 +3518,87 @@ ip6_config_merge_and_apply (NMDevice *self, if (priv->wwan_ip6_config) nm_ip6_config_merge (composite, priv->wwan_ip6_config); - /* Merge user overrides into the composite config. Generated+assumed - * connections come from the system not the user and merging them would - * be redundant, so don't bother. - */ + /* Merge user overrides into the composite config. For assumed connections, + * con_ip6_config is empty. */ + if (priv->con_ip6_config) + nm_ip6_config_merge (composite, priv->con_ip6_config); + connection = nm_device_get_connection (self); + + /* Add the default route. + * + * We keep track of the default route of a device in a private field. + * NMDevice needs to know the default route at this point, because the gateway + * might require a direct route (see below). + * + * But also, we don't want to add the default route to priv->ip6_config, + * because the default route from the setting might not be the same that + * NMDefaultRouteManager eventually configures (because the it might + * tweak the effective metric). + */ + + /* unless we come to a different conclusion below, we have no default route and + * the route is assumed. */ priv->default_route.v6_has = FALSE; priv->default_route.v6_is_assumed = TRUE; - if (connection) { - gboolean assumed = nm_device_uses_assumed_connection (self); - NMPlatformIP6Route *route = &priv->default_route.v6; - if (!nm_settings_connection_get_nm_generated_assumed (NM_SETTINGS_CONNECTION (connection))) { - nm_ip6_config_merge_setting (composite, - nm_connection_get_setting_ip6_config (connection), - nm_device_get_ip6_route_metric (self)); - } + if (!commit) { + /* during a non-commit event, we always pickup whatever is configured. */ + goto END_ADD_DEFAULT_ROUTE; + } + + if (nm_device_uses_assumed_connection (self)) + goto END_ADD_DEFAULT_ROUTE; + + + /* we are about to commit (for a non-assumed connection). Enforce whatever we have + * configured. */ + priv->default_route.v6_is_assumed = FALSE; + + if ( !connection + || !nm_default_route_manager_ip6_connection_has_default_route (nm_default_route_manager_get (), connection)) + goto END_ADD_DEFAULT_ROUTE; + + if (!nm_ip6_config_get_num_addresses (composite)) { + /* without addresses we can have no default route. */ + goto END_ADD_DEFAULT_ROUTE; + } + + gateway = nm_ip6_config_get_gateway (composite); + if (!gateway) + goto END_ADD_DEFAULT_ROUTE; + - /* Add the default route. - * - * We keep track of the default route of a device in a private field. - * NMDevice needs to know the default route at this point, because the gateway - * might require a direct route (see below). - * - * But also, we don't want to add the default route to priv->ip4_config, - * because the default route from the setting might not be the same that - * NMDefaultRouteManager eventually configures (because the it might - * tweak the effective metric). + has_direct_route = nm_ip6_config_get_direct_route_for_host (composite, gateway) != NULL; + + + + priv->default_route.v6_has = TRUE; + memset (&priv->default_route.v6, 0, sizeof (priv->default_route.v6)); + priv->default_route.v6.source = NM_IP_CONFIG_SOURCE_USER; + priv->default_route.v6.gateway = *gateway; + priv->default_route.v6.metric = nm_device_get_ip6_route_metric (self); + priv->default_route.v6.mss = nm_ip6_config_get_mss (composite); + + if (!has_direct_route) { + NMPlatformIP6Route r = priv->default_route.v6; + + /* add a direct route to the gateway */ + r.network = *gateway; + r.plen = 128; + r.gateway = in6addr_any; + nm_ip6_config_add_route (composite, &r); + } + +END_ADD_DEFAULT_ROUTE: + + if (priv->default_route.v6_is_assumed) { + /* If above does not explicitly assign a default route, we always pick up the + * default route based on what is currently configured. + * That means that even managed connections with never-default, can + * get a default route (if configured externally). */ - if ( !assumed - && nm_default_route_manager_ip6_connection_has_default_route (nm_default_route_manager_get (), connection)) { - const struct in6_addr *gateway = NULL; - - priv->default_route.v6_is_assumed = FALSE; - if ( (!commit && priv->ext_ip6_config_had_any_addresses) - || ( commit && nm_ip6_config_get_num_addresses (composite))) { - /* For managed interfaces, we can only configure a gateway, if either the external config indicates - * that we already have addresses, or if we are about to commit any addresses. - * Otherwise adding a default route will fail, because NMDefaultRouteManager does not add any - * addresses for the route. */ - gateway = nm_ip6_config_get_gateway (composite); - if (gateway) { - memset (route, 0, sizeof (*route)); - route->source = NM_IP_CONFIG_SOURCE_USER; - route->gateway = *gateway; - route->metric = nm_device_get_ip6_route_metric (self); - route->mss = nm_ip6_config_get_mss (composite); - priv->default_route.v6_has = TRUE; - - if ( gateway - && !nm_ip6_config_get_subnet_for_host (composite, gateway) - && !nm_ip6_config_get_direct_route_for_host (composite, gateway)) { - /* add a direct route to the gateway */ - NMPlatformIP6Route r = *route; - - r.network = *gateway; - r.plen = 128; - r.gateway = in6addr_any; - nm_ip6_config_add_route (composite, &r); - } - } - } - } else { - /* For interfaces that are assumed and that have no default-route by configuration, we assume - * the default connection and pick up whatever is configured. */ - priv->default_route.v6_has = _device_get_default_route_from_platform (self, AF_INET6, (NMPlatformIPRoute *) route); - } + priv->default_route.v6_has = _device_get_default_route_from_platform (self, AF_INET6, (NMPlatformIPRoute *) &priv->default_route.v6); } nm_ip6_config_addresses_sort (composite, @@ -6498,13 +6572,31 @@ update_ip_config (NMDevice *self, gboolean initial) /* IPv4 */ g_clear_object (&priv->ext_ip4_config); priv->ext_ip4_config = nm_ip4_config_capture (ifindex, capture_resolv_conf); - priv->ext_ip4_config_had_any_addresses = ( priv->ext_ip4_config - && nm_ip4_config_get_num_addresses (priv->ext_ip4_config) > 0); if (priv->ext_ip4_config) { if (initial) { g_clear_object (&priv->dev_ip4_config); capture_lease_config (self, priv->ext_ip4_config, &priv->dev_ip4_config, NULL, NULL); } + ensure_con_ipx_config (self); + + /* This function was called upon external changes. Remove the configuration + * (adresses,routes) that is no longer present externally from the interal + * config. This way, we don't readd addresses that were manually removed + * by the user. */ + if (priv->con_ip4_config) + nm_ip4_config_intersect (priv->con_ip4_config, priv->ext_ip4_config); + if (priv->dev_ip4_config) + nm_ip4_config_intersect (priv->dev_ip4_config, priv->ext_ip4_config); + if (priv->vpn4_config) + nm_ip4_config_intersect (priv->vpn4_config, priv->ext_ip4_config); + if (priv->wwan_ip4_config) + nm_ip4_config_intersect (priv->wwan_ip4_config, priv->ext_ip4_config); + + /* Remove parts from ext_ip4_config to only contain the information that + * was configured externally -- we already have the same configuration from + * internal origins. */ + if (priv->con_ip4_config) + nm_ip4_config_subtract (priv->ext_ip4_config, priv->con_ip4_config); if (priv->dev_ip4_config) nm_ip4_config_subtract (priv->ext_ip4_config, priv->dev_ip4_config); if (priv->vpn4_config) @@ -6518,14 +6610,34 @@ update_ip_config (NMDevice *self, gboolean initial) /* IPv6 */ g_clear_object (&priv->ext_ip6_config); priv->ext_ip6_config = nm_ip6_config_capture (ifindex, capture_resolv_conf, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - priv->ext_ip6_config_had_any_addresses = ( priv->ext_ip6_config - && nm_ip6_config_get_num_addresses (priv->ext_ip6_config) > 0); if (priv->ext_ip6_config) { /* Check this before modifying ext_ip6_config */ linklocal6_just_completed = priv->linklocal6_timeout_id && have_ip6_address (priv->ext_ip6_config, TRUE); + ensure_con_ipx_config (self); + + /* This function was called upon external changes. Remove the configuration + * (adresses,routes) that is no longer present externally from the interal + * config. This way, we don't readd addresses that were manually removed + * by the user. */ + if (priv->con_ip6_config) + nm_ip6_config_intersect (priv->con_ip6_config, priv->ext_ip6_config); + if (priv->ac_ip6_config) + nm_ip6_config_intersect (priv->ac_ip6_config, priv->ext_ip6_config); + if (priv->dhcp6_ip6_config) + nm_ip6_config_intersect (priv->dhcp6_ip6_config, priv->ext_ip6_config); + if (priv->wwan_ip6_config) + nm_ip6_config_intersect (priv->wwan_ip6_config, priv->ext_ip6_config); + if (priv->vpn6_config) + nm_ip6_config_intersect (priv->vpn6_config, priv->ext_ip6_config); + + /* Remove parts from ext_ip6_config to only contain the information that + * was configured externally -- we already have the same configuration from + * internal origins. */ + if (priv->con_ip6_config) + nm_ip6_config_subtract (priv->ext_ip6_config, priv->con_ip6_config); if (priv->ac_ip6_config) nm_ip6_config_subtract (priv->ext_ip6_config, priv->ac_ip6_config); if (priv->dhcp6_ip6_config) @@ -7117,20 +7229,19 @@ _cleanup_generic_post (NMDevice *self, gboolean deconfigure) */ nm_device_set_ip4_config (self, NULL, 0, TRUE, &ignored); nm_device_set_ip6_config (self, NULL, TRUE, &ignored); + g_clear_object (&priv->con_ip4_config); g_clear_object (&priv->dev_ip4_config); g_clear_object (&priv->ext_ip4_config); g_clear_object (&priv->wwan_ip4_config); g_clear_object (&priv->vpn4_config); g_clear_object (&priv->ip4_config); + g_clear_object (&priv->con_ip6_config); g_clear_object (&priv->ac_ip6_config); g_clear_object (&priv->ext_ip6_config); g_clear_object (&priv->vpn6_config); g_clear_object (&priv->wwan_ip6_config); g_clear_object (&priv->ip6_config); - priv->ext_ip4_config_had_any_addresses = FALSE; - priv->ext_ip6_config_had_any_addresses = FALSE; - clear_act_request (self); /* Clear legacy IPv4 address property */ diff --git a/src/nm-default-route-manager.c b/src/nm-default-route-manager.c index c09341a5e3..1ab7fdc63b 100644 --- a/src/nm-default-route-manager.c +++ b/src/nm-default-route-manager.c @@ -76,14 +76,14 @@ NM_DEFINE_SINGLETON_GETTER (NMDefaultRouteManager, nm_default_route_manager_get, #define _LOGW(addr_family, ...) _LOG (LOGL_WARN , addr_family, __VA_ARGS__) #define _LOGE(addr_family, ...) _LOG (LOGL_ERR , addr_family, __VA_ARGS__) -#define LOG_ENTRY_FMT "entry[%u/%s:%p:%s:%c%c]" +#define LOG_ENTRY_FMT "entry[%u/%s:%p:%s:%c:%csync]" #define LOG_ENTRY_ARGS(entry_idx, entry) \ (entry_idx), \ NM_IS_DEVICE ((entry)->source.pointer) ? "dev" : "vpn", \ (entry)->source.pointer, \ NM_IS_DEVICE ((entry)->source.pointer) ? nm_device_get_iface ((entry)->source.device) : nm_vpn_connection_get_connection_id ((entry)->source.vpn), \ - ((entry)->never_default ? 'N' : 'n'), \ - ((entry)->synced ? 'S' : 's') + ((entry)->never_default ? '0' : '1'), \ + ((entry)->synced ? '+' : '-') /***********************************************************************************/ diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index fd46678026..97ca718a5e 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -541,6 +541,117 @@ nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src) g_object_thaw_notify (G_OBJECT (dst)); } +/*******************************************************************************/ + +static int +_addresses_get_index (const NMIP4Config *self, const NMPlatformIP4Address *addr) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->addresses->len; i++) { + const NMPlatformIP4Address *a = &g_array_index (priv->addresses, NMPlatformIP4Address, i); + + if (addr->address == a->address && + addr->plen == a->plen) + return (int) i; + } + return -1; +} + +static int +_nameservers_get_index (const NMIP4Config *self, guint32 ns) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->nameservers->len; i++) { + guint32 n = g_array_index (priv->nameservers, guint32, i); + + if (ns == n) + return (int) i; + } + return -1; +} + +static int +_routes_get_index (const NMIP4Config *self, const NMPlatformIP4Route *route) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->routes->len; i++) { + const NMPlatformIP4Route *r = &g_array_index (priv->routes, NMPlatformIP4Route, i); + + if ( route->network == r->network + && route->plen == r->plen) + return (int) i; + } + return -1; +} + +static int +_domains_get_index (const NMIP4Config *self, const char *domain) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->domains->len; i++) { + const char *d = g_ptr_array_index (priv->domains, i); + + if (g_strcmp0 (domain, d) == 0) + return (int) i; + } + return -1; +} + +static int +_searches_get_index (const NMIP4Config *self, const char *search) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->searches->len; i++) { + const char *s = g_ptr_array_index (priv->searches, i); + + if (g_strcmp0 (search, s) == 0) + return (int) i; + } + return -1; +} + +static int +_nis_servers_get_index (const NMIP4Config *self, guint32 nis_server) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->nis->len; i++) { + guint32 n = g_array_index (priv->nis, guint32, i); + + if (n == nis_server) + return (int) i; + } + return -1; +} + +static int +_wins_get_index (const NMIP4Config *self, guint32 wins_server) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->wins->len; i++) { + guint32 n = g_array_index (priv->wins, guint32, i); + + if (n == wins_server) + return (int) i; + } + return -1; +} + +/*******************************************************************************/ + /** * nm_ip4_config_subtract: * @dst: config from which to remove everything in @src @@ -551,7 +662,8 @@ nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src) void nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src) { - guint32 i, j; + guint32 i; + gint idx; g_return_if_fail (src != NULL); g_return_if_fail (dst != NULL); @@ -560,31 +672,16 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src) /* addresses */ for (i = 0; i < nm_ip4_config_get_num_addresses (src); i++) { - const NMPlatformIP4Address *src_addr = nm_ip4_config_get_address (src, i); - - for (j = 0; j < nm_ip4_config_get_num_addresses (dst); j++) { - const NMPlatformIP4Address *dst_addr = nm_ip4_config_get_address (dst, j); - - if (src_addr->address == dst_addr->address && - src_addr->plen == dst_addr->plen) { - nm_ip4_config_del_address (dst, j); - break; - } - } + idx = _addresses_get_index (dst, nm_ip4_config_get_address (src, i)); + if (idx >= 0) + nm_ip4_config_del_address (dst, idx); } /* nameservers */ for (i = 0; i < nm_ip4_config_get_num_nameservers (src); i++) { - guint32 src_ns = nm_ip4_config_get_nameserver (src, i); - - for (j = 0; j < nm_ip4_config_get_num_nameservers (dst); j++) { - guint32 dst_ns = nm_ip4_config_get_nameserver (dst, j); - - if (dst_ns == src_ns) { - nm_ip4_config_del_nameserver (dst, j); - break; - } - } + idx = _nameservers_get_index (dst, nm_ip4_config_get_nameserver (src, i)); + if (idx >= 0) + nm_ip4_config_del_nameserver (dst, idx); } /* default gateway */ @@ -596,44 +693,23 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src) /* routes */ for (i = 0; i < nm_ip4_config_get_num_routes (src); i++) { - const NMPlatformIP4Route *src_route = nm_ip4_config_get_route (src, i); - - for (j = 0; j < nm_ip4_config_get_num_routes (dst); j++) { - const NMPlatformIP4Route *dst_route = nm_ip4_config_get_route (dst, j); - - if (src_route->network == dst_route->network && src_route->plen == dst_route->plen) { - nm_ip4_config_del_route (dst, j); - break; - } - } + idx = _routes_get_index (dst, nm_ip4_config_get_route (src, i)); + if (idx >= 0) + nm_ip4_config_del_route (dst, idx); } /* domains */ for (i = 0; i < nm_ip4_config_get_num_domains (src); i++) { - const char *src_domain = nm_ip4_config_get_domain (src, i); - - for (j = 0; j < nm_ip4_config_get_num_domains (dst); j++) { - const char *dst_domain = nm_ip4_config_get_domain (dst, j); - - if (g_strcmp0 (src_domain, dst_domain) == 0) { - nm_ip4_config_del_domain (dst, j); - break; - } - } + idx = _domains_get_index (dst, nm_ip4_config_get_domain (src, i)); + if (idx >= 0) + nm_ip4_config_del_domain (dst, idx); } /* dns searches */ for (i = 0; i < nm_ip4_config_get_num_searches (src); i++) { - const char *src_search = nm_ip4_config_get_search (src, i); - - for (j = 0; j < nm_ip4_config_get_num_searches (dst); j++) { - const char *dst_search = nm_ip4_config_get_search (dst, j); - - if (g_strcmp0 (src_search, dst_search) == 0) { - nm_ip4_config_del_search (dst, j); - break; - } - } + idx = _searches_get_index (dst, nm_ip4_config_get_search (src, i)); + if (idx >= 0) + nm_ip4_config_del_search (dst, idx); } /* MSS */ @@ -646,16 +722,9 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src) /* NIS */ for (i = 0; i < nm_ip4_config_get_num_nis_servers (src); i++) { - guint32 src_nis = nm_ip4_config_get_nis_server (src, i); - - for (j = 0; j < nm_ip4_config_get_num_nis_servers (dst); j++) { - guint32 dst_nis = nm_ip4_config_get_nis_server (dst, j); - - if (dst_nis == src_nis) { - nm_ip4_config_del_nis_server (dst, j); - break; - } - } + idx = _nis_servers_get_index (dst, nm_ip4_config_get_nis_server (src, i)); + if (idx >= 0) + nm_ip4_config_del_nis_server (dst, idx); } if (g_strcmp0 (nm_ip4_config_get_nis_domain (src), nm_ip4_config_get_nis_domain (dst)) == 0) @@ -663,16 +732,91 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src) /* WINS */ for (i = 0; i < nm_ip4_config_get_num_wins (src); i++) { - guint32 src_wins = nm_ip4_config_get_wins (src, i); + idx = _wins_get_index (dst, nm_ip4_config_get_wins (src, i)); + if (idx >= 0) + nm_ip4_config_del_wins (dst, idx); + } - for (j = 0; j < nm_ip4_config_get_num_wins (dst); j++) { - guint32 dst_wins = nm_ip4_config_get_wins (dst, j); + g_object_thaw_notify (G_OBJECT (dst)); +} - if (dst_wins == src_wins) { - nm_ip4_config_del_wins (dst, j); - break; - } - } +void +nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src) +{ + guint32 i; + gint idx; + + g_return_if_fail (src != NULL); + g_return_if_fail (dst != NULL); + + g_object_freeze_notify (G_OBJECT (dst)); + + /* addresses */ + for (i = 0; i < nm_ip4_config_get_num_addresses (dst); ) { + idx = _addresses_get_index (src, nm_ip4_config_get_address (dst, i)); + if (idx < 0) + nm_ip4_config_del_address (dst, i); + else + i++; + } + + /* nameservers */ + for (i = 0; i < nm_ip4_config_get_num_nameservers (dst); ) { + idx = _nameservers_get_index (src, nm_ip4_config_get_nameserver (dst, i)); + if (idx < 0) + nm_ip4_config_del_nameserver (dst, i); + else + i++; + } + + /* 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); + + /* routes */ + for (i = 0; i < nm_ip4_config_get_num_routes (dst); ) { + idx = _routes_get_index (src, nm_ip4_config_get_route (dst, i)); + if (idx < 0) + nm_ip4_config_del_route (dst, i); + else + i++; + } + + /* domains */ + for (i = 0; i < nm_ip4_config_get_num_domains (dst); ) { + idx = _domains_get_index (src, nm_ip4_config_get_domain (dst, i)); + if (idx < 0) + nm_ip4_config_del_domain (dst, i); + else + i++; + } + + /* dns searches */ + for (i = 0; i < nm_ip4_config_get_num_searches (dst); ) { + idx = _searches_get_index (src, nm_ip4_config_get_search (dst, i)); + if (idx < 0) + nm_ip4_config_del_search (dst, i); + else + i++; + } + + /* NIS */ + for (i = 0; i < nm_ip4_config_get_num_nis_servers (dst); ) { + idx = _nis_servers_get_index (src, nm_ip4_config_get_nis_server (dst, i)); + if (idx < 0) + nm_ip4_config_del_nis_server (dst, i); + else + i++; + } + + /* WINS */ + for (i = 0; i < nm_ip4_config_get_num_wins (dst); ) { + idx = _wins_get_index (src, nm_ip4_config_get_wins (dst, i)); + if (idx < 0) + nm_ip4_config_del_wins (dst, i); + else + i++; } g_object_thaw_notify (G_OBJECT (dst)); diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index 5ac455d84f..2b3b24e6af 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -71,6 +71,7 @@ NMSetting *nm_ip4_config_create_setting (const NMIP4Config *config); /* Utility functions */ void nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src); void nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src); +void nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src); gboolean nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relevant_changes); gboolean nm_ip4_config_destination_is_direct (const NMIP4Config *config, guint32 dest, int plen); void nm_ip4_config_dump (const NMIP4Config *config, const char *detail); diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index db64e72618..a148d826e6 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -653,6 +653,85 @@ nm_ip6_config_destination_is_direct (const NMIP6Config *config, const struct in6 return FALSE; } +/*******************************************************************************/ + +static int +_addresses_get_index (const NMIP6Config *self, const NMPlatformIP6Address *addr) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->addresses->len; i++) { + const NMPlatformIP6Address *a = &g_array_index (priv->addresses, NMPlatformIP6Address, i); + + if (IN6_ARE_ADDR_EQUAL (&addr->address, &a->address)) + return (int) i; + } + return -1; +} + +static int +_nameservers_get_index (const NMIP6Config *self, const struct in6_addr *ns) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->nameservers->len; i++) { + const struct in6_addr *n = &g_array_index (priv->nameservers, struct in6_addr, i); + + if (IN6_ARE_ADDR_EQUAL (ns, n)) + return (int) i; + } + return -1; +} + +static int +_routes_get_index (const NMIP6Config *self, const NMPlatformIP6Route *route) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->routes->len; i++) { + const NMPlatformIP6Route *r = &g_array_index (priv->routes, NMPlatformIP6Route, i); + + if (routes_are_duplicate (route, r, FALSE)) + return (int) i; + } + return -1; +} + +static int +_domains_get_index (const NMIP6Config *self, const char *domain) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->domains->len; i++) { + const char *d = g_ptr_array_index (priv->domains, i); + + if (g_strcmp0 (domain, d) == 0) + return (int) i; + } + return -1; +} + +static int +_searches_get_index (const NMIP6Config *self, const char *search) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->searches->len; i++) { + const char *s = g_ptr_array_index (priv->searches, i); + + if (g_strcmp0 (search, s) == 0) + return (int) i; + } + return -1; +} + +/*******************************************************************************/ + /** * nm_ip6_config_subtract: * @dst: config from which to remove everything in @src @@ -663,7 +742,8 @@ nm_ip6_config_destination_is_direct (const NMIP6Config *config, const struct in6 void nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src) { - guint32 i, j; + guint i; + gint idx; const struct in6_addr *dst_tmp, *src_tmp; g_return_if_fail (src != NULL); @@ -673,30 +753,16 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src) /* addresses */ for (i = 0; i < nm_ip6_config_get_num_addresses (src); i++) { - const NMPlatformIP6Address *src_addr = nm_ip6_config_get_address (src, i); - - for (j = 0; j < nm_ip6_config_get_num_addresses (dst); j++) { - const NMPlatformIP6Address *dst_addr = nm_ip6_config_get_address (dst, j); - - if (IN6_ARE_ADDR_EQUAL (&src_addr->address, &dst_addr->address)) { - nm_ip6_config_del_address (dst, j); - break; - } - } + idx = _addresses_get_index (dst, nm_ip6_config_get_address (src, i)); + if (idx >= 0) + nm_ip6_config_del_address (dst, idx); } /* nameservers */ for (i = 0; i < nm_ip6_config_get_num_nameservers (src); i++) { - const struct in6_addr *src_ns = nm_ip6_config_get_nameserver (src, i); - - for (j = 0; j < nm_ip6_config_get_num_nameservers (dst); j++) { - const struct in6_addr *dst_ns = nm_ip6_config_get_nameserver (dst, j); - - if (IN6_ARE_ADDR_EQUAL (src_ns, dst_ns)) { - nm_ip6_config_del_nameserver (dst, j); - break; - } - } + idx = _nameservers_get_index (dst, nm_ip6_config_get_nameserver (src, i)); + if (idx >= 0) + nm_ip6_config_del_nameserver (dst, idx); } /* default gateway */ @@ -710,44 +776,23 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src) /* routes */ for (i = 0; i < nm_ip6_config_get_num_routes (src); i++) { - const NMPlatformIP6Route *src_route = nm_ip6_config_get_route (src, i); - - for (j = 0; j < nm_ip6_config_get_num_routes (dst); j++) { - const NMPlatformIP6Route *dst_route = nm_ip6_config_get_route (dst, j); - - if (routes_are_duplicate (src_route, dst_route, FALSE)) { - nm_ip6_config_del_route (dst, j); - break; - } - } + idx = _routes_get_index (dst, nm_ip6_config_get_route (src, i)); + if (idx >= 0) + nm_ip6_config_del_route (dst, idx); } /* domains */ for (i = 0; i < nm_ip6_config_get_num_domains (src); i++) { - const char *src_domain = nm_ip6_config_get_domain (src, i); - - for (j = 0; j < nm_ip6_config_get_num_domains (dst); j++) { - const char *dst_domain = nm_ip6_config_get_domain (dst, j); - - if (g_strcmp0 (src_domain, dst_domain) == 0) { - nm_ip6_config_del_domain (dst, j); - break; - } - } + idx = _domains_get_index (dst, nm_ip6_config_get_domain (src, i)); + if (idx >= 0) + nm_ip6_config_del_domain (dst, idx); } /* dns searches */ for (i = 0; i < nm_ip6_config_get_num_searches (src); i++) { - const char *src_search = nm_ip6_config_get_search (src, i); - - for (j = 0; j < nm_ip6_config_get_num_searches (dst); j++) { - const char *dst_search = nm_ip6_config_get_search (dst, j); - - if (g_strcmp0 (src_search, dst_search) == 0) { - nm_ip6_config_del_search (dst, j); - break; - } - } + idx = _searches_get_index (dst, nm_ip6_config_get_search (src, i)); + if (idx >= 0) + nm_ip6_config_del_search (dst, idx); } if (nm_ip6_config_get_mss (src) == nm_ip6_config_get_mss (dst)) @@ -756,6 +801,76 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src) g_object_thaw_notify (G_OBJECT (dst)); } +void +nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src) +{ + guint i; + gint idx; + const struct in6_addr *dst_tmp, *src_tmp; + + g_return_if_fail (src != NULL); + g_return_if_fail (dst != NULL); + + g_object_freeze_notify (G_OBJECT (dst)); + + /* addresses */ + for (i = 0; i < nm_ip6_config_get_num_addresses (dst); ) { + idx = _addresses_get_index (src, nm_ip6_config_get_address (dst, i)); + if (idx < 0) + nm_ip6_config_del_address (dst, i); + else + i++; + } + + /* nameservers */ + for (i = 0; i < nm_ip6_config_get_num_nameservers (dst); ) { + idx = _nameservers_get_index (src, nm_ip6_config_get_nameserver (dst, i)); + if (idx < 0) + nm_ip6_config_del_nameserver (dst, i); + else + i++; + } + + /* default gateway */ + dst_tmp = nm_ip6_config_get_gateway (dst); + if (dst_tmp) { + src_tmp = nm_ip6_config_get_gateway (src); + if ( !nm_ip6_config_get_num_addresses (dst) + || !src_tmp + || !IN6_ARE_ADDR_EQUAL (src_tmp, dst_tmp)) + nm_ip6_config_set_gateway (dst, NULL); + } + + /* routes */ + for (i = 0; i < nm_ip6_config_get_num_routes (dst); ) { + idx = _routes_get_index (src, nm_ip6_config_get_route (dst, i)); + if (idx < 0) + nm_ip6_config_del_route (dst, i); + else + i++; + } + + /* domains */ + for (i = 0; i < nm_ip6_config_get_num_domains (src); ) { + idx = _domains_get_index (src, nm_ip6_config_get_domain (dst, i)); + if (idx < 0) + nm_ip6_config_del_domain (dst, i); + else + i++; + } + + /* dns searches */ + for (i = 0; i < nm_ip6_config_get_num_searches (src); i++) { + idx = _searches_get_index (src, nm_ip6_config_get_search (dst, i)); + if (idx < 0) + nm_ip6_config_del_search (dst, i); + else + i++; + } + + g_object_thaw_notify (G_OBJECT (dst)); +} + /** * nm_ip6_config_replace: * @dst: config which will be replaced with everything in @src diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index f1d2dc8dd9..04c9e00341 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -71,6 +71,7 @@ NMSetting *nm_ip6_config_create_setting (const NMIP6Config *config); /* Utility functions */ void nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src); void nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src); +void nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src); gboolean nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relevant_changes); int nm_ip6_config_destination_is_direct (const NMIP6Config *config, const struct in6_addr *dest, int plen); void nm_ip6_config_dump (const NMIP6Config *config, const char *detail); |