diff --git a/Makefile.am b/Makefile.am
index 1a6b756a61..45e1488f14 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -965,6 +965,8 @@ introspection_sources = \
introspection/org.freedesktop.NetworkManager.Device.IPTunnel.h \
introspection/org.freedesktop.NetworkManager.Device.Infiniband.c \
introspection/org.freedesktop.NetworkManager.Device.Infiniband.h \
+ introspection/org.freedesktop.NetworkManager.Device.Loopback.c \
+ introspection/org.freedesktop.NetworkManager.Device.Loopback.h \
introspection/org.freedesktop.NetworkManager.Device.Lowpan.c \
introspection/org.freedesktop.NetworkManager.Device.Lowpan.h \
introspection/org.freedesktop.NetworkManager.Device.Macsec.c \
@@ -1052,6 +1054,7 @@ DBUS_INTERFACE_DOCS = \
docs/api/dbus-org.freedesktop.NetworkManager.Device.Generic.xml \
docs/api/dbus-org.freedesktop.NetworkManager.Device.IPTunnel.xml \
docs/api/dbus-org.freedesktop.NetworkManager.Device.Infiniband.xml \
+ docs/api/dbus-org.freedesktop.NetworkManager.Device.Loopback.xml \
docs/api/dbus-org.freedesktop.NetworkManager.Device.Lowpan.xml \
docs/api/dbus-org.freedesktop.NetworkManager.Device.Macsec.xml \
docs/api/dbus-org.freedesktop.NetworkManager.Device.Macvlan.xml \
@@ -1120,6 +1123,7 @@ dbusinterfaces_DATA = \
introspection/org.freedesktop.NetworkManager.Device.Generic.xml \
introspection/org.freedesktop.NetworkManager.Device.IPTunnel.xml \
introspection/org.freedesktop.NetworkManager.Device.Infiniband.xml \
+ introspection/org.freedesktop.NetworkManager.Device.Loopback.xml \
introspection/org.freedesktop.NetworkManager.Device.Lowpan.xml \
introspection/org.freedesktop.NetworkManager.Device.Macsec.xml \
introspection/org.freedesktop.NetworkManager.Device.Macvlan.xml \
@@ -1201,6 +1205,7 @@ src_libnm_core_impl_lib_h_pub_real = \
src/libnm-core-public/nm-setting-ip-tunnel.h \
src/libnm-core-public/nm-setting-ip4-config.h \
src/libnm-core-public/nm-setting-ip6-config.h \
+ src/libnm-core-public/nm-setting-loopback.h \
src/libnm-core-public/nm-setting-macsec.h \
src/libnm-core-public/nm-setting-macvlan.h \
src/libnm-core-public/nm-setting-match.h \
@@ -1280,6 +1285,7 @@ src_libnm_core_impl_lib_c_settings_real = \
src/libnm-core-impl/nm-setting-ip-tunnel.c \
src/libnm-core-impl/nm-setting-ip4-config.c \
src/libnm-core-impl/nm-setting-ip6-config.c \
+ src/libnm-core-impl/nm-setting-loopback.c \
src/libnm-core-impl/nm-setting-macsec.c \
src/libnm-core-impl/nm-setting-macvlan.c \
src/libnm-core-impl/nm-setting-match.c \
@@ -1674,6 +1680,7 @@ libnm_lib_h_pub_real = \
src/libnm-client-public/nm-device-generic.h \
src/libnm-client-public/nm-device-infiniband.h \
src/libnm-client-public/nm-device-ip-tunnel.h \
+ src/libnm-client-public/nm-device-loopback.h \
src/libnm-client-public/nm-device-macsec.h \
src/libnm-client-public/nm-device-macvlan.h \
src/libnm-client-public/nm-device-modem.h \
@@ -1744,6 +1751,7 @@ libnm_lib_c_real = \
src/libnm-client-impl/nm-device-generic.c \
src/libnm-client-impl/nm-device-infiniband.c \
src/libnm-client-impl/nm-device-ip-tunnel.c \
+ src/libnm-client-impl/nm-device-loopback.c \
src/libnm-client-impl/nm-device-macsec.c \
src/libnm-client-impl/nm-device-macvlan.c \
src/libnm-client-impl/nm-device-modem.c \
@@ -2503,6 +2511,8 @@ src_core_libNetworkManager_la_SOURCES = \
src/core/devices/nm-device-infiniband.h \
src/core/devices/nm-device-ip-tunnel.c \
src/core/devices/nm-device-ip-tunnel.h \
+ src/core/devices/nm-device-loopback.c \
+ src/core/devices/nm-device-loopback.h \
src/core/devices/nm-device-macsec.c \
src/core/devices/nm-device-macsec.h \
src/core/devices/nm-device-macvlan.c \
diff --git a/docs/api/Makefile.am b/docs/api/Makefile.am
index c89dbc4494..5553f06968 100644
--- a/docs/api/Makefile.am
+++ b/docs/api/Makefile.am
@@ -54,6 +54,7 @@ content_files = \
dbus-org.freedesktop.NetworkManager.Device.Generic.xml \
dbus-org.freedesktop.NetworkManager.Device.IPTunnel.xml \
dbus-org.freedesktop.NetworkManager.Device.Infiniband.xml \
+ dbus-org.freedesktop.NetworkManager.Device.Loopback.xml \
dbus-org.freedesktop.NetworkManager.Device.Macsec.xml \
dbus-org.freedesktop.NetworkManager.Device.Macvlan.xml \
dbus-org.freedesktop.NetworkManager.Device.Modem.xml \
diff --git a/docs/api/network-manager-docs.xml b/docs/api/network-manager-docs.xml
index 442b05aa7d..d8f4725cf6 100644
--- a/docs/api/network-manager-docs.xml
+++ b/docs/api/network-manager-docs.xml
@@ -193,6 +193,7 @@
+
diff --git a/docs/libnm/libnm-docs.xml b/docs/libnm/libnm-docs.xml
index 11a1b73011..e54fda6c51 100644
--- a/docs/libnm/libnm-docs.xml
+++ b/docs/libnm/libnm-docs.xml
@@ -331,6 +331,7 @@ print ("NetworkManager version " + client.get_version())]]>
+
@@ -380,6 +381,7 @@ print ("NetworkManager version " + client.get_version())]]>
+
diff --git a/introspection/meson.build b/introspection/meson.build
index 7d495f7af3..9a35548842 100644
--- a/introspection/meson.build
+++ b/introspection/meson.build
@@ -17,6 +17,7 @@ ifaces = [
'org.freedesktop.NetworkManager.Device.Generic',
'org.freedesktop.NetworkManager.Device.IPTunnel',
'org.freedesktop.NetworkManager.Device.Infiniband',
+ 'org.freedesktop.NetworkManager.Device.Loopback',
'org.freedesktop.NetworkManager.Device.Lowpan',
'org.freedesktop.NetworkManager.Device.Macsec',
'org.freedesktop.NetworkManager.Device.Macvlan',
diff --git a/introspection/org.freedesktop.NetworkManager.Device.Loopback.xml b/introspection/org.freedesktop.NetworkManager.Device.Loopback.xml
new file mode 100644
index 0000000000..059b5d7e14
--- /dev/null
+++ b/introspection/org.freedesktop.NetworkManager.Device.Loopback.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml
index 301172e4cc..2c1fc85217 100644
--- a/man/NetworkManager.conf.xml
+++ b/man/NetworkManager.conf.xml
@@ -1010,6 +1010,10 @@ ipv6.ip6-privacy=0
removes extraneous routes from the tables.
+
+ loopback.mtu
+ If configured explicitly to 0, the MTU is not reconfigured during device activation unless it is required due to IPv6 constraints. If left unspecified, a DHCP/IPv6 SLAAC provided value is used or the MTU is left unspecified on activation.
+
sriov.autoprobe-drivers
If left unspecified, drivers are autoprobed when the SR-IOV VF gets created.
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 4f5ecb4496..e5c1f743a8 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -13,6 +13,7 @@ src/core/devices/nm-device-ethernet-utils.c
src/core/devices/nm-device-ethernet.c
src/core/devices/nm-device-infiniband.c
src/core/devices/nm-device-ip-tunnel.c
+src/core/devices/nm-device-loopback.c
src/core/devices/nm-device-macvlan.c
src/core/devices/nm-device-tun.c
src/core/devices/nm-device-veth.c
@@ -47,6 +48,7 @@ src/libnm-client-impl/nm-device-ethernet.c
src/libnm-client-impl/nm-device-generic.c
src/libnm-client-impl/nm-device-infiniband.c
src/libnm-client-impl/nm-device-ip-tunnel.c
+src/libnm-client-impl/nm-device-loopback.c
src/libnm-client-impl/nm-device-macvlan.c
src/libnm-client-impl/nm-device-modem.c
src/libnm-client-impl/nm-device-olpc-mesh.c
diff --git a/src/core/devices/nm-device-factory.c b/src/core/devices/nm-device-factory.c
index 41e9480fe5..2f0ae2e8e5 100644
--- a/src/core/devices/nm-device-factory.c
+++ b/src/core/devices/nm-device-factory.c
@@ -398,6 +398,7 @@ nm_device_factory_manager_load_factories(NMDeviceFactoryManagerFactoryFunc callb
_ADD_INTERNAL(nm_ethernet_device_factory_get_type);
_ADD_INTERNAL(nm_infiniband_device_factory_get_type);
_ADD_INTERNAL(nm_ip_tunnel_device_factory_get_type);
+ _ADD_INTERNAL(nm_loopback_device_factory_get_type);
_ADD_INTERNAL(nm_macsec_device_factory_get_type);
_ADD_INTERNAL(nm_macvlan_device_factory_get_type);
_ADD_INTERNAL(nm_ppp_device_factory_get_type);
diff --git a/src/core/devices/nm-device-loopback.c b/src/core/devices/nm-device-loopback.c
new file mode 100644
index 0000000000..129cbb8a85
--- /dev/null
+++ b/src/core/devices/nm-device-loopback.c
@@ -0,0 +1,163 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2022 Red Hat, Inc.
+ */
+
+#include "src/core/nm-default-daemon.h"
+#include "nm-device-loopback.h"
+#include "nm-device-private.h"
+#include "libnm-platform/nm-platform.h"
+#include "nm-device-factory.h"
+#include "nm-setting-loopback.h"
+#include "libnm-core-aux-intern/nm-libnm-core-utils.h"
+
+#define _NMLOG_DEVICE_TYPE NMDeviceLoopback
+#include "nm-device-logging.h"
+
+/*****************************************************************************/
+
+struct _NMDeviceLoopback {
+ NMDevice parent;
+};
+
+struct _NMDeviceLoopbackClass {
+ NMDeviceClass parent;
+};
+
+G_DEFINE_TYPE(NMDeviceLoopback, nm_device_loopback, NM_TYPE_DEVICE)
+
+/*****************************************************************************/
+
+static NMDeviceCapabilities
+get_generic_capabilities(NMDevice *dev)
+{
+ /* In many aspects, loopback is a software device. Still, don't return
+ * NM_DEVICE_CAP_IS_SOFTWARE here, because we cannot delete nor create
+ * such an interface. */
+ return NM_DEVICE_CAP_NONE;
+}
+
+static guint32
+get_configured_mtu(NMDevice *device, NMDeviceMtuSource *out_source, gboolean *out_force)
+{
+ return nm_device_get_configured_mtu_from_connection(device,
+ NM_TYPE_SETTING_LOOPBACK,
+ out_source);
+}
+
+static const char *
+get_auto_ip_config_method(NMDevice *device, int addr_family)
+{
+ return NM_IS_IPv4(addr_family) ? NM_SETTING_IP4_CONFIG_METHOD_MANUAL
+ : NM_SETTING_IP6_CONFIG_METHOD_MANUAL;
+}
+
+static gboolean
+complete_connection(NMDevice *device,
+ NMConnection *connection,
+ const char *specific_object,
+ NMConnection *const *existing_connections,
+ GError **error)
+{
+ nm_utils_complete_generic_with_params(nm_device_get_platform(device),
+ connection,
+ NM_SETTING_LOOPBACK_SETTING_NAME,
+ existing_connections,
+ NULL,
+ _("Loopback connection"),
+ NULL,
+ nm_device_get_ip_iface(device));
+
+ _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_LOOPBACK);
+
+ return TRUE;
+}
+
+static void
+update_connection(NMDevice *device, NMConnection *connection)
+{
+ _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_LOOPBACK);
+}
+
+static gboolean
+can_reapply_change(NMDevice *device,
+ const char *setting_name,
+ NMSetting *s_old,
+ NMSetting *s_new,
+ GHashTable *diffs,
+ GError **error)
+{
+ if (!nm_streq(setting_name, NM_SETTING_LOOPBACK_SETTING_NAME)) {
+ return NM_DEVICE_CLASS(nm_device_loopback_parent_class)
+ ->can_reapply_change(device, setting_name, s_old, s_new, diffs, error);
+ }
+
+ return nm_device_hash_check_invalid_keys(diffs,
+ NM_SETTING_LOOPBACK_SETTING_NAME,
+ error,
+ NM_SETTING_LOOPBACK_MTU);
+}
+
+/*****************************************************************************/
+
+static const NMDBusInterfaceInfoExtended interface_info_device_loopback = {
+ .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT(NM_DBUS_INTERFACE_DEVICE_LOOPBACK, ),
+};
+
+static void
+nm_device_loopback_init(NMDeviceLoopback *self)
+{}
+
+static void
+nm_device_loopback_class_init(NMDeviceLoopbackClass *klass)
+{
+ NMDeviceClass *device_class = NM_DEVICE_CLASS(klass);
+ NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass);
+
+ dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_loopback);
+
+ device_class->connection_type_supported = NM_SETTING_LOOPBACK_SETTING_NAME;
+ device_class->connection_type_check_compatible = NM_SETTING_LOOPBACK_SETTING_NAME;
+ device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_LOOPBACK);
+
+ device_class->complete_connection = complete_connection;
+ device_class->get_generic_capabilities = get_generic_capabilities;
+ device_class->update_connection = update_connection;
+ device_class->act_stage1_prepare_set_hwaddr_ethernet = TRUE;
+ device_class->get_auto_ip_config_method = get_auto_ip_config_method;
+ device_class->get_configured_mtu = get_configured_mtu;
+ device_class->can_reapply_change = can_reapply_change;
+}
+
+/*****************************************************************************/
+
+#define NM_TYPE_LOOPBACK_DEVICE_FACTORY (nm_loopback_device_factory_get_type())
+#define NM_LOOPBACK_DEVICE_FACTORY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_LOOPBACK_DEVICE_FACTORY, NMLoopbackDeviceFactory))
+
+static NMDevice *
+create_device(NMDeviceFactory *factory,
+ const char *iface,
+ const NMPlatformLink *plink,
+ NMConnection *connection,
+ gboolean *out_ignore)
+{
+ return g_object_new(NM_TYPE_DEVICE_LOOPBACK,
+ NM_DEVICE_IFACE,
+ iface,
+ NM_DEVICE_TYPE_DESC,
+ "Loopback",
+ NM_DEVICE_DEVICE_TYPE,
+ NM_DEVICE_TYPE_LOOPBACK,
+ NM_DEVICE_LINK_TYPE,
+ NM_LINK_TYPE_LOOPBACK,
+ NULL);
+}
+
+NM_DEVICE_FACTORY_DEFINE_INTERNAL(
+ LOOPBACK,
+ Loopback,
+ loopback,
+ NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_LOOPBACK)
+ NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_LOOPBACK_SETTING_NAME),
+ factory_class->create_device = create_device;);
diff --git a/src/core/devices/nm-device-loopback.h b/src/core/devices/nm-device-loopback.h
new file mode 100644
index 0000000000..42db8ec050
--- /dev/null
+++ b/src/core/devices/nm-device-loopback.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2022 Red Hat, Inc.
+ */
+
+#ifndef __NETWORKMANAGER_DEVICE_LOOPBACK_H__
+#define __NETWORKMANAGER_DEVICE_LOOPBACK_H__
+
+#include "nm-device-generic.h"
+
+#define NM_TYPE_DEVICE_LOOPBACK (nm_device_loopback_get_type())
+#define NM_DEVICE_LOOPBACK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_LOOPBACK, NMDeviceLoopback))
+#define NM_DEVICE_LOOPBACK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_LOOPBACK, NMDeviceLoopbackClass))
+#define NM_IS_DEVICE_LOOPBACK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_LOOPBACK))
+#define NM_IS_DEVICE_LOOPBACK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_LOOPBACK))
+#define NM_DEVICE_LOOPBACK_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_LOOPBACK, NMDeviceLoopbackClass))
+
+typedef struct _NMDeviceLoopback NMDeviceLoopback;
+typedef struct _NMDeviceLoopbackClass NMDeviceLoopbackClass;
+
+GType nm_device_loopback_get_type(void);
+
+#endif /* __NETWORKMANAGER_DEVICE_LOOPBACK_H__ */
diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c
index 0a046f1e45..78d2809e9b 100644
--- a/src/core/devices/nm-device.c
+++ b/src/core/devices/nm-device.c
@@ -77,6 +77,7 @@
#include "nm-device-generic.h"
#include "nm-device-bridge.h"
+#include "nm-device-loopback.h"
#include "nm-device-vlan.h"
#include "nm-device-vrf.h"
#include "nm-device-wireguard.h"
@@ -1581,6 +1582,9 @@ _prop_get_ipv4_link_local(NMDevice *self)
if (!s_ip4)
return NM_SETTING_IP4_LL_DISABLED;
+ if (NM_IS_DEVICE_LOOPBACK(self))
+ return NM_SETTING_IP4_LL_DISABLED;
+
link_local = nm_setting_ip4_config_get_link_local(s_ip4);
if (link_local == NM_SETTING_IP4_LL_DEFAULT) {
@@ -2734,12 +2738,6 @@ _ethtool_state_set(NMDevice *self)
/*****************************************************************************/
-static gboolean
-is_loopback(NMDevice *self)
-{
- return NM_IS_DEVICE_GENERIC(self) && NM_DEVICE_GET_PRIVATE(self)->ifindex == 1;
-}
-
gboolean
nm_device_is_vpn(NMDevice *self)
{
@@ -4999,6 +4997,9 @@ nm_device_get_route_metric_default(NMDeviceType device_type)
*/
switch (device_type) {
+ case NM_DEVICE_TYPE_LOOPBACK:
+ return 30;
+
/* 50 is also used for VPN plugins (NM_VPN_ROUTE_METRIC_DEFAULT).
*
* Note that returning 50 from this function means that this device-type is
@@ -5419,7 +5420,7 @@ concheck_is_possible(NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- if (!nm_device_is_real(self) || is_loopback(self))
+ if (!nm_device_is_real(self) || NM_IS_DEVICE_LOOPBACK(self))
return FALSE;
/* we enable periodic checks for every device state (except UNKNOWN). Especially with
@@ -7457,11 +7458,6 @@ realize_start_setup(NMDevice *self,
NM_UNMANAGED_EXTERNAL_DOWN,
_dev_unmanaged_is_external_down(self, TRUE));
- /* Unmanaged the loopback device with an explicit NM_UNMANAGED_BY_TYPE flag.
- * Later we might want to manage 'lo' too. Currently, that doesn't work because
- * NetworkManager might down the interface or remove the 127.0.0.1 address. */
- nm_device_set_unmanaged_flags(self, NM_UNMANAGED_BY_TYPE, is_loopback(self));
-
nm_device_set_unmanaged_by_user_udev(self);
nm_device_set_unmanaged_by_user_conf(self);
@@ -7651,9 +7647,9 @@ nm_device_unrealize(NMDevice *self, gboolean remove_resources, GError **error)
nm_device_set_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT, TRUE);
nm_device_set_unmanaged_flags(self,
- NM_UNMANAGED_PARENT | NM_UNMANAGED_BY_TYPE
- | NM_UNMANAGED_USER_UDEV | NM_UNMANAGED_USER_EXPLICIT
- | NM_UNMANAGED_EXTERNAL_DOWN | NM_UNMANAGED_IS_SLAVE,
+ NM_UNMANAGED_PARENT | NM_UNMANAGED_USER_UDEV
+ | NM_UNMANAGED_USER_EXPLICIT | NM_UNMANAGED_EXTERNAL_DOWN
+ | NM_UNMANAGED_IS_SLAVE,
NM_UNMAN_FLAG_OP_FORGET);
nm_device_state_changed(self,
@@ -10795,7 +10791,8 @@ _dev_ipll6_set_llstate(NMDevice *self, NML3IPv6LLState llstate, const struct in6
|| (!priv->ipll_data_6.v6.ipv6ll
&& NM_IN_SET(priv->ipll_data_6.v6.llstate,
NM_L3_IPV6LL_STATE_NONE,
- NM_L3_IPV6LL_STATE_DEFUNCT)));
+ NM_L3_IPV6LL_STATE_DEFUNCT,
+ NM_L3_IPV6LL_STATE_READY)));
switch (priv->ipll_data_6.v6.llstate) {
case NM_L3_IPV6LL_STATE_NONE:
@@ -10878,6 +10875,11 @@ _dev_ipll6_start(NMDevice *self)
if (priv->ipll_data_6.v6.ipv6ll)
return;
+ if (NM_IS_DEVICE_LOOPBACK(self)) {
+ _dev_ipll6_set_llstate(self, NM_L3_IPV6LL_STATE_READY, NULL);
+ return;
+ }
+
if (!priv->l3cfg) {
_LOGD(LOGD_IP6, "linklocal6: no IP link for IPv6");
goto out_fail;
@@ -10989,6 +10991,10 @@ nm_device_get_configured_mtu_from_connection(NMDevice *self,
if (setting)
mtu = nm_setting_wireguard_get_mtu(NM_SETTING_WIREGUARD(setting));
global_property_name = NM_CON_DEFAULT("wireguard.mtu");
+ } else if (setting_type == NM_TYPE_SETTING_LOOPBACK) {
+ if (setting)
+ mtu = nm_setting_loopback_get_mtu(NM_SETTING_LOOPBACK(setting));
+ global_property_name = NM_CON_DEFAULT("loopback.mtu");
} else
g_return_val_if_reached(0);
@@ -14124,7 +14130,6 @@ NM_UTILS_FLAGS2STR_DEFINE(nm_unmanaged_flags2str,
NM_UTILS_FLAGS2STR(NM_UNMANAGED_SLEEPING, "sleeping"),
NM_UTILS_FLAGS2STR(NM_UNMANAGED_QUITTING, "quitting"),
NM_UTILS_FLAGS2STR(NM_UNMANAGED_PARENT, "parent"),
- NM_UTILS_FLAGS2STR(NM_UNMANAGED_BY_TYPE, "by-type"),
NM_UTILS_FLAGS2STR(NM_UNMANAGED_PLATFORM_INIT, "platform-init"),
NM_UTILS_FLAGS2STR(NM_UNMANAGED_USER_EXPLICIT, "user-explicit"),
NM_UTILS_FLAGS2STR(NM_UNMANAGED_BY_DEFAULT, "by-default"),
@@ -17123,10 +17128,12 @@ get_address_for_hostname_dns_lookup(NMDevice *self, int addr_family)
if (head_entry) {
c_list_for_each_entry (iter, &head_entry->lst_entries_head, lst_entries) {
- const NMPlatformIPAddress *addr = NMP_OBJECT_CAST_IP_ADDRESS(iter->obj);
+ const NMPlatformIPXAddress *addr = NMP_OBJECT_CAST_IPX_ADDRESS(iter->obj);
if (IS_IPv4) {
- return g_inet_address_new_from_bytes(addr->address_ptr, G_SOCKET_FAMILY_IPV4);
+ if (nm_ip4_addr_is_loopback(addr->a4.address))
+ continue;
+ return g_inet_address_new_from_bytes(addr->ax.address_ptr, G_SOCKET_FAMILY_IPV4);
}
/* For IPv6 prefer, in order:
@@ -17135,15 +17142,19 @@ get_address_for_hostname_dns_lookup(NMDevice *self, int addr_family)
* - link-local
*/
- if (!IN6_IS_ADDR_LINKLOCAL(addr->address_ptr)) {
- if (!(addr->n_ifa_flags & IFA_F_DEPRECATED)) {
- return g_inet_address_new_from_bytes(addr->address_ptr, G_SOCKET_FAMILY_IPV6);
+ if (IN6_ARE_ADDR_EQUAL(&addr->a6.address, &in6addr_loopback))
+ continue;
+
+ if (!IN6_IS_ADDR_LINKLOCAL(addr->ax.address_ptr)) {
+ if (!(addr->ax.n_ifa_flags & IFA_F_DEPRECATED)) {
+ return g_inet_address_new_from_bytes(addr->ax.address_ptr,
+ G_SOCKET_FAMILY_IPV6);
}
- addr6_nonll = addr->address_ptr;
+ addr6_nonll = addr->ax.address_ptr;
continue;
}
- addr6_ll = addr->address_ptr;
+ addr6_ll = addr->ax.address_ptr;
}
if (addr6_nonll || addr6_ll)
@@ -17543,7 +17554,7 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps
nm_assert(priv->type == NM_DEVICE_TYPE_UNKNOWN);
priv->type = g_value_get_uint(value);
nm_assert(priv->type > NM_DEVICE_TYPE_UNKNOWN);
- nm_assert(priv->type <= NM_DEVICE_TYPE_VRF);
+ nm_assert(priv->type <= NM_DEVICE_TYPE_LOOPBACK);
break;
case PROP_LINK_TYPE:
/* construct-only */
diff --git a/src/core/devices/nm-device.h b/src/core/devices/nm-device.h
index de850e68f2..cbf5929f54 100644
--- a/src/core/devices/nm-device.h
+++ b/src/core/devices/nm-device.h
@@ -562,7 +562,6 @@ void nm_device_copy_ip6_dns_config(NMDevice *self, NMDevice *from_device);
* @NM_UNMANAGED_SLEEPING: %TRUE when unmanaged because NM is sleeping.
* @NM_UNMANAGED_QUITTING: %TRUE when unmanaged because NM is shutting down.
* @NM_UNMANAGED_PARENT: %TRUE when unmanaged due to parent device being unmanaged
- * @NM_UNMANAGED_BY_TYPE: %TRUE for unmanaging device by type, like loopback.
* @NM_UNMANAGED_PLATFORM_INIT: %TRUE when unmanaged because platform link not
* yet initialized. Unrealized device are also unmanaged for this reason.
* @NM_UNMANAGED_USER_EXPLICIT: %TRUE when unmanaged by explicit user decision
@@ -593,20 +592,19 @@ typedef enum {
NM_UNMANAGED_SLEEPING = (1LL << 0),
NM_UNMANAGED_QUITTING = (1LL << 1),
NM_UNMANAGED_PARENT = (1LL << 2),
- NM_UNMANAGED_BY_TYPE = (1LL << 3),
- NM_UNMANAGED_PLATFORM_INIT = (1LL << 4),
- NM_UNMANAGED_USER_EXPLICIT = (1LL << 5),
- NM_UNMANAGED_USER_SETTINGS = (1LL << 6),
+ NM_UNMANAGED_PLATFORM_INIT = (1LL << 3),
+ NM_UNMANAGED_USER_EXPLICIT = (1LL << 4),
+ NM_UNMANAGED_USER_SETTINGS = (1LL << 5),
/* These flags can be non-effective and be overwritten
* by other flags. */
- NM_UNMANAGED_BY_DEFAULT = (1LL << 7),
- NM_UNMANAGED_USER_CONF = (1LL << 8),
- NM_UNMANAGED_USER_UDEV = (1LL << 9),
- NM_UNMANAGED_EXTERNAL_DOWN = (1LL << 10),
- NM_UNMANAGED_IS_SLAVE = (1LL << 11),
+ NM_UNMANAGED_BY_DEFAULT = (1LL << 6),
+ NM_UNMANAGED_USER_CONF = (1LL << 7),
+ NM_UNMANAGED_USER_UDEV = (1LL << 8),
+ NM_UNMANAGED_EXTERNAL_DOWN = (1LL << 9),
+ NM_UNMANAGED_IS_SLAVE = (1LL << 10),
- NM_UNMANAGED_ALL = ((1LL << 12) - 1),
+ NM_UNMANAGED_ALL = ((1LL << 11) - 1),
} NMUnmanagedFlags;
typedef enum {
diff --git a/src/core/dns/nm-dns-systemd-resolved.c b/src/core/dns/nm-dns-systemd-resolved.c
index 5a22fa25ca..e402f244ac 100644
--- a/src/core/dns/nm-dns-systemd-resolved.c
+++ b/src/core/dns/nm-dns-systemd-resolved.c
@@ -418,6 +418,8 @@ prepare_one_interface(NMDnsSystemdResolved *self, const InterfaceConfig *ic)
gboolean has_default_route = FALSE;
guint i;
+ nm_assert(ic->ifindex != NM_LOOPBACK_IFINDEX);
+
g_variant_builder_init(&dns, G_VARIANT_TYPE("(ia(iay))"));
g_variant_builder_add(&dns, "i", ic->ifindex);
g_variant_builder_open(&dns, G_VARIANT_TYPE("a(iay)"));
@@ -708,17 +710,22 @@ update(NMDnsPlugin *plugin,
nm_assert(ifindex == nm_l3_config_data_get_ifindex(ip_data->l3cd));
- ic = g_hash_table_lookup(interfaces, GINT_TO_POINTER(ifindex));
- if (!ic) {
- ic = g_slice_new(InterfaceConfig);
- *ic = (InterfaceConfig){
- .ifindex = ifindex,
- .ip_data_list = g_ptr_array_sized_new(4),
- };
- g_hash_table_insert(interfaces, GINT_TO_POINTER(ifindex), ic);
- }
+ /** systemd-resolved API is per-link, and loopback is not supported.
+ * Unclear what to do about DNS configuration on loopback. Just skip
+ * it here. */
+ if (ifindex != NM_LOOPBACK_IFINDEX) {
+ ic = g_hash_table_lookup(interfaces, GINT_TO_POINTER(ifindex));
+ if (!ic) {
+ ic = g_slice_new(InterfaceConfig);
+ *ic = (InterfaceConfig){
+ .ifindex = ifindex,
+ .ip_data_list = g_ptr_array_sized_new(4),
+ };
+ g_hash_table_insert(interfaces, GINT_TO_POINTER(ifindex), ic);
+ }
- g_ptr_array_add(ic->ip_data_list, ip_data);
+ g_ptr_array_add(ic->ip_data_list, ip_data);
+ }
}
free_pending_updates(self);
diff --git a/src/core/meson.build b/src/core/meson.build
index f3359ad0f5..d830fbdd89 100644
--- a/src/core/meson.build
+++ b/src/core/meson.build
@@ -103,6 +103,7 @@ libNetworkManager = static_library(
'devices/nm-device-generic.c',
'devices/nm-device-infiniband.c',
'devices/nm-device-ip-tunnel.c',
+ 'devices/nm-device-loopback.c',
'devices/nm-device-macsec.c',
'devices/nm-device-macvlan.c',
'devices/nm-device-ppp.c',
diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c
index 963e381b14..f3b7f556f9 100644
--- a/src/core/nm-l3cfg.c
+++ b/src/core/nm-l3cfg.c
@@ -1430,7 +1430,8 @@ _acd_data_free(AcdData *acd_data)
}
static guint
-_acd_data_collect_tracks_data(const AcdData *acd_data,
+_acd_data_collect_tracks_data(NML3Cfg *self,
+ const AcdData *acd_data,
NMTernary dirty_selector,
guint32 *out_best_acd_timeout_msec,
NML3AcdDefendType *out_best_acd_defend_type)
@@ -1466,6 +1467,12 @@ _acd_data_collect_tracks_data(const AcdData *acd_data,
nm_assert(n == 0 || best_acd_defend_type > _NM_L3_ACD_DEFEND_TYPE_NONE);
nm_assert(best_acd_defend_type <= NM_L3_ACD_DEFEND_TYPE_ALWAYS);
+ if (self->priv.ifindex == NM_LOOPBACK_IFINDEX) {
+ /* On loopback interface, ACD makes no sense. We always force the
+ * timeout to zero, which means no ACD. */
+ best_acd_timeout_msec = 0;
+ }
+
NM_SET_OUT(out_best_acd_timeout_msec, n > 0 ? best_acd_timeout_msec : 0u);
NM_SET_OUT(out_best_acd_defend_type, best_acd_defend_type);
return n;
@@ -2313,7 +2320,8 @@ _l3_acd_data_state_change(NML3Cfg *self,
return;
handle_init:
- if (_acd_data_collect_tracks_data(acd_data,
+ if (_acd_data_collect_tracks_data(self,
+ acd_data,
NM_TERNARY_FALSE,
&acd_timeout_msec,
&acd_defend_type)
@@ -2362,7 +2370,8 @@ handle_init:
/* we just did a commit of the IP configuration and now visit all ACD states
* and kick off the necessary actions... */
- if (_acd_data_collect_tracks_data(acd_data,
+ if (_acd_data_collect_tracks_data(self,
+ acd_data,
NM_TERNARY_TRUE,
&acd_timeout_msec,
&acd_defend_type)
@@ -2465,7 +2474,8 @@ handle_init:
/* after a timeout, re-probe the address. This only happens if the caller
* does not deconfigure the address after USED/CONFLICT. But in that case,
* we eventually want to retry. */
- if (_acd_data_collect_tracks_data(acd_data,
+ if (_acd_data_collect_tracks_data(self,
+ acd_data,
NM_TERNARY_TRUE,
&acd_timeout_msec,
&acd_defend_type)
@@ -3713,6 +3723,27 @@ _l3cfg_update_combined_config(NML3Cfg *self,
&hook_data);
}
+ if (self->priv.ifindex == NM_LOOPBACK_IFINDEX) {
+ if (!nm_l3_config_data_lookup_address_4(l3cd,
+ NM_IPV4LO_NETWORK,
+ 8,
+ NM_IPV4LO_NETWORK)) {
+ const NMPlatformIP4Address ip4_address = (NMPlatformIP4Address){
+ .address = NM_IPV4LO_NETWORK,
+ .ifindex = 1,
+ .plen = 8,
+ };
+ nm_l3_config_data_add_address_4(l3cd, &ip4_address);
+ }
+ if (!nm_l3_config_data_lookup_address_6(l3cd, &in6addr_loopback)) {
+ const NMPlatformIP6Address ip6_address = (NMPlatformIP6Address){
+ .address = IN6ADDR_LOOPBACK_INIT,
+ .ifindex = 1,
+ .plen = 128,
+ };
+ nm_l3_config_data_add_address_6(l3cd, &ip6_address);
+ }
+ }
for (i = 0; i < l3_config_datas_len; i++) {
const L3ConfigData *l3cd_data = l3_config_datas_arr[i];
int IS_IPv4;
@@ -4552,6 +4583,28 @@ _l3_commit_one(NML3Cfg *self,
}
}
+ if (self->priv.ifindex == NM_LOOPBACK_IFINDEX) {
+ if (!addresses) {
+ addresses = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref);
+ if (IS_IPv4) {
+ g_ptr_array_add(addresses,
+ nmp_object_new(NMP_OBJECT_TYPE_IP4_ADDRESS,
+ &((const NMPlatformIP4Address){
+ .address = NM_IPV4LO_NETWORK,
+ .ifindex = 1,
+ .plen = 8,
+ })));
+ } else {
+ g_ptr_array_add(addresses,
+ nmp_object_new(NMP_OBJECT_TYPE_IP6_ADDRESS,
+ &((const NMPlatformIP6Address){
+ .address = IN6ADDR_LOOPBACK_INIT,
+ .ifindex = 1,
+ .plen = 128,
+ })));
+ }
+ }
+ }
/* FIXME(l3cfg): need to honor and set nm_l3_config_data_get_ndisc_*(). */
/* FIXME(l3cfg): need to honor and set nm_l3_config_data_get_mtu(). */
@@ -4559,7 +4612,10 @@ _l3_commit_one(NML3Cfg *self,
addr_family,
self->priv.ifindex,
addresses,
- addresses_prune);
+ addresses_prune,
+ self->priv.ifindex == NM_LOOPBACK_IFINDEX
+ ? NMP_IP_ADDRESS_SYNC_FLAGS_NO_AUTO_NOPREFIXROUTE
+ : NMP_IP_ADDRESS_SYNC_FLAGS_NONE);
_nodev_routes_sync(self, addr_family, commit_type, routes_nodev);
diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c
index e21048bf79..aa9c9d5332 100644
--- a/src/core/nm-manager.c
+++ b/src/core/nm-manager.c
@@ -19,6 +19,7 @@
#include "NetworkManagerUtils.h"
#include "devices/nm-device-factory.h"
#include "devices/nm-device-generic.h"
+#include "devices/nm-device-loopback.h"
#include "devices/nm-device.h"
#include "dns/nm-dns-manager.h"
#include "dhcp/nm-dhcp-manager.h"
@@ -1464,8 +1465,11 @@ find_best_device_state(NMManager *manager)
NMActiveConnection *ac;
c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) {
- NMActiveConnectionState ac_state = nm_active_connection_get_state(ac);
+ NMActiveConnectionState ac_state;
+ if (NM_IS_DEVICE_LOOPBACK(nm_active_connection_get_device(ac)))
+ continue;
+ ac_state = nm_active_connection_get_state(ac);
switch (ac_state) {
case NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
if (nm_active_connection_get_default(ac, AF_UNSPEC)) {
@@ -7089,10 +7093,6 @@ nm_manager_write_device_state(NMManager *self, NMDevice *device, int *out_ifinde
ifindex = nm_device_get_ip_ifindex(device);
if (ifindex <= 0)
return FALSE;
- if (ifindex == 1) {
- /* ignore loopback */
- return FALSE;
- }
if (!nm_platform_link_get(priv->platform, ifindex))
return FALSE;
diff --git a/src/libnm-base/nm-base.h b/src/libnm-base/nm-base.h
index ff062a18b8..a8d6b2c892 100644
--- a/src/libnm-base/nm-base.h
+++ b/src/libnm-base/nm-base.h
@@ -393,6 +393,12 @@ typedef struct {
#define NM_BOND_PORT_QUEUE_ID_DEF 0
+/****************************************************************************/
+
+/* ifindex generation is per-net namespace, and loopback is always the first
+ * device in the network namespace, thus any loopback device should get ifindex 1. */
+#define NM_LOOPBACK_IFINDEX 1
+
/*****************************************************************************/
/* NM_CRYPTO_ERROR is part of public API in libnm (implemented in libnm-core).
diff --git a/src/libnm-client-impl/libnm.ver b/src/libnm-client-impl/libnm.ver
index e414b7e64d..508ade089b 100644
--- a/src/libnm-client-impl/libnm.ver
+++ b/src/libnm-client-impl/libnm.ver
@@ -1839,8 +1839,11 @@ global:
libnm_1_40_0 {
global:
nm_conn_wireguard_import;
+ nm_device_loopback_get_type;
nm_mptcp_flags_get_type;
nm_setting_connection_get_wait_activation_delay;
nm_setting_ip4_link_local_get_type;
nm_setting_ip6_config_get_mtu;
+ nm_setting_loopback_get_mtu;
+ nm_setting_loopback_get_type;
} libnm_1_38_0;
diff --git a/src/libnm-client-impl/meson.build b/src/libnm-client-impl/meson.build
index 46464a6328..72f1be9d0c 100644
--- a/src/libnm-client-impl/meson.build
+++ b/src/libnm-client-impl/meson.build
@@ -17,6 +17,7 @@ libnm_client_impl_sources = files(
'nm-device-generic.c',
'nm-device-infiniband.c',
'nm-device-ip-tunnel.c',
+ 'nm-device-loopback.c',
'nm-device-macsec.c',
'nm-device-macvlan.c',
'nm-device-modem.c',
diff --git a/src/libnm-client-impl/nm-client.c b/src/libnm-client-impl/nm-client.c
index a2ca833336..de8fb7d4cc 100644
--- a/src/libnm-client-impl/nm-client.c
+++ b/src/libnm-client-impl/nm-client.c
@@ -31,6 +31,7 @@
#include "nm-device-generic.h"
#include "nm-device-infiniband.h"
#include "nm-device-ip-tunnel.h"
+#include "nm-device-loopback.h"
#include "nm-device-macsec.h"
#include "nm-device-macvlan.h"
#include "nm-device-modem.h"
diff --git a/src/libnm-client-impl/nm-device-loopback.c b/src/libnm-client-impl/nm-device-loopback.c
new file mode 100644
index 0000000000..24ebcc126f
--- /dev/null
+++ b/src/libnm-client-impl/nm-device-loopback.c
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2022 Red Hat, Inc.
+ */
+
+#include "libnm-client-impl/nm-default-libnm.h"
+
+#include "nm-device-loopback.h"
+
+#include "nm-object-private.h"
+#include "nm-setting-loopback.h"
+#include "nm-setting-connection.h"
+
+/*****************************************************************************/
+
+struct _NMDeviceLoopback {
+ NMDevice parent;
+};
+
+struct _NMDeviceLoopbackClass {
+ NMDeviceClass parent;
+};
+
+G_DEFINE_TYPE(NMDeviceLoopback, nm_device_loopback, NM_TYPE_DEVICE)
+
+#define NM_DEVICE_LOOPBACK_GET_PRIVATE(self) \
+ _NM_GET_PRIVATE(self, NMDeviceLoopback, NM_IS_DEVICE_LOOPBACK, NMObject, NMDevice)
+
+/*****************************************************************************/
+
+static gboolean
+connection_compatible(NMDevice *device, NMConnection *connection, GError **error)
+{
+ const char *iface_name;
+
+ if (!NM_DEVICE_CLASS(nm_device_loopback_parent_class)
+ ->connection_compatible(device, connection, error))
+ return FALSE;
+
+ if (!nm_connection_is_type(connection, NM_SETTING_LOOPBACK_SETTING_NAME)) {
+ g_set_error_literal(error,
+ NM_DEVICE_ERROR,
+ NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
+ _("The connection was not a loopback connection."));
+ return FALSE;
+ }
+
+ iface_name = nm_connection_get_interface_name(connection);
+ if (!iface_name) {
+ g_set_error_literal(error,
+ NM_DEVICE_ERROR,
+ NM_DEVICE_ERROR_INVALID_CONNECTION,
+ _("The connection did not specify an interface name."));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static GType
+get_setting_type(NMDevice *device)
+{
+ return NM_TYPE_SETTING_LOOPBACK;
+}
+
+/*****************************************************************************/
+
+static void
+nm_device_loopback_init(NMDeviceLoopback *device)
+{}
+
+const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_loopback =
+ NML_DBUS_META_IFACE_INIT(NM_DBUS_INTERFACE_DEVICE_LOOPBACK,
+ nm_device_loopback_get_type,
+ NML_DBUS_META_INTERFACE_PRIO_INSTANTIATE_30, );
+
+static void
+nm_device_loopback_class_init(NMDeviceLoopbackClass *loopback_class)
+{
+ NMDeviceClass *device_class = NM_DEVICE_CLASS(loopback_class);
+
+ device_class->connection_compatible = connection_compatible;
+ device_class->get_setting_type = get_setting_type;
+}
diff --git a/src/libnm-client-impl/nm-device.c b/src/libnm-client-impl/nm-device.c
index 238e7c1709..fcf07a6b52 100644
--- a/src/libnm-client-impl/nm-device.c
+++ b/src/libnm-client-impl/nm-device.c
@@ -312,6 +312,7 @@ coerce_type(NMDeviceType type)
case NM_DEVICE_TYPE_WIREGUARD:
case NM_DEVICE_TYPE_WIFI_P2P:
case NM_DEVICE_TYPE_VRF:
+ case NM_DEVICE_TYPE_LOOPBACK:
return type;
}
return NM_DEVICE_TYPE_UNKNOWN;
@@ -1811,6 +1812,8 @@ get_type_name(NMDevice *device)
return _("Wi-Fi P2P");
case NM_DEVICE_TYPE_VRF:
return _("VRF");
+ case NM_DEVICE_TYPE_LOOPBACK:
+ return _("Loopback");
case NM_DEVICE_TYPE_GENERIC:
case NM_DEVICE_TYPE_UNUSED1:
case NM_DEVICE_TYPE_UNUSED2:
diff --git a/src/libnm-client-impl/nm-libnm-utils.c b/src/libnm-client-impl/nm-libnm-utils.c
index 6a7c155e76..8064fd775f 100644
--- a/src/libnm-client-impl/nm-libnm-utils.c
+++ b/src/libnm-client-impl/nm-libnm-utils.c
@@ -693,6 +693,7 @@ const NMLDBusMetaIface *const _nml_dbus_meta_ifaces[] = {
&_nml_dbus_meta_iface_nm_device_generic,
&_nml_dbus_meta_iface_nm_device_iptunnel,
&_nml_dbus_meta_iface_nm_device_infiniband,
+ &_nml_dbus_meta_iface_nm_device_loopback,
&_nml_dbus_meta_iface_nm_device_lowpan,
&_nml_dbus_meta_iface_nm_device_macsec,
&_nml_dbus_meta_iface_nm_device_macvlan,
diff --git a/src/libnm-client-impl/nm-libnm-utils.h b/src/libnm-client-impl/nm-libnm-utils.h
index 9d9cfa2530..69754c6a09 100644
--- a/src/libnm-client-impl/nm-libnm-utils.h
+++ b/src/libnm-client-impl/nm-libnm-utils.h
@@ -556,7 +556,7 @@ struct _NMLDBusMetaIface {
NML_DBUS_META_IFACE_OBJ_PROPERTIES(), \
##__VA_ARGS__)
-extern const NMLDBusMetaIface *const _nml_dbus_meta_ifaces[44];
+extern const NMLDBusMetaIface *const _nml_dbus_meta_ifaces[45];
extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm;
extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_accesspoint;
@@ -572,6 +572,7 @@ extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_dummy;
extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_generic;
extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_infiniband;
extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_iptunnel;
+extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_loopback;
extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_lowpan;
extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_macsec;
extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_macvlan;
diff --git a/src/libnm-client-public/NetworkManager.h b/src/libnm-client-public/NetworkManager.h
index 1cd94d1110..6d8a643b30 100644
--- a/src/libnm-client-public/NetworkManager.h
+++ b/src/libnm-client-public/NetworkManager.h
@@ -42,6 +42,7 @@
#include "nm-setting-ip6-config.h"
#include "nm-setting-ip-config.h"
#include "nm-setting-ip-tunnel.h"
+#include "nm-setting-loopback.h"
#include "nm-setting-macsec.h"
#include "nm-setting-macvlan.h"
#include "nm-setting-match.h"
@@ -109,6 +110,7 @@
#include "nm-device-generic.h"
#include "nm-device-infiniband.h"
#include "nm-device-ip-tunnel.h"
+#include "nm-device-loopback.h"
#include "nm-device-macsec.h"
#include "nm-device-macvlan.h"
#include "nm-device-modem.h"
diff --git a/src/libnm-client-public/meson.build b/src/libnm-client-public/meson.build
index 5232bcb486..bac7e4574b 100644
--- a/src/libnm-client-public/meson.build
+++ b/src/libnm-client-public/meson.build
@@ -20,6 +20,7 @@ libnm_client_headers = files(
'nm-device-generic.h',
'nm-device-infiniband.h',
'nm-device-ip-tunnel.h',
+ 'nm-device-loopback.h',
'nm-device-macsec.h',
'nm-device-macvlan.h',
'nm-device-modem.h',
diff --git a/src/libnm-client-public/nm-autoptr.h b/src/libnm-client-public/nm-autoptr.h
index 6c34946ca7..31ae2cce26 100644
--- a/src/libnm-client-public/nm-autoptr.h
+++ b/src/libnm-client-public/nm-autoptr.h
@@ -43,6 +43,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMDeviceEthernet, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMDeviceGeneric, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMDeviceIPTunnel, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMDeviceInfiniband, g_object_unref)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMDeviceLoopback, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMDeviceMacsec, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMDeviceMacvlan, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMDeviceModem, g_object_unref)
@@ -82,6 +83,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingIP6Config, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingIPConfig, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingIPTunnel, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingInfiniband, g_object_unref)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingLoopback, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingMacsec, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingMacvlan, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingMatch, g_object_unref)
diff --git a/src/libnm-client-public/nm-device-loopback.h b/src/libnm-client-public/nm-device-loopback.h
new file mode 100644
index 0000000000..67e58417ba
--- /dev/null
+++ b/src/libnm-client-public/nm-device-loopback.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2022 Red Hat, Inc.
+ */
+
+#ifndef __NM_DEVICE_LOOPBACK_H__
+#define __NM_DEVICE_LOOPBACK_H__
+
+#if !defined(__NETWORKMANAGER_H_INSIDE__) && !defined(NETWORKMANAGER_COMPILATION)
+#error "Only can be included directly."
+#endif
+
+#include "nm-device.h"
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_DEVICE_LOOPBACK (nm_device_loopback_get_type())
+#define NM_DEVICE_LOOPBACK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_LOOPBACK, NMDeviceLoopback))
+#define NM_DEVICE_LOOPBACK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_LOOPBACK, NMDeviceLoopbackClass))
+#define NM_IS_DEVICE_LOOPBACK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_LOOPBACK))
+#define NM_IS_DEVICE_LOOPBACK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_LOOPBACK))
+#define NM_DEVICE_LOOPBACK_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_LOOPBACK, NMDeviceLoopbackClass))
+
+#define NM_DEVICE_LOOPBACK_HW_ADDRESS "hw-address"
+
+/**
+ * NMDeviceLoopback:
+ */
+typedef struct _NMDeviceLoopback NMDeviceLoopback;
+typedef struct _NMDeviceLoopbackClass NMDeviceLoopbackClass;
+
+GType nm_device_loopback_get_type(void);
+
+G_END_DECLS
+
+#endif /* __NM_DEVICE_LOOPBACK_H__ */
diff --git a/src/libnm-core-impl/meson.build b/src/libnm-core-impl/meson.build
index 83c290857c..d779236ea1 100644
--- a/src/libnm-core-impl/meson.build
+++ b/src/libnm-core-impl/meson.build
@@ -24,6 +24,7 @@ libnm_core_settings_sources = files(
'nm-setting-ip-tunnel.c',
'nm-setting-ip4-config.c',
'nm-setting-ip6-config.c',
+ 'nm-setting-loopback.c',
'nm-setting-macsec.c',
'nm-setting-macvlan.c',
'nm-setting-match.c',
diff --git a/src/libnm-core-impl/nm-meta-setting-base-impl.c b/src/libnm-core-impl/nm-meta-setting-base-impl.c
index 69daa76c9d..49d94e5cb6 100644
--- a/src/libnm-core-impl/nm-meta-setting-base-impl.c
+++ b/src/libnm-core-impl/nm-meta-setting-base-impl.c
@@ -32,6 +32,7 @@
#include "nm-setting-ip-tunnel.h"
#include "nm-setting-ip4-config.h"
#include "nm-setting-ip6-config.h"
+#include "nm-setting-loopback.h"
#include "nm-setting-macsec.h"
#include "nm-setting-macvlan.h"
#include "nm-setting-match.h"
@@ -358,6 +359,13 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = {
.setting_name = NM_SETTING_IP_TUNNEL_SETTING_NAME,
.get_setting_gtype = nm_setting_ip_tunnel_get_type,
},
+ [NM_META_SETTING_TYPE_LOOPBACK] =
+ {
+ .meta_type = NM_META_SETTING_TYPE_LOOPBACK,
+ .setting_priority = NM_SETTING_PRIORITY_HW_BASE,
+ .setting_name = NM_SETTING_LOOPBACK_SETTING_NAME,
+ .get_setting_gtype = nm_setting_loopback_get_type,
+ },
[NM_META_SETTING_TYPE_MACSEC] =
{
.meta_type = NM_META_SETTING_TYPE_MACSEC,
@@ -608,6 +616,7 @@ const NMMetaSettingType nm_meta_setting_types_by_priority[] = {
NM_META_SETTING_TYPE_GSM,
NM_META_SETTING_TYPE_INFINIBAND,
NM_META_SETTING_TYPE_IP_TUNNEL,
+ NM_META_SETTING_TYPE_LOOPBACK,
NM_META_SETTING_TYPE_MACSEC,
NM_META_SETTING_TYPE_MACVLAN,
NM_META_SETTING_TYPE_OVS_BRIDGE,
diff --git a/src/libnm-core-impl/nm-setting-loopback.c b/src/libnm-core-impl/nm-setting-loopback.c
new file mode 100644
index 0000000000..984bae0c04
--- /dev/null
+++ b/src/libnm-core-impl/nm-setting-loopback.c
@@ -0,0 +1,192 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2022 Red Hat, Inc.
+ */
+
+#include "libnm-core-impl/nm-default-libnm-core.h"
+
+#include "nm-setting-loopback.h"
+
+#include "nm-connection-private.h"
+#include "nm-setting-connection.h"
+#include "nm-setting-private.h"
+
+/**
+ * SECTION:nm-setting-loopback
+ * @short_description: Describes connection properties for loopback interfaces
+ *
+ * The #NMSettingLoopback object is a #NMSetting subclass that describes properties
+ * necessary for connection to loopback devices
+ **/
+
+/*****************************************************************************/
+
+NM_GOBJECT_PROPERTIES_DEFINE(NMSettingLoopback, PROP_MTU, );
+
+typedef struct {
+ guint32 mtu;
+} NMSettingLoopbackPrivate;
+
+/**
+ * NMSettingLoopback:
+ *
+ * Loopback Link Settings
+ */
+struct _NMSettingLoopback {
+ NMSetting parent;
+};
+
+struct _NMSettingLoopbackClass {
+ NMSettingClass parent;
+ gpointer padding[4];
+};
+
+#define NM_SETTING_LOOPBACK_GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((o), NM_TYPE_SETTING_LOOPBACK, NMSettingLoopbackPrivate))
+
+G_DEFINE_TYPE(NMSettingLoopback, nm_setting_loopback, NM_TYPE_SETTING)
+
+/*****************************************************************************/
+
+/**
+ * nm_setting_loopback_get_mtu:
+ * @setting: the #NMSettingLoopback
+ *
+ * Returns: the #NMSettingLoopback:mtu property of the setting
+ **/
+guint32
+nm_setting_loopback_get_mtu(NMSettingLoopback *setting)
+{
+ g_return_val_if_fail(NM_IS_SETTING_LOOPBACK(setting), 0);
+
+ return NM_SETTING_LOOPBACK_GET_PRIVATE(setting)->mtu;
+}
+
+static gboolean
+verify(NMSetting *setting, NMConnection *connection, GError **error)
+{
+ if (connection) {
+ NMSettingIPConfig *s_ip4;
+ NMSettingIPConfig *s_ip6;
+ const char *method;
+
+ if ((s_ip4 = nm_connection_get_setting_ip4_config(connection))) {
+ if ((method = nm_setting_ip_config_get_method(s_ip4))
+ && !NM_IN_STRSET(method,
+ NM_SETTING_IP4_CONFIG_METHOD_AUTO,
+ NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) {
+ g_set_error(error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("ipv4 method \"%s\" is not supported for loopback"),
+ method);
+ g_prefix_error(error,
+ "%s.%s: ",
+ NM_SETTING_IP4_CONFIG_SETTING_NAME,
+ NM_SETTING_IP_CONFIG_METHOD);
+ return FALSE;
+ }
+ if (!NM_IN_SET(nm_setting_ip4_config_get_link_local(NM_SETTING_IP4_CONFIG(s_ip4)),
+ NM_SETTING_IP4_LL_DEFAULT,
+ NM_SETTING_IP4_LL_AUTO,
+ NM_SETTING_IP4_LL_DISABLED)) {
+ g_set_error(error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("ipv4.link-local cannot be enabled for loopback"));
+ g_prefix_error(error,
+ "%s.%s: ",
+ NM_SETTING_IP4_CONFIG_SETTING_NAME,
+ NM_SETTING_IP4_CONFIG_LINK_LOCAL);
+ return FALSE;
+ }
+ }
+ if ((s_ip6 = nm_connection_get_setting_ip6_config(connection))) {
+ if ((method = nm_setting_ip_config_get_method(s_ip6))
+ && !NM_IN_STRSET(method,
+ NM_SETTING_IP6_CONFIG_METHOD_AUTO,
+ NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) {
+ g_set_error(error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("ipv6 method \"%s\" is not supported for loopback"),
+ method);
+ g_prefix_error(error,
+ "%s.%s: ",
+ NM_SETTING_IP6_CONFIG_SETTING_NAME,
+ NM_SETTING_IP_CONFIG_METHOD);
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+}
+
+/*****************************************************************************/
+
+static void
+nm_setting_loopback_init(NMSettingLoopback *setting)
+{}
+
+/**
+ * nm_setting_loopback_new:
+ *
+ * Creates a new #NMSettingLoopback object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingLoopback object
+ *
+ * Since: 1.40
+ **/
+NMSetting *
+nm_setting_loopback_new(void)
+{
+ return g_object_new(NM_TYPE_SETTING_LOOPBACK, NULL);
+}
+
+static void
+nm_setting_loopback_class_init(NMSettingLoopbackClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ NMSettingClass *setting_class = NM_SETTING_CLASS(klass);
+ GArray *properties_override = _nm_sett_info_property_override_create_array();
+
+ g_type_class_add_private(klass, sizeof(NMSettingLoopbackPrivate));
+
+ object_class->get_property = _nm_setting_property_get_property_direct;
+ object_class->set_property = _nm_setting_property_set_property_direct;
+
+ setting_class->verify = verify;
+
+ /**
+ * NMSettingLoopback:mtu:
+ *
+ * If non-zero, only transmit packets of the specified size or smaller,
+ * breaking larger packets up into multiple Ethernet frames.
+ *
+ * Since: 1.40
+ **/
+ /* ---ifcfg-rh---
+ * property: mtu
+ * variable: MTU
+ * description: MTU of the interface.
+ * ---end---
+ */
+ _nm_setting_property_define_direct_uint32(properties_override,
+ obj_properties,
+ NM_SETTING_LOOPBACK_MTU,
+ PROP_MTU,
+ 0,
+ G_MAXUINT32,
+ 0,
+ NM_SETTING_PARAM_FUZZY_IGNORE,
+ NMSettingLoopbackPrivate,
+ mtu);
+
+ g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+
+ _nm_setting_class_commit(setting_class,
+ NM_META_SETTING_TYPE_LOOPBACK,
+ NULL,
+ properties_override,
+ NM_SETT_INFO_PRIVATE_OFFSET_FROM_CLASS);
+}
diff --git a/src/libnm-core-impl/tests/test-setting.c b/src/libnm-core-impl/tests/test-setting.c
index 6306437118..fcff3de536 100644
--- a/src/libnm-core-impl/tests/test-setting.c
+++ b/src/libnm-core-impl/tests/test-setting.c
@@ -121,7 +121,7 @@ test_nm_meta_setting_types_by_priority(void)
G_STATIC_ASSERT_EXPR(_NM_META_SETTING_TYPE_NUM
== G_N_ELEMENTS(nm_meta_setting_types_by_priority));
- G_STATIC_ASSERT_EXPR(_NM_META_SETTING_TYPE_NUM == 52);
+ G_STATIC_ASSERT_EXPR(_NM_META_SETTING_TYPE_NUM == 53);
arr = g_ptr_array_new_with_free_func(g_object_unref);
diff --git a/src/libnm-core-intern/nm-core-internal.h b/src/libnm-core-intern/nm-core-internal.h
index ee4cc25b42..e2f2690276 100644
--- a/src/libnm-core-intern/nm-core-internal.h
+++ b/src/libnm-core-intern/nm-core-internal.h
@@ -43,6 +43,7 @@
#include "nm-setting-ip-tunnel.h"
#include "nm-setting-ip4-config.h"
#include "nm-setting-ip6-config.h"
+#include "nm-setting-loopback.h"
#include "nm-setting-macsec.h"
#include "nm-setting-macvlan.h"
#include "nm-setting-match.h"
diff --git a/src/libnm-core-intern/nm-meta-setting-base-impl.h b/src/libnm-core-intern/nm-meta-setting-base-impl.h
index 1268865954..ea2175f84c 100644
--- a/src/libnm-core-intern/nm-meta-setting-base-impl.h
+++ b/src/libnm-core-intern/nm-meta-setting-base-impl.h
@@ -127,6 +127,7 @@ typedef enum _nm_packed {
NM_META_SETTING_TYPE_IP_TUNNEL,
NM_META_SETTING_TYPE_IP4_CONFIG,
NM_META_SETTING_TYPE_IP6_CONFIG,
+ NM_META_SETTING_TYPE_LOOPBACK,
NM_META_SETTING_TYPE_MACSEC,
NM_META_SETTING_TYPE_MACVLAN,
NM_META_SETTING_TYPE_MATCH,
diff --git a/src/libnm-core-public/meson.build b/src/libnm-core-public/meson.build
index f1da4d023d..beeeaedd47 100644
--- a/src/libnm-core-public/meson.build
+++ b/src/libnm-core-public/meson.build
@@ -29,6 +29,7 @@ libnm_core_headers = files(
'nm-setting-ip-tunnel.h',
'nm-setting-ip4-config.h',
'nm-setting-ip6-config.h',
+ 'nm-setting-loopback.h',
'nm-setting-macsec.h',
'nm-setting-macvlan.h',
'nm-setting-match.h',
diff --git a/src/libnm-core-public/nm-core-types.h b/src/libnm-core-public/nm-core-types.h
index c86c28fa47..4db0c86e3d 100644
--- a/src/libnm-core-public/nm-core-types.h
+++ b/src/libnm-core-public/nm-core-types.h
@@ -35,6 +35,7 @@ typedef struct _NMSettingIP6Config NMSettingIP6Config;
typedef struct _NMSettingIPConfig NMSettingIPConfig;
typedef struct _NMSettingIPTunnel NMSettingIPTunnel;
typedef struct _NMSettingInfiniband NMSettingInfiniband;
+typedef struct _NMSettingLoopback NMSettingLoopback;
typedef struct _NMSettingMacsec NMSettingMacsec;
typedef struct _NMSettingMacvlan NMSettingMacvlan;
typedef struct _NMSettingMatch NMSettingMatch;
diff --git a/src/libnm-core-public/nm-dbus-interface.h b/src/libnm-core-public/nm-dbus-interface.h
index 4557dde0fb..3960b198a7 100644
--- a/src/libnm-core-public/nm-dbus-interface.h
+++ b/src/libnm-core-public/nm-dbus-interface.h
@@ -39,6 +39,7 @@
#define NM_DBUS_INTERFACE_DEVICE_GRE NM_DBUS_INTERFACE_DEVICE ".Gre"
#define NM_DBUS_INTERFACE_DEVICE_INFINIBAND NM_DBUS_INTERFACE_DEVICE ".Infiniband"
#define NM_DBUS_INTERFACE_DEVICE_IP_TUNNEL NM_DBUS_INTERFACE_DEVICE ".IPTunnel"
+#define NM_DBUS_INTERFACE_DEVICE_LOOPBACK NM_DBUS_INTERFACE_DEVICE ".Loopback"
#define NM_DBUS_INTERFACE_DEVICE_MACSEC NM_DBUS_INTERFACE_DEVICE ".Macsec"
#define NM_DBUS_INTERFACE_DEVICE_MACVLAN NM_DBUS_INTERFACE_DEVICE ".Macvlan"
#define NM_DBUS_INTERFACE_DEVICE_MODEM NM_DBUS_INTERFACE_DEVICE ".Modem"
@@ -216,6 +217,7 @@ typedef enum {
* @NM_DEVICE_TYPE_WIREGUARD: a WireGuard interface
* @NM_DEVICE_TYPE_WIFI_P2P: an 802.11 Wi-Fi P2P device. Since: 1.16.
* @NM_DEVICE_TYPE_VRF: A VRF (Virtual Routing and Forwarding) interface. Since: 1.24.
+ * @NM_DEVICE_TYPE_LOOPBACK: a loopback interface. Since: 1.40.
*
* #NMDeviceType values indicate the type of hardware represented by a
* device object.
@@ -253,6 +255,7 @@ typedef enum {
NM_DEVICE_TYPE_WIREGUARD = 29,
NM_DEVICE_TYPE_WIFI_P2P = 30,
NM_DEVICE_TYPE_VRF = 31,
+ NM_DEVICE_TYPE_LOOPBACK = 32,
} NMDeviceType;
/**
diff --git a/src/libnm-core-public/nm-setting-loopback.h b/src/libnm-core-public/nm-setting-loopback.h
new file mode 100644
index 0000000000..0ec7308adb
--- /dev/null
+++ b/src/libnm-core-public/nm-setting-loopback.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2022 Red Hat, Inc.
+ */
+
+#ifndef __NM_SETTING_LOOPBACK_H__
+#define __NM_SETTING_LOOPBACK_H__
+
+#if !defined(__NETWORKMANAGER_H_INSIDE__) && !defined(NETWORKMANAGER_COMPILATION)
+#error "Only can be included directly."
+#endif
+
+#include "nm-setting.h"
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_SETTING_LOOPBACK (nm_setting_loopback_get_type())
+#define NM_SETTING_LOOPBACK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SETTING_LOOPBACK, NMSettingLoopback))
+#define NM_SETTING_LOOPBACK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_SETTING_LOOPBACKCONFIG, NMSettingLoopbackClass))
+#define NM_IS_SETTING_LOOPBACK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_SETTING_LOOPBACK))
+#define NM_IS_SETTING_LOOPBACK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_SETTING_LOOPBACK))
+#define NM_SETTING_LOOPBACK_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_SETTING_LOOPBACK, NMSettingLoopbackClass))
+
+#define NM_SETTING_LOOPBACK_SETTING_NAME "loopback"
+
+#define NM_SETTING_LOOPBACK_MTU "mtu"
+
+typedef struct _NMSettingLoopbackClass NMSettingLoopbackClass;
+
+NM_AVAILABLE_IN_1_40
+GType nm_setting_loopback_get_type(void);
+NM_AVAILABLE_IN_1_40
+NMSetting *nm_setting_loopback_new(void);
+
+guint32 nm_setting_loopback_get_mtu(NMSettingLoopback *setting);
+
+G_END_DECLS
+
+#endif /* __NM_SETTING_LOOPBACK_H__ */
diff --git a/src/libnm-glib-aux/nm-inet-utils.h b/src/libnm-glib-aux/nm-inet-utils.h
index d9246d459b..2c1bd4126e 100644
--- a/src/libnm-glib-aux/nm-inet-utils.h
+++ b/src/libnm-glib-aux/nm-inet-utils.h
@@ -232,6 +232,7 @@ gboolean nm_ip6_addr_is_ula(const struct in6_addr *address);
#define NM_IPV4LL_NETWORK ((in_addr_t) htonl(0xA9FE0000lu))
#define NM_IPV4LL_NETMASK ((in_addr_t) htonl(0xFFFF0000lu))
+#define NM_IPV4LO_NETWORK ((in_addr_t) htonl(0x7F000001lu))
static inline gboolean
nm_ip4_addr_is_loopback(in_addr_t addr)
diff --git a/src/libnm-glib-aux/tests/test-shared-general.c b/src/libnm-glib-aux/tests/test-shared-general.c
index 5d9072e177..d4f250d3e1 100644
--- a/src/libnm-glib-aux/tests/test-shared-general.c
+++ b/src/libnm-glib-aux/tests/test-shared-general.c
@@ -259,6 +259,7 @@ test_nm_ip4_addr_is_loopback(void)
g_assert(!nm_ip4_addr_is_loopback(nmtst_inet4_from_string("126.5.0.1")));
g_assert(!nm_ip4_addr_is_loopback(nmtst_inet4_from_string("128.5.0.1")));
g_assert(!nm_ip4_addr_is_loopback(nmtst_inet4_from_string("129.5.0.1")));
+ g_assert_cmpint(nmtst_inet4_from_string("127.0.0.1"), ==, NM_IPV4LO_NETWORK);
}
/*****************************************************************************/
diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c
index ff635b33fe..33a2f103bb 100644
--- a/src/libnm-platform/nm-platform.c
+++ b/src/libnm-platform/nm-platform.c
@@ -4105,6 +4105,8 @@ ip6_address_scope_cmp_descending(gconstpointer p_a, gconstpointer p_b, gpointer
* by the function.
* Addresses that are both contained in @known_addresses and @addresses_prune
* will be configured.
+ * @flag: determine if the noprefixroute tag will be automatically added for
+ * the addresses configured
*
* A convenience function to synchronize addresses for a specific interface
* with the least possible disturbance. It simply removes addresses that are
@@ -4113,11 +4115,12 @@ ip6_address_scope_cmp_descending(gconstpointer p_a, gconstpointer p_b, gpointer
* Returns: %TRUE on success.
*/
gboolean
-nm_platform_ip_address_sync(NMPlatform *self,
- int addr_family,
- int ifindex,
- GPtrArray *known_addresses,
- GPtrArray *addresses_prune)
+nm_platform_ip_address_sync(NMPlatform *self,
+ int addr_family,
+ int ifindex,
+ GPtrArray *known_addresses,
+ GPtrArray *addresses_prune,
+ NMPIPAddressSyncFlags flag)
{
gint32 now = 0;
const int IS_IPv4 = NM_IS_IPv4(addr_family);
@@ -4529,18 +4532,22 @@ next_plat:;
nm_platform_ip4_broadcast_address_from_addr(&known_address->a4),
lifetime,
preferred,
- IFA_F_NOPREFIXROUTE,
+ flag == NMP_IP_ADDRESS_SYNC_FLAGS_NO_AUTO_NOPREFIXROUTE ? 0
+ : IFA_F_NOPREFIXROUTE,
known_address->a4.label))
success = FALSE;
} else {
- if (!nm_platform_ip6_address_add(self,
- ifindex,
- known_address->a6.address,
- known_address->a6.plen,
- known_address->a6.peer_address,
- lifetime,
- preferred,
- IFA_F_NOPREFIXROUTE | known_address->a6.n_ifa_flags))
+ if (!nm_platform_ip6_address_add(
+ self,
+ ifindex,
+ known_address->a6.address,
+ known_address->a6.plen,
+ known_address->a6.peer_address,
+ lifetime,
+ preferred,
+ (flag == NMP_IP_ADDRESS_SYNC_FLAGS_NO_AUTO_NOPREFIXROUTE ? 0
+ : IFA_F_NOPREFIXROUTE)
+ | known_address->a6.n_ifa_flags))
success = FALSE;
}
}
@@ -4568,7 +4575,12 @@ nm_platform_ip_address_flush(NMPlatform *self, int addr_family, int ifindex)
addresses_prune =
nm_platform_ip_address_get_prune_list(self, addr_family2, ifindex, NULL, 0);
- if (!nm_platform_ip_address_sync(self, addr_family2, ifindex, NULL, addresses_prune))
+ if (!nm_platform_ip_address_sync(self,
+ addr_family2,
+ ifindex,
+ NULL,
+ addresses_prune,
+ NMP_IP_ADDRESS_SYNC_FLAGS_NONE))
success = FALSE;
}
return success;
diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h
index 2570a47dda..de447f4d33 100644
--- a/src/libnm-platform/nm-platform.h
+++ b/src/libnm-platform/nm-platform.h
@@ -2324,11 +2324,17 @@ nm_platform_ip_address_delete(NMPlatform *
}
}
-gboolean nm_platform_ip_address_sync(NMPlatform *self,
- int addr_family,
- int ifindex,
- GPtrArray *known_addresses,
- GPtrArray *addresses_prune);
+typedef enum {
+ NMP_IP_ADDRESS_SYNC_FLAGS_NONE,
+ NMP_IP_ADDRESS_SYNC_FLAGS_NO_AUTO_NOPREFIXROUTE,
+} NMPIPAddressSyncFlags;
+
+gboolean nm_platform_ip_address_sync(NMPlatform *self,
+ int addr_family,
+ int ifindex,
+ GPtrArray *known_addresses,
+ GPtrArray *addresses_prune,
+ NMPIPAddressSyncFlags flag);
GPtrArray *
nm_platform_ip_address_get_prune_list(NMPlatform *self,
diff --git a/src/libnmc-setting/nm-meta-setting-base-impl.c b/src/libnmc-setting/nm-meta-setting-base-impl.c
index 69daa76c9d..49d94e5cb6 100644
--- a/src/libnmc-setting/nm-meta-setting-base-impl.c
+++ b/src/libnmc-setting/nm-meta-setting-base-impl.c
@@ -32,6 +32,7 @@
#include "nm-setting-ip-tunnel.h"
#include "nm-setting-ip4-config.h"
#include "nm-setting-ip6-config.h"
+#include "nm-setting-loopback.h"
#include "nm-setting-macsec.h"
#include "nm-setting-macvlan.h"
#include "nm-setting-match.h"
@@ -358,6 +359,13 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = {
.setting_name = NM_SETTING_IP_TUNNEL_SETTING_NAME,
.get_setting_gtype = nm_setting_ip_tunnel_get_type,
},
+ [NM_META_SETTING_TYPE_LOOPBACK] =
+ {
+ .meta_type = NM_META_SETTING_TYPE_LOOPBACK,
+ .setting_priority = NM_SETTING_PRIORITY_HW_BASE,
+ .setting_name = NM_SETTING_LOOPBACK_SETTING_NAME,
+ .get_setting_gtype = nm_setting_loopback_get_type,
+ },
[NM_META_SETTING_TYPE_MACSEC] =
{
.meta_type = NM_META_SETTING_TYPE_MACSEC,
@@ -608,6 +616,7 @@ const NMMetaSettingType nm_meta_setting_types_by_priority[] = {
NM_META_SETTING_TYPE_GSM,
NM_META_SETTING_TYPE_INFINIBAND,
NM_META_SETTING_TYPE_IP_TUNNEL,
+ NM_META_SETTING_TYPE_LOOPBACK,
NM_META_SETTING_TYPE_MACSEC,
NM_META_SETTING_TYPE_MACVLAN,
NM_META_SETTING_TYPE_OVS_BRIDGE,
diff --git a/src/libnmc-setting/nm-meta-setting-base-impl.h b/src/libnmc-setting/nm-meta-setting-base-impl.h
index 1268865954..ea2175f84c 100644
--- a/src/libnmc-setting/nm-meta-setting-base-impl.h
+++ b/src/libnmc-setting/nm-meta-setting-base-impl.h
@@ -127,6 +127,7 @@ typedef enum _nm_packed {
NM_META_SETTING_TYPE_IP_TUNNEL,
NM_META_SETTING_TYPE_IP4_CONFIG,
NM_META_SETTING_TYPE_IP6_CONFIG,
+ NM_META_SETTING_TYPE_LOOPBACK,
NM_META_SETTING_TYPE_MACSEC,
NM_META_SETTING_TYPE_MACVLAN,
NM_META_SETTING_TYPE_MATCH,
diff --git a/src/libnmc-setting/nm-meta-setting-desc.c b/src/libnmc-setting/nm-meta-setting-desc.c
index 2e471d66a5..f7054bed34 100644
--- a/src/libnmc-setting/nm-meta-setting-desc.c
+++ b/src/libnmc-setting/nm-meta-setting-desc.c
@@ -6584,6 +6584,21 @@ static const NMMetaPropertyInfo *const property_infos_IP_TUNNEL[] = {
NULL
};
+#undef _CURRENT_NM_META_SETTING_TYPE
+#define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_LOOPBACK
+static const NMMetaPropertyInfo *const property_infos_LOOPBACK[] = {
+ PROPERTY_INFO_WITH_DESC (NM_SETTING_LOOPBACK_MTU,
+ .is_cli_option = TRUE,
+ .property_alias = "mtu",
+ .prompt = N_("MTU"),
+ .property_type = &_pt_gobject_mtu,
+ .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (mtu,
+ .get_fcn = MTU_GET_FCN (NMSettingLoopback, nm_setting_loopback_get_mtu),
+ ),
+ ),
+ NULL
+};
+
#undef _CURRENT_NM_META_SETTING_TYPE
#define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_MACSEC
static const NMMetaPropertyInfo *const property_infos_MACSEC[] = {
@@ -8337,6 +8352,7 @@ _setting_init_fcn_wireless (ARGS_SETTING_INIT_FCN)
#define SETTING_PRETTY_NAME_IP4_CONFIG N_("IPv4 protocol")
#define SETTING_PRETTY_NAME_IP6_CONFIG N_("IPv6 protocol")
#define SETTING_PRETTY_NAME_IP_TUNNEL N_("IP-tunnel settings")
+#define SETTING_PRETTY_NAME_LOOPBACK N_("Loopback settings")
#define SETTING_PRETTY_NAME_MACSEC N_("MACsec connection")
#define SETTING_PRETTY_NAME_MACVLAN N_("macvlan connection")
#define SETTING_PRETTY_NAME_MATCH N_("Match")
@@ -8496,6 +8512,12 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
NM_META_SETTING_VALID_PART_ITEM (ETHTOOL, FALSE),
),
),
+ SETTING_INFO (LOOPBACK,
+ .valid_parts = NM_META_SETTING_VALID_PARTS (
+ NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE),
+ NM_META_SETTING_VALID_PART_ITEM (LOOPBACK, TRUE),
+ ),
+ ),
SETTING_INFO (MACSEC,
.valid_parts = NM_META_SETTING_VALID_PARTS (
NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE),
diff --git a/src/libnmc-setting/settings-docs.h.in b/src/libnmc-setting/settings-docs.h.in
index 2aef829a46..b783f635f1 100644
--- a/src/libnmc-setting/settings-docs.h.in
+++ b/src/libnmc-setting/settings-docs.h.in
@@ -431,5 +431,6 @@
#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_FROM_DNS_LOOKUP N_("Whether the system hostname can be determined from reverse DNS lookup of addresses on this device. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1).")
#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_ONLY_FROM_DEFAULT N_("If set to NM_TERNARY_TRUE (1), NetworkManager attempts to get the hostname via DHCPv4/DHCPv6 or reverse DNS lookup on this device only when the device has the default route for the given address family (IPv4/IPv6). If set to NM_TERNARY_FALSE (0), the hostname can be set from this device even if it doesn't have the default route. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_FALSE (0).")
#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_PRIORITY N_("The relative priority of this connection to determine the system hostname. A lower numerical value is better (higher priority). A connection with higher priority is considered before connections with lower priority. If the value is zero, it can be overridden by a global value from NetworkManager configuration. If the property doesn't have a value in the global configuration, the value is assumed to be 100. Negative values have the special effect of excluding other connections with a greater numerical priority value; so in presence of at least one negative priority, only connections with the lowest priority value will be used to determine the hostname.")
+#define DESCRIBE_DOC_NM_SETTING_LOOPBACK_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple Ethernet frames.")
#define DESCRIBE_DOC_NM_SETTING_OVS_EXTERNAL_IDS_DATA N_("A dictionary of key/value pairs with exernal-ids for OVS.")
#define DESCRIBE_DOC_NM_SETTING_VETH_PEER N_("This property specifies the peer interface name of the veth. This property is mandatory.")
diff --git a/src/nmcli/generate-docs-nm-settings-nmcli.xml.in b/src/nmcli/generate-docs-nm-settings-nmcli.xml.in
index b6d275c69d..ef59525878 100644
--- a/src/nmcli/generate-docs-nm-settings-nmcli.xml.in
+++ b/src/nmcli/generate-docs-nm-settings-nmcli.xml.in
@@ -762,6 +762,11 @@
+
+
+