diff --git a/Makefile.am b/Makefile.am index 19242c14bc..f83cf25bd7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1021,6 +1021,8 @@ introspection_sources = \ introspection/org.freedesktop.NetworkManager.Device.Dummy.h \ introspection/org.freedesktop.NetworkManager.Device.Generic.c \ introspection/org.freedesktop.NetworkManager.Device.Generic.h \ + introspection/org.freedesktop.NetworkManager.Device.Hsr.c \ + introspection/org.freedesktop.NetworkManager.Device.Hsr.h \ introspection/org.freedesktop.NetworkManager.Device.IPTunnel.c \ introspection/org.freedesktop.NetworkManager.Device.IPTunnel.h \ introspection/org.freedesktop.NetworkManager.Device.Infiniband.c \ @@ -1112,6 +1114,7 @@ DBUS_INTERFACE_DOCS = \ docs/api/dbus-org.freedesktop.NetworkManager.Device.Bridge.xml \ docs/api/dbus-org.freedesktop.NetworkManager.Device.Dummy.xml \ docs/api/dbus-org.freedesktop.NetworkManager.Device.Generic.xml \ + docs/api/dbus-org.freedesktop.NetworkManager.Device.Hsr.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 \ @@ -1181,6 +1184,7 @@ dbusinterfaces_DATA = \ introspection/org.freedesktop.NetworkManager.Device.Bridge.xml \ introspection/org.freedesktop.NetworkManager.Device.Dummy.xml \ introspection/org.freedesktop.NetworkManager.Device.Generic.xml \ + introspection/org.freedesktop.NetworkManager.Device.Hsr.xml \ introspection/org.freedesktop.NetworkManager.Device.IPTunnel.xml \ introspection/org.freedesktop.NetworkManager.Device.Infiniband.xml \ introspection/org.freedesktop.NetworkManager.Device.Loopback.xml \ @@ -1260,6 +1264,7 @@ src_libnm_core_impl_lib_h_pub_real = \ src/libnm-core-public/nm-setting-generic.h \ src/libnm-core-public/nm-setting-gsm.h \ src/libnm-core-public/nm-setting-hostname.h \ + src/libnm-core-public/nm-setting-hsr.h \ src/libnm-core-public/nm-setting-infiniband.h \ src/libnm-core-public/nm-setting-ip-config.h \ src/libnm-core-public/nm-setting-ip-tunnel.h \ @@ -1342,6 +1347,7 @@ src_libnm_core_impl_lib_c_settings_real = \ src/libnm-core-impl/nm-setting-generic.c \ src/libnm-core-impl/nm-setting-gsm.c \ src/libnm-core-impl/nm-setting-hostname.c \ + src/libnm-core-impl/nm-setting-hsr.c \ src/libnm-core-impl/nm-setting-infiniband.c \ src/libnm-core-impl/nm-setting-ip-config.c \ src/libnm-core-impl/nm-setting-ip-tunnel.c \ @@ -1741,6 +1747,7 @@ libnm_lib_h_pub_real = \ src/libnm-client-public/nm-device-dummy.h \ src/libnm-client-public/nm-device-ethernet.h \ src/libnm-client-public/nm-device-generic.h \ + src/libnm-client-public/nm-device-hsr.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 \ @@ -1812,6 +1819,7 @@ libnm_lib_c_real = \ src/libnm-client-impl/nm-device-dummy.c \ src/libnm-client-impl/nm-device-ethernet.c \ src/libnm-client-impl/nm-device-generic.c \ + src/libnm-client-impl/nm-device-hsr.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 \ @@ -2656,6 +2664,8 @@ src_core_libNetworkManager_la_SOURCES = \ src/core/devices/nm-device-dummy.h \ src/core/devices/nm-device-ethernet.c \ src/core/devices/nm-device-ethernet.h \ + src/core/devices/nm-device-hsr.c \ + src/core/devices/nm-device-hsr.h \ src/core/devices/nm-device-infiniband.c \ src/core/devices/nm-device-infiniband.h \ src/core/devices/nm-device-ip-tunnel.c \ diff --git a/docs/api/Makefile.am b/docs/api/Makefile.am index 4bdce0e00b..069fd63959 100644 --- a/docs/api/Makefile.am +++ b/docs/api/Makefile.am @@ -39,6 +39,7 @@ content_files = \ dbus-org.freedesktop.NetworkManager.Device.Bridge.xml \ dbus-org.freedesktop.NetworkManager.Device.Dummy.xml \ dbus-org.freedesktop.NetworkManager.Device.Generic.xml \ + dbus-org.freedesktop.NetworkManager.Device.Hsr.xml \ dbus-org.freedesktop.NetworkManager.Device.IPTunnel.xml \ dbus-org.freedesktop.NetworkManager.Device.Infiniband.xml \ dbus-org.freedesktop.NetworkManager.Device.Loopback.xml \ diff --git a/docs/api/network-manager-docs.xml b/docs/api/network-manager-docs.xml index 5c45ca74ee..faee87992e 100644 --- a/docs/api/network-manager-docs.xml +++ b/docs/api/network-manager-docs.xml @@ -183,6 +183,7 @@ + diff --git a/docs/libnm/libnm-docs.xml b/docs/libnm/libnm-docs.xml index 18a3fe05ba..f2b5658cdf 100644 --- a/docs/libnm/libnm-docs.xml +++ b/docs/libnm/libnm-docs.xml @@ -319,6 +319,7 @@ print ("NetworkManager version " + client.get_version())]]> + @@ -374,6 +375,7 @@ print ("NetworkManager version " + client.get_version())]]> + diff --git a/introspection/meson.build b/introspection/meson.build index 9a35548842..77479277ac 100644 --- a/introspection/meson.build +++ b/introspection/meson.build @@ -15,6 +15,7 @@ ifaces = [ 'org.freedesktop.NetworkManager.Device.Bridge', 'org.freedesktop.NetworkManager.Device.Dummy', 'org.freedesktop.NetworkManager.Device.Generic', + 'org.freedesktop.NetworkManager.Device.Hsr', 'org.freedesktop.NetworkManager.Device.IPTunnel', 'org.freedesktop.NetworkManager.Device.Infiniband', 'org.freedesktop.NetworkManager.Device.Loopback', diff --git a/introspection/org.freedesktop.NetworkManager.Device.Hsr.xml b/introspection/org.freedesktop.NetworkManager.Device.Hsr.xml new file mode 100644 index 0000000000..599ddb6f9e --- /dev/null +++ b/introspection/org.freedesktop.NetworkManager.Device.Hsr.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/core/devices/nm-device-factory.c b/src/core/devices/nm-device-factory.c index 2f0ae2e8e5..c97fbb57d1 100644 --- a/src/core/devices/nm-device-factory.c +++ b/src/core/devices/nm-device-factory.c @@ -396,6 +396,7 @@ nm_device_factory_manager_load_factories(NMDeviceFactoryManagerFactoryFunc callb _ADD_INTERNAL(nm_bridge_device_factory_get_type); _ADD_INTERNAL(nm_dummy_device_factory_get_type); _ADD_INTERNAL(nm_ethernet_device_factory_get_type); + _ADD_INTERNAL(nm_hsr_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); diff --git a/src/core/devices/nm-device-hsr.c b/src/core/devices/nm-device-hsr.c new file mode 100644 index 0000000000..eef99afade --- /dev/null +++ b/src/core/devices/nm-device-hsr.c @@ -0,0 +1,290 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023 Red Hat, Inc. + */ + +#include "src/core/nm-default-daemon.h" + +#include "nm-manager.h" +#include "nm-device-hsr.h" + +#include + +#include "libnm-core-intern/nm-core-internal.h" +#include "nm-act-request.h" +#include "nm-device-private.h" +#include "nm-setting-hsr.h" +#include "libnm-platform/nm-platform.h" +#include "nm-device-factory.h" + +#define _NMLOG_DEVICE_TYPE NMDeviceHsr +#include "nm-device-logging.h" + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceHsr, + PROP_PORT1, + PROP_PORT2, + PROP_SUPERVISION_ADDRESS, + PROP_MULTICAST_SPEC, + PROP_PRP, ); + +typedef struct { + NMPlatformLnkHsr props; +} NMDeviceHsrPrivate; + +struct _NMDeviceHsr { + NMDevice parent; + NMDeviceHsrPrivate _priv; +}; + +struct _NMDeviceHsrClass { + NMDeviceClass parent; +}; + +G_DEFINE_TYPE(NMDeviceHsr, nm_device_hsr, NM_TYPE_DEVICE) + +#define NM_DEVICE_HSR_GET_PRIVATE(self) \ + _NM_GET_PRIVATE(self, NMDeviceHsr, NM_IS_DEVICE_HSR, NMDevice) + +/*****************************************************************************/ + +static NMDeviceCapabilities +get_generic_capabilities(NMDevice *dev) +{ + return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; +} + +static void +update_properties(NMDevice *device) +{ + NMDeviceHsr *self; + NMDeviceHsrPrivate *priv; + const NMPlatformLink *plink; + const NMPlatformLnkHsr *props; + int ifindex; + + g_return_if_fail(NM_IS_DEVICE_HSR(device)); + self = NM_DEVICE_HSR(device); + priv = NM_DEVICE_HSR_GET_PRIVATE(self); + + ifindex = nm_device_get_ifindex(device); + g_return_if_fail(ifindex > 0); + props = nm_platform_link_get_lnk_hsr(nm_device_get_platform(device), ifindex, &plink); + + if (!props) { + _LOGW(LOGD_PLATFORM, "could not get HSR properties"); + return; + } + + g_object_freeze_notify((GObject *) device); + +#define CHECK_PROPERTY_CHANGED(field, prop) \ + G_STMT_START \ + { \ + if (priv->props.field != props->field) { \ + priv->props.field = props->field; \ + _notify(self, prop); \ + } \ + } \ + G_STMT_END + + CHECK_PROPERTY_CHANGED(port1, PROP_PORT1); + CHECK_PROPERTY_CHANGED(port2, PROP_PORT2); + CHECK_PROPERTY_CHANGED(multicast_spec, PROP_MULTICAST_SPEC); + CHECK_PROPERTY_CHANGED(prp, PROP_PRP); + + if (!nm_ether_addr_equal(&priv->props.supervision_address, &props->supervision_address)) + _notify(self, PROP_SUPERVISION_ADDRESS); + + g_object_thaw_notify((GObject *) device); +} + +static void +link_changed(NMDevice *device, const NMPlatformLink *pllink) +{ + NM_DEVICE_CLASS(nm_device_hsr_parent_class)->link_changed(device, pllink); + update_properties(device); +} + +static gboolean +create_and_realize(NMDevice *device, + NMConnection *connection, + NMDevice *parent, + const NMPlatformLink **out_plink, + GError **error) +{ + const char *iface = nm_device_get_iface(device); + NMSettingHsr *s_hsr; + NMPlatformLnkHsr lnk = {}; + int r; + + s_hsr = _nm_connection_get_setting(connection, NM_TYPE_SETTING_HSR); + nm_assert(s_hsr); + + if (nm_setting_hsr_get_port1(s_hsr) != NULL) + lnk.port1 = nm_platform_link_get_ifindex(NM_PLATFORM_GET, nm_setting_hsr_get_port1(s_hsr)); + if (nm_setting_hsr_get_port2(s_hsr) != NULL) + lnk.port2 = nm_platform_link_get_ifindex(NM_PLATFORM_GET, nm_setting_hsr_get_port2(s_hsr)); + if (nm_setting_hsr_get_supervision_address(s_hsr) != NULL) + nm_ether_addr_from_string(&lnk.supervision_address, + nm_setting_hsr_get_supervision_address(s_hsr)); + lnk.multicast_spec = nm_setting_hsr_get_multicast_spec(s_hsr); + lnk.prp = nm_setting_hsr_get_prp(s_hsr); + r = nm_platform_link_hsr_add(nm_device_get_platform(device), iface, &lnk, out_plink); + if (r < 0) { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create HSR interface '%s' for '%s': %s", + iface, + nm_connection_get_id(connection), + nm_strerror(r)); + return FALSE; + } + + return TRUE; +} + +/*****************************************************************************/ + +static void +get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + NMDeviceHsr *self = NM_DEVICE_HSR(object); + NMDeviceHsrPrivate *priv = NM_DEVICE_HSR_GET_PRIVATE(self); + NMDevice *port; + + switch (prop_id) { + case PROP_PORT1: + port = nm_manager_get_device_by_ifindex(NM_MANAGER_GET, priv->props.port1); + nm_dbus_utils_g_value_set_object_path(value, port); + break; + case PROP_PORT2: + port = nm_manager_get_device_by_ifindex(NM_MANAGER_GET, priv->props.port2); + nm_dbus_utils_g_value_set_object_path(value, port); + break; + case PROP_SUPERVISION_ADDRESS: + g_value_take_string(value, nm_ether_addr_to_string_dup(&priv->props.supervision_address)); + break; + case PROP_MULTICAST_SPEC: + g_value_set_uchar(value, priv->props.multicast_spec); + break; + case PROP_PRP: + g_value_set_boolean(value, priv->props.prp); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +nm_device_hsr_init(NMDeviceHsr *self) +{} + +/*****************************************************************************/ + +static const NMDBusInterfaceInfoExtended interface_info_device_hsr = { + .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( + NM_DBUS_INTERFACE_DEVICE_HSR, + .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Port1", "o", NM_DEVICE_HSR_PORT1), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Port2", "o", NM_DEVICE_HSR_PORT2), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("SupervisionAddress", + "s", + NM_DEVICE_HSR_SUPERVISION_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("MulticastSpec", + "y", + NM_DEVICE_HSR_MULTICAST_SPEC), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Prp", "b", NM_DEVICE_HSR_PRP), ), ), +}; + +static void +nm_device_hsr_class_init(NMDeviceHsrClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); + NMDeviceClass *device_class = NM_DEVICE_CLASS(klass); + + object_class->get_property = get_property; + + dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_hsr); + + device_class->connection_type_supported = NM_SETTING_HSR_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_HSR_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_HSR); + + device_class->link_changed = link_changed; + device_class->create_and_realize = create_and_realize; + device_class->get_generic_capabilities = get_generic_capabilities; + + obj_properties[PROP_PORT1] = g_param_spec_string(NM_DEVICE_HSR_PORT1, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_PORT2] = g_param_spec_string(NM_DEVICE_HSR_PORT2, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_SUPERVISION_ADDRESS] = + g_param_spec_string(NM_DEVICE_HSR_SUPERVISION_ADDRESS, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_MULTICAST_SPEC] = + g_param_spec_uchar(NM_DEVICE_HSR_MULTICAST_SPEC, + "", + "", + 0, + G_MAXUINT8, + 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_PRP] = g_param_spec_boolean(NM_DEVICE_HSR_PRP, + "", + "", + FALSE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); +} + +/*****************************************************************************/ + +#define NM_TYPE_HSR_DEVICE_FACTORY (nm_hsr_device_factory_get_type()) +#define NM_HSR_DEVICE_FACTORY(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_HSR_DEVICE_FACTORY, NMHsrDeviceFactory)) + +static NMDevice * +create_device(NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) +{ + return g_object_new(NM_TYPE_DEVICE_HSR, + NM_DEVICE_IFACE, + iface, + NM_DEVICE_TYPE_DESC, + "hsr", + NM_DEVICE_DEVICE_TYPE, + NM_DEVICE_TYPE_HSR, + NM_DEVICE_LINK_TYPE, + NM_LINK_TYPE_HSR, + NULL); +} + +NM_DEVICE_FACTORY_DEFINE_INTERNAL( + HSR, + Hsr, + hsr, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_HSR) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_HSR_SETTING_NAME), + factory_class->create_device = create_device;) diff --git a/src/core/devices/nm-device-hsr.h b/src/core/devices/nm-device-hsr.h new file mode 100644 index 0000000000..1da90358a5 --- /dev/null +++ b/src/core/devices/nm-device-hsr.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023 Red Hat, Inc. + */ + +#ifndef __NETWORKMANAGER_DEVICE_HSR_H__ +#define __NETWORKMANAGER_DEVICE_HSR_H__ + +#include "nm-device.h" + +#define NM_TYPE_DEVICE_HSR (nm_device_hsr_get_type()) +#define NM_DEVICE_HSR(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_HSR, NMDeviceHsr)) +#define NM_DEVICE_HSR_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_HSR, NMDeviceHsrClass)) +#define NM_IS_DEVICE_HSR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_HSR)) +#define NM_IS_DEVICE_HSR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_HSR)) +#define NM_DEVICE_HSR_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_HSR, NMDeviceHsrClass)) + +#define NM_DEVICE_HSR_PORT1 "port1" +#define NM_DEVICE_HSR_PORT2 "port2" +#define NM_DEVICE_HSR_SUPERVISION_ADDRESS "supervision-address" +#define NM_DEVICE_HSR_MULTICAST_SPEC "multicast-spec" +#define NM_DEVICE_HSR_PRP "prp" + +typedef struct _NMDeviceHsr NMDeviceHsr; +typedef struct _NMDeviceHsrClass NMDeviceHsrClass; + +GType nm_device_hsr_get_type(void); + +#endif /* __NETWORKMANAGER_DEVICE_HSR_H__ */ diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index f177fb2f82..be02526fba 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -5450,6 +5450,8 @@ nm_device_get_route_metric_default(NMDeviceType device_type) return 200; case NM_DEVICE_TYPE_WIMAX: return 250; + case NM_DEVICE_TYPE_HSR: + return 275; case NM_DEVICE_TYPE_BOND: return 300; case NM_DEVICE_TYPE_TEAM: @@ -18310,7 +18312,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_LOOPBACK); + nm_assert(priv->type <= NM_DEVICE_TYPE_HSR); break; case PROP_LINK_TYPE: /* construct-only */ diff --git a/src/core/meson.build b/src/core/meson.build index 6c1d463ed1..45b068a675 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -102,6 +102,7 @@ libNetworkManager = static_library( 'devices/nm-device-ethernet-utils.c', 'devices/nm-device-factory.c', 'devices/nm-device-generic.c', + 'devices/nm-device-hsr.c', 'devices/nm-device-infiniband.c', 'devices/nm-device-ip-tunnel.c', 'devices/nm-device-loopback.c', diff --git a/src/libnm-client-impl/libnm.ver b/src/libnm-client-impl/libnm.ver index 01df94c341..59b45d3227 100644 --- a/src/libnm-client-impl/libnm.ver +++ b/src/libnm-client-impl/libnm.ver @@ -1947,7 +1947,20 @@ global: libnm_1_46_0 { global: nm_access_point_get_bandwidth; + nm_device_hsr_get_multicast_spec; + nm_device_hsr_get_port1; + nm_device_hsr_get_port2; + nm_device_hsr_get_prp; + nm_device_hsr_get_supervision_address; + nm_device_hsr_get_type; nm_device_ip_tunnel_get_fwmark; nm_ethtool_optname_is_channels; nm_ethtool_optname_is_eee; + nm_setting_hsr_get_multicast_spec; + nm_setting_hsr_get_port1; + nm_setting_hsr_get_port2; + nm_setting_hsr_get_prp; + nm_setting_hsr_get_supervision_address; + nm_setting_hsr_get_type; + nm_setting_hsr_new; } libnm_1_44_0; diff --git a/src/libnm-client-impl/meson.build b/src/libnm-client-impl/meson.build index 967565362d..79ac95598a 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-dummy.c', 'nm-device-ethernet.c', 'nm-device-generic.c', + 'nm-device-hsr.c', 'nm-device-infiniband.c', 'nm-device-ip-tunnel.c', 'nm-device-loopback.c', diff --git a/src/libnm-client-impl/nm-client.c b/src/libnm-client-impl/nm-client.c index f3ab6d69e0..1598fb308d 100644 --- a/src/libnm-client-impl/nm-client.c +++ b/src/libnm-client-impl/nm-client.c @@ -29,6 +29,7 @@ #include "nm-device-dummy.h" #include "nm-device-ethernet.h" #include "nm-device-generic.h" +#include "nm-device-hsr.h" #include "nm-device-infiniband.h" #include "nm-device-ip-tunnel.h" #include "nm-device-loopback.h" diff --git a/src/libnm-client-impl/nm-device-hsr.c b/src/libnm-client-impl/nm-device-hsr.c new file mode 100644 index 0000000000..7160bf6d98 --- /dev/null +++ b/src/libnm-client-impl/nm-device-hsr.c @@ -0,0 +1,279 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023 Red Hat, Inc. + */ + +#include "libnm-client-impl/nm-default-libnm.h" + +#include "nm-device-hsr.h" + +#include "nm-setting-connection.h" +#include "nm-setting-hsr.h" +#include "nm-utils.h" +#include "nm-object-private.h" + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_PORT1, + PROP_PORT2, + PROP_SUPERVISION_ADDRESS, + PROP_MULTICAST_SPEC, + PROP_PRP, ); + +typedef struct { + char *supervision_address; + NMLDBusPropertyO port1; + NMLDBusPropertyO port2; + guint8 multicast_spec; + bool prp; +} NMDeviceHsrPrivate; + +struct _NMDeviceHsr { + NMDevice parent; + NMDeviceHsrPrivate _priv; +}; + +struct _NMDeviceHsrClass { + NMDeviceClass parent; +}; + +G_DEFINE_TYPE(NMDeviceHsr, nm_device_hsr, NM_TYPE_DEVICE) + +#define NM_DEVICE_HSR_GET_PRIVATE(self) \ + _NM_GET_PRIVATE(self, NMDeviceHsr, NM_IS_DEVICE_HSR, NMObject, NMDevice) + +/*****************************************************************************/ + +/** + * nm_device_hsr_get_port1: + * @device: a #NMDeviceHsr + * + * Returns: (transfer none): the device's port1 device + * + * Since: 1.46 + **/ +NMDevice * +nm_device_hsr_get_port1(NMDeviceHsr *device) +{ + g_return_val_if_fail(NM_IS_DEVICE_HSR(device), NULL); + + return nml_dbus_property_o_get_obj(&NM_DEVICE_HSR_GET_PRIVATE(device)->port1); +} + +/** + * nm_device_hsr_get_port2: + * @device: a #NMDeviceHsr + * + * Returns: (transfer none): the device's port2 device + * + * Since: 1.46 + **/ +NMDevice * +nm_device_hsr_get_port2(NMDeviceHsr *device) +{ + g_return_val_if_fail(NM_IS_DEVICE_HSR(device), NULL); + + return nml_dbus_property_o_get_obj(&NM_DEVICE_HSR_GET_PRIVATE(device)->port2); +} + +/** + * nm_device_hsr_get_supervision_address: + * @device: a #NMDeviceHsr + * + * Returns: the supervision MAC adddress + * + * Since: 1.46 + **/ +const char * +nm_device_hsr_get_supervision_address(NMDeviceHsr *device) +{ + g_return_val_if_fail(NM_IS_DEVICE_HSR(device), NULL); + + return NM_DEVICE_HSR_GET_PRIVATE(device)->supervision_address; +} + +/** + * nm_device_hsr_get_multicast_spec: + * @device: a #NMDeviceHsr + * + * Returns: the last byte of the supervision address + * + * Since: 1.46 + **/ +guint8 +nm_device_hsr_get_multicast_spec(NMDeviceHsr *device) +{ + g_return_val_if_fail(NM_IS_DEVICE_HSR(device), 0); + + return NM_DEVICE_HSR_GET_PRIVATE(device)->multicast_spec; +} + +/** + * nm_device_hsr_get_prp: + * @device: a #NMDeviceHsr + * + * Returns: whether PRP protocol is used or not + * + * Since: 1.46 + **/ +gboolean +nm_device_hsr_get_prp(NMDeviceHsr *device) +{ + g_return_val_if_fail(NM_IS_DEVICE_HSR(device), FALSE); + + return NM_DEVICE_HSR_GET_PRIVATE(device)->prp; +} + +/*****************************************************************************/ + +static void +nm_device_hsr_init(NMDeviceHsr *device) +{} + +static void +finalize(GObject *object) +{ + NMDeviceHsrPrivate *priv = NM_DEVICE_HSR_GET_PRIVATE(object); + + g_free(priv->supervision_address); + + G_OBJECT_CLASS(nm_device_hsr_parent_class)->finalize(object); +} + +static void +get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + NMDeviceHsr *device = NM_DEVICE_HSR(object); + + switch (prop_id) { + case PROP_PORT1: + g_value_set_object(value, nm_device_hsr_get_port1(device)); + break; + case PROP_PORT2: + g_value_set_object(value, nm_device_hsr_get_port2(device)); + break; + case PROP_SUPERVISION_ADDRESS: + g_value_set_string(value, nm_device_hsr_get_supervision_address(device)); + break; + case PROP_MULTICAST_SPEC: + g_value_set_uchar(value, nm_device_hsr_get_multicast_spec(device)); + break; + case PROP_PRP: + g_value_set_boolean(value, nm_device_hsr_get_prp(device)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_hsr = NML_DBUS_META_IFACE_INIT_PROP( + NM_DBUS_INTERFACE_DEVICE_HSR, + nm_device_hsr_get_type, + NML_DBUS_META_INTERFACE_PRIO_INSTANTIATE_30, + NML_DBUS_META_IFACE_DBUS_PROPERTIES( + NML_DBUS_META_PROPERTY_INIT_Y("MulticastSpec", + PROP_MULTICAST_SPEC, + NMDeviceHsr, + _priv.multicast_spec), + NML_DBUS_META_PROPERTY_INIT_O_PROP("Port1", + PROP_PORT1, + NMDeviceHsr, + _priv.port1, + nm_device_get_type), + NML_DBUS_META_PROPERTY_INIT_O_PROP("Port2", + PROP_PORT2, + NMDeviceHsr, + _priv.port2, + nm_device_get_type), + NML_DBUS_META_PROPERTY_INIT_B("Prp", PROP_PRP, NMDeviceHsr, _priv.prp), + NML_DBUS_META_PROPERTY_INIT_S("SupervisionAddress", + PROP_SUPERVISION_ADDRESS, + NMDeviceHsr, + _priv.supervision_address), ), ); + +static void +nm_device_hsr_class_init(NMDeviceHsrClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + NMObjectClass *nm_object_class = NM_OBJECT_CLASS(klass); + + object_class->get_property = get_property; + object_class->finalize = finalize; + + _NM_OBJECT_CLASS_INIT_PRIV_PTR_DIRECT(nm_object_class, NMDeviceHsr); + + _NM_OBJECT_CLASS_INIT_PROPERTY_O_FIELDS_1(nm_object_class, NMDeviceHsrPrivate, port1); + _NM_OBJECT_CLASS_INIT_PROPERTY_O_FIELDS_1(nm_object_class, NMDeviceHsrPrivate, port2); + + /** + * NMDeviceHsr:port1: + * + * The device's port1 device. + * + * Since: 1.46 + **/ + obj_properties[PROP_PORT1] = g_param_spec_object(NM_DEVICE_HSR_PORT1, + "", + "", + NM_TYPE_DEVICE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + /** + * NMDeviceHsr:port2: + * + * The device's port2 device. + * + * Since: 1.46 + **/ + obj_properties[PROP_PORT2] = g_param_spec_object(NM_DEVICE_HSR_PORT2, + "", + "", + NM_TYPE_DEVICE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + /** + * NMDeviceHsr:supervision-address: + * + * The device supervision MAC adddress. + * + * Since: 1.46 + **/ + obj_properties[PROP_SUPERVISION_ADDRESS] = + g_param_spec_string(NM_DEVICE_HSR_SUPERVISION_ADDRESS, + "", + "", + FALSE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + /** + * NMDeviceHsr:multicast-spec: + * + * The device last byte of the supervision address. + * + * Since: 1.46 + **/ + obj_properties[PROP_MULTICAST_SPEC] = + g_param_spec_uchar(NM_DEVICE_HSR_MULTICAST_SPEC, + "", + "", + 0, + G_MAXUINT8, + 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + /** + * NMDeviceHsr:prp: + * + * Whether the PRP protocol is used or not. + * + * Since: 1.46 + **/ + obj_properties[PROP_PRP] = g_param_spec_boolean(NM_DEVICE_HSR_PRP, + "", + "", + FALSE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + _nml_dbus_meta_class_init_with_properties(object_class, &_nml_dbus_meta_iface_nm_device_hsr); +} diff --git a/src/libnm-client-impl/nm-device.c b/src/libnm-client-impl/nm-device.c index e3e6ca6e0d..2d3be64c8e 100644 --- a/src/libnm-client-impl/nm-device.c +++ b/src/libnm-client-impl/nm-device.c @@ -313,6 +313,7 @@ coerce_type(NMDeviceType type) case NM_DEVICE_TYPE_WIFI_P2P: case NM_DEVICE_TYPE_VRF: case NM_DEVICE_TYPE_LOOPBACK: + case NM_DEVICE_TYPE_HSR: return type; } return NM_DEVICE_TYPE_UNKNOWN; @@ -1814,6 +1815,8 @@ get_type_name(NMDevice *device) return _("VRF"); case NM_DEVICE_TYPE_LOOPBACK: return _("Loopback"); + case NM_DEVICE_TYPE_HSR: + return _("HSR"); case NM_DEVICE_TYPE_GENERIC: case NM_DEVICE_TYPE_UNUSED1: case NM_DEVICE_TYPE_UNUSED2: diff --git a/src/libnm-client-public/NetworkManager.h b/src/libnm-client-public/NetworkManager.h index 61adee29d2..646431f62b 100644 --- a/src/libnm-client-public/NetworkManager.h +++ b/src/libnm-client-public/NetworkManager.h @@ -39,6 +39,7 @@ #include "nm-setting-generic.h" #include "nm-setting-gsm.h" #include "nm-setting-hostname.h" +#include "nm-setting-hsr.h" #include "nm-setting-infiniband.h" #include "nm-setting-ip4-config.h" #include "nm-setting-ip6-config.h" @@ -111,6 +112,7 @@ #include "nm-device-dummy.h" #include "nm-device-ethernet.h" #include "nm-device-generic.h" +#include "nm-device-hsr.h" #include "nm-device-infiniband.h" #include "nm-device-ip-tunnel.h" #include "nm-device-loopback.h" diff --git a/src/libnm-client-public/meson.build b/src/libnm-client-public/meson.build index bac7e4574b..dccbb11fe3 100644 --- a/src/libnm-client-public/meson.build +++ b/src/libnm-client-public/meson.build @@ -18,6 +18,7 @@ libnm_client_headers = files( 'nm-device-dummy.h', 'nm-device-ethernet.h', 'nm-device-generic.h', + 'nm-device-hsr.h', 'nm-device-infiniband.h', 'nm-device-ip-tunnel.h', 'nm-device-loopback.h', diff --git a/src/libnm-client-public/nm-autoptr.h b/src/libnm-client-public/nm-autoptr.h index fde6cccf32..c38f270c0c 100644 --- a/src/libnm-client-public/nm-autoptr.h +++ b/src/libnm-client-public/nm-autoptr.h @@ -41,6 +41,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMDeviceBt, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMDeviceDummy, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMDeviceEthernet, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMDeviceGeneric, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMDeviceHsr, 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) @@ -80,6 +81,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingEthtool, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingGeneric, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingGsm, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingHostname, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingHsr, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingIP4Config, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingIP6Config, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingIPConfig, g_object_unref) diff --git a/src/libnm-client-public/nm-device-hsr.h b/src/libnm-client-public/nm-device-hsr.h new file mode 100644 index 0000000000..102de95c90 --- /dev/null +++ b/src/libnm-client-public/nm-device-hsr.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023 Red Hat, Inc. + */ + +#ifndef __NM_DEVICE_HSR_H__ +#define __NM_DEVICE_HSR_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_HSR (nm_device_hsr_get_type()) +#define NM_DEVICE_HSR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_HSR, NMDeviceHsr)) +#define NM_DEVICE_HSR_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_HSR, NMDeviceHsClass)) +#define NM_IS_DEVICE_HSR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_HSR)) +#define NM_IS_DEVICE_HSR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_HSR)) +#define NM_DEVICE_HSR_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_HSR, NMDeviceHsrClass)) + +#define NM_DEVICE_HSR_PORT1 "port1" +#define NM_DEVICE_HSR_PORT2 "port2" +#define NM_DEVICE_HSR_SUPERVISION_ADDRESS "supervision-address" +#define NM_DEVICE_HSR_MULTICAST_SPEC "multicast-spec" +#define NM_DEVICE_HSR_PRP "prp" + +/** + * NMDeviceHsr: + * + * Since: 1.46 + */ +typedef struct _NMDeviceHsr NMDeviceHsr; +typedef struct _NMDeviceHsrClass NMDeviceHsrClass; + +NM_AVAILABLE_IN_1_46 +GType nm_device_hsr_get_type(void); + +NM_AVAILABLE_IN_1_46 +NMDevice *nm_device_hsr_get_port1(NMDeviceHsr *device); +NM_AVAILABLE_IN_1_46 +NMDevice *nm_device_hsr_get_port2(NMDeviceHsr *device); +NM_AVAILABLE_IN_1_46 +const char *nm_device_hsr_get_supervision_address(NMDeviceHsr *device); +NM_AVAILABLE_IN_1_46 +guint8 nm_device_hsr_get_multicast_spec(NMDeviceHsr *device); +NM_AVAILABLE_IN_1_46 +gboolean nm_device_hsr_get_prp(NMDeviceHsr *device); + +G_END_DECLS + +#endif /* __NM_DEVICE_HSR_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 3c409b60bd..6e853d7b76 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 @@ -1418,6 +1418,30 @@ gprop-type="gint" /> + + + + + + + diff --git a/src/libnm-core-impl/meson.build b/src/libnm-core-impl/meson.build index 635b417b7e..d6cf950557 100644 --- a/src/libnm-core-impl/meson.build +++ b/src/libnm-core-impl/meson.build @@ -19,6 +19,7 @@ libnm_core_settings_sources = files( 'nm-setting-generic.c', 'nm-setting-gsm.c', 'nm-setting-hostname.c', + 'nm-setting-hsr.c', 'nm-setting-infiniband.c', 'nm-setting-ip-config.c', 'nm-setting-ip-tunnel.c', diff --git a/src/libnm-core-impl/nm-connection.c b/src/libnm-core-impl/nm-connection.c index d156915682..2430acec59 100644 --- a/src/libnm-core-impl/nm-connection.c +++ b/src/libnm-core-impl/nm-connection.c @@ -3182,6 +3182,7 @@ nm_connection_is_virtual(NMConnection *connection) NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BRIDGE_SETTING_NAME, NM_SETTING_DUMMY_SETTING_NAME, + NM_SETTING_HSR_SETTING_NAME, NM_SETTING_IP_TUNNEL_SETTING_NAME, NM_SETTING_MACSEC_SETTING_NAME, NM_SETTING_MACVLAN_SETTING_NAME, diff --git a/src/libnm-core-impl/nm-keyfile.c b/src/libnm-core-impl/nm-keyfile.c index 078ea5d766..884bad5fa0 100644 --- a/src/libnm-core-impl/nm-keyfile.c +++ b/src/libnm-core-impl/nm-keyfile.c @@ -3044,6 +3044,10 @@ static const ParseInfoSetting *const parse_infos[_NM_META_SETTING_TYPE_NUM] = { PARSE_INFO_PROPERTY(NM_SETTING_CONNECTION_TYPE, .parser = setting_alias_parser, .writer = setting_alias_writer, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_HSR, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_HSR_SUPERVISION_ADDRESS, + .parser = mac_address_parser_ETHER, ), ), ), PARSE_INFO_SETTING( NM_META_SETTING_TYPE_INFINIBAND, PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_INFINIBAND_MAC_ADDRESS, 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 b531ae85a3..34a7d22e71 100644 --- a/src/libnm-core-impl/nm-meta-setting-base-impl.c +++ b/src/libnm-core-impl/nm-meta-setting-base-impl.c @@ -29,6 +29,7 @@ #include "nm-setting-generic.h" #include "nm-setting-gsm.h" #include "nm-setting-hostname.h" +#include "nm-setting-hsr.h" #include "nm-setting-infiniband.h" #include "nm-setting-ip-config.h" #include "nm-setting-ip-tunnel.h" @@ -335,6 +336,13 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = { .setting_name = NM_SETTING_HOSTNAME_SETTING_NAME, .get_setting_gtype = nm_setting_hostname_get_type, }, + [NM_META_SETTING_TYPE_HSR] = + { + .meta_type = NM_META_SETTING_TYPE_HSR, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_HSR_SETTING_NAME, + .get_setting_gtype = nm_setting_hsr_get_type, + }, [NM_META_SETTING_TYPE_INFINIBAND] = { .meta_type = NM_META_SETTING_TYPE_INFINIBAND, @@ -632,6 +640,7 @@ const NMMetaSettingType nm_meta_setting_types_by_priority[] = { NM_META_SETTING_TYPE_DUMMY, NM_META_SETTING_TYPE_GENERIC, NM_META_SETTING_TYPE_GSM, + NM_META_SETTING_TYPE_HSR, NM_META_SETTING_TYPE_INFINIBAND, NM_META_SETTING_TYPE_IP_TUNNEL, NM_META_SETTING_TYPE_LOOPBACK, diff --git a/src/libnm-core-impl/nm-setting-hsr.c b/src/libnm-core-impl/nm-setting-hsr.c new file mode 100644 index 0000000000..8802aa5836 --- /dev/null +++ b/src/libnm-core-impl/nm-setting-hsr.c @@ -0,0 +1,316 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023 Red Hat, Inc. + */ + +#include "libnm-core-impl/nm-default-libnm-core.h" + +#include "nm-setting-hsr.h" + +#include + +#include "nm-connection-private.h" +#include "nm-utils.h" +#include "nm-utils-private.h" + +/** + * SECTION:nm-setting-hsr + * @short_description: Describes connection properties for HSR/PRP interfaces + * + * The #NMSettingHsr object is a #NMSetting subclass that describes properties + * necessary for HSR/PRP connections. + **/ + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE(NMSettingHsr, + PROP_PORT1, + PROP_PORT2, + PROP_SUPERVISION_ADDRESS, + PROP_MULTICAST_SPEC, + PROP_PRP, ); + +typedef struct { + char *port1; + char *port2; + char *supervision_address; + guint32 multicast_spec; + bool prp; +} NMSettingHsrPrivate; + +/** + * NMSettingHsr: + * + * HSR/PRP Settings + */ +struct _NMSettingHsr { + NMSetting parent; + NMSettingHsrPrivate _priv; +}; + +struct _NMSettingHsrClass { + NMSettingClass parent; +}; + +G_DEFINE_TYPE(NMSettingHsr, nm_setting_hsr, NM_TYPE_SETTING) + +#define NM_SETTING_HSR_GET_PRIVATE(self) \ + _NM_GET_PRIVATE(self, NMSettingHsr, NM_IS_SETTING_HSR, NMSetting) + +/*****************************************************************************/ + +/** + * nm_setting_hsr_get_port1: + * @setting: the #NMSettingHsr + * + * Returns: the #NMSettingHsr:port1 property of the setting + * + * Since: 1.46 + **/ +const char * +nm_setting_hsr_get_port1(NMSettingHsr *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_HSR(setting), NULL); + + return NM_SETTING_HSR_GET_PRIVATE(setting)->port1; +} + +/** + * nm_setting_hsr_get_port2: + * @setting: the #NMSettingHsr + * + * Returns: the #NMSettingHsr:port2 property of the setting + * + * Since: 1.46 + **/ +const char * +nm_setting_hsr_get_port2(NMSettingHsr *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_HSR(setting), NULL); + + return NM_SETTING_HSR_GET_PRIVATE(setting)->port2; +} + +/** + * nm_setting_hsr_get_supervision_address: + * @setting: the #NMSettingHsr + * + * Returns: the #NMSettingHsr:supervision_address property of the setting + * + * Since: 1.46 + **/ +const char * +nm_setting_hsr_get_supervision_address(NMSettingHsr *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_HSR(setting), NULL); + + return NM_SETTING_HSR_GET_PRIVATE(setting)->supervision_address; +} + +/** + * nm_setting_hsr_get_multicast_spec: + * @setting: the #NMSettingHsr + * + * Returns: the #NMSettingHsr:multicast_spec property of the setting + * + * Since: 1.46 + **/ +guint32 +nm_setting_hsr_get_multicast_spec(NMSettingHsr *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_HSR(setting), 0); + + return NM_SETTING_HSR_GET_PRIVATE(setting)->multicast_spec; +} + +/** + * nm_setting_hsr_get_prp: + * @setting: the #NMSettingHsr + * + * Returns: the #NMSettingHsr:prp property of the setting + * + * Since: 1.46 + **/ +gboolean +nm_setting_hsr_get_prp(NMSettingHsr *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_HSR(setting), FALSE); + + return NM_SETTING_HSR_GET_PRIVATE(setting)->prp; +} + +/*****************************************************************************/ + +static gboolean +verify(NMSetting *setting, NMConnection *connection, GError **error) +{ + NMSettingHsrPrivate *priv = NM_SETTING_HSR_GET_PRIVATE(setting); + + if (!priv->port1) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_PROPERTY, + _("property is not specified")); + g_prefix_error(error, "%s.%s: ", NM_SETTING_HSR_SETTING_NAME, NM_SETTING_HSR_PORT1); + return FALSE; + } + if (!nm_utils_ifname_valid(priv->port1, NMU_IFACE_KERNEL, NULL)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid interface name"), + priv->port1); + g_prefix_error(error, "%s.%s: ", NM_SETTING_HSR_SETTING_NAME, NM_SETTING_HSR_PORT1); + return FALSE; + } + + if (!priv->port2) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_PROPERTY, + _("property is not specified")); + g_prefix_error(error, "%s.%s: ", NM_SETTING_HSR_SETTING_NAME, NM_SETTING_HSR_PORT2); + return FALSE; + } + if (!nm_utils_ifname_valid(priv->port2, NMU_IFACE_KERNEL, NULL)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid interface name"), + priv->port2); + g_prefix_error(error, "%s.%s: ", NM_SETTING_HSR_SETTING_NAME, NM_SETTING_HSR_PORT2); + return FALSE; + } + + if (priv->supervision_address && !nm_utils_hwaddr_valid(priv->supervision_address, ETH_ALEN)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid MAC address"), + priv->supervision_address); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_HSR_SETTING_NAME, + NM_SETTING_HSR_SUPERVISION_ADDRESS); + return FALSE; + } + + return TRUE; +} + +/*****************************************************************************/ + +static void +nm_setting_hsr_init(NMSettingHsr *setting) +{} + +/** + * nm_setting_hsr_new: + * + * Creates a new #NMSettingHsr object with default values. + * + * Returns: (transfer full): the new empty #NMSettingHsr object + * + * Since: 1.46 + **/ +NMSetting * +nm_setting_hsr_new(void) +{ + return g_object_new(NM_TYPE_SETTING_HSR, NULL); +} + +static void +nm_setting_hsr_class_init(NMSettingHsrClass *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; + + /** + * NMSettingHsr:port1: + * + * The port1 interface name of the HSR. This property is mandatory. + * + * Since: 1.46 + **/ + _nm_setting_property_define_direct_string(properties_override, + obj_properties, + NM_SETTING_HSR_PORT1, + PROP_PORT1, + NM_SETTING_PARAM_INFERRABLE, + NMSettingHsr, + _priv.port1); + + /** + * NMSettingHsr:port2: + * + * The port2 interface name of the HSR. This property is mandatory. + * + * Since: 1.46 + **/ + _nm_setting_property_define_direct_string(properties_override, + obj_properties, + NM_SETTING_HSR_PORT2, + PROP_PORT2, + NM_SETTING_PARAM_INFERRABLE, + NMSettingHsr, + _priv.port2); + + /** + * NMSettingHsr:supervision-address: + * + * The supervision MAC address. + * + * Since: 1.46 + **/ + _nm_setting_property_define_direct_string(properties_override, + obj_properties, + NM_SETTING_HSR_SUPERVISION_ADDRESS, + PROP_SUPERVISION_ADDRESS, + NM_SETTING_PARAM_INFERRABLE, + NMSettingHsr, + _priv.supervision_address); + + /** + * NMSettingHsr:multicast-spec: + * + * The last byte of supervision address. + * + * Since: 1.46 + **/ + _nm_setting_property_define_direct_uint32(properties_override, + obj_properties, + NM_SETTING_HSR_MULTICAST_SPEC, + PROP_MULTICAST_SPEC, + 0, + G_MAXUINT8, + 0, + NM_SETTING_PARAM_INFERRABLE, + NMSettingHsr, + _priv.multicast_spec); + + /** + * NMSettingHsr:prp: + * + * The protocol used by the interface, whether it is PRP or HSR. + * + * Since: 1.46 + **/ + _nm_setting_property_define_direct_boolean(properties_override, + obj_properties, + NM_SETTING_HSR_PRP, + PROP_PRP, + FALSE, + NM_SETTING_PARAM_INFERRABLE, + NMSettingHsr, + _priv.prp); + + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + _nm_setting_class_commit(setting_class, NM_META_SETTING_TYPE_HSR, NULL, properties_override, 0); +} diff --git a/src/libnm-core-intern/nm-core-internal.h b/src/libnm-core-intern/nm-core-internal.h index 16f972a9ce..7ed6644944 100644 --- a/src/libnm-core-intern/nm-core-internal.h +++ b/src/libnm-core-intern/nm-core-internal.h @@ -38,6 +38,7 @@ #include "nm-setting-dummy.h" #include "nm-setting-generic.h" #include "nm-setting-gsm.h" +#include "nm-setting-hsr.h" #include "nm-setting-hostname.h" #include "nm-setting-infiniband.h" #include "nm-setting-ip-tunnel.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 c6d1c2fcb6..9226183fe9 100644 --- a/src/libnm-core-intern/nm-meta-setting-base-impl.h +++ b/src/libnm-core-intern/nm-meta-setting-base-impl.h @@ -123,6 +123,7 @@ typedef enum _nm_packed { NM_META_SETTING_TYPE_GENERIC, NM_META_SETTING_TYPE_GSM, NM_META_SETTING_TYPE_HOSTNAME, + NM_META_SETTING_TYPE_HSR, NM_META_SETTING_TYPE_INFINIBAND, NM_META_SETTING_TYPE_IP_TUNNEL, NM_META_SETTING_TYPE_IP4_CONFIG, diff --git a/src/libnm-core-public/meson.build b/src/libnm-core-public/meson.build index c684d084ec..b5ed71e8c8 100644 --- a/src/libnm-core-public/meson.build +++ b/src/libnm-core-public/meson.build @@ -23,6 +23,7 @@ libnm_core_headers = files( 'nm-setting-ethtool.h', 'nm-setting-generic.h', 'nm-setting-gsm.h', + 'nm-setting-hsr.h', 'nm-setting-hostname.h', 'nm-setting-infiniband.h', 'nm-setting-ip-config.h', diff --git a/src/libnm-core-public/nm-core-types.h b/src/libnm-core-public/nm-core-types.h index 758733a1cc..d9a8225e8c 100644 --- a/src/libnm-core-public/nm-core-types.h +++ b/src/libnm-core-public/nm-core-types.h @@ -30,6 +30,7 @@ typedef struct _NMSettingEthtool NMSettingEthtool; typedef struct _NMSettingGeneric NMSettingGeneric; typedef struct _NMSettingGsm NMSettingGsm; typedef struct _NMSettingHostname NMSettingHostname; +typedef struct _NMSettingHsr NMSettingHsr; typedef struct _NMSettingIP4Config NMSettingIP4Config; typedef struct _NMSettingIP6Config NMSettingIP6Config; typedef struct _NMSettingIPConfig NMSettingIPConfig; diff --git a/src/libnm-core-public/nm-dbus-interface.h b/src/libnm-core-public/nm-dbus-interface.h index 549aad44c0..5acbf467f5 100644 --- a/src/libnm-core-public/nm-dbus-interface.h +++ b/src/libnm-core-public/nm-dbus-interface.h @@ -37,6 +37,7 @@ #define NM_DBUS_INTERFACE_DEVICE_DUMMY NM_DBUS_INTERFACE_DEVICE ".Dummy" #define NM_DBUS_INTERFACE_DEVICE_GENERIC NM_DBUS_INTERFACE_DEVICE ".Generic" #define NM_DBUS_INTERFACE_DEVICE_GRE NM_DBUS_INTERFACE_DEVICE ".Gre" +#define NM_DBUS_INTERFACE_DEVICE_HSR NM_DBUS_INTERFACE_DEVICE ".Hsr" #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" @@ -234,6 +235,7 @@ typedef enum { * @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. + * @NM_DEVICE_TYPE_HSR: A HSR/PRP device. Since: 1.46. * * #NMDeviceType values indicate the type of hardware represented by a * device object. @@ -272,6 +274,7 @@ typedef enum { NM_DEVICE_TYPE_WIFI_P2P = 30, NM_DEVICE_TYPE_VRF = 31, NM_DEVICE_TYPE_LOOPBACK = 32, + NM_DEVICE_TYPE_HSR = 33, } NMDeviceType; /** diff --git a/src/libnm-core-public/nm-setting-hsr.h b/src/libnm-core-public/nm-setting-hsr.h new file mode 100644 index 0000000000..8d11ba339b --- /dev/null +++ b/src/libnm-core-public/nm-setting-hsr.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023 Red Hat, Inc. + */ + +#ifndef __NM_SETTING_HSR_H__ +#define __NM_SETTING_HSR_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_HSR (nm_setting_hsr_get_type()) +#define NM_SETTING_HSR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SETTING_HSR, NMSettingHsr)) +#define NM_IS_SETTING_HSR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_SETTING_HSR)) +#define NM_IS_SETTING_HSR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_SETTING_HSR)) +#define NM_SETTING_HSR_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_SETTING_HSR, NMSettingHsrClass)) + +#define NM_SETTING_HSR_SETTING_NAME "hsr" + +#define NM_SETTING_HSR_PORT1 "port1" +#define NM_SETTING_HSR_PORT2 "port2" +#define NM_SETTING_HSR_SUPERVISION_ADDRESS "supervision-address" +#define NM_SETTING_HSR_MULTICAST_SPEC "multicast-spec" +#define NM_SETTING_HSR_PRP "prp" + +typedef struct _NMSettingHsrClass NMSettingHsrClass; + +NM_AVAILABLE_IN_1_46 +GType nm_setting_hsr_get_type(void); +NM_AVAILABLE_IN_1_46 +NMSetting *nm_setting_hsr_new(void); + +NM_AVAILABLE_IN_1_46 +const char *nm_setting_hsr_get_port1(NMSettingHsr *setting); +NM_AVAILABLE_IN_1_46 +const char *nm_setting_hsr_get_port2(NMSettingHsr *setting); +NM_AVAILABLE_IN_1_46 +const char *nm_setting_hsr_get_supervision_address(NMSettingHsr *setting); +NM_AVAILABLE_IN_1_46 +guint32 nm_setting_hsr_get_multicast_spec(NMSettingHsr *setting); +NM_AVAILABLE_IN_1_46 +gboolean nm_setting_hsr_get_prp(NMSettingHsr *setting); + +G_END_DECLS + +#endif /* __NM_SETTING_HSR_H__ */ diff --git a/src/libnm-glib-aux/nm-shared-utils.h b/src/libnm-glib-aux/nm-shared-utils.h index a99ae61229..4288e164e2 100644 --- a/src/libnm-glib-aux/nm-shared-utils.h +++ b/src/libnm-glib-aux/nm-shared-utils.h @@ -158,6 +158,7 @@ typedef enum { #define _NM_LINK_TYPE_SW_MASTER_FIRST NM_LINK_TYPE_BRIDGE NM_LINK_TYPE_BRIDGE, NM_LINK_TYPE_BOND, + NM_LINK_TYPE_HSR, NM_LINK_TYPE_TEAM, #define _NM_LINK_TYPE_SW_MASTER_LAST NM_LINK_TYPE_TEAM diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index a04dc3a939..b15766652a 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -229,6 +229,18 @@ G_STATIC_ASSERT(RTA_MAX == (__RTA_MAX - 1)); /*****************************************************************************/ +#define IFLA_HSR_UNSPEC 0 +#define IFLA_HSR_PORT1 1 +#define IFLA_HSR_PORT2 2 +#define IFLA_HSR_MULTICAST_SPEC 3 +#define IFLA_HSR_SUPERVISION_ADDR 4 +#define IFLA_HSR_SEQ_NR 5 +#define IFLA_HSR_VERSION 6 +#define IFLA_HSR_PROTOCOL 7 +#define __IFLA_HSR_MAX 8 + +/*****************************************************************************/ + #define IFLA_VTI_UNSPEC 0 #define IFLA_VTI_LINK 1 #define IFLA_VTI_IKEY 2 @@ -847,6 +859,7 @@ static const LinkDesc link_descs[] = { [NM_LINK_TYPE_BRIDGE] = {"bridge", "bridge", "bridge"}, [NM_LINK_TYPE_BOND] = {"bond", "bond", "bond"}, + [NM_LINK_TYPE_HSR] = {"hsr", "hsr", "hsr"}, [NM_LINK_TYPE_TEAM] = {"team", "team", NULL}, }; @@ -869,6 +882,7 @@ _link_type_from_rtnl_type(const char *name) NM_LINK_TYPE_DUMMY, /* "dummy" */ NM_LINK_TYPE_GRE, /* "gre" */ NM_LINK_TYPE_GRETAP, /* "gretap" */ + NM_LINK_TYPE_HSR, /* "hsr" */ NM_LINK_TYPE_IFB, /* "ifb" */ NM_LINK_TYPE_IP6GRE, /* "ip6gre" */ NM_LINK_TYPE_IP6GRETAP, /* "ip6gretap" */ @@ -943,6 +957,7 @@ _link_type_from_devtype(const char *name) NM_LINK_TYPE_BNEP, /* "bluetooth" */ NM_LINK_TYPE_BOND, /* "bond" */ NM_LINK_TYPE_BRIDGE, /* "bridge" */ + NM_LINK_TYPE_HSR, /* "hsr" */ NM_LINK_TYPE_PPP, /* "ppp" */ NM_LINK_TYPE_VLAN, /* "vlan" */ NM_LINK_TYPE_VRF, /* "vrf" */ @@ -1805,6 +1820,51 @@ _parse_lnk_gre(const char *kind, struct nlattr *info_data) /*****************************************************************************/ +static NMPObject * +_parse_lnk_hsr(const char *kind, struct nlattr *info_data) +{ + static const struct nla_policy policy[] = { + [IFLA_HSR_PORT1] = {.type = NLA_U32}, + [IFLA_HSR_PORT2] = {.type = NLA_U32}, + [IFLA_HSR_MULTICAST_SPEC] = {.type = NLA_U8}, + [IFLA_HSR_SUPERVISION_ADDR] = {.minlen = sizeof(NMEtherAddr)}, + [IFLA_HSR_PROTOCOL] = {.type = NLA_U8}, + }; + NMPlatformLnkHsr *props; + struct nlattr *tb[G_N_ELEMENTS(policy)]; + NMPObject *obj; + guint32 v_u32; + + if (!info_data || !kind) + return NULL; + + if (nla_parse_nested_arr(tb, info_data, policy) < 0) + return NULL; + + obj = nmp_object_new(NMP_OBJECT_TYPE_LNK_HSR, NULL); + props = &obj->lnk_hsr; + if (tb[IFLA_HSR_PORT1]) { + v_u32 = nla_get_u32(tb[IFLA_HSR_PORT1]); + if (v_u32 <= (unsigned) G_MAXINT) + props->port1 = v_u32; + } + if (tb[IFLA_HSR_PORT2]) { + v_u32 = nla_get_u32(tb[IFLA_HSR_PORT2]); + if (v_u32 <= (unsigned) G_MAXINT) + props->port2 = v_u32; + } + if (tb[IFLA_HSR_MULTICAST_SPEC]) + props->multicast_spec = nla_get_u8(tb[IFLA_HSR_MULTICAST_SPEC]); + if (tb[IFLA_HSR_SUPERVISION_ADDR]) + nla_memcpy(&props->supervision_address, tb[IFLA_HSR_SUPERVISION_ADDR], sizeof(NMEtherAddr)); + if (tb[IFLA_HSR_PROTOCOL]) + props->prp = nla_get_u8(tb[IFLA_HSR_PROTOCOL]); + + return obj; +} + +/*****************************************************************************/ + /* IFLA_IPOIB_* were introduced in the 3.7 kernel, but the kernel headers * we're building against might not have those properties even though the * running kernel might. @@ -3568,6 +3628,9 @@ _new_from_nl_link(NMPlatform *platform, case NM_LINK_TYPE_GRETAP: lnk_data = _parse_lnk_gre(nl_info_kind, nl_info_data); break; + case NM_LINK_TYPE_HSR: + lnk_data = _parse_lnk_hsr(nl_info_kind, nl_info_data); + break; case NM_LINK_TYPE_INFINIBAND: lnk_data = _parse_lnk_infiniband(nl_info_kind, nl_info_data); break; @@ -4998,6 +5061,29 @@ _nl_msg_new_link_set_linkinfo(struct nl_msg *msg, NMLinkType link_type, gconstpo NLA_PUT_U16(msg, IFLA_GRE_OFLAGS, htons(props->output_flags)); break; } + case NM_LINK_TYPE_HSR: + { + const NMPlatformLnkHsr *props = extra_data; + + nm_assert(props); + + if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) + goto nla_put_failure; + + NLA_PUT_U32(msg, IFLA_HSR_PORT1, props->port1); + NLA_PUT_U32(msg, IFLA_HSR_PORT2, props->port2); + + if (props->multicast_spec) + NLA_PUT_U8(msg, IFLA_HSR_MULTICAST_SPEC, props->multicast_spec); + if (!nm_ether_addr_is_zero(&props->supervision_address)) + NLA_PUT(msg, + IFLA_HSR_SUPERVISION_ADDR, + sizeof(props->supervision_address), + &props->supervision_address); + + NLA_PUT_U8(msg, IFLA_HSR_PROTOCOL, props->prp); + break; + } case NM_LINK_TYPE_SIT: { const NMPlatformLnkSit *props = extra_data; diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index 8b4c137eb5..5a12d92da1 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -1391,6 +1391,12 @@ nm_platform_link_add(NMPlatform *self, buf_p, buf_len); break; + case NM_LINK_TYPE_HSR: + nm_strbuf_append_str(&buf_p, &buf_len, ", "); + nm_platform_lnk_hsr_to_string((const NMPlatformLnkHsr *) extra_data, + buf_p, + buf_len); + break; case NM_LINK_TYPE_IP6TNL: case NM_LINK_TYPE_IP6GRE: case NM_LINK_TYPE_IP6GRETAP: @@ -2515,6 +2521,12 @@ nm_platform_link_get_lnk_gretap(NMPlatform *self, int ifindex, const NMPlatformL return _link_get_lnk(self, ifindex, NM_LINK_TYPE_GRETAP, out_link); } +const NMPlatformLnkHsr * +nm_platform_link_get_lnk_hsr(NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk(self, ifindex, NM_LINK_TYPE_HSR, out_link); +} + const NMPlatformLnkInfiniband * nm_platform_link_get_lnk_infiniband(NMPlatform *self, int ifindex, const NMPlatformLink **out_link) { @@ -6427,6 +6439,27 @@ nm_platform_lnk_gre_to_string(const NMPlatformLnkGre *lnk, char *buf, gsize len) return buf; } +const char * +nm_platform_lnk_hsr_to_string(const NMPlatformLnkHsr *lnk, char *buf, gsize len) +{ + if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len)) + return buf; + + g_snprintf(buf, + len, + "hsr " + "port1 %d " + "port2 %d " + "supervision_address " NM_ETHER_ADDR_FORMAT_STR " multicast_spec %u " + "prp %s", + lnk->port1, + lnk->port2, + NM_ETHER_ADDR_FORMAT_VAL(&lnk->supervision_address), + lnk->multicast_spec, + lnk->prp ? "on" : "off"); + return buf; +} + const char * nm_platform_lnk_infiniband_to_string(const NMPlatformLnkInfiniband *lnk, char *buf, gsize len) { @@ -8308,6 +8341,29 @@ nm_platform_lnk_gre_cmp(const NMPlatformLnkGre *a, const NMPlatformLnkGre *b) return 0; } +void +nm_platform_lnk_hsr_hash_update(const NMPlatformLnkHsr *obj, NMHashState *h) +{ + nm_hash_update_vals(h, + obj->port1, + obj->port2, + obj->supervision_address, + obj->multicast_spec, + NM_HASH_COMBINE_BOOLS(guint8, obj->prp)); +} + +int +nm_platform_lnk_hsr_cmp(const NMPlatformLnkHsr *a, const NMPlatformLnkHsr *b) +{ + NM_CMP_SELF(a, b); + NM_CMP_FIELD(a, b, port1); + NM_CMP_FIELD(a, b, port2); + NM_CMP_FIELD_MEMCMP(a, b, supervision_address); + NM_CMP_FIELD(a, b, multicast_spec); + NM_CMP_FIELD_BOOL(a, b, prp); + return 0; +} + void nm_platform_lnk_infiniband_hash_update(const NMPlatformLnkInfiniband *obj, NMHashState *h) { diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index 2794d4b36f..810a59133d 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -842,6 +842,14 @@ typedef struct { bool is_tap : 1; } _nm_alignas(NMPlatformObject) NMPlatformLnkGre; +typedef struct { + int port1; + int port2; + NMEtherAddr supervision_address; + guint8 multicast_spec; + bool prp : 1; +} _nm_alignas(NMPlatformObject) NMPlatformLnkHsr; + typedef struct { int p_key; const char *mode; @@ -1749,6 +1757,17 @@ nm_platform_link_gre_add(NMPlatform *self, out_link); } +static inline int +nm_platform_link_hsr_add(NMPlatform *self, + const char *name, + const NMPlatformLnkHsr *props, + const NMPlatformLink **out_link) +{ + g_return_val_if_fail(props, -NME_BUG); + + return nm_platform_link_add(self, NM_LINK_TYPE_HSR, name, 0, NULL, 0, 0, props, out_link); +} + static inline int nm_platform_link_sit_add(NMPlatform *self, const char *name, @@ -2068,6 +2087,8 @@ const NMPlatformLnkGre * nm_platform_link_get_lnk_gre(NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkGre * nm_platform_link_get_lnk_gretap(NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkHsr * +nm_platform_link_get_lnk_hsr(NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkIp6Tnl * nm_platform_link_get_lnk_ip6tnl(NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkIp6Tnl * @@ -2390,6 +2411,7 @@ const char *nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gs const char *nm_platform_lnk_bond_to_string(const NMPlatformLnkBond *lnk, char *buf, gsize len); const char *nm_platform_lnk_bridge_to_string(const NMPlatformLnkBridge *lnk, char *buf, gsize len); const char *nm_platform_lnk_gre_to_string(const NMPlatformLnkGre *lnk, char *buf, gsize len); +const char *nm_platform_lnk_hsr_to_string(const NMPlatformLnkHsr *lnk, char *buf, gsize len); const char * nm_platform_lnk_infiniband_to_string(const NMPlatformLnkInfiniband *lnk, char *buf, gsize len); const char *nm_platform_lnk_ip6tnl_to_string(const NMPlatformLnkIp6Tnl *lnk, char *buf, gsize len); @@ -2443,6 +2465,7 @@ int nm_platform_link_cmp(const NMPlatformLink *a, const NMPlatformLink *b); int nm_platform_lnk_bond_cmp(const NMPlatformLnkBond *a, const NMPlatformLnkBond *b); int nm_platform_lnk_bridge_cmp(const NMPlatformLnkBridge *a, const NMPlatformLnkBridge *b); int nm_platform_lnk_gre_cmp(const NMPlatformLnkGre *a, const NMPlatformLnkGre *b); +int nm_platform_lnk_hsr_cmp(const NMPlatformLnkHsr *a, const NMPlatformLnkHsr *b); int nm_platform_lnk_infiniband_cmp(const NMPlatformLnkInfiniband *a, const NMPlatformLnkInfiniband *b); int nm_platform_lnk_ip6tnl_cmp(const NMPlatformLnkIp6Tnl *a, const NMPlatformLnkIp6Tnl *b); @@ -2514,6 +2537,7 @@ void nm_platform_routing_rule_hash_update(const NMPlatformRoutingRule *obj, void nm_platform_lnk_bond_hash_update(const NMPlatformLnkBond *obj, NMHashState *h); void nm_platform_lnk_bridge_hash_update(const NMPlatformLnkBridge *obj, NMHashState *h); void nm_platform_lnk_gre_hash_update(const NMPlatformLnkGre *obj, NMHashState *h); +void nm_platform_lnk_hsr_hash_update(const NMPlatformLnkHsr *obj, NMHashState *h); void nm_platform_lnk_infiniband_hash_update(const NMPlatformLnkInfiniband *obj, NMHashState *h); void nm_platform_lnk_ip6tnl_hash_update(const NMPlatformLnkIp6Tnl *obj, NMHashState *h); void nm_platform_lnk_ipip_hash_update(const NMPlatformLnkIpIp *obj, NMHashState *h); diff --git a/src/libnm-platform/nmp-base.h b/src/libnm-platform/nmp-base.h index 578efa51b3..70b5d1bc55 100644 --- a/src/libnm-platform/nmp-base.h +++ b/src/libnm-platform/nmp-base.h @@ -159,6 +159,7 @@ typedef enum _nm_packed { NMP_OBJECT_TYPE_LNK_BRIDGE, NMP_OBJECT_TYPE_LNK_GRE, NMP_OBJECT_TYPE_LNK_GRETAP, + NMP_OBJECT_TYPE_LNK_HSR, NMP_OBJECT_TYPE_LNK_INFINIBAND, NMP_OBJECT_TYPE_LNK_IP6TNL, NMP_OBJECT_TYPE_LNK_IP6GRE, diff --git a/src/libnm-platform/nmp-object.c b/src/libnm-platform/nmp-object.c index 7e3fb1a3e8..4090da71a3 100644 --- a/src/libnm-platform/nmp-object.c +++ b/src/libnm-platform/nmp-object.c @@ -3485,6 +3485,18 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_gre_hash_update, .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_gre_cmp, }, + [NMP_OBJECT_TYPE_LNK_HSR - 1] = + { + .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), + .obj_type = NMP_OBJECT_TYPE_LNK_HSR, + .sizeof_data = sizeof(NMPObjectLnkHsr), + .sizeof_public = sizeof(NMPlatformLnkHsr), + .obj_type_name = "hsr", + .lnk_link_type = NM_LINK_TYPE_HSR, + .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_lnk_hsr_to_string, + .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_hsr_hash_update, + .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_hsr_cmp, + }, [NMP_OBJECT_TYPE_LNK_INFINIBAND - 1] = { .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), diff --git a/src/libnm-platform/nmp-object.h b/src/libnm-platform/nmp-object.h index 408f0318cb..19cace3de8 100644 --- a/src/libnm-platform/nmp-object.h +++ b/src/libnm-platform/nmp-object.h @@ -253,6 +253,10 @@ typedef struct { NMPlatformLnkGre _public; } NMPObjectLnkGre; +typedef struct { + NMPlatformLnkHsr _public; +} NMPObjectLnkHsr; + typedef struct { NMPlatformLnkInfiniband _public; } NMPObjectLnkInfiniband; @@ -377,6 +381,9 @@ struct _NMPObject { NMPlatformLnkGre lnk_gre; NMPObjectLnkGre _lnk_gre; + NMPlatformLnkHsr lnk_hsr; + NMPObjectLnkHsr _lnk_hsr; + NMPlatformLnkInfiniband lnk_infiniband; NMPObjectLnkInfiniband _lnk_infiniband; @@ -530,6 +537,7 @@ _NMP_OBJECT_TYPE_IS_OBJ_WITH_IFINDEX(NMPObjectType obj_type) case NMP_OBJECT_TYPE_LNK_BOND: case NMP_OBJECT_TYPE_LNK_GRE: case NMP_OBJECT_TYPE_LNK_GRETAP: + case NMP_OBJECT_TYPE_LNK_HSR: case NMP_OBJECT_TYPE_LNK_INFINIBAND: case NMP_OBJECT_TYPE_LNK_IP6TNL: case NMP_OBJECT_TYPE_LNK_IP6GRE: diff --git a/src/libnmc-setting/nm-meta-setting-base-impl.c b/src/libnmc-setting/nm-meta-setting-base-impl.c index b531ae85a3..34a7d22e71 100644 --- a/src/libnmc-setting/nm-meta-setting-base-impl.c +++ b/src/libnmc-setting/nm-meta-setting-base-impl.c @@ -29,6 +29,7 @@ #include "nm-setting-generic.h" #include "nm-setting-gsm.h" #include "nm-setting-hostname.h" +#include "nm-setting-hsr.h" #include "nm-setting-infiniband.h" #include "nm-setting-ip-config.h" #include "nm-setting-ip-tunnel.h" @@ -335,6 +336,13 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = { .setting_name = NM_SETTING_HOSTNAME_SETTING_NAME, .get_setting_gtype = nm_setting_hostname_get_type, }, + [NM_META_SETTING_TYPE_HSR] = + { + .meta_type = NM_META_SETTING_TYPE_HSR, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_HSR_SETTING_NAME, + .get_setting_gtype = nm_setting_hsr_get_type, + }, [NM_META_SETTING_TYPE_INFINIBAND] = { .meta_type = NM_META_SETTING_TYPE_INFINIBAND, @@ -632,6 +640,7 @@ const NMMetaSettingType nm_meta_setting_types_by_priority[] = { NM_META_SETTING_TYPE_DUMMY, NM_META_SETTING_TYPE_GENERIC, NM_META_SETTING_TYPE_GSM, + NM_META_SETTING_TYPE_HSR, NM_META_SETTING_TYPE_INFINIBAND, NM_META_SETTING_TYPE_IP_TUNNEL, NM_META_SETTING_TYPE_LOOPBACK, diff --git a/src/libnmc-setting/nm-meta-setting-base-impl.h b/src/libnmc-setting/nm-meta-setting-base-impl.h index c6d1c2fcb6..9226183fe9 100644 --- a/src/libnmc-setting/nm-meta-setting-base-impl.h +++ b/src/libnmc-setting/nm-meta-setting-base-impl.h @@ -123,6 +123,7 @@ typedef enum _nm_packed { NM_META_SETTING_TYPE_GENERIC, NM_META_SETTING_TYPE_GSM, NM_META_SETTING_TYPE_HOSTNAME, + NM_META_SETTING_TYPE_HSR, NM_META_SETTING_TYPE_INFINIBAND, NM_META_SETTING_TYPE_IP_TUNNEL, NM_META_SETTING_TYPE_IP4_CONFIG, diff --git a/src/libnmc-setting/nm-meta-setting-desc.c b/src/libnmc-setting/nm-meta-setting-desc.c index 650c54fa9f..a14cb5680c 100644 --- a/src/libnmc-setting/nm-meta-setting-desc.c +++ b/src/libnmc-setting/nm-meta-setting-desc.c @@ -6024,6 +6024,42 @@ static const NMMetaPropertyInfo *const property_infos_GSM[] = { NULL }; +#undef _CURRENT_NM_META_SETTING_TYPE +#define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_HSR +static const NMMetaPropertyInfo *const property_infos_HSR[] = { + PROPERTY_INFO_WITH_DESC (NM_SETTING_HSR_PORT1, + .is_cli_option = TRUE, + .property_alias = "port1", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = N_("hsr port1"), + .property_type = &_pt_gobject_string, + ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_HSR_PORT2, + .is_cli_option = TRUE, + .property_alias = "port2", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = N_("hsr port2"), + .property_type = &_pt_gobject_string, + ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_HSR_SUPERVISION_ADDRESS, + .is_cli_option = TRUE, + .property_alias = "supervision-address", + .prompt = N_("hsr supervision address"), + .property_type = &_pt_gobject_mac, + ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_HSR_MULTICAST_SPEC, + .is_cli_option = TRUE, + .property_alias = "multicast-spec", + .prompt = N_("hsr multicast spec"), + .property_type = &_pt_gobject_int, + ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_HSR_PRP, + .property_type = &_pt_gobject_bool, + ), + NULL +}; + + #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_HOSTNAME static const NMMetaPropertyInfo *const property_infos_HOSTNAME[] = { @@ -8559,6 +8595,7 @@ _setting_init_fcn_wireless (ARGS_SETTING_INIT_FCN) #define SETTING_PRETTY_NAME_GENERIC N_("Generic settings") #define SETTING_PRETTY_NAME_GSM N_("GSM mobile broadband connection") #define SETTING_PRETTY_NAME_HOSTNAME N_("Hostname settings") +#define SETTING_PRETTY_NAME_HSR N_("HSR settings") #define SETTING_PRETTY_NAME_INFINIBAND N_("InfiniBand connection") #define SETTING_PRETTY_NAME_IP4_CONFIG N_("IPv4 protocol") #define SETTING_PRETTY_NAME_IP6_CONFIG N_("IPv6 protocol") @@ -8702,6 +8739,12 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = { .setting_init_fcn = _setting_init_fcn_gsm, ), SETTING_INFO (HOSTNAME), + SETTING_INFO (HSR, + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (HSR, TRUE), + ), + ), SETTING_INFO (INFINIBAND, .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 b9c06e55eb..aba9a5ca2d 100644 --- a/src/libnmc-setting/settings-docs.h.in +++ b/src/libnmc-setting/settings-docs.h.in @@ -445,6 +445,11 @@ #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 \"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 \"true\" (1).") #define DESCRIBE_DOC_NM_SETTING_HOSTNAME_ONLY_FROM_DEFAULT N_("If set to \"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 \"false\" (0), the hostname can be set from this device even if it doesn't have the default route. When set to \"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 \"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_HSR_MULTICAST_SPEC N_("The last byte of supervision address.") +#define DESCRIBE_DOC_NM_SETTING_HSR_PORT1 N_("The port1 interface name of the HSR. This property is mandatory.") +#define DESCRIBE_DOC_NM_SETTING_HSR_PORT2 N_("The port2 interface name of the HSR. This property is mandatory.") +#define DESCRIBE_DOC_NM_SETTING_HSR_PRP N_("The protocol used by the interface, whether it is PRP or HSR.") +#define DESCRIBE_DOC_NM_SETTING_HSR_SUPERVISION_ADDRESS N_("The supervision MAC address.") #define DESCRIBE_DOC_NM_SETTING_LINK_GRO_MAX_SIZE N_("The maximum size of a packet built by the Generic Receive Offload stack for this device. The value must be between 0 and 4294967295. When set to -1, the existing value is preserved.") #define DESCRIBE_DOC_NM_SETTING_LINK_GSO_MAX_SEGMENTS N_("The maximum segments of a Generic Segment Offload packet the device should accept. The value must be between 0 and 4294967295. When set to -1, the existing value is preserved.") #define DESCRIBE_DOC_NM_SETTING_LINK_GSO_MAX_SIZE N_("The maximum size of a Generic Segment Offload packet the device should accept. The value must be between 0 and 4294967295. When set to -1, the existing value is preserved.") diff --git a/src/nmcli/connections.c b/src/nmcli/connections.c index 3b97da76a4..86d891e47c 100644 --- a/src/nmcli/connections.c +++ b/src/nmcli/connections.c @@ -1075,7 +1075,8 @@ const NmcMetaGenericInfo "," NM_SETTING_LINK_SETTING_NAME "," NM_SETTING_PROXY_SETTING_NAME \ "," NM_SETTING_TC_CONFIG_SETTING_NAME "," NM_SETTING_SRIOV_SETTING_NAME \ "," NM_SETTING_ETHTOOL_SETTING_NAME "," NM_SETTING_OVS_DPDK_SETTING_NAME \ - "," NM_SETTING_HOSTNAME_SETTING_NAME /* NM_SETTING_DUMMY_SETTING_NAME NM_SETTING_WIMAX_SETTING_NAME */ + "," NM_SETTING_HOSTNAME_SETTING_NAME "," NM_SETTING_HSR_SETTING_NAME +/* NM_SETTING_DUMMY_SETTING_NAME NM_SETTING_WIMAX_SETTING_NAME */ const NmcMetaGenericInfo *const nmc_fields_con_active_details_groups[] = { NMC_META_GENERIC_WITH_NESTED("GENERAL", metagen_con_active_general), /* 0 */ @@ -4561,6 +4562,7 @@ enable_type_settings_and_options(NmCli *nmc, NMConnection *con, GError **error) NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BRIDGE_SETTING_NAME, NM_SETTING_DUMMY_SETTING_NAME, + NM_SETTING_HSR_SETTING_NAME, NM_SETTING_OVS_BRIDGE_SETTING_NAME, NM_SETTING_OVS_PATCH_SETTING_NAME, NM_SETTING_OVS_PORT_SETTING_NAME, diff --git a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in index bea062b0f2..90ea08e95a 100644 --- a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in +++ b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in @@ -616,7 +616,7 @@ alias="type" nmcli-description="Base type of the connection. For hardware-dependent connections, should contain the setting name of the hardware-type specific setting (ie, "802-3-ethernet" or "802-11-wireless" or "bluetooth", etc), and for non-hardware dependent connections like VPN or otherwise, should contain the setting name of that setting type (ie, "vpn" or "bridge", etc)." format="string" - values="6lowpan, 802-11-olpc-mesh, 802-11-wireless, 802-3-ethernet, adsl, bluetooth, bond, bridge, cdma, dummy, generic, gsm, infiniband, ip-tunnel, loopback, macsec, macvlan, ovs-bridge, ovs-dpdk, ovs-interface, ovs-patch, ovs-port, pppoe, team, tun, veth, vlan, vpn, vrf, vxlan, wifi-p2p, wimax, wireguard, wpan" /> + values="6lowpan, 802-11-olpc-mesh, 802-11-wireless, 802-3-ethernet, adsl, bluetooth, bond, bridge, cdma, dummy, generic, gsm, hsr, infiniband, ip-tunnel, loopback, macsec, macvlan, ovs-bridge, ovs-dpdk, ovs-interface, ovs-patch, ovs-port, pppoe, team, tun, veth, vlan, vpn, vrf, vxlan, wifi-p2p, wimax, wireguard, wpan" /> + + + + + + +