mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-08 16:30:23 +01:00
platform: add mechanism to report removed IPv6 addresses that failed DAD
This commit is contained in:
parent
06bf0707ee
commit
3f84ee27a0
3 changed files with 111 additions and 2 deletions
|
|
@ -7672,6 +7672,14 @@ _rtnl_handle_msg(NMPlatform *platform, const struct nl_msg_lite *msg)
|
|||
}
|
||||
|
||||
case RTM_DELADDR:
|
||||
if (NMP_OBJECT_GET_TYPE(obj) == NMP_OBJECT_TYPE_IP6_ADDRESS) {
|
||||
const NMPlatformIP6Address *ip6 = NMP_OBJECT_CAST_IP6_ADDRESS(obj);
|
||||
|
||||
if (ip6->n_ifa_flags & IFA_F_DADFAILED) {
|
||||
nm_platform_ip6_dadfailed_set(platform, ip6->ifindex, &ip6->address, TRUE);
|
||||
}
|
||||
}
|
||||
/* fall-through */
|
||||
case RTM_DELLINK:
|
||||
case RTM_DELQDISC:
|
||||
case RTM_DELROUTE:
|
||||
|
|
|
|||
|
|
@ -195,6 +195,7 @@ typedef struct _NMPlatformPrivate {
|
|||
guint ip4_dev_route_blacklist_check_id;
|
||||
guint ip4_dev_route_blacklist_gc_timeout_id;
|
||||
GHashTable *ip4_dev_route_blacklist_hash;
|
||||
CList ip6_dadfailed_lst_head;
|
||||
NMDedupMultiIndex *multi_idx;
|
||||
NMPCache *cache;
|
||||
} NMPlatformPrivate;
|
||||
|
|
@ -3607,6 +3608,9 @@ nm_platform_ip6_address_add(NMPlatform *self,
|
|||
_LOG3D("address: adding or updating IPv6 address: %s",
|
||||
nm_platform_ip6_address_to_string(&addr, sbuf, sizeof(sbuf)));
|
||||
}
|
||||
|
||||
nm_platform_ip6_dadfailed_set(self, ifindex, &address, FALSE);
|
||||
|
||||
return klass
|
||||
->ip6_address_add(self, ifindex, address, plen, peer_address, lifetime, preferred, flags);
|
||||
}
|
||||
|
|
@ -9089,6 +9093,92 @@ nm_platform_netns_push(NMPlatform *self, NMPNetns **netns)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
struct in6_addr address;
|
||||
CList lst;
|
||||
gint64 timestamp_nsec;
|
||||
int ifindex;
|
||||
} IP6DadFailedAddr;
|
||||
|
||||
static void
|
||||
ip6_dadfailed_addr_free(IP6DadFailedAddr *addr)
|
||||
{
|
||||
c_list_unlink_stale(&addr->lst);
|
||||
nm_g_slice_free(addr);
|
||||
}
|
||||
|
||||
static void
|
||||
ip6_dadfailed_prune_old(NMPlatform *self, gint64 now_nsec)
|
||||
{
|
||||
NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self);
|
||||
IP6DadFailedAddr *addr;
|
||||
IP6DadFailedAddr *safe;
|
||||
|
||||
c_list_for_each_entry_safe (addr, safe, &priv->ip6_dadfailed_lst_head, lst) {
|
||||
if (addr->timestamp_nsec + (10 * NM_UTILS_NSEC_PER_SEC) > now_nsec)
|
||||
break;
|
||||
ip6_dadfailed_addr_free(addr);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_platform_ip6_dadfailed_check(NMPlatform *self, int ifindex, const struct in6_addr *ip6)
|
||||
{
|
||||
NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self);
|
||||
IP6DadFailedAddr *addr;
|
||||
|
||||
ip6_dadfailed_prune_old(self, nm_utils_get_monotonic_timestamp_nsec());
|
||||
|
||||
c_list_for_each_entry_prev (addr, &priv->ip6_dadfailed_lst_head, lst) {
|
||||
if (addr->ifindex == ifindex && IN6_ARE_ADDR_EQUAL(&addr->address, ip6)) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* If an IPv6 address fails DAD and has infinite lifetime, kernel just
|
||||
* sets the DADFAILED flag. However when the address has a finite
|
||||
* lifetime kernel deletes it immediately and the RTM_DELLINK netlink
|
||||
* message contains the DADFAILED flag. In the second case, we remove
|
||||
* the address from the platform cache and there is no way for
|
||||
* platform's clients to check whether DAD failed. To work around
|
||||
* this, we store all deleted-with-DADFAILED addresses and provide a
|
||||
* mechanism to access them.
|
||||
*/
|
||||
void
|
||||
nm_platform_ip6_dadfailed_set(NMPlatform *self,
|
||||
int ifindex,
|
||||
const struct in6_addr *ip6,
|
||||
gboolean failed)
|
||||
{
|
||||
NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self);
|
||||
gint64 now_nsec = nm_utils_get_monotonic_timestamp_nsec();
|
||||
IP6DadFailedAddr *addr;
|
||||
IP6DadFailedAddr *safe;
|
||||
|
||||
ip6_dadfailed_prune_old(self, now_nsec);
|
||||
|
||||
if (failed) {
|
||||
addr = g_slice_new(IP6DadFailedAddr);
|
||||
*addr = (IP6DadFailedAddr){
|
||||
.address = *ip6,
|
||||
.ifindex = ifindex,
|
||||
.timestamp_nsec = now_nsec,
|
||||
};
|
||||
c_list_link_tail(&priv->ip6_dadfailed_lst_head, &addr->lst);
|
||||
} else {
|
||||
c_list_for_each_entry_safe (addr, safe, &priv->ip6_dadfailed_lst_head, lst) {
|
||||
if (addr->ifindex == ifindex && IN6_ARE_ADDR_EQUAL(&addr->address, ip6)) {
|
||||
ip6_dadfailed_addr_free(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
const _NMPlatformVTableRouteUnion nm_platform_vtable_route = {
|
||||
.v4 =
|
||||
{
|
||||
|
|
@ -9174,8 +9264,8 @@ constructor(GType type, guint n_construct_params, GObjectConstructParam *constru
|
|||
priv = NM_PLATFORM_GET_PRIVATE(self);
|
||||
|
||||
priv->multi_idx = nm_dedup_multi_index_new();
|
||||
|
||||
priv->cache = nmp_cache_new(priv->multi_idx, priv->use_udev);
|
||||
priv->cache = nmp_cache_new(priv->multi_idx, priv->use_udev);
|
||||
c_list_init(&priv->ip6_dadfailed_lst_head);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
|
@ -9185,6 +9275,7 @@ finalize(GObject *object)
|
|||
{
|
||||
NMPlatform *self = NM_PLATFORM(object);
|
||||
NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self);
|
||||
IP6DadFailedAddr *addr;
|
||||
|
||||
nm_clear_g_source(&priv->ip4_dev_route_blacklist_check_id);
|
||||
nm_clear_g_source(&priv->ip4_dev_route_blacklist_gc_timeout_id);
|
||||
|
|
@ -9193,6 +9284,10 @@ finalize(GObject *object)
|
|||
nm_dedup_multi_index_unref(priv->multi_idx);
|
||||
nmp_cache_free(priv->cache);
|
||||
|
||||
while ((addr = c_list_first_entry(&priv->ip6_dadfailed_lst_head, IP6DadFailedAddr, lst))) {
|
||||
ip6_dadfailed_addr_free(addr);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS(nm_platform_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2386,4 +2386,10 @@ nm_platform_mptcp_addr_update(NMPlatform *self, NMOptionBool add, const NMPlatfo
|
|||
|
||||
GPtrArray *nm_platform_mptcp_addrs_dump(NMPlatform *self);
|
||||
|
||||
gboolean nm_platform_ip6_dadfailed_check(NMPlatform *self, int ifindex, const struct in6_addr *ip6);
|
||||
void nm_platform_ip6_dadfailed_set(NMPlatform *self,
|
||||
int ifindex,
|
||||
const struct in6_addr *ip6,
|
||||
gboolean failed);
|
||||
|
||||
#endif /* __NETWORKMANAGER_PLATFORM_H__ */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue