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" />
+
+
+
+
+
+
+