summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/nm-l3cfg.c69
-rw-r--r--src/core/nm-manager.c22
-rw-r--r--src/core/nm-netns.c19
-rw-r--r--src/core/nm-netns.h4
-rw-r--r--src/core/nm-policy.c35
-rw-r--r--src/nmtui/nmt-page-ip6.c1
6 files changed, 108 insertions, 42 deletions
diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c
index a7189d3e..0d20bf44 100644
--- a/src/core/nm-l3cfg.c
+++ b/src/core/nm-l3cfg.c
@@ -370,6 +370,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
@@ -4764,7 +4766,7 @@ next:
     }
 
 out:
-    nm_netns_watcher_remove_all(self->priv.netns, TAG, FALSE);
+    nm_netns_watcher_remove_dirty(self->priv.netns, TAG);
 }
 /*****************************************************************************/
 
@@ -4777,6 +4779,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,
@@ -4855,6 +4881,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
@@ -4881,6 +4909,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
@@ -4909,6 +4965,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(
@@ -5636,12 +5694,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);
diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c
index b96a9053..03285402 100644
--- a/src/core/nm-manager.c
+++ b/src/core/nm-manager.c
@@ -4536,7 +4536,7 @@ nm_manager_get_best_device_for_connection(NMManager            *self,
                                           NMSettingsConnection *sett_conn,
                                           NMConnection         *connection,
                                           gboolean              for_user_request,
-                                          GHashTable           *unavailable_devices,
+                                          GHashTable           *exclude_devices,
                                           GError              **error)
 {
     NMManagerPrivate       *priv = NM_MANAGER_GET_PRIVATE(self);
@@ -4619,7 +4619,7 @@ nm_manager_get_best_device_for_connection(NMManager            *self,
 
         ac_device = nm_active_connection_get_device(ac);
         if (ac_device
-            && ((unavailable_devices && g_hash_table_contains(unavailable_devices, ac_device))
+            && (nm_g_hash_table_contains(exclude_devices, ac_device)
                 || !nm_device_check_connection_available(ac_device, connection, flags, NULL, NULL)))
             ac_device = NULL;
 
@@ -4635,9 +4635,7 @@ nm_manager_get_best_device_for_connection(NMManager            *self,
                 NMDevice               *ac_device2 = nm_active_connection_get_device(ac2);
                 NMActiveConnectionState ac_state2;
 
-                if (!ac_device2
-                    || (unavailable_devices
-                        && g_hash_table_contains(unavailable_devices, ac_device2))
+                if (!ac_device2 || nm_g_hash_table_contains(exclude_devices, ac_device2)
                     || !nm_device_check_connection_available(ac_device2,
                                                              connection,
                                                              flags,
@@ -4698,7 +4696,19 @@ found_better:
         GError              *local = NULL;
         DeviceActivationPrio prio;
 
-        if (unavailable_devices && g_hash_table_contains(unavailable_devices, device))
+        if (nm_g_hash_table_contains(exclude_devices, device))
+            continue;
+
+        /* During startup, NM performs a cleanup of the ovsdb to remove previous entries.
+         * Before the device is suitable for the connection, it must have ovsdb->ready set
+         * to TRUE. Performing this check in all kind of interfaces is too agressive and leads
+         * to race conditions, e.g when a non-virtual bond port gets a carrier, preventing the
+         * device to be a good candidate for the connection. */
+        if (nm_device_get_device_type(device) == NM_DEVICE_TYPE_OVS_INTERFACE
+            && !nm_device_is_available(device,
+                                       for_user_request
+                                           ? NM_DEVICE_CHECK_DEV_AVAILABLE_FOR_USER_REQUEST
+                                           : NM_DEVICE_CHECK_DEV_AVAILABLE_NONE))
             continue;
 
         /* determine the priority of this device. Currently, this priority is independent
diff --git a/src/core/nm-netns.c b/src/core/nm-netns.c
index ed33d336..4d286561 100644
--- a/src/core/nm-netns.c
+++ b/src/core/nm-netns.c
@@ -1369,8 +1369,8 @@ nm_netns_watcher_remove_handle(NMNetns *self, NMNetnsWatcherHandle *handle)
         g_object_unref(self);
 }
 
-void
-nm_netns_watcher_remove_all(NMNetns *self, gconstpointer tag, gboolean all)
+static void
+watcher_remove(NMNetns *self, gconstpointer tag, gboolean all)
 {
     NMNetnsPrivate       *priv;
     WatcherByTag         *watcher_by_tag;
@@ -1420,6 +1420,21 @@ nm_netns_watcher_remove_all(NMNetns *self, gconstpointer tag, gboolean all)
     }
 }
 
+void
+nm_netns_watcher_remove_all(NMNetns *self, gconstpointer tag)
+{
+    watcher_remove(self, tag, TRUE);
+}
+
+/* Similar to nm_netns_watcher_remove_all(), but removes only watchers
+ * that were marked as "dirty" in a previous call of this function and were
+ * not added back via nm_netns_watcher_add() in the meantime. */
+void
+nm_netns_watcher_remove_dirty(NMNetns *self, gconstpointer tag)
+{
+    watcher_remove(self, tag, FALSE);
+}
+
 /*****************************************************************************/
 
 static void
diff --git a/src/core/nm-netns.h b/src/core/nm-netns.h
index 7725ae79..43e9c781 100644
--- a/src/core/nm-netns.h
+++ b/src/core/nm-netns.h
@@ -98,7 +98,7 @@ void nm_netns_watcher_add(NMNetns                  *self,
                           NMNetnsWatcherCallback    callback,
                           gpointer                  user_data);
 
-void
-nm_netns_watcher_remove_all(NMNetns *self, gconstpointer tag, gboolean all /* or only dirty */);
+void nm_netns_watcher_remove_all(NMNetns *self, gconstpointer tag);
+void nm_netns_watcher_remove_dirty(NMNetns *self, gconstpointer tag);
 
 #endif /* __NM_NETNS_H__ */
diff --git a/src/core/nm-policy.c b/src/core/nm-policy.c
index 05d4d006..57edb69a 100644
--- a/src/core/nm-policy.c
+++ b/src/core/nm-policy.c
@@ -1873,8 +1873,7 @@ unblock_autoconnect_for_children(NMPolicy   *self,
                                  const char *parent_device,
                                  const char *parent_uuid_settings,
                                  const char *parent_uuid_applied,
-                                 const char *parent_mac_addr,
-                                 gboolean    reset_devcon_autoconnect)
+                                 const char *parent_mac_addr)
 {
     NMPolicyPrivate             *priv = NM_POLICY_GET_PRIVATE(self);
     NMSettingsConnection *const *connections;
@@ -1915,10 +1914,8 @@ unblock_autoconnect_for_children(NMPolicy   *self,
                           parent_mac_addr))
             continue;
 
-        if (reset_devcon_autoconnect) {
-            if (nm_manager_devcon_autoconnect_retries_reset(priv->manager, NULL, sett_conn))
-                changed = TRUE;
-        }
+        if (nm_manager_devcon_autoconnect_retries_reset(priv->manager, NULL, sett_conn))
+            changed = TRUE;
 
         /* unblock the devices associated with that connection */
         if (nm_manager_devcon_autoconnect_blocked_reason_set(
@@ -1940,12 +1937,11 @@ static void
 unblock_autoconnect_for_ports(NMPolicy   *self,
                               const char *controller_device,
                               const char *controller_uuid_settings,
-                              const char *controller_uuid_applied,
-                              gboolean    reset_devcon_autoconnect)
+                              const char *controller_uuid_applied)
 {
     NMPolicyPrivate             *priv = NM_POLICY_GET_PRIVATE(self);
     NMSettingsConnection *const *connections;
-    gboolean                     changed;
+    gboolean                     changed = FALSE;
     guint                        i;
 
     _LOGT(LOGD_CORE,
@@ -1959,7 +1955,6 @@ unblock_autoconnect_for_ports(NMPolicy   *self,
                               "\"",
                               ""));
 
-    changed     = FALSE;
     connections = nm_settings_get_connections(priv->settings, NULL);
     for (i = 0; connections[i]; i++) {
         NMSettingsConnection *sett_conn = connections[i];
@@ -1977,10 +1972,8 @@ unblock_autoconnect_for_ports(NMPolicy   *self,
                           controller_uuid_settings))
             continue;
 
-        if (reset_devcon_autoconnect) {
-            if (nm_manager_devcon_autoconnect_retries_reset(priv->manager, NULL, sett_conn))
-                changed = TRUE;
-        }
+        if (nm_manager_devcon_autoconnect_retries_reset(priv->manager, NULL, sett_conn))
+            changed = TRUE;
 
         /* unblock the devices associated with that connection */
         if (nm_manager_devcon_autoconnect_blocked_reason_set(
@@ -2015,7 +2008,7 @@ unblock_autoconnect_for_ports_for_sett_conn(NMPolicy *self, NMSettingsConnection
     controller_uuid_settings = nm_setting_connection_get_uuid(s_con);
     controller_device        = nm_setting_connection_get_interface_name(s_con);
 
-    unblock_autoconnect_for_ports(self, controller_device, controller_uuid_settings, NULL, TRUE);
+    unblock_autoconnect_for_ports(self, controller_device, controller_uuid_settings, NULL);
 }
 
 static void
@@ -2028,7 +2021,6 @@ activate_port_or_children_connections(NMPolicy *self,
     const char   *controller_uuid_applied  = NULL;
     const char   *parent_mac_addr          = NULL;
     NMActRequest *req;
-    gboolean      internal_activation = FALSE;
 
     controller_device = nm_device_get_iface(device);
     nm_assert(controller_device);
@@ -2039,7 +2031,6 @@ activate_port_or_children_connections(NMPolicy *self,
     if (req) {
         NMConnection         *connection;
         NMSettingsConnection *sett_conn;
-        NMAuthSubject        *subject;
 
         sett_conn = nm_active_connection_get_settings_connection(NM_ACTIVE_CONNECTION(req));
         if (sett_conn)
@@ -2051,25 +2042,19 @@ activate_port_or_children_connections(NMPolicy *self,
 
         if (nm_streq0(controller_uuid_settings, controller_uuid_applied))
             controller_uuid_applied = NULL;
-
-        subject = nm_active_connection_get_subject(NM_ACTIVE_CONNECTION(req));
-        internal_activation =
-            subject && (nm_auth_subject_get_subject_type(subject) == NM_AUTH_SUBJECT_TYPE_INTERNAL);
     }
 
     if (!activate_children_connections_only) {
         unblock_autoconnect_for_ports(self,
                                       controller_device,
                                       controller_uuid_settings,
-                                      controller_uuid_applied,
-                                      !internal_activation);
+                                      controller_uuid_applied);
     }
     unblock_autoconnect_for_children(self,
                                      controller_device,
                                      controller_uuid_settings,
                                      controller_uuid_applied,
-                                     parent_mac_addr,
-                                     !internal_activation);
+                                     parent_mac_addr);
 }
 
 static gboolean
diff --git a/src/nmtui/nmt-page-ip6.c b/src/nmtui/nmt-page-ip6.c
index 7e7a48c5..bd29a3a7 100644
--- a/src/nmtui/nmt-page-ip6.c
+++ b/src/nmtui/nmt-page-ip6.c
@@ -29,6 +29,7 @@ static NmtNewtPopupEntry ip6methods[] = {
     {N_("Automatic (DHCP-only)"), NM_SETTING_IP6_CONFIG_METHOD_DHCP},
     {N_("Link-Local"), NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL},
     {N_("Manual"), NM_SETTING_IP6_CONFIG_METHOD_MANUAL},
+    {N_("Shared"), NM_SETTING_IP6_CONFIG_METHOD_SHARED},
     {N_("Disabled"), NM_SETTING_IP6_CONFIG_METHOD_DISABLED},
     {NULL, NULL}};