device,default-route-manager: merge branch 'th/default-route-resync'

This commit is contained in:
Thomas Haller 2017-03-16 15:58:32 +01:00
commit 6197c27f24
5 changed files with 161 additions and 91 deletions

View file

@ -121,7 +121,7 @@ parent_hwaddr_maybe_changed (NMDevice *parent,
*/
s_ip6 = nm_connection_get_setting_ip6_config (connection);
if (s_ip6)
nm_device_reactivate_ip6_config (NM_DEVICE (self), s_ip6, s_ip6);
nm_device_reactivate_ip6_config (NM_DEVICE (self), s_ip6, s_ip6, FALSE);
}
}

View file

@ -302,6 +302,9 @@ typedef struct _NMDevicePrivate {
bool up:1; /* IFF_UP */
bool v4_commit_first_time:1;
bool v6_commit_first_time:1;
/* Generic DHCP stuff */
guint32 dhcp_timeout;
char * dhcp_anycast_address;
@ -332,9 +335,6 @@ typedef struct _NMDevicePrivate {
NMPlatformIP6Route v6;
} default_route;
bool v4_commit_first_time;
bool v6_commit_first_time;
/* DHCPv4 tracking */
struct {
NMDhcpClient * client;
@ -8418,7 +8418,8 @@ _nm_device_hash_check_invalid_keys (GHashTable *hash, const char *setting_name,
void
nm_device_reactivate_ip4_config (NMDevice *self,
NMSettingIPConfig *s_ip4_old,
NMSettingIPConfig *s_ip4_new)
NMSettingIPConfig *s_ip4_new,
gboolean force_restart)
{
NMDevicePrivate *priv;
const char *method_old, *method_new;
@ -8434,14 +8435,17 @@ nm_device_reactivate_ip4_config (NMDevice *self,
s_ip4_new,
nm_device_get_ip4_route_metric (self));
method_old = s_ip4_old ?
nm_setting_ip_config_get_method (s_ip4_old) :
NM_SETTING_IP4_CONFIG_METHOD_DISABLED;
method_new = s_ip4_new ?
nm_setting_ip_config_get_method (s_ip4_new) :
NM_SETTING_IP4_CONFIG_METHOD_DISABLED;
if (!force_restart) {
method_old = s_ip4_old
? nm_setting_ip_config_get_method (s_ip4_old)
: NM_SETTING_IP4_CONFIG_METHOD_DISABLED;
method_new = s_ip4_new
? nm_setting_ip_config_get_method (s_ip4_new)
: NM_SETTING_IP4_CONFIG_METHOD_DISABLED;
force_restart = !nm_streq0 (method_old, method_new);
}
if (!nm_streq0 (method_old, method_new)) {
if (force_restart) {
_cleanup_ip4_pre (self, CLEANUP_TYPE_DECONFIGURE);
_set_ip_state (self, AF_INET, IP_WAIT);
if (!nm_device_activate_stage3_ip4_start (self))
@ -8456,7 +8460,8 @@ nm_device_reactivate_ip4_config (NMDevice *self,
void
nm_device_reactivate_ip6_config (NMDevice *self,
NMSettingIPConfig *s_ip6_old,
NMSettingIPConfig *s_ip6_new)
NMSettingIPConfig *s_ip6_new,
gboolean force_restart)
{
NMDevicePrivate *priv;
const char *method_old, *method_new;
@ -8472,14 +8477,17 @@ nm_device_reactivate_ip6_config (NMDevice *self,
s_ip6_new,
nm_device_get_ip6_route_metric (self));
method_old = s_ip6_old ?
nm_setting_ip_config_get_method (s_ip6_old) :
NM_SETTING_IP6_CONFIG_METHOD_IGNORE;
method_new = s_ip6_new ?
nm_setting_ip_config_get_method (s_ip6_new) :
NM_SETTING_IP6_CONFIG_METHOD_IGNORE;
if (!force_restart) {
method_old = s_ip6_old
? nm_setting_ip_config_get_method (s_ip6_old)
: NM_SETTING_IP6_CONFIG_METHOD_IGNORE;
method_new = s_ip6_new
? nm_setting_ip_config_get_method (s_ip6_new)
: NM_SETTING_IP6_CONFIG_METHOD_IGNORE;
force_restart = !nm_streq0 (method_old, method_new);
}
if (!nm_streq0 (method_old, method_new)) {
if (force_restart) {
_cleanup_ip6_pre (self, CLEANUP_TYPE_DECONFIGURE);
_set_ip_state (self, AF_INET6, IP_WAIT);
if (!nm_device_activate_stage3_ip6_start (self))
@ -8676,6 +8684,9 @@ check_and_reapply_connection (NMDevice *self,
} else
con_old = con_new = applied;
priv->v4_commit_first_time = TRUE;
priv->v6_commit_first_time = TRUE;
/**************************************************************************
* Reapply changes
*************************************************************************/
@ -8690,8 +8701,8 @@ check_and_reapply_connection (NMDevice *self,
s_ip6_old = nm_connection_get_setting_ip6_config (con_old);
s_ip6_new = nm_connection_get_setting_ip6_config (con_new);
nm_device_reactivate_ip4_config (self, s_ip4_old, s_ip4_new);
nm_device_reactivate_ip6_config (self, s_ip6_old, s_ip6_new);
nm_device_reactivate_ip4_config (self, s_ip4_old, s_ip4_new, TRUE);
nm_device_reactivate_ip6_config (self, s_ip6_old, s_ip6_new, TRUE);
reactivate_proxy_config (self);

View file

@ -657,10 +657,12 @@ void nm_device_update_firewall_zone (NMDevice *self);
void nm_device_update_metered (NMDevice *self);
void nm_device_reactivate_ip4_config (NMDevice *device,
NMSettingIPConfig *s_ip4_old,
NMSettingIPConfig *s_ip4_new);
NMSettingIPConfig *s_ip4_new,
gboolean force_restart);
void nm_device_reactivate_ip6_config (NMDevice *device,
NMSettingIPConfig *s_ip6_old,
NMSettingIPConfig *s_ip6_new);
NMSettingIPConfig *s_ip6_new,
gboolean force_restart);
gboolean nm_device_update_hw_address (NMDevice *self);
void nm_device_update_initial_hw_address (NMDevice *self);

View file

@ -124,7 +124,7 @@ NM_DEFINE_SINGLETON_GETTER (NMDefaultRouteManager, nm_default_route_manager_get,
const Entry *const __entry = (entry); \
\
_nm_log (__level, __domain, 0, \
"%s: entry[%u/%s:%p:%s:%c:%csync]: "_NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
"%s: entry[%u/%s:%p:%s:%chas:%csync]: "_NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
self != singleton_instance \
? nm_sprintf_buf (__prefix_buf, "%s%c[%p]", \
_NMLOG2_PREFIX_NAME, \
@ -135,7 +135,7 @@ NM_DEFINE_SINGLETON_GETTER (NMDefaultRouteManager, nm_default_route_manager_get,
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_active_connection_get_settings_connection_id (NM_ACTIVE_CONNECTION (__entry->source.vpn)), \
(__entry->never_default ? '0' : '1'), \
(__entry->never_default ? '-' : '+'), \
(__entry->synced ? '+' : '-') \
_NM_UTILS_MACRO_REST(__VA_ARGS__)); \
} \
@ -480,17 +480,6 @@ _get_assumed_interface_metrics (const VTableIP *vtable, NMDefaultRouteManager *s
return result;
}
static int
_sort_metrics_ascending_fcn (gconstpointer a, gconstpointer b)
{
guint32 m_a = *((guint32 *) a);
guint32 m_b = *((guint32 *) b);
if (m_a < m_b)
return -1;
return m_a == m_b ? 0 : 1;
}
static gboolean
_resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *changed_entry, const Entry *old_entry, gboolean external_change)
{
@ -533,8 +522,6 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c
for (i = 0; i < entries->len; i++) {
entry = g_ptr_array_index (entries, i);
g_assert (entry != old_entry);
if (entry->never_default)
continue;
@ -589,12 +576,15 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c
/* for the changed entry, the previous metric was either old_entry->effective_metric,
* or none. Hence, we only have to remember what is going to change. */
g_array_append_val (changed_metrics, expected_metric);
if (old_entry) {
if (!old_entry) {
_LOG2D (vtable, i, entry, "sync:add %s (%u)",
vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) expected_metric);
} else if (old_entry != changed_entry) {
_LOG2D (vtable, i, entry, "sync:update %s (%u -> %u)",
vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) old_entry->effective_metric,
(guint) expected_metric);
} else {
_LOG2D (vtable, i, entry, "sync:add %s (%u)",
_LOG2D (vtable, i, entry, "sync:resync %s (%u)",
vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) expected_metric);
}
} else if (entry->effective_metric != expected_metric) {
@ -621,7 +611,7 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c
g_array_free (routes, TRUE);
g_array_sort (changed_metrics, _sort_metrics_ascending_fcn);
g_array_sort_with_data (changed_metrics, nm_cmp_uint32_p_with_data, NULL);
last_metric = -1;
for (j = 0; j < changed_metrics->len; j++) {
expected_metric = g_array_index (changed_metrics, guint32, j);
@ -672,7 +662,11 @@ _entry_at_idx_update (const VTableIP *vtable, NMDefaultRouteManager *self, guint
entry->effective_metric = entry->route.rx.metric;
_LOG2D (vtable, entry_idx, entry, "%s %s (%"G_GUINT32_FORMAT")",
old_entry ? "record:update" : "record:add ",
old_entry
? (entry != old_entry
? "record:update"
: "record:resync")
: "record:add ",
vtable->vt->route_to_string (&entry->route, NULL, 0),
entry->effective_metric);
@ -709,7 +703,9 @@ _entry_at_idx_remove (const VTableIP *vtable, NMDefaultRouteManager *self, guint
/*****************************************************************************/
static void
_ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self, gpointer source)
_ipx_update_default_route (const VTableIP *vtable,
NMDefaultRouteManager *self,
gpointer source)
{
NMDefaultRouteManagerPrivate *priv;
Entry *entry;
@ -781,9 +777,8 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self,
default_route = &rt.rx;
never_default = TRUE;
synced = TRUE;
} else
synced = default_route && !is_assumed;
}
synced = !is_assumed;
} else {
NMConnection *connection = nm_active_connection_get_applied_connection ((NMActiveConnection *) vpn);
@ -875,12 +870,18 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self,
new_entry.never_default = never_default;
new_entry.synced = synced;
if (memcmp (entry, &new_entry, sizeof (new_entry)) == 0)
return;
old_entry = *entry;
*entry = new_entry;
_entry_at_idx_update (vtable, self, entry_idx, &old_entry);
if (memcmp (entry, &new_entry, sizeof (new_entry)) == 0) {
if (!synced) {
/* the internal book-keeping doesn't change, so don't do a full
* sync of the configured routes. */
return;
}
_entry_at_idx_update (vtable, self, entry_idx, entry);
} else {
old_entry = *entry;
*entry = new_entry;
_entry_at_idx_update (vtable, self, entry_idx, &old_entry);
}
} else {
/* delete */
_entry_at_idx_remove (vtable, self, entry_idx);
@ -888,13 +889,15 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self,
}
void
nm_default_route_manager_ip4_update_default_route (NMDefaultRouteManager *self, gpointer source)
nm_default_route_manager_ip4_update_default_route (NMDefaultRouteManager *self,
gpointer source)
{
_ipx_update_default_route (&vtable_ip4, self, source);
}
void
nm_default_route_manager_ip6_update_default_route (NMDefaultRouteManager *self, gpointer source)
nm_default_route_manager_ip6_update_default_route (NMDefaultRouteManager *self,
gpointer source)
{
_ipx_update_default_route (&vtable_ip6, self, source);
}
@ -1256,7 +1259,7 @@ static const VTableIP vtable_ip6 = {
/*****************************************************************************/
static gboolean
_resync_idle_now (NMDefaultRouteManager *self)
_resync_now (NMDefaultRouteManager *self)
{
gboolean has_v4_changes, has_v6_changes;
gboolean changed = FALSE;
@ -1271,7 +1274,7 @@ _resync_idle_now (NMDefaultRouteManager *self)
priv->resync.has_v4_changes = FALSE;
priv->resync.has_v6_changes = FALSE;
priv->resync.idle_handle = 0;
nm_clear_g_source (&priv->resync.idle_handle);
priv->resync.backoff_wait_time_ms =
priv->resync.backoff_wait_time_ms == 0
? 100
@ -1288,6 +1291,64 @@ _resync_idle_now (NMDefaultRouteManager *self)
_resync_idle_cancel (self);
}
return changed;
}
/**
* nm_default_route_manager_resync:
* @self: the #NMDefaultRouteManager instance
* @af_family: the address family to resync, can be
* AF_INET, AF_INET6 or AF_UNSPEC to sync both.
*
* #NMDefaultRouteManager keeps an internal list of configured
* routes. Usually, it configures routes in the system only
* - when that internal list changes due to
* nm_default_route_manager_ip4_update_default_route() or
* nm_default_route_manager_ip6_update_default_route().
* - when platform notifies about changes, via _resync_idle_now().
* This forces a resync to update the internal bookkeeping
* with what is currently configured in the system, but also
* reconfigure the system with all non-assumed default routes.
*
* Returns: %TRUE if anything changed during resync.
*/
gboolean
nm_default_route_manager_resync (NMDefaultRouteManager *self,
int af_family)
{
NMDefaultRouteManagerPrivate *priv;
g_return_val_if_fail (NM_IS_DEFAULT_ROUTE_MANAGER (self), FALSE);
g_return_val_if_fail (NM_IN_SET (af_family, AF_INET, AF_INET6, AF_UNSPEC), FALSE);
priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
if (priv->disposed)
return FALSE;
switch (af_family) {
case AF_INET:
priv->resync.has_v4_changes = TRUE;
break;
case AF_INET6:
priv->resync.has_v6_changes = TRUE;
break;
default:
priv->resync.has_v4_changes = TRUE;
priv->resync.has_v6_changes = TRUE;
break;
}
return _resync_now (self);
}
static gboolean
_resync_idle_now (NMDefaultRouteManager *self)
{
NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
priv->resync.idle_handle = 0;
_resync_now (self);
return G_SOURCE_REMOVE;
}
@ -1333,15 +1394,36 @@ _resync_idle_reschedule (NMDefaultRouteManager *self)
}
static void
_platform_ipx_route_changed_cb (const VTableIP *vtable,
NMDefaultRouteManager *self,
const NMPlatformIPRoute *route)
_platform_changed_cb (NMPlatform *platform,
int obj_type_i,
int ifindex,
gpointer platform_object,
int change_type_i,
NMDefaultRouteManager *self)
{
NMDefaultRouteManagerPrivate *priv;
const NMPObjectType obj_type = obj_type_i;
const VTableIP *vtable;
if (route && !NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) {
/* we only care about address changes or changes of default route. */
return;
switch (obj_type) {
case NMP_OBJECT_TYPE_IP4_ADDRESS:
vtable = &vtable_ip4;
break;
case NMP_OBJECT_TYPE_IP6_ADDRESS:
vtable = &vtable_ip6;
break;
case NMP_OBJECT_TYPE_IP4_ROUTE:
if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (platform_object))
return;
vtable = &vtable_ip4;
break;
case NMP_OBJECT_TYPE_IP6_ROUTE:
if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (platform_object))
return;
vtable = &vtable_ip6;
break;
default:
g_return_if_reached ();
}
priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
@ -1359,34 +1441,6 @@ _platform_ipx_route_changed_cb (const VTableIP *vtable,
_resync_idle_reschedule (self);
}
static void
_platform_changed_cb (NMPlatform *platform,
int obj_type_i,
int ifindex,
gpointer platform_object,
int change_type_i,
NMDefaultRouteManager *self)
{
const NMPObjectType obj_type = obj_type_i;
switch (obj_type) {
case NMP_OBJECT_TYPE_IP4_ADDRESS:
_platform_ipx_route_changed_cb (&vtable_ip4, self, NULL);
break;
case NMP_OBJECT_TYPE_IP6_ADDRESS:
_platform_ipx_route_changed_cb (&vtable_ip6, self, NULL);
break;
case NMP_OBJECT_TYPE_IP4_ROUTE:
_platform_ipx_route_changed_cb (&vtable_ip4, self, (const NMPlatformIPRoute *) platform_object);
break;
case NMP_OBJECT_TYPE_IP6_ROUTE:
_platform_ipx_route_changed_cb (&vtable_ip6, self, (const NMPlatformIPRoute *) platform_object);
break;
default:
g_return_if_reached ();
}
}
/*****************************************************************************/
static void

View file

@ -61,4 +61,7 @@ NMIP6Config *nm_default_route_manager_ip6_get_best_config (NMDefaultRouteManager
NMDevice **out_device,
NMVpnConnection **out_vpn);
gboolean nm_default_route_manager_resync (NMDefaultRouteManager *self,
int af_family);
#endif /* NM_DEFAULT_ROUTE_MANAGER_H */