summary refs log tree commit diff
path: root/src/core/nm-l3cfg.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/nm-l3cfg.c')
-rw-r--r--src/core/nm-l3cfg.c69
1 files changed, 62 insertions, 7 deletions
diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c
index fb48b860..a9aa506d 100644
--- a/src/core/nm-l3cfg.c
+++ b/src/core/nm-l3cfg.c
@@ -372,6 +372,8 @@ G_DEFINE_TYPE(NML3Cfg, nm_l3cfg, G_TYPE_OBJECT)
 #define _NETNS_WATCHER_IP_ADDR_TAG(self, addr_family) \
     ((gconstpointer) & (((char *) self)[1 + NM_IS_IPv4(addr_family)]))
 
+#define _NETNS_WATCHER_MPTCP_IPV6_TAG(self) ((gconstpointer) & (((char *) self)[3]))
+
 /*****************************************************************************/
 
 #define _NMLOG_DOMAIN      LOGD_CORE
@@ -4960,7 +4962,7 @@ next:
     }
 
 out:
-    nm_netns_watcher_remove_all(self->priv.netns, TAG, FALSE);
+    nm_netns_watcher_remove_dirty(self->priv.netns, TAG);
 }
 /*****************************************************************************/
 
@@ -4973,6 +4975,30 @@ _global_tracker_mptcp_untrack(NML3Cfg *self, int addr_family)
                                           TRUE);
 }
 
+static void
+mptcp_ipv6_addr_cb(NMNetns                       *netns,
+                   NMNetnsWatcherType             watcher_type,
+                   const NMNetnsWatcherData      *watcher_data,
+                   gconstpointer                  tag,
+                   const NMNetnsWatcherEventData *event_data,
+                   gpointer                       user_data)
+{
+    NML3Cfg *self = user_data;
+
+    if (event_data->ip_addr.change_type == NM_PLATFORM_SIGNAL_REMOVED)
+        return;
+
+    nm_assert(NMP_OBJECT_GET_TYPE(event_data->ip_addr.obj) == NMP_OBJECT_TYPE_IP6_ADDRESS);
+
+    if (event_data->ip_addr.obj->ip6_address.n_ifa_flags & IFA_F_TENTATIVE)
+        return;
+
+    /* We are inside the handler for a platform event, we should not
+     * perform other operations on platform synchronously. Schedule a
+     * commit in a idle handler. */
+    nm_l3cfg_commit_on_idle_schedule(self, NM_L3_CFG_COMMIT_TYPE_AUTO);
+}
+
 static gboolean
 _l3_commit_mptcp_af(NML3Cfg          *self,
                     NML3CfgCommitType commit_type,
@@ -5051,6 +5077,8 @@ _l3_commit_mptcp_af(NML3Cfg          *self,
                                                         self->priv.p->combined_l3cd_commited,
                                                         addr_family,
                                                         (const NMPlatformIPAddress **) &addr) {
+                const NMPObject *obj;
+
                 /* We want to evaluate the  with-{loopback,link_local}-{4,6} flags based on the actual
                  * ifa_scope that the address will have once we configure it.
                  * "addr" is an address we want to configure, we expect that it will
@@ -5077,6 +5105,34 @@ _l3_commit_mptcp_af(NML3Cfg          *self,
                     break;
                 }
 
+                obj = nm_platform_ip_address_get(self->priv.platform,
+                                                 addr_family,
+                                                 self->priv.ifindex,
+                                                 addr);
+                if (!obj) {
+                    /* The address is not yet configured in platform, typically due to
+                     * IPv4 DAD; skip it for now otherwise the kernel will try to use
+                     * the endpoint, it will fail, and it will never try it again. */
+                    goto skip_addr;
+                }
+                if (!IS_IPv4 && (obj->ip6_address.n_ifa_flags & IFA_F_TENTATIVE)) {
+                    NMNetnsWatcherData watcher_data = {};
+
+                    /* The endpoint is not usable when the address is tentative.
+                     * Watch the address until it becomes non-tentative and then
+                     * schedule a new commit. */
+                    watcher_data.ip_addr.addr.addr_family = AF_INET6;
+                    watcher_data.ip_addr.addr.addr.addr6  = addr->a6.address;
+
+                    nm_netns_watcher_add(self->priv.netns,
+                                         NM_NETNS_WATCHER_TYPE_IP_ADDR,
+                                         &watcher_data,
+                                         _NETNS_WATCHER_MPTCP_IPV6_TAG(self),
+                                         mptcp_ipv6_addr_cb,
+                                         self);
+                    goto skip_addr;
+                }
+
                 a.addr = nm_ip_addr_init(addr_family, addr->ax.address_ptr);
 
                 /* We track the address with different priorities, that depends
@@ -5105,6 +5161,8 @@ skip_addr:
             }
         }
 
+        nm_netns_watcher_remove_dirty(self->priv.netns, _NETNS_WATCHER_MPTCP_IPV6_TAG(self));
+
         if (!any_tracked) {
             /* We need to make it known that this ifindex is used. Track a dummy object. */
             if (nmp_global_tracker_track(
@@ -5841,12 +5899,9 @@ finalize(GObject *object)
     gboolean changed;
 
     if (self->priv.netns) {
-        nm_netns_watcher_remove_all(self->priv.netns,
-                                    _NETNS_WATCHER_IP_ADDR_TAG(self, AF_INET),
-                                    TRUE);
-        nm_netns_watcher_remove_all(self->priv.netns,
-                                    _NETNS_WATCHER_IP_ADDR_TAG(self, AF_INET6),
-                                    TRUE);
+        nm_netns_watcher_remove_all(self->priv.netns, _NETNS_WATCHER_IP_ADDR_TAG(self, AF_INET));
+        nm_netns_watcher_remove_all(self->priv.netns, _NETNS_WATCHER_IP_ADDR_TAG(self, AF_INET6));
+        nm_netns_watcher_remove_all(self->priv.netns, _NETNS_WATCHER_MPTCP_IPV6_TAG(self));
     }
 
     nm_prioq_destroy(&self->priv.p->failedobj_prioq);