summaryrefslogtreecommitdiff
path: root/src/devices/nm-device.c
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2020-09-07 16:11:59 +0200
committerThomas Haller <thaller@redhat.com>2020-09-07 16:11:59 +0200
commit19c8332f05f4c0680f496282e3396aef7d2a91f0 (patch)
tree2eff1c8073173b13555cd32b886c4ca44f792f13 /src/devices/nm-device.c
parent97c1bed37e46906f5450f53333e903c679f47ffe (diff)
parent4038a8ff993f9fb30611d76a6937c6ff3e730966 (diff)
downloadNetworkManager-19c8332f05f4c0680f496282e3396aef7d2a91f0.tar.gz
l3cfg: merge branch 'th/l3cfg-7'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/618
Diffstat (limited to 'src/devices/nm-device.c')
-rw-r--r--src/devices/nm-device.c359
1 files changed, 335 insertions, 24 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 0f47a2c3ba..53a3085bea 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -28,6 +28,8 @@
#include "nm-libnm-core-intern/nm-ethtool-utils.h"
#include "nm-libnm-core-intern/nm-common-macros.h"
#include "nm-device-private.h"
+#include "nm-l3cfg.h"
+#include "nm-l3-config-data.h"
#include "NetworkManagerUtils.h"
#include "nm-manager.h"
#include "platform/nm-platform.h"
@@ -134,6 +136,21 @@ typedef struct {
typedef void (*AcdCallback) (NMDevice *, NMIP4Config **, gboolean);
+typedef enum {
+ /* The various NML3ConfigData types that we track explicitly. Note that
+ * their relative order matters: higher numbers in this enum means more
+ * important (and during merge overwrites other settings). */
+ L3_CONFIG_DATA_TYPE_LL_4,
+ L3_CONFIG_DATA_TYPE_AC_6,
+ L3_CONFIG_DATA_TYPE_DHCP_4,
+ L3_CONFIG_DATA_TYPE_DHCP_6,
+ L3_CONFIG_DATA_TYPE_DEV_4,
+ L3_CONFIG_DATA_TYPE_DEV_6,
+ L3_CONFIG_DATA_TYPE_SETTING,
+ _L3_CONFIG_DATA_TYPE_NUM,
+ _L3_CONFIG_DATA_TYPE_NONE,
+} L3ConfigDataType;
+
typedef struct {
AcdCallback callback;
NMDevice *device;
@@ -286,23 +303,29 @@ typedef struct _NMDevicePrivate {
char * path;
union {
- NML3Cfg *const l3cfg;
- NML3Cfg *l3cfg_;
+ const char *const iface;
+ char * iface_;
};
-
union {
- NML3Cfg *const ip_l3cfg;
- NML3Cfg *ip_l3cfg_;
+ const char *const ip_iface;
+ char * ip_iface_;
};
union {
- const char *const iface;
- char * iface_;
+ NML3Cfg *const l3cfg;
+ NML3Cfg *l3cfg_;
};
+
union {
const int ifindex;
int ifindex_;
};
+ union {
+ const int ip_ifindex;
+ int ip_ifindex_;
+ };
+
+ const NML3ConfigData *l3cds[_L3_CONFIG_DATA_TYPE_NUM];
int parent_ifindex;
@@ -320,14 +343,6 @@ typedef struct _NMDevicePrivate {
bool update_ip_config_completed_v4:1;
bool update_ip_config_completed_v6:1;
- union {
- const char *const ip_iface;
- char * ip_iface_;
- };
- union {
- const int ip_ifindex;
- int ip_ifindex_;
- };
NMDeviceType type;
char * type_desc;
NMLinkType link_type;
@@ -419,6 +434,14 @@ typedef struct _NMDevicePrivate {
* in the future. This is used to extend the grace period in this particular case. */
gint64 carrier_wait_until_ms;
+ union {
+ struct {
+ NML3ConfigMergeFlags l3config_merge_flags_6;
+ NML3ConfigMergeFlags l3config_merge_flags_4;
+ };
+ NML3ConfigMergeFlags l3config_merge_flags_x[2];
+ };
+
bool carrier:1;
bool ignore_carrier:1;
@@ -435,6 +458,8 @@ typedef struct _NMDevicePrivate {
bool v4_route_table_initialized:1;
bool v6_route_table_initialized:1;
+ bool l3config_merge_flags_has:1;
+
bool v4_route_table_all_sync_before:1;
bool v6_route_table_all_sync_before:1;
@@ -678,6 +703,10 @@ static void nm_device_slave_notify_release (NMDevice *self, NMDeviceStateReason
static void addrconf6_start_with_link_ready (NMDevice *self);
static gboolean linklocal6_start (NMDevice *self);
+static guint32 default_route_metric_penalty_get (NMDevice *self, int addr_family);
+
+static guint get_ipv4_dad_timeout (NMDevice *self);
+
static void _carrier_wait_check_queued_act_request (NMDevice *self);
static gint64 _get_carrier_wait_ms (NMDevice *self);
@@ -1233,6 +1262,21 @@ nm_device_ip_config_new (NMDevice *self, int addr_family)
: (gpointer) nm_device_ip6_config_new (self);
}
+NML3ConfigData *
+nm_device_create_l3_config_data (NMDevice *self)
+{
+ int ifindex;
+
+ nm_assert (NM_IS_DEVICE (self));
+
+ ifindex = nm_device_get_ip_ifindex (self);
+ if (ifindex <= 0)
+ g_return_val_if_reached (NULL);
+
+ return nm_l3_config_data_new (nm_device_get_multi_index (self),
+ ifindex);
+}
+
static void
applied_config_clear (AppliedConfig *config)
{
@@ -1755,6 +1799,246 @@ _set_ip_state (NMDevice *self, int addr_family, NMDeviceIPState new_state)
/*****************************************************************************/
+static L3ConfigDataType
+_dev_l3_config_data_tag_to_type (NMDevice *self,
+ gconstpointer tag)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+ int d;
+
+ if ( tag < ((gpointer) &priv->l3cds[0])
+ || tag >= ((gpointer) &priv->l3cds[G_N_ELEMENTS (priv->l3cds)]))
+ return _L3_CONFIG_DATA_TYPE_NONE;
+
+ d = ((const NML3ConfigData **) tag) - (&priv->l3cds[0]);
+
+ nm_assert (d >= 0);
+ nm_assert (d < _L3_CONFIG_DATA_TYPE_NUM);
+ nm_assert (tag == &priv->l3cds[d]);
+ return d;
+}
+
+static NML3ConfigMergeFlags
+_dev_l3_get_merge_flags (NMDevice *self,
+ L3ConfigDataType type)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+ NML3ConfigMergeFlags flags;
+ NMConnection *connection;
+ NMSettingIPConfig *s_ip;
+
+ if (G_UNLIKELY (!priv->l3config_merge_flags_has)) {
+ int IS_IPv4;
+
+ connection = nm_device_get_applied_connection (self);
+
+ for (IS_IPv4 = 0; IS_IPv4 < 2; IS_IPv4++) {
+ flags = NM_L3_CONFIG_MERGE_FLAGS_NONE;
+
+ if ( connection
+ && (s_ip = nm_connection_get_setting_ip_config (connection, IS_IPv4 ? AF_INET : AF_INET6))) {
+
+ if (nm_setting_ip_config_get_ignore_auto_routes (s_ip))
+ flags |= NM_L3_CONFIG_MERGE_FLAGS_NO_ROUTES;
+
+ if (nm_setting_ip_config_get_ignore_auto_dns (s_ip))
+ flags |= NM_L3_CONFIG_MERGE_FLAGS_NO_DNS;
+
+ if ( nm_setting_ip_config_get_never_default (s_ip)
+ || nm_setting_ip_config_get_gateway (s_ip)) {
+ /* if the connection has an explicit gateway, we also ignore
+ * the default routes from other sources. */
+ flags |= NM_L3_CONFIG_MERGE_FLAGS_NO_DEFAULT_ROUTES;
+ }
+ }
+
+ priv->l3config_merge_flags_x[IS_IPv4] = flags;
+ }
+ priv->l3config_merge_flags_has = TRUE;
+ }
+
+ switch (type) {
+
+ case L3_CONFIG_DATA_TYPE_SETTING:
+ case L3_CONFIG_DATA_TYPE_LL_4:
+ return NM_L3_CONFIG_MERGE_FLAGS_NONE;
+
+ case L3_CONFIG_DATA_TYPE_DHCP_4:
+ case L3_CONFIG_DATA_TYPE_DEV_4:
+ return priv->l3config_merge_flags_4;
+
+ case L3_CONFIG_DATA_TYPE_AC_6:
+ case L3_CONFIG_DATA_TYPE_DHCP_6:
+ case L3_CONFIG_DATA_TYPE_DEV_6:
+ return priv->l3config_merge_flags_6;
+
+ case _L3_CONFIG_DATA_TYPE_NUM:
+ case _L3_CONFIG_DATA_TYPE_NONE:
+ break;
+ }
+ return nm_assert_unreachable_val (NM_L3_CONFIG_MERGE_FLAGS_NONE);
+}
+
+_nm_unused /* FIXME(l3cfg) */
+static gboolean
+_dev_l3_register_l3cds_set_one (NMDevice *self,
+ L3ConfigDataType l3cd_type,
+ const NML3ConfigData *l3cd)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+ nm_auto_unref_l3cd const NML3ConfigData *l3cd_old_free = NULL;
+ const NML3ConfigData *l3cd_old;
+ gboolean changed = FALSE;
+
+ l3cd_old = priv->l3cds[l3cd_type];
+ if (l3cd != priv->l3cds[l3cd_type]) {
+ l3cd_old_free = g_steal_pointer (&priv->l3cds[l3cd_type]);
+ if (l3cd)
+ priv->l3cds[l3cd_type] = nm_l3_config_data_ref_and_seal (l3cd);
+ }
+
+ if (priv->l3cfg) {
+ if (nm_l3cfg_add_config (priv->l3cfg,
+ &priv->l3cds[l3cd_type],
+ FALSE,
+ priv->l3cds[l3cd_type],
+ l3cd_type,
+ default_route_metric_penalty_get (self, AF_INET),
+ default_route_metric_penalty_get (self, AF_INET6),
+ get_ipv4_dad_timeout (self),
+ _dev_l3_get_merge_flags (self, l3cd_type)))
+ changed = TRUE;
+
+ if ( l3cd_old
+ && l3cd_old != l3cd) {
+ if (nm_l3cfg_remove_config (priv->l3cfg, &priv->l3cds[l3cd_type], l3cd_old))
+ changed = TRUE;
+ }
+ }
+
+ return changed;
+}
+
+static gboolean
+_dev_l3_register_l3cds (NMDevice *self,
+ NML3Cfg *l3cfg,
+ gboolean do_add /* else remove */)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+ guint32 default_route_penalty_4 = 0;
+ guint32 default_route_penalty_6 = 0;
+ guint32 acd_timeout_msec = 0;
+ gboolean is_external;
+ gboolean changed;
+ int i;
+
+ if (!l3cfg)
+ return FALSE;
+
+ is_external = nm_device_sys_iface_state_is_external (self);
+ if (!is_external) {
+ default_route_penalty_4 = default_route_metric_penalty_get (self, AF_INET);
+ default_route_penalty_6 = default_route_metric_penalty_get (self, AF_INET6);
+ acd_timeout_msec = get_ipv4_dad_timeout (self);
+ }
+
+ changed = FALSE;
+ for (i = 0; i < G_N_ELEMENTS (priv->l3cds); i++) {
+ if (!priv->l3cds[i])
+ continue;
+ if (!do_add) {
+ if (nm_l3cfg_remove_config (l3cfg, &priv->l3cds[i], priv->l3cds[i]))
+ changed = TRUE;
+ continue;
+ }
+ if (is_external)
+ continue;
+ if (nm_l3cfg_add_config (l3cfg,
+ &priv->l3cds[i],
+ FALSE,
+ priv->l3cds[i],
+ i,
+ default_route_penalty_4,
+ default_route_penalty_6,
+ acd_timeout_msec,
+ _dev_l3_get_merge_flags (self, i)))
+ changed = TRUE;
+ }
+
+ return changed;
+}
+
+_nm_unused /* FIXME(l3cfg) */
+static gboolean
+_dev_l3_platform_commit (NMDevice *self)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+ gboolean success;
+
+ if (!priv->l3cfg)
+ return FALSE;
+
+ if (nm_device_sys_iface_state_is_external (self))
+ return TRUE;
+
+ success = nm_l3cfg_platform_commit (priv->l3cfg,
+ nm_device_sys_iface_state_is_external_or_assume (self)
+ ? NM_L3_CFG_COMMIT_TYPE_ASSUME
+ : NM_L3_CFG_COMMIT_TYPE_UPDATE,
+ AF_UNSPEC,
+ NULL);
+ return success;
+}
+
+static void
+_dev_l3_cfg_acd_maybe_comlete (NMDevice *self)
+{
+ /* FIXME(l3cfg) */
+}
+
+static void
+_dev_l3_cfg_notify_cb (NML3Cfg *l3cfg,
+ int notify_type_i,
+ const NML3ConfigNotifyPayload *payload,
+ NMDevice *self)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+
+ nm_assert (l3cfg == priv->l3cfg);
+
+ switch ((NML3ConfigNotifyType) notify_type_i) {
+ case NM_L3_CONFIG_NOTIFY_TYPE_ACD_FAILED: {
+ const NML3ConfigNotifyPayloadAcdFailedSource *sources = payload->acd_failed.sources;
+ guint sources_len = payload->acd_failed.sources_len;
+ guint i;
+
+ for (i = 0; i < sources_len; i++) {
+ L3ConfigDataType l3cd_type = _dev_l3_config_data_tag_to_type (self, sources[i].tag);
+
+ if (NM_IN_SET (l3cd_type, L3_CONFIG_DATA_TYPE_DHCP_4)) {
+ nm_dhcp_client_decline (priv->dhcp_data_4.client, "Address conflict detected", NULL);
+ nm_device_ip_method_failed (self, AF_INET,
+ NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE);
+ return;
+ }
+ }
+ _dev_l3_cfg_acd_maybe_comlete (self);
+ return;
+ }
+ case NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED:
+ _dev_l3_cfg_acd_maybe_comlete (self);
+ return;
+ case NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED:
+ /* FIXME(l3cfg) */
+ return;
+ case _NM_L3_CONFIG_NOTIFY_TYPE_NUM:
+ break;
+ }
+ nm_assert_not_reached ();
+}
+
+/*****************************************************************************/
+
const char *
nm_device_get_udi (NMDevice *self)
{
@@ -1776,7 +2060,8 @@ _set_ifindex (NMDevice *self, int ifindex, gboolean is_ip_ifindex)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
gs_unref_object NML3Cfg *l3cfg_old = NULL;
- NML3Cfg **p_l3cfg;
+ gboolean l3_changed;
+ int ip_ifindex_new;
int *p_ifindex;
if (ifindex < 0)
@@ -1791,24 +2076,47 @@ _set_ifindex (NMDevice *self, int ifindex, gboolean is_ip_ifindex)
*p_ifindex = ifindex;
- p_l3cfg = is_ip_ifindex
- ? &priv->ip_l3cfg_
- : &priv->l3cfg_;
+ ip_ifindex_new = nm_device_get_ip_ifindex (self);
- l3cfg_old = g_steal_pointer (p_l3cfg);
- if (ifindex > 0)
- *p_l3cfg = nm_netns_access_l3cfg (priv->netns, ifindex);
+ if (priv->l3cfg) {
+ if ( ip_ifindex_new <= 0
+ || ip_ifindex_new != nm_l3cfg_get_ifindex (priv->l3cfg)) {
+ g_signal_handlers_disconnect_by_func (priv->l3cfg,
+ G_CALLBACK (_dev_l3_cfg_notify_cb),
+ self);
+ l3cfg_old = g_steal_pointer (&priv->l3cfg_);
+ }
+ }
+ if ( !priv->l3cfg
+ && ip_ifindex_new > 0) {
+ priv->l3cfg_ = nm_netns_access_l3cfg (priv->netns, ip_ifindex_new);
+
+ g_signal_connect (priv->l3cfg,
+ NM_L3CFG_SIGNAL_NOTIFY,
+ G_CALLBACK (_dev_l3_cfg_notify_cb),
+ self);
+ }
_LOGD (LOGD_DEVICE,
"ifindex: set %sifindex %d%s%s%s%s%s%s",
is_ip_ifindex ? "ip-" : "",
ifindex,
- NM_PRINT_FMT_QUOTED (l3cfg_old, " (old-l3cfg: ", nm_hash_obfuscated_ptr_str_a (l3cfg_old), ")", ""),
- NM_PRINT_FMT_QUOTED (*p_l3cfg, " (l3cfg: ", nm_hash_obfuscated_ptr_str_a (*p_l3cfg), ")", ""));
+ NM_PRINT_FMT_QUOTED (l3cfg_old && l3cfg_old != priv->l3cfg, " (old-l3cfg: ", nm_hash_obfuscated_ptr_str_a (l3cfg_old), ")", ""),
+ NM_PRINT_FMT_QUOTED (priv->l3cfg && l3cfg_old != priv->l3cfg, " (l3cfg: ", nm_hash_obfuscated_ptr_str_a (priv->l3cfg), ")", ""));
if (!is_ip_ifindex)
_notify (self, PROP_IFINDEX);
+ l3_changed = FALSE;
+ if (_dev_l3_register_l3cds (self, priv->l3cfg, TRUE))
+ l3_changed = TRUE;
+ if (_dev_l3_register_l3cds (self, l3cfg_old, FALSE))
+ l3_changed = TRUE;
+
+ if (l3_changed) {
+ /* FIXME(l3cfg) */
+ }
+
return TRUE;
}
@@ -7089,6 +7397,7 @@ activate_stage1_device_prepare (NMDevice *self)
priv->v4_route_table_initialized = FALSE;
priv->v6_route_table_initialized = FALSE;
+ priv->l3config_merge_flags_has = FALSE;
_set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_NONE);
_set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_NONE);
@@ -12569,6 +12878,7 @@ check_and_reapply_connection (NMDevice *self,
priv->v4_route_table_initialized = FALSE;
priv->v6_route_table_initialized = FALSE;
+ priv->l3config_merge_flags_has = FALSE;
/**************************************************************************
* Reapply changes
@@ -15653,6 +15963,7 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type)
priv->v4_route_table_initialized = FALSE;
priv->v6_route_table_initialized = FALSE;
+ priv->l3config_merge_flags_has = FALSE;
priv->v4_route_table_all_sync_before = FALSE;
priv->v6_route_table_all_sync_before = FALSE;