mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-27 00:00:08 +01:00
core: merge branch 'th/ip6-temp-addr-sync-rh1542609'
https://github.com/NetworkManager/NetworkManager/pull/65 https://bugzilla.redhat.com/show_bug.cgi?id=1542609
This commit is contained in:
commit
fa41e5852c
10 changed files with 341 additions and 160 deletions
|
|
@ -2816,6 +2816,8 @@ ndisc_set_router_config (NMNDisc *ndisc, NMDevice *self)
|
|||
nm_dedup_multi_iter_for_each (&ipconf_iter, head_entry) {
|
||||
const NMPlatformIP6Address *addr = NMP_OBJECT_CAST_IP6_ADDRESS (ipconf_iter.current->obj);
|
||||
NMNDiscAddress *ndisc_addr;
|
||||
guint32 lifetime, preferred;
|
||||
gint32 base;
|
||||
|
||||
if (IN6_IS_ADDR_LINKLOCAL (&addr->address))
|
||||
continue;
|
||||
|
|
@ -2827,12 +2829,28 @@ ndisc_set_router_config (NMNDisc *ndisc, NMDevice *self)
|
|||
if (addr->plen != 64)
|
||||
continue;
|
||||
|
||||
/* resolve the timestamps relative to a new base.
|
||||
*
|
||||
* Note that for convenience, platform @addr might have timestamp and/or
|
||||
* lifetime unset. We don't allow that flexibility for ndisc and require
|
||||
* well defined timestamps. */
|
||||
if (addr->timestamp) {
|
||||
nm_assert (addr->timestamp < G_MAXINT32);
|
||||
base = addr->timestamp;
|
||||
} else
|
||||
base = now;
|
||||
|
||||
lifetime = nm_utils_lifetime_get (addr->timestamp, addr->lifetime, addr->preferred,
|
||||
base, &preferred);
|
||||
if (!lifetime)
|
||||
continue;
|
||||
|
||||
g_array_set_size (addresses, addresses->len+1);
|
||||
ndisc_addr = &g_array_index (addresses, NMNDiscAddress, addresses->len-1);
|
||||
ndisc_addr->address = addr->address;
|
||||
ndisc_addr->timestamp = addr->timestamp;
|
||||
ndisc_addr->lifetime = addr->lifetime;
|
||||
ndisc_addr->preferred = addr->preferred;
|
||||
ndisc_addr->timestamp = base;
|
||||
ndisc_addr->lifetime = lifetime;
|
||||
ndisc_addr->preferred = preferred;
|
||||
}
|
||||
|
||||
len = nm_ip6_config_get_num_nameservers (priv->ip6_config);
|
||||
|
|
@ -11511,6 +11529,7 @@ queued_ip6_config_change (gpointer user_data)
|
|||
NMDevicePrivate *priv;
|
||||
GSList *iter;
|
||||
gboolean need_ipv6ll = FALSE;
|
||||
NMPlatform *platform;
|
||||
|
||||
g_return_val_if_fail (NM_IS_DEVICE (self), G_SOURCE_REMOVE);
|
||||
|
||||
|
|
@ -11537,14 +11556,24 @@ queued_ip6_config_change (gpointer user_data)
|
|||
} else
|
||||
update_ip_config (self, AF_INET6, FALSE);
|
||||
|
||||
if (priv->state < NM_DEVICE_STATE_DEACTIVATING
|
||||
&& nm_platform_link_get (nm_device_get_platform (self), priv->ifindex)) {
|
||||
if ( priv->state < NM_DEVICE_STATE_DEACTIVATING
|
||||
&& (platform = nm_device_get_platform (self))
|
||||
&& nm_platform_link_get (platform, priv->ifindex)) {
|
||||
/* Handle DAD failures */
|
||||
for (iter = priv->dad6_failed_addrs; iter; iter = g_slist_next (iter)) {
|
||||
const NMPlatformIP6Address *addr = iter->data;
|
||||
for (iter = priv->dad6_failed_addrs; iter; iter = iter->next) {
|
||||
const NMPObject *obj = iter->data;
|
||||
const NMPlatformIP6Address *addr = NMP_OBJECT_CAST_IP6_ADDRESS (obj);
|
||||
const NMPlatformIP6Address *addr2;
|
||||
|
||||
if (addr->addr_source >= NM_IP_CONFIG_SOURCE_USER)
|
||||
addr2 = NMP_OBJECT_CAST_IP6_ADDRESS (nm_platform_lookup_obj (platform,
|
||||
NMP_CACHE_ID_TYPE_OBJECT_TYPE,
|
||||
obj));
|
||||
if ( addr2
|
||||
&& ( NM_FLAGS_HAS (addr2->n_ifa_flags, IFA_F_SECONDARY)
|
||||
|| !NM_FLAGS_HAS (addr2->n_ifa_flags, IFA_F_DADFAILED))) {
|
||||
/* the address still/again exists and is not in DADFAILED state. Skip it. */
|
||||
continue;
|
||||
}
|
||||
|
||||
_LOGI (LOGD_IP6, "ipv6: duplicate address check failed for the %s address",
|
||||
nm_platform_ip6_address_to_string (addr, NULL, 0));
|
||||
|
|
@ -11567,7 +11596,7 @@ queued_ip6_config_change (gpointer user_data)
|
|||
check_and_add_ipv6ll_addr (self);
|
||||
}
|
||||
|
||||
g_slist_free_full (priv->dad6_failed_addrs, g_free);
|
||||
g_slist_free_full (priv->dad6_failed_addrs, (GDestroyNotify) nmp_object_unref);
|
||||
priv->dad6_failed_addrs = NULL;
|
||||
|
||||
/* Check if DAD is still pending */
|
||||
|
|
@ -11623,12 +11652,13 @@ device_ipx_changed (NMPlatform *platform,
|
|||
case NMP_OBJECT_TYPE_IP6_ADDRESS:
|
||||
addr = platform_object;
|
||||
|
||||
if ( priv->state > NM_DEVICE_STATE_DISCONNECTED
|
||||
if ( !NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_SECONDARY)
|
||||
&& priv->state > NM_DEVICE_STATE_DISCONNECTED
|
||||
&& priv->state < NM_DEVICE_STATE_DEACTIVATING
|
||||
&& ( (change_type == NM_PLATFORM_SIGNAL_CHANGED && addr->n_ifa_flags & IFA_F_DADFAILED)
|
||||
|| (change_type == NM_PLATFORM_SIGNAL_REMOVED && addr->n_ifa_flags & IFA_F_TENTATIVE))) {
|
||||
priv->dad6_failed_addrs = g_slist_append (priv->dad6_failed_addrs,
|
||||
g_memdup (addr, sizeof (NMPlatformIP6Address)));
|
||||
priv->dad6_failed_addrs = g_slist_prepend (priv->dad6_failed_addrs,
|
||||
(gpointer) nmp_object_ref (NMP_OBJECT_UP_CAST (addr)));
|
||||
}
|
||||
/* fall through */
|
||||
case NMP_OBJECT_TYPE_IP6_ROUTE:
|
||||
|
|
@ -14684,7 +14714,7 @@ finalize (GObject *object)
|
|||
g_free (priv->hw_addr_perm);
|
||||
g_free (priv->hw_addr_initial);
|
||||
g_slist_free (priv->pending_actions);
|
||||
g_slist_free_full (priv->dad6_failed_addrs, g_free);
|
||||
g_slist_free_full (priv->dad6_failed_addrs, (GDestroyNotify) nmp_object_unref);
|
||||
g_clear_pointer (&priv->physical_port_id, g_free);
|
||||
g_free (priv->udi);
|
||||
g_free (priv->iface);
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE (
|
|||
);
|
||||
|
||||
enum {
|
||||
CONFIG_CHANGED,
|
||||
CONFIG_RECEIVED,
|
||||
RA_TIMEOUT,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
|
@ -235,7 +235,7 @@ static void
|
|||
_emit_config_change (NMNDisc *self, NMNDiscConfigMap changed)
|
||||
{
|
||||
_config_changed_log (self, changed);
|
||||
g_signal_emit (self, signals[CONFIG_CHANGED], 0,
|
||||
g_signal_emit (self, signals[CONFIG_RECEIVED], 0,
|
||||
_data_complete (&NM_NDISC_GET_PRIVATE (self)->rdata),
|
||||
(guint) changed);
|
||||
}
|
||||
|
|
@ -349,6 +349,9 @@ nm_ndisc_add_address (NMNDisc *ndisc, const NMNDiscAddress *new)
|
|||
NMNDiscDataInternal *rdata = &priv->rdata;
|
||||
guint i;
|
||||
|
||||
nm_assert (new);
|
||||
nm_assert (new->timestamp > 0 && new->timestamp < G_MAXINT32);
|
||||
|
||||
for (i = 0; i < rdata->addresses->len; i++) {
|
||||
NMNDiscAddress *item = &g_array_index (rdata->addresses, NMNDiscAddress, i);
|
||||
|
||||
|
|
@ -936,7 +939,7 @@ _config_changed_log (NMNDisc *ndisc, NMNDiscConfigMap changed)
|
|||
get_exp (str_exp, now_ns, gateway));
|
||||
}
|
||||
for (i = 0; i < rdata->addresses->len; i++) {
|
||||
NMNDiscAddress *address = &g_array_index (rdata->addresses, NMNDiscAddress, i);
|
||||
const NMNDiscAddress *address = &g_array_index (rdata->addresses, NMNDiscAddress, i);
|
||||
|
||||
inet_ntop (AF_INET6, &address->address, addrstr, sizeof (addrstr));
|
||||
_LOGD (" address %s exp %s", addrstr,
|
||||
|
|
@ -1003,7 +1006,7 @@ clean_addresses (NMNDisc *ndisc, gint32 now, NMNDiscConfigMap *changed, gint32 *
|
|||
rdata = &NM_NDISC_GET_PRIVATE (ndisc)->rdata;
|
||||
|
||||
for (i = 0; i < rdata->addresses->len; ) {
|
||||
NMNDiscAddress *item = &g_array_index (rdata->addresses, NMNDiscAddress, i);
|
||||
const NMNDiscAddress *item = &g_array_index (rdata->addresses, NMNDiscAddress, i);
|
||||
|
||||
if (item->lifetime != NM_NDISC_INFINITY) {
|
||||
gint32 expiry = get_expiry (item);
|
||||
|
|
@ -1378,7 +1381,7 @@ nm_ndisc_class_init (NMNDiscClass *klass)
|
|||
G_PARAM_STATIC_STRINGS);
|
||||
g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
|
||||
|
||||
signals[CONFIG_CHANGED] =
|
||||
signals[CONFIG_RECEIVED] =
|
||||
g_signal_new (NM_NDISC_CONFIG_RECEIVED,
|
||||
G_OBJECT_CLASS_TYPE (klass),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
|
|
|
|||
|
|
@ -3891,12 +3891,11 @@ nm_utils_lifetime_rebase_relative_time_on_now (guint32 timestamp,
|
|||
return t;
|
||||
}
|
||||
|
||||
gboolean
|
||||
guint32
|
||||
nm_utils_lifetime_get (guint32 timestamp,
|
||||
guint32 lifetime,
|
||||
guint32 preferred,
|
||||
gint32 now,
|
||||
guint32 *out_lifetime,
|
||||
guint32 *out_preferred)
|
||||
{
|
||||
guint32 t_lifetime, t_preferred;
|
||||
|
|
@ -3904,38 +3903,39 @@ nm_utils_lifetime_get (guint32 timestamp,
|
|||
nm_assert (now >= 0);
|
||||
|
||||
if (timestamp == 0 && lifetime == 0) {
|
||||
/* We treat lifetime==0 && timestamp == 0 addresses as permanent addresses to allow easy
|
||||
/* We treat lifetime==0 && timestamp==0 addresses as permanent addresses to allow easy
|
||||
* creation of such addresses (without requiring to set the lifetime fields to
|
||||
* NM_PLATFORM_LIFETIME_PERMANENT). The real lifetime==0 addresses (E.g. DHCP6 telling us
|
||||
* to drop an address will have timestamp set.
|
||||
*/
|
||||
NM_SET_OUT (out_lifetime, NM_PLATFORM_LIFETIME_PERMANENT);
|
||||
NM_SET_OUT (out_preferred, NM_PLATFORM_LIFETIME_PERMANENT);
|
||||
g_return_val_if_fail (preferred == 0, TRUE);
|
||||
} else {
|
||||
if (now <= 0)
|
||||
now = nm_utils_get_monotonic_timestamp_s ();
|
||||
t_lifetime = nm_utils_lifetime_rebase_relative_time_on_now (timestamp, lifetime, now);
|
||||
if (!t_lifetime) {
|
||||
NM_SET_OUT (out_lifetime, 0);
|
||||
NM_SET_OUT (out_preferred, 0);
|
||||
return FALSE;
|
||||
}
|
||||
t_preferred = nm_utils_lifetime_rebase_relative_time_on_now (timestamp, preferred, now);
|
||||
|
||||
NM_SET_OUT (out_lifetime, t_lifetime);
|
||||
NM_SET_OUT (out_preferred, MIN (t_preferred, t_lifetime));
|
||||
|
||||
/* Assert that non-permanent addresses have a (positive) @timestamp. nm_utils_lifetime_rebase_relative_time_on_now()
|
||||
* treats addresses with timestamp 0 as *now*. Addresses passed to _address_get_lifetime() always
|
||||
* should have a valid @timestamp, otherwise on every re-sync, their lifetime will be extended anew.
|
||||
*/
|
||||
g_return_val_if_fail ( timestamp != 0
|
||||
|| ( lifetime == NM_PLATFORM_LIFETIME_PERMANENT
|
||||
&& preferred == NM_PLATFORM_LIFETIME_PERMANENT), TRUE);
|
||||
g_return_val_if_fail (t_preferred <= t_lifetime, TRUE);
|
||||
g_return_val_if_fail (preferred == 0, NM_PLATFORM_LIFETIME_PERMANENT);
|
||||
return NM_PLATFORM_LIFETIME_PERMANENT;
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
if (now <= 0)
|
||||
now = nm_utils_get_monotonic_timestamp_s ();
|
||||
|
||||
t_lifetime = nm_utils_lifetime_rebase_relative_time_on_now (timestamp, lifetime, now);
|
||||
if (!t_lifetime) {
|
||||
NM_SET_OUT (out_preferred, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
t_preferred = nm_utils_lifetime_rebase_relative_time_on_now (timestamp, preferred, now);
|
||||
|
||||
NM_SET_OUT (out_preferred, MIN (t_preferred, t_lifetime));
|
||||
|
||||
/* Assert that non-permanent addresses have a (positive) @timestamp. nm_utils_lifetime_rebase_relative_time_on_now()
|
||||
* treats addresses with timestamp 0 as *now*. Addresses passed to _address_get_lifetime() always
|
||||
* should have a valid @timestamp, otherwise on every re-sync, their lifetime will be extended anew.
|
||||
*/
|
||||
g_return_val_if_fail ( timestamp != 0
|
||||
|| ( lifetime == NM_PLATFORM_LIFETIME_PERMANENT
|
||||
&& preferred == NM_PLATFORM_LIFETIME_PERMANENT), t_lifetime);
|
||||
g_return_val_if_fail (t_preferred <= t_lifetime, t_lifetime);
|
||||
|
||||
return t_lifetime;
|
||||
}
|
||||
|
||||
const char *
|
||||
|
|
|
|||
|
|
@ -408,12 +408,11 @@ guint32 nm_utils_lifetime_rebase_relative_time_on_now (guint32 timestamp,
|
|||
guint32 duration,
|
||||
gint32 now);
|
||||
|
||||
gboolean nm_utils_lifetime_get (guint32 timestamp,
|
||||
guint32 lifetime,
|
||||
guint32 preferred,
|
||||
gint32 now,
|
||||
guint32 *out_lifetime,
|
||||
guint32 *out_preferred);
|
||||
guint32 nm_utils_lifetime_get (guint32 timestamp,
|
||||
guint32 lifetime,
|
||||
guint32 preferred,
|
||||
gint32 now,
|
||||
guint32 *out_preferred);
|
||||
|
||||
gboolean nm_utils_ip4_address_is_link_local (in_addr_t addr);
|
||||
|
||||
|
|
|
|||
|
|
@ -566,7 +566,7 @@ nm_ip6_config_commit (const NMIP6Config *self,
|
|||
ifindex,
|
||||
route_table_sync);
|
||||
|
||||
nm_platform_ip6_address_sync (platform, ifindex, addresses, TRUE);
|
||||
nm_platform_ip6_address_sync (platform, ifindex, addresses, FALSE);
|
||||
|
||||
if (!nm_platform_ip_route_sync (platform,
|
||||
AF_INET6,
|
||||
|
|
|
|||
|
|
@ -4829,6 +4829,12 @@ link_refresh (NMPlatform *platform, int ifindex)
|
|||
return !!nm_platform_link_get_obj (platform, ifindex, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
refresh_all (NMPlatform *platform, NMPObjectType obj_type)
|
||||
{
|
||||
do_request_one_type (platform, obj_type);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
link_set_netns (NMPlatform *platform,
|
||||
int ifindex,
|
||||
|
|
@ -7196,6 +7202,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
|
|||
platform_class->link_add = link_add;
|
||||
platform_class->link_delete = link_delete;
|
||||
|
||||
platform_class->refresh_all = refresh_all;
|
||||
platform_class->link_refresh = link_refresh;
|
||||
|
||||
platform_class->link_set_netns = link_set_netns;
|
||||
|
|
|
|||
|
|
@ -1117,6 +1117,21 @@ nm_platform_link_supports_slaves (NMPlatform *self, int ifindex)
|
|||
return (nm_platform_link_get_type (self, ifindex) & 0x20000);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_platform_refresh_all:
|
||||
* @self: platform instance
|
||||
* @obj_type: The object type to request.
|
||||
*
|
||||
* Resync and re-request all objects from kernel of a certain @obj_type.
|
||||
*/
|
||||
void
|
||||
nm_platform_refresh_all (NMPlatform *self, NMPObjectType obj_type)
|
||||
{
|
||||
_CHECK_SELF_VOID (self, klass);
|
||||
|
||||
klass->refresh_all (self, obj_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_platform_link_refresh:
|
||||
* @self: platform instance
|
||||
|
|
@ -3110,35 +3125,68 @@ nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr addr
|
|||
return NMP_OBJECT_CAST_IP6_ADDRESS (obj);
|
||||
}
|
||||
|
||||
static int
|
||||
array_ip6_address_position (const GPtrArray *addresses,
|
||||
const NMPlatformIP6Address *address,
|
||||
gint32 now,
|
||||
gboolean ignore_ll)
|
||||
static gboolean
|
||||
_addr_array_clean_expired (int addr_family, int ifindex, GPtrArray *array, guint32 now, GHashTable **idx)
|
||||
{
|
||||
guint len = addresses ? addresses->len : 0;
|
||||
guint i, pos;
|
||||
guint i;
|
||||
gboolean any_addrs = FALSE;
|
||||
|
||||
nm_assert (!ignore_ll || !IN6_IS_ADDR_LINKLOCAL (&address->address));
|
||||
nm_assert_addr_family (addr_family);
|
||||
nm_assert (ifindex > 0);
|
||||
nm_assert (now > 0);
|
||||
|
||||
for (i = 0, pos = 0; i < len; i++) {
|
||||
NMPlatformIP6Address *candidate = NMP_OBJECT_CAST_IP6_ADDRESS (addresses->pdata[i]);
|
||||
if (!array)
|
||||
return FALSE;
|
||||
|
||||
if ( IN6_ARE_ADDR_EQUAL (&candidate->address, &address->address)
|
||||
&& candidate->plen == address->plen
|
||||
&& nm_utils_lifetime_get (candidate->timestamp,
|
||||
candidate->lifetime,
|
||||
candidate->preferred,
|
||||
now,
|
||||
NULL,
|
||||
NULL))
|
||||
return pos;
|
||||
/* remove all addresses that are already expired. */
|
||||
for (i = 0; i < array->len; i++) {
|
||||
const NMPlatformIPAddress *a = NMP_OBJECT_CAST_IP_ADDRESS (array->pdata[i]);
|
||||
|
||||
if (!ignore_ll || !IN6_IS_ADDR_LINKLOCAL (&candidate->address))
|
||||
pos++;
|
||||
#if NM_MORE_ASSERTS > 10
|
||||
nm_assert (a);
|
||||
nm_assert (a->ifindex == ifindex);
|
||||
{
|
||||
const NMPObject *o = NMP_OBJECT_UP_CAST (a);
|
||||
guint j;
|
||||
|
||||
nm_assert (NMP_OBJECT_GET_CLASS (o)->addr_family == addr_family);
|
||||
for (j = i + 1; j < array->len; j++) {
|
||||
const NMPObject *o2 = array->pdata[j];
|
||||
|
||||
nm_assert (NMP_OBJECT_GET_TYPE (o) == NMP_OBJECT_GET_TYPE (o2));
|
||||
nm_assert (!nmp_object_id_equal (o, o2));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (NM_FLAGS_HAS (a->n_ifa_flags, IFA_F_SECONDARY)) {
|
||||
/* temporary addresses are never added explicitly by NetworkManager but
|
||||
* kernel adds them via mngtempaddr flag.
|
||||
*
|
||||
* We drop them from this list. */
|
||||
goto clear_and_next;
|
||||
}
|
||||
|
||||
if (!nm_utils_lifetime_get (a->timestamp, a->lifetime, a->preferred,
|
||||
now, NULL))
|
||||
goto clear_and_next;
|
||||
|
||||
if (idx) {
|
||||
if (G_UNLIKELY (!*idx)) {
|
||||
*idx = g_hash_table_new ((GHashFunc) nmp_object_id_hash,
|
||||
(GEqualFunc) nmp_object_id_equal);
|
||||
}
|
||||
if (!g_hash_table_add (*idx, (gpointer) NMP_OBJECT_UP_CAST (a)))
|
||||
nm_assert_not_reached ();
|
||||
}
|
||||
any_addrs = TRUE;
|
||||
continue;
|
||||
|
||||
clear_and_next:
|
||||
nmp_object_unref (g_steal_pointer (&array->pdata[i]));
|
||||
}
|
||||
|
||||
return -1;
|
||||
return any_addrs;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
|
@ -3322,39 +3370,8 @@ nm_platform_ip4_address_sync (NMPlatform *self,
|
|||
|
||||
_CHECK_SELF (self, klass, FALSE);
|
||||
|
||||
if (known_addresses) {
|
||||
/* remove all addresses that are already expired. */
|
||||
for (i = 0; i < known_addresses->len; i++) {
|
||||
const NMPObject *o;
|
||||
|
||||
o = known_addresses->pdata[i];
|
||||
nm_assert (o);
|
||||
|
||||
known_address = NMP_OBJECT_CAST_IP4_ADDRESS (known_addresses->pdata[i]);
|
||||
|
||||
if (!nm_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred,
|
||||
now, NULL, NULL))
|
||||
goto delete_and_next;
|
||||
|
||||
if (G_UNLIKELY (!known_addresses_idx)) {
|
||||
known_addresses_idx = g_hash_table_new ((GHashFunc) nmp_object_id_hash,
|
||||
(GEqualFunc) nmp_object_id_equal);
|
||||
}
|
||||
if (!g_hash_table_insert (known_addresses_idx, (gpointer) o, (gpointer) o)) {
|
||||
/* duplicate? Keep only the first instance. */
|
||||
goto delete_and_next;
|
||||
}
|
||||
|
||||
continue;
|
||||
delete_and_next:
|
||||
nmp_object_unref (o);
|
||||
known_addresses->pdata[i] = NULL;
|
||||
}
|
||||
|
||||
if ( !known_addresses_idx
|
||||
|| g_hash_table_size (known_addresses_idx) == 0)
|
||||
known_addresses = NULL;
|
||||
}
|
||||
if (!_addr_array_clean_expired (AF_INET, ifindex, known_addresses, now, &known_addresses_idx))
|
||||
known_addresses = NULL;
|
||||
|
||||
plat_addresses = nm_platform_lookup_clone (self,
|
||||
nmp_lookup_init_object (&lookup,
|
||||
|
|
@ -3451,8 +3468,9 @@ delete_and_next:
|
|||
|
||||
known_address = NMP_OBJECT_CAST_IP4_ADDRESS (o);
|
||||
|
||||
if (!nm_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred,
|
||||
now, &lifetime, &preferred))
|
||||
lifetime = nm_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred,
|
||||
now, &preferred);
|
||||
if (!lifetime)
|
||||
goto delete_and_next2;
|
||||
|
||||
if (!nm_platform_ip4_address_add (self, ifindex, known_address->address, known_address->plen,
|
||||
|
|
@ -3474,9 +3492,15 @@ delete_and_next2:
|
|||
* nm_platform_ip6_address_sync:
|
||||
* @self: platform instance
|
||||
* @ifindex: Interface index
|
||||
* @known_addresses: List of IPv6 addresses, as NMPObject. The list
|
||||
* is not modified.
|
||||
* @keep_link_local: Don't remove link-local address
|
||||
* @known_addresses: List of addresses. The list will be modified and only
|
||||
* addresses that were successfully added will be kept in the list.
|
||||
* That means, expired addresses and addresses that could not be added
|
||||
* will be dropped.
|
||||
* Hence, the input argument @known_addresses is also an output argument
|
||||
* telling which addresses were succesfully added.
|
||||
* Addresses are removed by unrefing the instance via nmp_object_unref()
|
||||
* and leaving a NULL tombstone.
|
||||
* @full_sync: Also remove link-local and temporary addresses.
|
||||
*
|
||||
* A convenience function to synchronize addresses for a specific interface
|
||||
* with the least possible disturbance. It simply removes addresses that are
|
||||
|
|
@ -3487,60 +3511,114 @@ delete_and_next2:
|
|||
gboolean
|
||||
nm_platform_ip6_address_sync (NMPlatform *self,
|
||||
int ifindex,
|
||||
const GPtrArray *known_addresses,
|
||||
gboolean keep_link_local)
|
||||
GPtrArray *known_addresses,
|
||||
gboolean full_sync)
|
||||
{
|
||||
gs_unref_ptrarray GPtrArray *plat_addresses = NULL;
|
||||
NMPlatformIP6Address *address;
|
||||
gint32 now = nm_utils_get_monotonic_timestamp_s ();
|
||||
int i, position;
|
||||
guint i_plat, i_know;
|
||||
gs_unref_hashtable GHashTable *known_addresses_idx = NULL;
|
||||
NMPLookup lookup;
|
||||
guint32 ifa_flags;
|
||||
gboolean remove = FALSE;
|
||||
|
||||
/* @plat_addresses and @known_addresses are in increasing priority order */
|
||||
if (!_addr_array_clean_expired (AF_INET6, ifindex, known_addresses, now, &known_addresses_idx))
|
||||
known_addresses = NULL;
|
||||
|
||||
/* @plat_addresses is in decreasing priority order (highest priority addresses first), contrary to
|
||||
* @known_addresses which is in increasing priority order (lowest priority addresses first). */
|
||||
plat_addresses = nm_platform_lookup_clone (self,
|
||||
nmp_lookup_init_object (&lookup,
|
||||
NMP_OBJECT_TYPE_IP6_ADDRESS,
|
||||
ifindex),
|
||||
NULL, NULL);
|
||||
|
||||
if (plat_addresses) {
|
||||
/* First, remove unknown addresses from platform */
|
||||
for (i = 0; i < plat_addresses->len; i++) {
|
||||
address = NMP_OBJECT_CAST_IP6_ADDRESS (plat_addresses->pdata[i]);
|
||||
gboolean delete_remaining;
|
||||
guint known_addresses_len;
|
||||
|
||||
if (keep_link_local && IN6_IS_ADDR_LINKLOCAL (&address->address))
|
||||
continue;
|
||||
known_addresses_len = known_addresses ? known_addresses->len : 0;
|
||||
|
||||
position = array_ip6_address_position (known_addresses, address, now, FALSE);
|
||||
if (position < 0) {
|
||||
nm_platform_ip6_address_delete (self, ifindex, address->address, address->plen);
|
||||
g_ptr_array_remove_index (plat_addresses, i);
|
||||
i--;
|
||||
/* First, compare every address whether it is still a "known address", that is, whether
|
||||
* to keep it or to delete it.
|
||||
*
|
||||
* If we don't find a matching valid address in @known_addresses, we will delete
|
||||
* plat_addr.
|
||||
*
|
||||
* Certain addresses, like link-local or temporary addresses, are ignored by this function
|
||||
* if not run with full_sync.
|
||||
*
|
||||
* Note that we mark handled addresses by setting it to %NULL in @plat_addresses array. */
|
||||
for (i_plat = 0; i_plat < plat_addresses->len; i_plat++) {
|
||||
const NMPObject *plat_obj = plat_addresses->pdata[i_plat];
|
||||
const NMPObject *know_obj;
|
||||
const NMPlatformIP6Address *plat_addr = NMP_OBJECT_CAST_IP6_ADDRESS (plat_obj);
|
||||
|
||||
if ( NM_FLAGS_HAS (plat_addr->n_ifa_flags, IFA_F_SECONDARY)
|
||||
|| IN6_IS_ADDR_LINKLOCAL (&plat_addr->address)) {
|
||||
if (!full_sync) {
|
||||
/* just mark as handled, without actually deleting the address. */
|
||||
goto clear_and_next;
|
||||
}
|
||||
} else if (known_addresses_idx) {
|
||||
know_obj = g_hash_table_lookup (known_addresses_idx, plat_obj);
|
||||
if ( know_obj
|
||||
&& plat_addr->plen == NMP_OBJECT_CAST_IP6_ADDRESS (know_obj)->plen) {
|
||||
/* technically, plen is not part of the ID for IPv6 addresses and thus
|
||||
* @plat_addr is essentially the same address as @know_addr (regrading
|
||||
* its identity, not its other attributes).
|
||||
* However, we cannot modify an existing addresses' plen without
|
||||
* removing and readding it. Thus, only keep plat_addr, if the plen
|
||||
* matches.
|
||||
*
|
||||
* keep this one, and continue */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
nm_platform_ip6_address_delete (self, ifindex, plat_addr->address, plat_addr->plen);
|
||||
clear_and_next:
|
||||
nmp_object_unref (g_steal_pointer (&plat_addresses->pdata[i_plat]));
|
||||
}
|
||||
|
||||
/* Start from addresses with lower priority and remove them if they are
|
||||
* in a wrong position. Removing an address also removes all addresses
|
||||
* with higher priority. We ignore link-local addresses when determining
|
||||
* positions.
|
||||
*/
|
||||
for (i = 0, position = 0; i < plat_addresses->len; i++) {
|
||||
address = NMP_OBJECT_CAST_IP6_ADDRESS (plat_addresses->pdata[i]);
|
||||
/* Next, we must preserve the priority of the routes. That is, source address
|
||||
* selection will choose addresses in the order as they are reported by kernel.
|
||||
* Note that the order in @plat_addresses of the remaining matches is highest
|
||||
* priority first.
|
||||
* We need to compare this to the order in @known_addresses (which has lowest
|
||||
* priority first).
|
||||
*
|
||||
* If we find a first discrepancy, we need to delete all remaining addresses
|
||||
* from that point on, because below we must re-add all the addresses in the
|
||||
* right order to get their priority right. */
|
||||
i_plat = plat_addresses->len;
|
||||
i_know = 0;
|
||||
delete_remaining = FALSE;
|
||||
while (i_plat > 0) {
|
||||
const NMPlatformIP6Address *plat_addr = NMP_OBJECT_CAST_IP6_ADDRESS (plat_addresses->pdata[--i_plat]);
|
||||
|
||||
if (IN6_IS_ADDR_LINKLOCAL (&address->address))
|
||||
if (!plat_addr)
|
||||
continue;
|
||||
|
||||
if ( remove
|
||||
|| position != array_ip6_address_position (known_addresses,
|
||||
address,
|
||||
now,
|
||||
TRUE)) {
|
||||
nm_platform_ip6_address_delete (self, ifindex, address->address, address->plen);
|
||||
remove = TRUE;
|
||||
if (!delete_remaining) {
|
||||
for (; i_know < known_addresses_len; i_know++) {
|
||||
const NMPlatformIP6Address *know_addr = NMP_OBJECT_CAST_IP6_ADDRESS (known_addresses->pdata[i_know]);
|
||||
|
||||
if (!know_addr)
|
||||
continue;
|
||||
|
||||
if (IN6_ARE_ADDR_EQUAL (&plat_addr->address, &know_addr->address)) {
|
||||
/* we have a match. Mark address as handled. */
|
||||
i_know++;
|
||||
goto next_plat;
|
||||
}
|
||||
break;
|
||||
}
|
||||
delete_remaining = TRUE;
|
||||
}
|
||||
|
||||
position++;
|
||||
nm_platform_ip6_address_delete (self, ifindex, plat_addr->address, plat_addr->plen);
|
||||
next_plat:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3554,18 +3632,15 @@ nm_platform_ip6_address_sync (NMPlatform *self,
|
|||
/* Add missing addresses. New addresses are added by kernel with top
|
||||
* priority.
|
||||
*/
|
||||
for (i = 0; i < known_addresses->len; i++) {
|
||||
const NMPlatformIP6Address *known_address = NMP_OBJECT_CAST_IP6_ADDRESS (known_addresses->pdata[i]);
|
||||
for (i_know = 0; i_know < known_addresses->len; i_know++) {
|
||||
const NMPlatformIP6Address *known_address = NMP_OBJECT_CAST_IP6_ADDRESS (known_addresses->pdata[i_know]);
|
||||
guint32 lifetime, preferred;
|
||||
|
||||
if (NM_FLAGS_HAS (known_address->n_ifa_flags, IFA_F_SECONDARY)) {
|
||||
/* Kernel manages these */
|
||||
if (!known_address)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!nm_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred,
|
||||
now, &lifetime, &preferred))
|
||||
continue;
|
||||
lifetime = nm_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred,
|
||||
now, &preferred);
|
||||
|
||||
if (!nm_platform_ip6_address_add (self, ifindex, known_address->address,
|
||||
known_address->plen, known_address->peer_address,
|
||||
|
|
@ -3593,7 +3668,7 @@ nm_platform_ip_address_flush (NMPlatform *self,
|
|||
if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET))
|
||||
success &= nm_platform_ip4_address_sync (self, ifindex, NULL);
|
||||
if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET6))
|
||||
success &= nm_platform_ip6_address_sync (self, ifindex, NULL, FALSE);
|
||||
success &= nm_platform_ip6_address_sync (self, ifindex, NULL, TRUE);
|
||||
return success;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -719,6 +719,8 @@ typedef struct {
|
|||
gboolean (*sysctl_set) (NMPlatform *, const char *pathid, int dirfd, const char *path, const char *value);
|
||||
char * (*sysctl_get) (NMPlatform *, const char *pathid, int dirfd, const char *path);
|
||||
|
||||
void (*refresh_all) (NMPlatform *self, NMPObjectType obj_type);
|
||||
|
||||
gboolean (*link_add) (NMPlatform *,
|
||||
const char *name,
|
||||
NMLinkType type,
|
||||
|
|
@ -1033,6 +1035,8 @@ gboolean nm_platform_sysctl_set_ip6_hop_limit_safe (NMPlatform *self, const char
|
|||
const char *nm_platform_if_indextoname (NMPlatform *self, int ifindex, char *out_ifname/* of size IFNAMSIZ */);
|
||||
int nm_platform_if_nametoindex (NMPlatform *self, const char *ifname);
|
||||
|
||||
void nm_platform_refresh_all (NMPlatform *self, NMPObjectType obj_type);
|
||||
|
||||
const NMPObject *nm_platform_link_get_obj (NMPlatform *self,
|
||||
int ifindex,
|
||||
gboolean visible_only);
|
||||
|
|
@ -1256,8 +1260,8 @@ gboolean nm_platform_ip6_address_add (NMPlatform *self,
|
|||
guint32 flags);
|
||||
gboolean nm_platform_ip4_address_delete (NMPlatform *self, int ifindex, in_addr_t address, guint8 plen, in_addr_t peer_address);
|
||||
gboolean nm_platform_ip6_address_delete (NMPlatform *self, int ifindex, struct in6_addr address, guint8 plen);
|
||||
gboolean nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, GPtrArray *known_addresse);
|
||||
gboolean nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, const GPtrArray *known_addresses, gboolean keep_link_local);
|
||||
gboolean nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, GPtrArray *known_addresses);
|
||||
gboolean nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, GPtrArray *known_addresses, gboolean full_sync);
|
||||
gboolean nm_platform_ip_address_flush (NMPlatform *self,
|
||||
int addr_family,
|
||||
int ifindex);
|
||||
|
|
|
|||
|
|
@ -1768,6 +1768,54 @@ nmp_cache_lookup_link_full (const NMPCache *cache,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static NMDedupMultiIdxMode
|
||||
_obj_get_add_mode (const NMPObject *obj)
|
||||
{
|
||||
/* new objects are usually appended to the list. Except for
|
||||
* addresses, which are prepended during `ip address add`.
|
||||
*
|
||||
* Actually, for routes it is more complicated, because depending on
|
||||
* `ip route append`, `ip route replace`, `ip route prepend`, the object
|
||||
* will be added at the tail, at the front, or even replace an element
|
||||
* in the list. However, that is handled separately by nmp_cache_update_netlink_route()
|
||||
* and of no concern here. */
|
||||
if (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj),
|
||||
NMP_OBJECT_TYPE_IP4_ADDRESS,
|
||||
NMP_OBJECT_TYPE_IP6_ADDRESS))
|
||||
return NM_DEDUP_MULTI_IDX_MODE_PREPEND;
|
||||
return NM_DEDUP_MULTI_IDX_MODE_APPEND;
|
||||
}
|
||||
|
||||
static void
|
||||
_idxcache_update_order_for_dump (NMPCache *cache,
|
||||
const NMDedupMultiEntry *entry)
|
||||
{
|
||||
const NMPClass *klass;
|
||||
const guint8 *i_idx_type;
|
||||
const NMDedupMultiEntry *entry2;
|
||||
|
||||
nm_dedup_multi_entry_reorder (entry, NULL, TRUE);
|
||||
|
||||
klass = NMP_OBJECT_GET_CLASS (entry->obj);
|
||||
for (i_idx_type = klass->supported_cache_ids; *i_idx_type; i_idx_type++) {
|
||||
NMPCacheIdType id_type = *i_idx_type;
|
||||
|
||||
if (id_type == NMP_CACHE_ID_TYPE_OBJECT_TYPE)
|
||||
continue;
|
||||
|
||||
entry2 = nm_dedup_multi_index_lookup_obj (cache->multi_idx,
|
||||
_idx_type_get (cache, id_type),
|
||||
entry->obj);
|
||||
if (!entry2)
|
||||
continue;
|
||||
|
||||
nm_assert (entry2 != entry);
|
||||
nm_assert (entry2->obj == entry->obj);
|
||||
|
||||
nm_dedup_multi_entry_reorder (entry2, NULL, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_idxcache_update_other_cache_ids (NMPCache *cache,
|
||||
NMPCacheIdType cache_id_type,
|
||||
|
|
@ -1827,7 +1875,7 @@ _idxcache_update_other_cache_ids (NMPCache *cache,
|
|||
obj_new,
|
||||
is_dump
|
||||
? NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE
|
||||
: NM_DEDUP_MULTI_IDX_MODE_APPEND,
|
||||
: _obj_get_add_mode (obj_new),
|
||||
is_dump
|
||||
? NULL
|
||||
: entry_order,
|
||||
|
|
@ -1905,7 +1953,7 @@ _idxcache_update (NMPCache *cache,
|
|||
obj_new,
|
||||
is_dump
|
||||
? NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE
|
||||
: NM_DEDUP_MULTI_IDX_MODE_APPEND,
|
||||
: _obj_get_add_mode (obj_new),
|
||||
NULL,
|
||||
entry_old ?: NM_DEDUP_MULTI_ENTRY_MISSING,
|
||||
NULL,
|
||||
|
|
@ -2162,6 +2210,8 @@ nmp_cache_update_netlink (NMPCache *cache,
|
|||
}
|
||||
|
||||
if (nmp_object_equal (obj_old, obj_hand_over)) {
|
||||
if (is_dump)
|
||||
_idxcache_update_order_for_dump (cache, entry_old);
|
||||
nm_dedup_multi_entry_set_dirty (entry_old, FALSE);
|
||||
NM_SET_OUT (out_obj_new, nmp_object_ref (obj_old));
|
||||
return NMP_CACHE_OPS_UNCHANGED;
|
||||
|
|
@ -2235,6 +2285,8 @@ nmp_cache_update_netlink_route (NMPCache *cache,
|
|||
}
|
||||
|
||||
if (nmp_object_equal (entry_old->obj, obj_hand_over)) {
|
||||
if (is_dump)
|
||||
_idxcache_update_order_for_dump (cache, entry_old);
|
||||
nm_dedup_multi_entry_set_dirty (entry_old, FALSE);
|
||||
goto update_done;
|
||||
}
|
||||
|
|
@ -2258,9 +2310,8 @@ update_done:
|
|||
* properly find @obj_replaced. */
|
||||
resync_required = FALSE;
|
||||
entry_replace = NULL;
|
||||
if (is_dump) {
|
||||
if (is_dump)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!entry_new) {
|
||||
if ( NM_FLAGS_HAS (nlmsgflags, NLM_F_REPLACE)
|
||||
|
|
@ -2275,6 +2326,8 @@ update_done:
|
|||
goto out;
|
||||
}
|
||||
|
||||
/* FIXME: for routes, we only maintain the order correctly for the BY_WEAK_ID
|
||||
* index. For all other indexes their order becomes messed up. */
|
||||
entry_cur = _lookup_entry_with_idx_type (cache,
|
||||
NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID,
|
||||
entry_new->obj);
|
||||
|
|
|
|||
|
|
@ -730,6 +730,16 @@ const NMDedupMultiEntry *nm_platform_lookup_entry (NMPlatform *platform,
|
|||
NMPCacheIdType cache_id_type,
|
||||
const NMPObject *obj);
|
||||
|
||||
static inline const NMPObject *
|
||||
nm_platform_lookup_obj (NMPlatform *platform,
|
||||
NMPCacheIdType cache_id_type,
|
||||
const NMPObject *obj)
|
||||
{
|
||||
return nm_dedup_multi_entry_get_obj (nm_platform_lookup_entry (platform,
|
||||
cache_id_type,
|
||||
obj));
|
||||
}
|
||||
|
||||
static inline const NMDedupMultiHeadEntry *
|
||||
nm_platform_lookup_obj_type (NMPlatform *platform,
|
||||
NMPObjectType obj_type)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue