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 @@ + + +