summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFernando Fernandez Mancera <ffmancera@riseup.net>2023-10-27 14:01:13 +0200
committerFernando Fernandez Mancera <ffmancera@riseup.net>2023-12-05 08:05:00 +0100
commitc653656aa8a39082b937655b044906a436a7a037 (patch)
treeefa3adfd621eb2010d11a5b7acf0d5c3cf37a609
parentf6bc12936fb83861932ced16b8fff58e05cc072f (diff)
HSR: add support to HSR/PRP interfaceff/prp_hsr_support
This patch add support to HSR/PRP interface. Please notice that PRP driver is represented as HSR too. They are different drivers but on kernel they are integrated together. HSR/PRP is a network protocol standard for Ethernet that provides seamless failover against failure of any network component. It intends to be transparent to the application. These protocols are useful for applications that request high availability and short switchover time e.g electrical substation or high power inverters. https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1791
-rw-r--r--Makefile.am10
-rw-r--r--docs/api/Makefile.am1
-rw-r--r--docs/api/network-manager-docs.xml1
-rw-r--r--docs/libnm/libnm-docs.xml2
-rw-r--r--introspection/meson.build1
-rw-r--r--introspection/org.freedesktop.NetworkManager.Device.Hsr.xml51
-rw-r--r--src/core/devices/nm-device-factory.c1
-rw-r--r--src/core/devices/nm-device-hsr.c290
-rw-r--r--src/core/devices/nm-device-hsr.h31
-rw-r--r--src/core/devices/nm-device.c4
-rw-r--r--src/core/meson.build1
-rw-r--r--src/libnm-client-impl/libnm.ver13
-rw-r--r--src/libnm-client-impl/meson.build1
-rw-r--r--src/libnm-client-impl/nm-client.c1
-rw-r--r--src/libnm-client-impl/nm-device-hsr.c279
-rw-r--r--src/libnm-client-impl/nm-device.c3
-rw-r--r--src/libnm-client-public/NetworkManager.h2
-rw-r--r--src/libnm-client-public/meson.build1
-rw-r--r--src/libnm-client-public/nm-autoptr.h2
-rw-r--r--src/libnm-client-public/nm-device-hsr.h56
-rw-r--r--src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in24
-rw-r--r--src/libnm-core-impl/meson.build1
-rw-r--r--src/libnm-core-impl/nm-connection.c1
-rw-r--r--src/libnm-core-impl/nm-keyfile.c4
-rw-r--r--src/libnm-core-impl/nm-meta-setting-base-impl.c9
-rw-r--r--src/libnm-core-impl/nm-setting-hsr.c316
-rw-r--r--src/libnm-core-intern/nm-core-internal.h1
-rw-r--r--src/libnm-core-intern/nm-meta-setting-base-impl.h1
-rw-r--r--src/libnm-core-public/meson.build1
-rw-r--r--src/libnm-core-public/nm-core-types.h1
-rw-r--r--src/libnm-core-public/nm-dbus-interface.h3
-rw-r--r--src/libnm-core-public/nm-setting-hsr.h52
-rw-r--r--src/libnm-glib-aux/nm-shared-utils.h1
-rw-r--r--src/libnm-platform/nm-linux-platform.c86
-rw-r--r--src/libnm-platform/nm-platform.c56
-rw-r--r--src/libnm-platform/nm-platform.h24
-rw-r--r--src/libnm-platform/nmp-base.h1
-rw-r--r--src/libnm-platform/nmp-object.c12
-rw-r--r--src/libnm-platform/nmp-object.h8
-rw-r--r--src/libnmc-setting/nm-meta-setting-base-impl.c9
-rw-r--r--src/libnmc-setting/nm-meta-setting-base-impl.h1
-rw-r--r--src/libnmc-setting/nm-meta-setting-desc.c43
-rw-r--r--src/libnmc-setting/settings-docs.h.in5
-rw-r--r--src/nmcli/connections.c4
-rw-r--r--src/nmcli/gen-metadata-nm-settings-nmcli.xml.in25
-rw-r--r--vapi/NM-1.0.metadata2
46 files changed, 1439 insertions, 3 deletions
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 @@
<xi:include href="dbus-org.freedesktop.NetworkManager.Device.Bridge.xml"/>
<xi:include href="dbus-org.freedesktop.NetworkManager.Device.Dummy.xml"/>
<xi:include href="dbus-org.freedesktop.NetworkManager.Device.Generic.xml"/>
+ <xi:include href="dbus-org.freedesktop.NetworkManager.Device.Hsr.xml"/>
<xi:include href="dbus-org.freedesktop.NetworkManager.Device.IPTunnel.xml"/>
<xi:include href="dbus-org.freedesktop.NetworkManager.Device.Infiniband.xml"/>
<xi:include href="dbus-org.freedesktop.NetworkManager.Device.Loopback.xml"/>
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())]]></programlisting></in
<xi:include href="xml/nm-setting-generic.xml"/>
<xi:include href="xml/nm-setting-gsm.xml"/>
<xi:include href="xml/nm-setting-hostname.xml"/>
+ <xi:include href="xml/nm-setting-hsr.xml"/>
<xi:include href="xml/nm-setting-infiniband.xml"/>
<xi:include href="xml/nm-setting-ip-config.xml"/>
<xi:include href="xml/nm-setting-ip-tunnel.xml"/>
@@ -374,6 +375,7 @@ print ("NetworkManager version " + client.get_version())]]></programlisting></in
<xi:include href="xml/nm-device-dummy.xml"/>
<xi:include href="xml/nm-device-ethernet.xml"/>
<xi:include href="xml/nm-device-generic.xml"/>
+ <xi:include href="xml/nm-device-hsr.xml"/>
<xi:include href="xml/nm-device-infiniband.xml"/>
<xi:include href="xml/nm-device-ip-tunnel.xml"/>
<xi:include href="xml/nm-device-loopback.xml"/>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<node name="/">
+ <!--
+ org.freedesktop.NetworkManager.Device.Hsr:
+ @short_description: HSR Device.
+
+ -->
+ <interface name="org.freedesktop.NetworkManager.Device.Hsr">
+
+ <!--
+ Port1:
+ @since: 1.46
+
+ The device's port1 device.
+ -->
+ <property name="Port1" type="o" access="read"/>
+
+ <!--
+ Port2:
+ @since: 1.46
+
+ The device's port2 device.
+ -->
+ <property name="Port2" type="o" access="read"/>
+
+ <!--
+ SupervisionAddress:
+ @since: 1.46
+
+ The supervision MAC address.
+ -->
+ <property name="SupervisionAddress" type="s" access="read"/>
+
+ <!--
+ MulticastSpec:
+ @since: 1.46
+
+ The last byte of the supervision address.
+ -->
+ <property name="MulticastSpec" type="y" access="read"/>
+
+ <!--
+ Prp:
+ @since: 1.46
+
+ Whether the PRP protocol is used or not.
+ -->
+ <property name="Prp" type="b" access="read"/>
+
+ </interface>
+</node>
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 <linux/if_ether.h>
+
+#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 <NetworkManager.h> 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"
/>
</setting>
+ <setting name="hsr"
+ gtype="NMSettingHsr"
+ >
+ <property name="multicast-spec"
+ dbus-type="u"
+ gprop-type="guint"
+ />
+ <property name="port1"
+ dbus-type="s"
+ gprop-type="gchararray"
+ />
+ <property name="port2"
+ dbus-type="s"
+ gprop-type="gchararray"
+ />
+ <property name="prp"
+ dbus-type="b"
+ gprop-type="gboolean"
+ />
+ <property name="supervision-address"
+ dbus-type="s"
+ gprop-type="gchararray"
+ />
+ </setting>
<setting name="infiniband"
gtype="NMSettingInfiniband"
>
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
@@ -3045,6 +3045,10 @@ static const ParseInfoSetting *const parse_infos[_NM_META_SETTING_TYPE_NUM] = {
.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,
.parser = mac_address_parser_INFINIBAND, ), ), ),
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 <linux/if_ether.h>
+
+#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 <NetworkManager.h> 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)
{
@@ -6428,6 +6440,27 @@ 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)
+{
+ 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)
{
char str_p_key[64];
@@ -8309,6 +8342,29 @@ nm_platform_lnk_gre_cmp(const NMPlatformLnkGre *a, const NMPlatformLnkGre *b)
}
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)
{
nm_hash_update_val(h, obj->p_key);
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
@@ -843,6 +843,14 @@ typedef struct {
} _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;
} _nm_alignas(NMPlatformObject) NMPlatformLnkInfiniband;
@@ -1750,6 +1758,17 @@ nm_platform_link_gre_add(NMPlatform *self,
}
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,
const NMPlatformLnkSit *props,
@@ -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
@@ -254,6 +254,10 @@ typedef struct {
} 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
@@ -6025,6 +6025,42 @@ static const NMMetaPropertyInfo *const property_infos_GSM[] = {
};
#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[] = {
PROPERTY_INFO (NM_SETTING_HOSTNAME_PRIORITY, DESCRIBE_DOC_NM_SETTING_HOSTNAME_PRIORITY,
@@ -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, &quot;802-3-ethernet&quot; or &quot;802-11-wireless&quot; or &quot;bluetooth&quot;, etc), and for non-hardware dependent connections like VPN or otherwise, should contain the setting name of that setting type (ie, &quot;vpn&quot; or &quot;bridge&quot;, 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" />
<property name="interface-name"
alias="ifname"
nmcli-description="The name of the network interface this connection is bound to. If not set, then the connection can be attached to any interface of the appropriate type (subject to restrictions imposed by other settings). For software devices this specifies the name of the created device. For connection types where interface names cannot easily be made persistent (e.g. mobile broadband or USB Ethernet), this property should not be used. Setting this property restricts the interfaces a connection can be used with, and if interface names change or are reordered the connection may be applied to the wrong interface."
@@ -1135,6 +1135,29 @@
format="ternary"
values="true/yes/on, false/no/off, default/unknown" />
</setting>
+ <setting name="hsr" >
+ <property name="port1"
+ alias="port1"
+ nmcli-description="The port1 interface name of the HSR. This property is mandatory."
+ format="string" />
+ <property name="port2"
+ alias="port2"
+ nmcli-description="The port2 interface name of the HSR. This property is mandatory."
+ format="string" />
+ <property name="supervision-address"
+ alias="supervision-address"
+ nmcli-description="The supervision MAC address."
+ format="MAC address" />
+ <property name="multicast-spec"
+ alias="multicast-spec"
+ nmcli-description="The last byte of supervision address."
+ format="integer"
+ values="0 - 255" />
+ <property name="prp"
+ nmcli-description="The protocol used by the interface, whether it is PRP or HSR."
+ format="boolean"
+ values="true/yes/on, false/no/off" />
+ </setting>
<setting name="infiniband" >
<property name="mac-address"
alias="mac"
diff --git a/vapi/NM-1.0.metadata b/vapi/NM-1.0.metadata
index 44e2674e70..12d0fc6c17 100644
--- a/vapi/NM-1.0.metadata
+++ b/vapi/NM-1.0.metadata
@@ -31,6 +31,7 @@ SETTING_ETHTOOL_* parent="NM.SettingEthtool" name="SETTIN
SETTING_GENERIC_* parent="NM.SettingGeneric" name="SETTING_GENERIC_(.+)"
SETTING_GSM_* parent="NM.SettingGsm" name="SETTING_GSM_(.+)"
SETTING_HOSTNAME_* parent="NM.SettingHostname" name="SETTING_HOSTNAME_(.+)"
+SETTING_HSR_* parent="NM.SettingHsr" name="SETTING_HSR_(.+)"
SETTING_INFINIBAND_* parent="NM.SettingInfiniband" name="SETTING_INFINIBAND_(.+)"
SETTING_IP4_CONFIG_* parent="NM.SettingIP4Config" name="SETTING_IP4_CONFIG_(.+)"
SETTING_IP6_CONFIG_* parent="NM.SettingIP6Config" name="SETTING_IP6_CONFIG_(.+)"
@@ -111,6 +112,7 @@ DEVICE_BT_* parent="NM.DeviceBt" name="DEVICE
DEVICE_DUMMY_* parent="NM.DeviceDummy" name="DEVICE_DUMMY_(.+)"
DEVICE_ETHERNET_* parent="NM.DeviceEthernet" name="DEVICE_ETHERNET_(.+)"
DEVICE_GENERIC_* parent="NM.DeviceGeneric" name="DEVICE_GENERIC_(.+)"
+DEVICE_HSR_* parent="NM.DeviceHsr" name="DEVICE_HSR_(.+)"
DEVICE_INFINIBAND_* parent="NM.DeviceInfiniband" name="DEVICE_INFINIBAND_(.+)"
DEVICE_IP_TUNNEL_* parent="NM.DeviceIPTunnel" name="DEVICE_IP_TUNNEL_(.+)"
DEVICE_LOOPBACK_* parent="NM.DeviceLoopback" name="DEVICE_LOOPBACK_(.+)"