From e8618f03d7d8735946a82de8ce4257dd92328b20 Mon Sep 17 00:00:00 2001 From: Wen Liang Date: Sun, 12 Jun 2022 19:50:09 -0400 Subject: [PATCH] support loopback interface Support managing the loopback interface through NM as the users want to set the proper mtu for loopback interface when forwarding the packets. Additionally, the IP addresses, DNS, route and routing rules are also allowed to configure for the loopback connection profiles. https://bugzilla.redhat.com/show_bug.cgi?id=2060905 --- Makefile.am | 10 + NEWS | 6 + docs/api/Makefile.am | 1 + docs/api/network-manager-docs.xml | 1 + docs/libnm/libnm-docs.xml | 2 + introspection/meson.build | 1 + ...desktop.NetworkManager.Device.Loopback.xml | 8 + man/NetworkManager.conf.xml | 4 + po/POTFILES.in | 2 + src/core/devices/nm-device-factory.c | 1 + src/core/devices/nm-device-loopback.c | 163 +++++++++++++++ src/core/devices/nm-device-loopback.h | 27 +++ src/core/devices/nm-device.c | 61 +++--- src/core/devices/nm-device.h | 20 +- src/core/dns/nm-dns-systemd-resolved.c | 9 + src/core/meson.build | 1 + src/core/nm-l3cfg.c | 71 ++++++- src/core/nm-manager.c | 13 +- src/libnm-client-impl/libnm.ver | 6 + src/libnm-client-impl/meson.build | 1 + src/libnm-client-impl/nm-client.c | 1 + src/libnm-client-impl/nm-device-loopback.c | 81 ++++++++ src/libnm-client-impl/nm-device.c | 3 + src/libnm-client-impl/nm-libnm-utils.c | 1 + src/libnm-client-impl/nm-libnm-utils.h | 3 +- src/libnm-client-public/NetworkManager.h | 2 + src/libnm-client-public/meson.build | 1 + src/libnm-client-public/nm-autoptr.h | 2 + src/libnm-client-public/nm-device-loopback.h | 41 ++++ ...gen-metadata-nm-settings-libnm-core.xml.in | 8 + src/libnm-core-impl/meson.build | 1 + .../nm-meta-setting-base-impl.c | 9 + src/libnm-core-impl/nm-setting-loopback.c | 194 ++++++++++++++++++ src/libnm-core-impl/tests/test-setting.c | 2 +- src/libnm-core-intern/nm-core-internal.h | 1 + .../nm-meta-setting-base-impl.h | 1 + src/libnm-core-public/meson.build | 1 + src/libnm-core-public/nm-core-types.h | 1 + src/libnm-core-public/nm-dbus-interface.h | 3 + src/libnm-core-public/nm-setting-loopback.h | 44 ++++ src/libnm-platform/nm-platform.c | 59 +++++- src/libnm-platform/nm-platform.h | 25 +++ .../nm-meta-setting-base-impl.c | 9 + .../nm-meta-setting-base-impl.h | 1 + src/libnmc-setting/nm-meta-setting-desc.c | 22 ++ src/libnmc-setting/settings-docs.h.in | 1 + .../gen-metadata-nm-settings-nmcli.xml.in | 5 + 47 files changed, 880 insertions(+), 50 deletions(-) create mode 100644 introspection/org.freedesktop.NetworkManager.Device.Loopback.xml create mode 100644 src/core/devices/nm-device-loopback.c create mode 100644 src/core/devices/nm-device-loopback.h create mode 100644 src/libnm-client-impl/nm-device-loopback.c create mode 100644 src/libnm-client-public/nm-device-loopback.h create mode 100644 src/libnm-core-impl/nm-setting-loopback.c create mode 100644 src/libnm-core-public/nm-setting-loopback.h diff --git a/Makefile.am b/Makefile.am index 51bdca457b..3c294ab767 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1024,6 +1024,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 \ @@ -1111,6 +1113,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 \ @@ -1179,6 +1182,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 \ @@ -1260,6 +1264,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 \ @@ -1339,6 +1344,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 \ @@ -1732,6 +1738,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 \ @@ -1802,6 +1809,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 \ @@ -2618,6 +2626,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/NEWS b/NEWS index b4737fe8a9..8da2cf83de 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,12 @@ USE AT YOUR OWN RISK. NOT RECOMMENDED FOR PRODUCTION USE! switch. * dns: support specifying DNS-over-TLS server name (SNI) for static name servers. Only works with systemd-resolved plugin. +* Add support of loopback interface and a new connection type "loopback". On D-Bus, + the loopback interface now has the "org.freedesktop.NetworkManager.Device.Loopback" + interface instead of org.freedesktop.NetworkManager.Device.Generic". + Loopback handling is special in that when the NetworkManager profile is + deactivated, the interfaces will still be up and configured with a 127.0.0.1 + address. ============================================= NetworkManager-1.40 diff --git a/docs/api/Makefile.am b/docs/api/Makefile.am index 359e91fd8f..4bdce0e00b 100644 --- a/docs/api/Makefile.am +++ b/docs/api/Makefile.am @@ -41,6 +41,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 441a89e751..d20f01a2e2 100644 --- a/docs/libnm/libnm-docs.xml +++ b/docs/libnm/libnm-docs.xml @@ -332,6 +332,7 @@ print ("NetworkManager version " + client.get_version())]]> + @@ -381,6 +382,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..902363317c --- /dev/null +++ b/introspection/org.freedesktop.NetworkManager.Device.Loopback.xml @@ -0,0 +1,8 @@ + + + + + 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 a1a5730075..a0a3045029 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 7783a82e68..a3f82ba6e2 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" @@ -1588,6 +1589,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) { @@ -2741,13 +2745,6 @@ _ethtool_state_set(NMDevice *self) /*****************************************************************************/ -static gboolean -is_loopback(NMDevice *self) -{ - return NM_IS_DEVICE_GENERIC(self) - && NM_DEVICE_GET_PRIVATE(self)->ifindex == NM_LOOPBACK_IFINDEX; -} - gboolean nm_device_is_vpn(NMDevice *self) { @@ -5019,6 +5016,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 @@ -5439,7 +5439,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 @@ -7485,11 +7485,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); @@ -7679,9 +7674,8 @@ 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_BY_TYPE | NM_UNMANAGED_USER_UDEV - | NM_UNMANAGED_USER_EXPLICIT | NM_UNMANAGED_EXTERNAL_DOWN - | NM_UNMANAGED_IS_SLAVE, + 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, @@ -10839,7 +10833,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: @@ -10922,6 +10917,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; @@ -11033,6 +11033,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); @@ -14169,7 +14173,6 @@ NM_UTILS_FLAGS2STR_DEFINE(nm_unmanaged_flags2str, NMUnmanagedFlags, NM_UTILS_FLAGS2STR(NM_UNMANAGED_SLEEPING, "sleeping"), NM_UTILS_FLAGS2STR(NM_UNMANAGED_QUITTING, "quitting"), - 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"), @@ -17212,10 +17215,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: @@ -17224,15 +17229,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) @@ -17639,7 +17648,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 3dfa572064..cd898085be 100644 --- a/src/core/devices/nm-device.h +++ b/src/core/devices/nm-device.h @@ -566,7 +566,6 @@ void nm_device_copy_ip6_dns_config(NMDevice *self, NMDevice *from_device); * @NM_UNMANAGED_NONE: placeholder value * @NM_UNMANAGED_SLEEPING: %TRUE when unmanaged because NM is sleeping. * @NM_UNMANAGED_QUITTING: %TRUE when unmanaged because NM is shutting down. - * @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 @@ -596,20 +595,19 @@ typedef enum { * the device cannot be managed. */ NM_UNMANAGED_SLEEPING = (1LL << 0), NM_UNMANAGED_QUITTING = (1LL << 1), - NM_UNMANAGED_BY_TYPE = (1LL << 2), - NM_UNMANAGED_PLATFORM_INIT = (1LL << 3), - NM_UNMANAGED_USER_EXPLICIT = (1LL << 4), - NM_UNMANAGED_USER_SETTINGS = (1LL << 5), + NM_UNMANAGED_PLATFORM_INIT = (1LL << 2), + NM_UNMANAGED_USER_EXPLICIT = (1LL << 3), + NM_UNMANAGED_USER_SETTINGS = (1LL << 4), /* These flags can be non-effective and be overwritten * by other flags. */ - 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_BY_DEFAULT = (1LL << 5), + NM_UNMANAGED_USER_CONF = (1LL << 6), + NM_UNMANAGED_USER_UDEV = (1LL << 7), + NM_UNMANAGED_EXTERNAL_DOWN = (1LL << 8), + NM_UNMANAGED_IS_SLAVE = (1LL << 9), - NM_UNMANAGED_ALL = ((1LL << 11) - 1), + NM_UNMANAGED_ALL = ((1LL << 10) - 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 96e2794c6a..6bdc8460a8 100644 --- a/src/core/dns/nm-dns-systemd-resolved.c +++ b/src/core/dns/nm-dns-systemd-resolved.c @@ -477,6 +477,8 @@ prepare_one_interface(NMDnsSystemdResolved *self, const InterfaceConfig *ic) guint i; gboolean require_dns_ex = FALSE; + 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)")); @@ -791,6 +793,13 @@ update(NMDnsPlugin *plugin, nm_assert(ifindex == nm_l3_config_data_get_ifindex(ip_data->l3cd)); + if (ifindex == NM_LOOPBACK_IFINDEX) { + /* systemd-resolved API is per-link, and loopback is not supported. + * Unclear what to do about DNS configuration on loopback. Just skip + * it here. */ + continue; + } + ic = g_hash_table_lookup(interfaces, GINT_TO_POINTER(ifindex)); if (!ic) { ic = g_slice_new(InterfaceConfig); diff --git a/src/core/meson.build b/src/core/meson.build index 523a51ca94..6c1d463ed1 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -104,6 +104,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 d69f28b64c..bd13bda4ab 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) @@ -3748,6 +3758,38 @@ _l3cfg_update_combined_config(NML3Cfg *self, &hook_data); } + if (self->priv.ifindex == NM_LOOPBACK_IFINDEX) { + NMPlatformIPXAddress ax; + NMPlatformIPXRoute rx; + + if (!nm_l3_config_data_lookup_address_4(l3cd, + NM_IPV4LO_ADDR1, + NM_IPV4LO_PREFIXLEN, + NM_IPV4LO_ADDR1)) { + nm_l3_config_data_add_address_4( + l3cd, + nm_platform_ip4_address_init_loopback_addr1(&ax.a4)); + } + if (!nm_l3_config_data_lookup_address_6(l3cd, &in6addr_loopback)) { + nm_l3_config_data_add_address_6(l3cd, + nm_platform_ip6_address_init_loopback(&ax.a6)); + } + + rx.r4 = (NMPlatformIP4Route){ + .ifindex = NM_LOOPBACK_IFINDEX, + .rt_source = NM_IP_CONFIG_SOURCE_KERNEL, + .network = NM_IPV4LO_ADDR1, + .plen = NM_IPV4LO_PREFIXLEN, + .table_coerced = nm_platform_route_table_coerce(RT_TABLE_LOCAL), + .scope_inv = nm_platform_route_scope_inv(RT_SCOPE_HOST), + .type_coerced = nm_platform_route_type_coerce(RTN_LOCAL), + .pref_src = NM_IPV4LO_ADDR1, + }; + nm_platform_ip_route_normalize(AF_INET, &rx.rx); + if (!nm_l3_config_data_lookup_route(l3cd, AF_INET, &rx.rx)) { + nm_l3_config_data_add_route_4(l3cd, &rx.r4); + } + } for (i = 0; i < l3_config_datas_len; i++) { const L3ConfigData *l3cd_data = l3_config_datas_arr[i]; int IS_IPv4; @@ -4587,6 +4629,23 @@ _l3_commit_one(NML3Cfg *self, } } + if (self->priv.ifindex == NM_LOOPBACK_IFINDEX) { + if (!addresses) { + NMPlatformIPXAddress ax; + + 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, + nm_platform_ip4_address_init_loopback_addr1(&ax.a4))); + } else { + g_ptr_array_add(addresses, + nmp_object_new(NMP_OBJECT_TYPE_IP6_ADDRESS, + nm_platform_ip6_address_init_loopback(&ax.a6))); + } + } + } /* 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(). */ @@ -4595,7 +4654,9 @@ _l3_commit_one(NML3Cfg *self, self->priv.ifindex, addresses, addresses_prune, - NMP_IP_ADDRESS_SYNC_FLAGS_WITH_NOPREFIXROUTE); + self->priv.ifindex == NM_LOOPBACK_IFINDEX + ? NMP_IP_ADDRESS_SYNC_FLAGS_NONE + : NMP_IP_ADDRESS_SYNC_FLAGS_WITH_NOPREFIXROUTE); _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 7c04e8e4e5..c71e649c15 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" @@ -1461,8 +1462,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)) { @@ -3340,6 +3344,9 @@ _get_best_connectivity(NMManager *self, int addr_family) NMConnectivityState state; gint64 metric; + if (NM_IS_DEVICE_LOOPBACK(dev)) + continue; + r = nm_device_get_best_default_route(dev, addr_family); if (r) metric = NMP_OBJECT_CAST_IP_ROUTE(r)->metric; @@ -7087,10 +7094,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 == NM_LOOPBACK_IFINDEX) { - /* ignore loopback */ - return FALSE; - } if (!nm_platform_link_get(priv->platform, ifindex)) return FALSE; diff --git a/src/libnm-client-impl/libnm.ver b/src/libnm-client-impl/libnm.ver index 6d706dff4a..42cb4e752e 100644 --- a/src/libnm-client-impl/libnm.ver +++ b/src/libnm-client-impl/libnm.ver @@ -1883,6 +1883,12 @@ libnm_1_42_0 { global: nm_client_wait_shutdown; nm_client_wait_shutdown_finish; + nm_device_loopback_get_type; + nm_setting_ip_config_get_dhcp_iaid; + nm_setting_ip_config_get_dhcp_iaid; + nm_setting_loopback_get_mtu; + nm_setting_loopback_get_type; + nm_setting_loopback_new; nm_setting_ovs_interface_get_ofport_request; nm_utils_ensure_gtypes; } libnm_1_40_0; diff --git a/src/libnm-client-impl/meson.build b/src/libnm-client-impl/meson.build index d72ed545b4..143126c51a 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 7935b4bb81..57d3607cf5 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..9163f38dfe --- /dev/null +++ b/src/libnm-client-impl/nm-device-loopback.c @@ -0,0 +1,81 @@ +/* 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) + +/*****************************************************************************/ + +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 f773c7f81d..9d51226347 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 da13c615cb..a60706bdd7 100644 --- a/src/libnm-client-impl/nm-libnm-utils.h +++ b/src/libnm-client-impl/nm-libnm-utils.h @@ -565,7 +565,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; @@ -581,6 +581,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 cae8596662..da661db93b 100644 --- a/src/libnm-client-public/NetworkManager.h +++ b/src/libnm-client-public/NetworkManager.h @@ -44,6 +44,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" @@ -111,6 +112,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..ae5dcc47cd --- /dev/null +++ b/src/libnm-client-public/nm-device-loopback.h @@ -0,0 +1,41 @@ +/* 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)) + +/** + * NMDeviceLoopback: + * + * Since: 1.42 + */ +typedef struct _NMDeviceLoopback NMDeviceLoopback; +typedef struct _NMDeviceLoopbackClass NMDeviceLoopbackClass; + +NM_AVAILABLE_IN_1_42 +GType nm_device_loopback_get_type(void); + +G_END_DECLS + +#endif /* __NM_DEVICE_LOOPBACK_H__ */ diff --git a/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in b/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in index 77bbdcca53..42fd7c4773 100644 --- a/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in +++ b/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in @@ -1721,6 +1721,14 @@ gprop-type="gchararray" /> + + + diff --git a/src/libnm-core-impl/meson.build b/src/libnm-core-impl/meson.build index 25d4c6b859..f1bd2a081c 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 5e627cfc7d..e93a1555dc 100644 --- a/src/libnm-core-impl/nm-meta-setting-base-impl.c +++ b/src/libnm-core-impl/nm-meta-setting-base-impl.c @@ -34,6 +34,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" @@ -360,6 +361,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, @@ -610,6 +618,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..ea777491a8 --- /dev/null +++ b/src/libnm-core-impl/nm-setting-loopback.c @@ -0,0 +1,194 @@ +/* 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 + * + * Since: 1.42 + */ +struct _NMSettingLoopback { + NMSetting parent; + NMSettingLoopbackPrivate _priv; +}; + +struct _NMSettingLoopbackClass { + NMSettingClass parent; +}; + +#define NM_SETTING_LOOPBACK_GET_PRIVATE(self) \ + _NM_GET_PRIVATE(self, NMSettingLoopback, NM_IS_SETTING_LOOPBACK) + +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 + * + * Since: 1.42 + **/ +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.42 + **/ +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(); + + 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.42 + **/ + /* ---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, + NMSettingLoopback, + _priv.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, + 0); +} diff --git a/src/libnm-core-impl/tests/test-setting.c b/src/libnm-core-impl/tests/test-setting.c index 50da9cae5e..b8267de487 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 df9a6d047b..ba28bc75f1 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 6e1a84a1dd..0baf14bbc3 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" @@ -218,6 +219,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.42. * * #NMDeviceType values indicate the type of hardware represented by a * device object. @@ -255,6 +257,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..96b9c6d890 --- /dev/null +++ b/src/libnm-core-public/nm-setting-loopback.h @@ -0,0 +1,44 @@ +/* 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_42 +GType nm_setting_loopback_get_type(void); +NM_AVAILABLE_IN_1_42 +NMSetting *nm_setting_loopback_new(void); + +NM_AVAILABLE_IN_1_42 +guint32 nm_setting_loopback_get_mtu(NMSettingLoopback *setting); + +G_END_DECLS + +#endif /* __NM_SETTING_LOOPBACK_H__ */ diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index 885829e059..5b970686d7 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -4564,7 +4564,26 @@ nm_platform_ip_address_get_prune_list(NMPlatform *self, c_list_for_each (iter, &head_entry->lst_entries_head) { const NMPObject *obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj; - if (!IS_IPv4) { + if (IS_IPv4) { + const NMPlatformIP4Address *a4 = NMP_OBJECT_CAST_IP4_ADDRESS(obj); + + if (a4->address == NM_IPV4LO_ADDR1 && a4->plen == NM_IPV4LO_PREFIXLEN) { + const NMPlatformIP4Address addr = (NMPlatformIP4Address){ + .ifindex = NM_LOOPBACK_IFINDEX, + .address = NM_IPV4LO_ADDR1, + .peer_address = NM_IPV4LO_ADDR1, + .plen = NM_IPV4LO_PREFIXLEN, + .use_ip4_broadcast_address = TRUE, + }; + + if (nm_platform_ip4_address_cmp(a4, + &addr, + NM_PLATFORM_IP_ADDRESS_CMP_TYPE_SEMANTICALLY) + == 0) { + continue; + } + } + } else { const NMPlatformIP6Address *a6 = NMP_OBJECT_CAST_IP6_ADDRESS(obj); if (NM_FLAGS_HAS(a6->n_ifa_flags, IFA_F_SECONDARY) @@ -4665,6 +4684,44 @@ nm_platform_ip_route_get_prune_list(NMPlatform *self, * pruning them. */ if (NM_IS_IPv4(addr_family)) { + if (ifindex == NM_LOOPBACK_IFINDEX + && NM_IN_SET(rt->r4.network, NM_IPV4LO_ADDR1, NM_IPV4LO_NETWORK)) { + NMPlatformIP4Route r; + + if (rt->r4.network == NM_IPV4LO_ADDR1) { + r = (NMPlatformIP4Route){ + .ifindex = NM_LOOPBACK_IFINDEX, + .type_coerced = nm_platform_route_type_coerce(RTN_LOCAL), + .table_coerced = nm_platform_route_table_coerce(local_table), + .network = NM_IPV4LO_ADDR1, + .plen = 32, + .metric = 0, + .rt_source = NM_IPV4LO_ADDR1, + .scope_inv = nm_platform_route_scope_inv(RT_SCOPE_HOST), + .pref_src = NM_IPV4LO_ADDR1, + }; + } else { + r = (NMPlatformIP4Route){ + .ifindex = NM_LOOPBACK_IFINDEX, + .type_coerced = nm_platform_route_type_coerce(RTN_LOCAL), + .table_coerced = nm_platform_route_table_coerce(local_table), + .network = NM_IPV4LO_NETWORK, + .plen = NM_IPV4LO_PREFIXLEN, + .metric = 0, + .rt_source = NM_IPV4LO_ADDR1, + .scope_inv = nm_platform_route_scope_inv(RT_SCOPE_HOST), + .pref_src = NM_IPV4LO_ADDR1, + }; + } + + if (nm_platform_ip4_route_cmp(&rt->r4, + &r, + NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) + == 0) { + continue; + } + } + /* for each IPv4 address kernel adds a route like * * local $ADDR dev $IFACE table local proto kernel scope host src $PRIMARY_ADDR diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index 32773b67ad..36df3db94f 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -2464,4 +2464,29 @@ void nm_platform_ip6_dadfailed_set(NMPlatform *self, const struct in6_addr *ip6, gboolean failed); +/*****************************************************************************/ + +static inline NMPlatformIP4Address * +nm_platform_ip4_address_init_loopback_addr1(NMPlatformIP4Address *a) +{ + *a = ((NMPlatformIP4Address){ + .address = NM_IPV4LO_ADDR1, + .peer_address = NM_IPV4LO_ADDR1, + .ifindex = NM_LOOPBACK_IFINDEX, + .plen = NM_IPV4LO_PREFIXLEN, + }); + return a; +} + +static inline NMPlatformIP6Address * +nm_platform_ip6_address_init_loopback(NMPlatformIP6Address *a) +{ + *a = ((NMPlatformIP6Address){ + .address = IN6ADDR_LOOPBACK_INIT, + .ifindex = NM_LOOPBACK_IFINDEX, + .plen = 128, + }); + return a; +} + #endif /* __NETWORKMANAGER_PLATFORM_H__ */ diff --git a/src/libnmc-setting/nm-meta-setting-base-impl.c b/src/libnmc-setting/nm-meta-setting-base-impl.c index 5e627cfc7d..e93a1555dc 100644 --- a/src/libnmc-setting/nm-meta-setting-base-impl.c +++ b/src/libnmc-setting/nm-meta-setting-base-impl.c @@ -34,6 +34,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" @@ -360,6 +361,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, @@ -610,6 +618,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 c4e5e7de03..40dd28f31b 100644 --- a/src/libnmc-setting/nm-meta-setting-desc.c +++ b/src/libnmc-setting/nm-meta-setting-desc.c @@ -6561,6 +6561,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[] = { @@ -8317,6 +8332,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") @@ -8476,6 +8492,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 2873abd127..2f2d561297 100644 --- a/src/libnmc-setting/settings-docs.h.in +++ b/src/libnmc-setting/settings-docs.h.in @@ -432,5 +432,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/gen-metadata-nm-settings-nmcli.xml.in b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in index 941b1e353e..41be4a8e8c 100644 --- a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in +++ b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in @@ -762,6 +762,11 @@ + + +