diff --git a/docs/api/network-manager-docs.xml b/docs/api/network-manager-docs.xml
index a7cf24610..caff6fa4f 100644
--- a/docs/api/network-manager-docs.xml
+++ b/docs/api/network-manager-docs.xml
@@ -186,6 +186,7 @@
+
diff --git a/docs/libnm/libnm-docs.xml b/docs/libnm/libnm-docs.xml
index 1b37fdd25..4ed079393 100644
--- a/docs/libnm/libnm-docs.xml
+++ b/docs/libnm/libnm-docs.xml
@@ -325,6 +325,7 @@ print ("NetworkManager version " + client.get_version())]]>
+
@@ -378,6 +379,7 @@ print ("NetworkManager version " + client.get_version())]]>
+
diff --git a/introspection/meson.build b/introspection/meson.build
index 81afa7d67..16bb5ed42 100644
--- a/introspection/meson.build
+++ b/introspection/meson.build
@@ -18,6 +18,7 @@ ifaces = [
'org.freedesktop.NetworkManager.Device.Hsr',
'org.freedesktop.NetworkManager.Device.IPTunnel',
'org.freedesktop.NetworkManager.Device.Infiniband',
+ 'org.freedesktop.NetworkManager.Device.Ipvlan',
'org.freedesktop.NetworkManager.Device.Loopback',
'org.freedesktop.NetworkManager.Device.Lowpan',
'org.freedesktop.NetworkManager.Device.Macsec',
diff --git a/introspection/org.freedesktop.NetworkManager.Device.Ipvlan.xml b/introspection/org.freedesktop.NetworkManager.Device.Ipvlan.xml
new file mode 100644
index 000000000..db7a779d1
--- /dev/null
+++ b/introspection/org.freedesktop.NetworkManager.Device.Ipvlan.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/core/devices/nm-device-factory.c b/src/core/devices/nm-device-factory.c
index 22c8fa5aa..bd771b7cf 100644
--- a/src/core/devices/nm-device-factory.c
+++ b/src/core/devices/nm-device-factory.c
@@ -415,6 +415,7 @@ nm_device_factory_manager_load_factories(NMDeviceFactoryManagerFactoryFunc callb
_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_ipvlan_device_factory_get_type);
_ADD_INTERNAL(nm_loopback_device_factory_get_type);
_ADD_INTERNAL(nm_macsec_device_factory_get_type);
_ADD_INTERNAL(nm_macvlan_device_factory_get_type);
diff --git a/src/core/devices/nm-device-ipvlan.c b/src/core/devices/nm-device-ipvlan.c
new file mode 100644
index 000000000..662e3ff28
--- /dev/null
+++ b/src/core/devices/nm-device-ipvlan.c
@@ -0,0 +1,487 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024 Red Hat, Inc.
+ */
+
+#include "src/core/nm-default-daemon.h"
+
+#include "nm-device-ipvlan.h"
+
+#include
+
+#include "libnm-core-intern/nm-core-internal.h"
+#include "nm-device-private.h"
+#include "settings/nm-settings.h"
+#include "nm-act-request.h"
+#include "nm-manager.h"
+#include "libnm-core-aux-intern/nm-libnm-core-utils.h"
+#include "libnm-platform/nm-platform.h"
+#include "nm-device-factory.h"
+#include "nm-setting-ipvlan.h"
+#include "nm-setting-wired.h"
+#include "nm-active-connection.h"
+#include "nm-utils.h"
+
+#define _NMLOG_DEVICE_TYPE NMDeviceIpvlan
+#include "nm-device-logging.h"
+
+/*****************************************************************************/
+
+NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceIpvlan, PROP_MODE, PROP_PRIVATE, PROP_VEPA, );
+
+typedef struct {
+ NMPlatformLnkIpvlan props;
+} NMDeviceIpvlanPrivate;
+
+struct _NMDeviceIpvlan {
+ NMDevice parent;
+ NMDeviceIpvlanPrivate _priv;
+};
+
+struct _NMDeviceIpvlanClass {
+ NMDeviceClass parent;
+};
+
+G_DEFINE_TYPE(NMDeviceIpvlan, nm_device_ipvlan, NM_TYPE_DEVICE);
+
+#define NM_DEVICE_IPVLAN_GET_PRIVATE(self) \
+ _NM_GET_PRIVATE(self, NMDeviceIpvlan, NM_IS_DEVICE_IPVLAN, NMDevice)
+
+/*****************************************************************************/
+
+static int modes[][2] = {
+ {NM_SETTING_IPVLAN_MODE_L2, IPVLAN_MODE_L2},
+ {NM_SETTING_IPVLAN_MODE_L3, IPVLAN_MODE_L3},
+ {NM_SETTING_IPVLAN_MODE_L3S, IPVLAN_MODE_L3S},
+};
+
+static int
+setting_mode_to_platform(int mode)
+{
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS(modes); i++) {
+ if (modes[i][0] == mode)
+ return modes[i][1];
+ }
+
+ return -1;
+}
+
+static int
+platform_mode_to_setting(int mode)
+{
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS(modes); i++) {
+ if (modes[i][1] == mode)
+ return modes[i][0];
+ }
+
+ return 0;
+}
+
+static const char *
+platform_mode_to_string(guint mode)
+{
+ switch (mode) {
+ case IPVLAN_MODE_L2:
+ return "l2";
+ case IPVLAN_MODE_L3:
+ return "l3";
+ case IPVLAN_MODE_L3S:
+ return "l3s";
+ default:
+ return "unknown";
+ }
+}
+
+/*****************************************************************************/
+
+static void
+update_properties(NMDevice *device)
+{
+ NMDeviceIpvlan *self = NM_DEVICE_IPVLAN(device);
+ NMDeviceIpvlanPrivate *priv = NM_DEVICE_IPVLAN_GET_PRIVATE(self);
+ GObject *object = G_OBJECT(device);
+ const NMPlatformLnkIpvlan *props;
+ const NMPlatformLink *plink;
+
+ props = nm_platform_link_get_lnk_ipvlan(nm_device_get_platform(device),
+ nm_device_get_ifindex(device),
+ &plink);
+
+ if (!props) {
+ _LOGW(LOGD_PLATFORM, "could not get IPVLAN properties");
+ return;
+ }
+
+ g_object_freeze_notify(object);
+
+ nm_device_parent_set_ifindex(device, plink->parent);
+
+#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(mode, PROP_MODE);
+ CHECK_PROPERTY_CHANGED(private_flag, PROP_PRIVATE);
+ CHECK_PROPERTY_CHANGED(vepa, PROP_VEPA);
+
+ g_object_thaw_notify(object);
+}
+
+static void
+link_changed(NMDevice *device, const NMPlatformLink *pllink)
+{
+ NM_DEVICE_CLASS(nm_device_ipvlan_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);
+ NMSettingIpvlan *s_ipvlan;
+ NMPlatformLnkIpvlan lnk = {};
+ int parent_ifindex;
+ int r;
+
+ s_ipvlan = _nm_connection_get_setting(connection, NM_TYPE_SETTING_IPVLAN);
+ nm_assert(s_ipvlan);
+
+ if (!parent) {
+ g_set_error(error,
+ NM_DEVICE_ERROR,
+ NM_DEVICE_ERROR_MISSING_DEPENDENCIES,
+ "IPVLAN device cannot be created without a parent interface");
+ return FALSE;
+ }
+
+ parent_ifindex = nm_device_get_ifindex(parent);
+ if (parent_ifindex <= 0) {
+ g_set_error(error,
+ NM_DEVICE_ERROR,
+ NM_DEVICE_ERROR_MISSING_DEPENDENCIES,
+ "cannot retrieve ifindex of interface %s (%s)",
+ nm_device_get_iface(parent),
+ nm_device_get_type_desc(parent));
+ return FALSE;
+ }
+
+ if (setting_mode_to_platform(nm_setting_ipvlan_get_mode(s_ipvlan)) < 0) {
+ g_set_error(error,
+ NM_DEVICE_ERROR,
+ NM_DEVICE_ERROR_FAILED,
+ "unsupported IPVLAN mode %u in connection %s",
+ nm_setting_ipvlan_get_mode(s_ipvlan),
+ nm_connection_get_uuid(connection));
+ return FALSE;
+ }
+ lnk.mode = setting_mode_to_platform(nm_setting_ipvlan_get_mode(s_ipvlan));
+ lnk.private_flag = nm_setting_ipvlan_get_private(s_ipvlan);
+ lnk.vepa = nm_setting_ipvlan_get_vepa(s_ipvlan);
+
+ r = nm_platform_link_ipvlan_add(nm_device_get_platform(device),
+ iface,
+ parent_ifindex,
+ &lnk,
+ out_plink);
+
+ if (r < 0) {
+ g_set_error(error,
+ NM_DEVICE_ERROR,
+ NM_DEVICE_ERROR_CREATION_FAILED,
+ "Failed to create IPVLAN interface '%s' for '%s': %s",
+ iface,
+ nm_connection_get_id(connection),
+ nm_strerror(r));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*****************************************************************************/
+
+static NMDeviceCapabilities
+get_generic_capabilities(NMDevice *device)
+{
+ return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE;
+}
+
+/*****************************************************************************/
+
+static gboolean
+is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags)
+{
+ if (!nm_device_parent_get_device(device))
+ return FALSE;
+ return NM_DEVICE_CLASS(nm_device_ipvlan_parent_class)->is_available(device, flags);
+}
+
+/*****************************************************************************/
+
+static gboolean
+check_connection_compatible(NMDevice *device,
+ NMConnection *connection,
+ gboolean check_properties,
+ GError **error)
+{
+ NMDeviceIpvlanPrivate *priv = NM_DEVICE_IPVLAN_GET_PRIVATE(device);
+ NMSettingIpvlan *s_ipvlan;
+ const char *parent = NULL;
+
+ if (!NM_DEVICE_CLASS(nm_device_ipvlan_parent_class)
+ ->check_connection_compatible(device, connection, check_properties, error))
+ return FALSE;
+
+ s_ipvlan = _nm_connection_get_setting(connection, NM_TYPE_SETTING_IPVLAN);
+
+ if (check_properties && nm_device_is_real(device)) {
+ if (setting_mode_to_platform(nm_setting_ipvlan_get_mode(s_ipvlan)) != priv->props.mode) {
+ nm_utils_error_set_literal(error,
+ NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
+ "IPVLAN mode setting differs");
+ return FALSE;
+ }
+
+ if (nm_setting_ipvlan_get_private(s_ipvlan) != priv->props.private_flag) {
+ nm_utils_error_set_literal(error,
+ NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
+ "IPVLAN private flag setting differs");
+ return FALSE;
+ }
+ if (nm_setting_ipvlan_get_vepa(s_ipvlan) != priv->props.vepa) {
+ nm_utils_error_set_literal(error,
+ NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
+ "IPVLAN VEPA flag setting differs");
+ return FALSE;
+ }
+
+ /* Check parent interface; could be an interface name or a UUID */
+ parent = nm_setting_ipvlan_get_parent(s_ipvlan);
+ if (parent) {
+ if (!nm_device_match_parent(device, parent)) {
+ nm_utils_error_set_literal(error,
+ NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
+ "IPVLAN parent setting differs");
+ return FALSE;
+ }
+ } else {
+ /* Parent could be a MAC address in an NMSettingWired */
+ if (!nm_device_match_parent_hwaddr(device, connection, TRUE)) {
+ nm_utils_error_set_literal(error,
+ NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
+ "IPVLAN parent mac setting differs");
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+}
+
+static void
+update_connection(NMDevice *device, NMConnection *connection)
+{
+ NMDeviceIpvlanPrivate *priv = NM_DEVICE_IPVLAN_GET_PRIVATE(device);
+ NMSettingIpvlan *s_ipvlan = _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_IPVLAN);
+
+ if (priv->props.mode != setting_mode_to_platform(nm_setting_ipvlan_get_mode(s_ipvlan)))
+ g_object_set(s_ipvlan,
+ NM_SETTING_IPVLAN_MODE,
+ platform_mode_to_setting(priv->props.mode),
+ NULL);
+
+ if (priv->props.private_flag != nm_setting_ipvlan_get_private(s_ipvlan))
+ g_object_set(s_ipvlan, NM_SETTING_IPVLAN_PRIVATE, priv->props.private_flag, NULL);
+
+ if (priv->props.vepa != nm_setting_ipvlan_get_vepa(s_ipvlan))
+ g_object_set(s_ipvlan, NM_SETTING_IPVLAN_VEPA, priv->props.vepa, NULL);
+
+ g_object_set(
+ s_ipvlan,
+ NM_SETTING_IPVLAN_PARENT,
+ nm_device_parent_find_for_connection(device, nm_setting_ipvlan_get_parent(s_ipvlan)),
+ NULL);
+}
+
+/*****************************************************************************/
+
+static void
+get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ NMDeviceIpvlanPrivate *priv = NM_DEVICE_IPVLAN_GET_PRIVATE(object);
+
+ switch (prop_id) {
+ case PROP_MODE:
+ g_value_set_string(value, platform_mode_to_string(priv->props.mode));
+ break;
+ case PROP_PRIVATE:
+ g_value_set_boolean(value, priv->props.private_flag);
+ break;
+ case PROP_VEPA:
+ g_value_set_boolean(value, priv->props.vepa);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+/*****************************************************************************/
+
+static void
+nm_device_ipvlan_init(NMDeviceIpvlan *self)
+{}
+
+static const NMDBusInterfaceInfoExtended interface_info_device_ipvlan = {
+ .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT(
+ NM_DBUS_INTERFACE_DEVICE_IPVLAN,
+ .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS(
+ NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Parent", "o", NM_DEVICE_PARENT),
+ NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Mode", "s", NM_DEVICE_IPVLAN_MODE),
+ NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Private",
+ "b",
+ NM_DEVICE_IPVLAN_PRIVATE),
+ NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Vepa",
+ "b",
+ NM_DEVICE_IPVLAN_VEPA), ), ),
+};
+
+static void
+nm_device_ipvlan_class_init(NMDeviceIpvlanClass *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_ipvlan);
+
+ device_class->connection_type_supported = NM_SETTING_IPVLAN_SETTING_NAME;
+ device_class->connection_type_check_compatible = NM_SETTING_IPVLAN_SETTING_NAME;
+ device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_IPVLAN);
+
+ device_class->check_connection_compatible = check_connection_compatible;
+ device_class->create_and_realize = create_and_realize;
+ device_class->get_generic_capabilities = get_generic_capabilities;
+ device_class->is_available = is_available;
+ device_class->link_changed = link_changed;
+ device_class->update_connection = update_connection;
+
+ obj_properties[PROP_MODE] = g_param_spec_string(NM_DEVICE_IPVLAN_MODE,
+ "",
+ "",
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ obj_properties[PROP_PRIVATE] = g_param_spec_boolean(NM_DEVICE_IPVLAN_PRIVATE,
+ "",
+ "",
+ TRUE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ obj_properties[PROP_VEPA] = g_param_spec_boolean(NM_DEVICE_IPVLAN_VEPA,
+ "",
+ "",
+ TRUE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+}
+
+/*****************************************************************************/
+
+#define NM_TYPE_IPVLAN_DEVICE_FACTORY (nm_ipvlan_device_factory_get_type())
+#define NM_IPVLAN_DEVICE_FACTORY(obj) \
+ (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_IPVLAN_DEVICE_FACTORY, NMIpvlanDeviceFactory))
+
+static NMDevice *
+create_device(NMDeviceFactory *factory,
+ const char *iface,
+ const NMPlatformLink *plink,
+ NMConnection *connection,
+ gboolean *out_ignore)
+{
+ NMSettingIpvlan *s_ipvlan;
+
+ if (connection) {
+ s_ipvlan = _nm_connection_get_setting(connection, NM_TYPE_SETTING_IPVLAN);
+ nm_assert(s_ipvlan);
+ }
+
+ return g_object_new(NM_TYPE_DEVICE_IPVLAN,
+ NM_DEVICE_IFACE,
+ iface,
+ NM_DEVICE_TYPE_DESC,
+ "Ipvlan",
+ NM_DEVICE_DEVICE_TYPE,
+ NM_DEVICE_TYPE_IPVLAN,
+ NM_DEVICE_LINK_TYPE,
+ NM_LINK_TYPE_IPVLAN,
+ NULL);
+}
+
+static const char *
+get_connection_parent(NMDeviceFactory *factory, NMConnection *connection)
+{
+ NMSettingIpvlan *s_ipvlan;
+ NMSettingWired *s_wired;
+ const char *parent = NULL;
+
+ g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_IPVLAN_SETTING_NAME), NULL);
+
+ s_ipvlan = _nm_connection_get_setting(connection, NM_TYPE_SETTING_IPVLAN);
+ nm_assert(s_ipvlan);
+
+ parent = nm_setting_ipvlan_get_parent(s_ipvlan);
+ if (parent)
+ return parent;
+
+ /* Try the hardware address from the IPVLAN connection's hardware setting */
+ s_wired = nm_connection_get_setting_wired(connection);
+ if (s_wired)
+ return nm_setting_wired_get_mac_address(s_wired);
+
+ return NULL;
+}
+
+static char *
+get_connection_iface(NMDeviceFactory *factory, NMConnection *connection, const char *parent_iface)
+{
+ NMSettingIpvlan *s_ipvlan;
+ const char *ifname;
+
+ g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_IPVLAN_SETTING_NAME), NULL);
+
+ s_ipvlan = _nm_connection_get_setting(connection, NM_TYPE_SETTING_IPVLAN);
+ nm_assert(s_ipvlan);
+
+ if (!parent_iface)
+ return NULL;
+
+ ifname = nm_connection_get_interface_name(connection);
+ return g_strdup(ifname);
+}
+
+NM_DEVICE_FACTORY_DEFINE_INTERNAL(
+ IPVLAN,
+ Ipvlan,
+ ipvlan,
+ NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_IPVLAN)
+ NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_IPVLAN_SETTING_NAME),
+ factory_class->create_device = create_device;
+ factory_class->get_connection_parent = get_connection_parent;
+ factory_class->get_connection_iface = get_connection_iface;);
diff --git a/src/core/devices/nm-device-ipvlan.h b/src/core/devices/nm-device-ipvlan.h
new file mode 100644
index 000000000..6a228abe8
--- /dev/null
+++ b/src/core/devices/nm-device-ipvlan.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024 Red Hat, Inc.
+ */
+
+#ifndef __NETWORKMANAGER_DEVICE_IPVLAN_H__
+#define __NETWORKMANAGER_DEVICE_IPVLAN_H__
+
+#include "nm-device.h"
+
+#define NM_TYPE_DEVICE_IPVLAN (nm_device_ipvlan_get_type())
+#define NM_DEVICE_IPVLAN(obj) \
+ (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_IPVLAN, NMDeviceIpvlan))
+#define NM_DEVICE_IPVLAN_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_IPVLAN, NMDeviceIpvlanClass))
+#define NM_IS_DEVICE_IPVLAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_IPVLAN))
+#define NM_IS_DEVICE_IPVLAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_IPVLAN))
+#define NM_DEVICE_IPVLAN_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_IPVLAN, NMDeviceIpvlanClass))
+
+#define NM_DEVICE_IPVLAN_PARENT "parent"
+#define NM_DEVICE_IPVLAN_MODE "mode"
+#define NM_DEVICE_IPVLAN_PRIVATE "private"
+#define NM_DEVICE_IPVLAN_VEPA "vepa"
+
+typedef struct _NMDeviceIpvlan NMDeviceIpvlan;
+typedef struct _NMDeviceIpvlanClass NMDeviceIpvlanClass;
+
+GType nm_device_ipvlan_get_type(void);
+
+#endif /* __NETWORKMANAGER_DEVICE_IPVLAN_H__ */
diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c
index 927a33fa0..803ea7371 100644
--- a/src/core/devices/nm-device.c
+++ b/src/core/devices/nm-device.c
@@ -5632,6 +5632,8 @@ nm_device_get_route_metric_default(NMDeviceType device_type)
return 400;
case NM_DEVICE_TYPE_MACVLAN:
return 410;
+ case NM_DEVICE_TYPE_IPVLAN:
+ return 420;
case NM_DEVICE_TYPE_BRIDGE:
return 425;
case NM_DEVICE_TYPE_TUN:
@@ -18700,7 +18702,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_HSR);
+ nm_assert(priv->type <= NM_DEVICE_TYPE_IPVLAN);
break;
case PROP_LINK_TYPE:
/* construct-only */
diff --git a/src/core/meson.build b/src/core/meson.build
index 4419ff629..6dd60be87 100644
--- a/src/core/meson.build
+++ b/src/core/meson.build
@@ -105,6 +105,7 @@ libNetworkManager = static_library(
'devices/nm-device-hsr.c',
'devices/nm-device-infiniband.c',
'devices/nm-device-ip-tunnel.c',
+ 'devices/nm-device-ipvlan.c',
'devices/nm-device-loopback.c',
'devices/nm-device-macsec.c',
'devices/nm-device-macvlan.c',
diff --git a/src/libnm-client-impl/libnm.ver b/src/libnm-client-impl/libnm.ver
index 23e6042fb..eb3645b2c 100644
--- a/src/libnm-client-impl/libnm.ver
+++ b/src/libnm-client-impl/libnm.ver
@@ -2007,4 +2007,20 @@ libnm_1_50_0 {
global:
nm_setting_wireless_channel_width_get_type;
nm_setting_wireless_get_channel_width;
-} libnm_1_48_0;
\ No newline at end of file
+} libnm_1_48_0;
+
+libnm_1_52_0 {
+global:
+ nm_device_ipvlan_get_mode;
+ nm_device_ipvlan_get_parent;
+ nm_device_ipvlan_get_private;
+ nm_device_ipvlan_get_type;
+ nm_device_ipvlan_get_vepa;
+ nm_setting_ipvlan_get_mode;
+ nm_setting_ipvlan_get_parent;
+ nm_setting_ipvlan_get_private;
+ nm_setting_ipvlan_get_type;
+ nm_setting_ipvlan_get_vepa;
+ nm_setting_ipvlan_mode_get_type;
+ nm_setting_ipvlan_new;
+} libnm_1_50_0;
diff --git a/src/libnm-client-impl/meson.build b/src/libnm-client-impl/meson.build
index 3dd2338a8..e50e8fbdb 100644
--- a/src/libnm-client-impl/meson.build
+++ b/src/libnm-client-impl/meson.build
@@ -20,6 +20,7 @@ libnm_client_impl_sources = files(
'nm-device-hsr.c',
'nm-device-infiniband.c',
'nm-device-ip-tunnel.c',
+ 'nm-device-ipvlan.c',
'nm-device-loopback.c',
'nm-device-macsec.c',
'nm-device-macvlan.c',
diff --git a/src/libnm-client-impl/nm-client.c b/src/libnm-client-impl/nm-client.c
index 4ecc83899..9715981fe 100644
--- a/src/libnm-client-impl/nm-client.c
+++ b/src/libnm-client-impl/nm-client.c
@@ -32,6 +32,7 @@
#include "nm-device-hsr.h"
#include "nm-device-infiniband.h"
#include "nm-device-ip-tunnel.h"
+#include "nm-device-ipvlan.h"
#include "nm-device-loopback.h"
#include "nm-device-macsec.h"
#include "nm-device-macvlan.h"
diff --git a/src/libnm-client-impl/nm-device-ipvlan.c b/src/libnm-client-impl/nm-device-ipvlan.c
new file mode 100644
index 000000000..85d799c26
--- /dev/null
+++ b/src/libnm-client-impl/nm-device-ipvlan.c
@@ -0,0 +1,233 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024 Red Hat, Inc.
+ */
+
+#include "libnm-client-impl/nm-default-libnm.h"
+
+#include "nm-device-ipvlan.h"
+
+#include "nm-setting-connection.h"
+#include "nm-setting-ipvlan.h"
+#include "nm-utils.h"
+#include "nm-object-private.h"
+
+/*****************************************************************************/
+
+NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_PARENT, PROP_MODE, PROP_PRIVATE, PROP_VEPA, );
+
+typedef struct {
+ NMLDBusPropertyO parent;
+ char *mode;
+ bool private_flag;
+ bool vepa;
+} NMDeviceIpvlanPrivate;
+
+struct _NMDeviceIpvlan {
+ NMDevice parent;
+ NMDeviceIpvlanPrivate _priv;
+};
+
+struct _NMDeviceIpvlanClass {
+ NMDeviceClass parent;
+};
+
+G_DEFINE_TYPE(NMDeviceIpvlan, nm_device_ipvlan, NM_TYPE_DEVICE)
+
+#define NM_DEVICE_IPVLAN_GET_PRIVATE(self) \
+ _NM_GET_PRIVATE(self, NMDeviceIpvlan, NM_IS_DEVICE_IPVLAN, NMObject, NMDevice)
+
+/*****************************************************************************/
+
+/**
+ * nm_device_ipvlan_get_parent:
+ * @device: a #NMDeviceIpvlan
+ *
+ * Returns: (transfer none): the device's parent device
+ *
+ * Since: 1.52
+ **/
+NMDevice *
+nm_device_ipvlan_get_parent(NMDeviceIpvlan *device)
+{
+ g_return_val_if_fail(NM_IS_DEVICE_IPVLAN(device), FALSE);
+
+ return nml_dbus_property_o_get_obj(&NM_DEVICE_IPVLAN_GET_PRIVATE(device)->parent);
+}
+
+/**
+ * nm_device_ipvlan_get_mode:
+ * @device: a #NMDeviceIpvlan
+ *
+ * Gets the IPVLAN mode of the device.
+ *
+ * Returns: the IPVLAN mode. This is the internal string used by the
+ * device, and must not be modified.
+ *
+ * Since: 1.52
+ **/
+const char *
+nm_device_ipvlan_get_mode(NMDeviceIpvlan *device)
+{
+ g_return_val_if_fail(NM_IS_DEVICE_IPVLAN(device), NULL);
+
+ return _nml_coerce_property_str_not_empty(NM_DEVICE_IPVLAN_GET_PRIVATE(device)->mode);
+}
+
+/**
+ * nm_device_ipvlan_get_private
+ * @device: a #NMDeviceIpvlan
+ *
+ * Gets the private flag of the device.
+ *
+ * Returns: the private flag of the device.
+ *
+ * Since: 1.52
+ **/
+gboolean
+nm_device_ipvlan_get_private(NMDeviceIpvlan *device)
+{
+ g_return_val_if_fail(NM_IS_DEVICE_IPVLAN(device), FALSE);
+
+ return NM_DEVICE_IPVLAN_GET_PRIVATE(device)->private_flag;
+}
+
+/**
+ * nm_device_ipvlan_get_vepa
+ * @device: a #NMDeviceIpvlan
+ *
+ * Gets the VEPA flag of the device.
+ *
+ * Returns: the VEPA flag of the device.
+ *
+ * Since: 1.52
+ **/
+gboolean
+nm_device_ipvlan_get_vepa(NMDeviceIpvlan *device)
+{
+ g_return_val_if_fail(NM_IS_DEVICE_IPVLAN(device), FALSE);
+
+ return NM_DEVICE_IPVLAN_GET_PRIVATE(device)->vepa;
+}
+
+/*****************************************************************************/
+
+static void
+get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ NMDeviceIpvlan *device = NM_DEVICE_IPVLAN(object);
+
+ switch (prop_id) {
+ case PROP_PARENT:
+ g_value_set_object(value, nm_device_ipvlan_get_parent(device));
+ break;
+ case PROP_MODE:
+ g_value_set_string(value, nm_device_ipvlan_get_mode(device));
+ break;
+ case PROP_PRIVATE:
+ g_value_set_boolean(value, nm_device_ipvlan_get_private(device));
+ break;
+ case PROP_VEPA:
+ g_value_set_boolean(value, nm_device_ipvlan_get_vepa(device));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+nm_device_ipvlan_init(NMDeviceIpvlan *device)
+{}
+
+static void
+finalize(GObject *object)
+{
+ NMDeviceIpvlanPrivate *priv = NM_DEVICE_IPVLAN_GET_PRIVATE(object);
+
+ g_free(priv->mode);
+
+ G_OBJECT_CLASS(nm_device_ipvlan_parent_class)->finalize(object);
+}
+
+const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_ipvlan = NML_DBUS_META_IFACE_INIT_PROP(
+ NM_DBUS_INTERFACE_DEVICE_IPVLAN,
+ nm_device_ipvlan_get_type,
+ NML_DBUS_META_INTERFACE_PRIO_INSTANTIATE_30,
+ NML_DBUS_META_IFACE_DBUS_PROPERTIES(
+ NML_DBUS_META_PROPERTY_INIT_S("Mode", PROP_MODE, NMDeviceIpvlan, _priv.mode),
+ NML_DBUS_META_PROPERTY_INIT_O_PROP("Parent",
+ PROP_PARENT,
+ NMDeviceIpvlan,
+ _priv.parent,
+ nm_device_get_type),
+ NML_DBUS_META_PROPERTY_INIT_B("Private", PROP_PRIVATE, NMDeviceIpvlan, _priv.private_flag),
+ NML_DBUS_META_PROPERTY_INIT_B("Vepa", PROP_VEPA, NMDeviceIpvlan, _priv.vepa), ), );
+
+static void
+nm_device_ipvlan_class_init(NMDeviceIpvlanClass *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, NMDeviceIpvlan);
+
+ _NM_OBJECT_CLASS_INIT_PROPERTY_O_FIELDS_1(nm_object_class, NMDeviceIpvlanPrivate, parent);
+
+ /**
+ * NMDeviceIpvlan:parent:
+ *
+ * The devices's parent device.
+ *
+ * Since: 1.52
+ **/
+ obj_properties[PROP_PARENT] = g_param_spec_object(NM_DEVICE_IPVLAN_PARENT,
+ "",
+ "",
+ NM_TYPE_DEVICE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * NMDeviceIpvlan:mode:
+ *
+ * The IPVLAN mode.
+ *
+ * Since: 1.52
+ **/
+ obj_properties[PROP_MODE] = g_param_spec_string(NM_DEVICE_IPVLAN_MODE,
+ "",
+ "",
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * NMDeviceIpvlan:private:
+ *
+ * Whether the device has the private flag.
+ *
+ * Since: 1.52
+ **/
+ obj_properties[PROP_PRIVATE] = g_param_spec_boolean(NM_DEVICE_IPVLAN_PRIVATE,
+ "",
+ "",
+ FALSE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * NMDeviceIpvlan:vepa:
+ *
+ * Whether the device has the VEPA flag.
+ *
+ * Since: 1.52
+ **/
+ obj_properties[PROP_VEPA] = g_param_spec_boolean(NM_DEVICE_IPVLAN_VEPA,
+ "",
+ "",
+ FALSE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ _nml_dbus_meta_class_init_with_properties(object_class, &_nml_dbus_meta_iface_nm_device_ipvlan);
+}
diff --git a/src/libnm-client-impl/nm-device.c b/src/libnm-client-impl/nm-device.c
index dc868f5b9..a95501894 100644
--- a/src/libnm-client-impl/nm-device.c
+++ b/src/libnm-client-impl/nm-device.c
@@ -314,6 +314,7 @@ coerce_type(NMDeviceType type)
case NM_DEVICE_TYPE_VRF:
case NM_DEVICE_TYPE_LOOPBACK:
case NM_DEVICE_TYPE_HSR:
+ case NM_DEVICE_TYPE_IPVLAN:
return type;
}
return NM_DEVICE_TYPE_UNKNOWN;
@@ -1817,6 +1818,8 @@ get_type_name(NMDevice *device)
return _("Loopback");
case NM_DEVICE_TYPE_HSR:
return _("HSR");
+ case NM_DEVICE_TYPE_IPVLAN:
+ return _("IPVLAN");
case NM_DEVICE_TYPE_GENERIC:
case NM_DEVICE_TYPE_UNUSED1:
case NM_DEVICE_TYPE_UNUSED2:
diff --git a/src/libnm-client-impl/nm-libnm-utils.c b/src/libnm-client-impl/nm-libnm-utils.c
index 8af234cea..1b25c92ca 100644
--- a/src/libnm-client-impl/nm-libnm-utils.c
+++ b/src/libnm-client-impl/nm-libnm-utils.c
@@ -785,6 +785,7 @@ const NMLDBusMetaIface *const _nml_dbus_meta_ifaces[] = {
&_nml_dbus_meta_iface_nm_device_hsr,
&_nml_dbus_meta_iface_nm_device_iptunnel,
&_nml_dbus_meta_iface_nm_device_infiniband,
+ &_nml_dbus_meta_iface_nm_device_ipvlan,
&_nml_dbus_meta_iface_nm_device_loopback,
&_nml_dbus_meta_iface_nm_device_lowpan,
&_nml_dbus_meta_iface_nm_device_macsec,
diff --git a/src/libnm-client-impl/nm-libnm-utils.h b/src/libnm-client-impl/nm-libnm-utils.h
index 61ff442d1..f47b1a509 100644
--- a/src/libnm-client-impl/nm-libnm-utils.h
+++ b/src/libnm-client-impl/nm-libnm-utils.h
@@ -579,7 +579,7 @@ struct _NMLDBusMetaIface {
NML_DBUS_META_IFACE_OBJ_PROPERTIES(), \
##__VA_ARGS__)
-extern const NMLDBusMetaIface *const _nml_dbus_meta_ifaces[46];
+extern const NMLDBusMetaIface *const _nml_dbus_meta_ifaces[47];
extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm;
extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_accesspoint;
@@ -596,6 +596,7 @@ extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_generic;
extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_hsr;
extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_infiniband;
extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_iptunnel;
+extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_ipvlan;
extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_loopback;
extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_lowpan;
extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_macsec;
diff --git a/src/libnm-client-public/NetworkManager.h b/src/libnm-client-public/NetworkManager.h
index 646431f62..3608168f9 100644
--- a/src/libnm-client-public/NetworkManager.h
+++ b/src/libnm-client-public/NetworkManager.h
@@ -45,6 +45,7 @@
#include "nm-setting-ip6-config.h"
#include "nm-setting-ip-config.h"
#include "nm-setting-ip-tunnel.h"
+#include "nm-setting-ipvlan.h"
#include "nm-setting-link.h"
#include "nm-setting-loopback.h"
#include "nm-setting-macsec.h"
@@ -115,6 +116,7 @@
#include "nm-device-hsr.h"
#include "nm-device-infiniband.h"
#include "nm-device-ip-tunnel.h"
+#include "nm-device-ipvlan.h"
#include "nm-device-loopback.h"
#include "nm-device-macsec.h"
#include "nm-device-macvlan.h"
diff --git a/src/libnm-client-public/meson.build b/src/libnm-client-public/meson.build
index dccbb11fe..b8ae9cce0 100644
--- a/src/libnm-client-public/meson.build
+++ b/src/libnm-client-public/meson.build
@@ -21,6 +21,7 @@ libnm_client_headers = files(
'nm-device-hsr.h',
'nm-device-infiniband.h',
'nm-device-ip-tunnel.h',
+ 'nm-device-ipvlan.h',
'nm-device-loopback.h',
'nm-device-macsec.h',
'nm-device-macvlan.h',
diff --git a/src/libnm-client-public/nm-autoptr.h b/src/libnm-client-public/nm-autoptr.h
index c38f270c0..0f6e59c4a 100644
--- a/src/libnm-client-public/nm-autoptr.h
+++ b/src/libnm-client-public/nm-autoptr.h
@@ -44,6 +44,7 @@ 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(NMDeviceIpvlan, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMDeviceLoopback, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMDeviceMacsec, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMDeviceMacvlan, g_object_unref)
@@ -87,6 +88,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingIP6Config, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingIPConfig, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingIPTunnel, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingInfiniband, g_object_unref)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingIpvlan, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingLink, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingLoopback, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingMacsec, g_object_unref)
diff --git a/src/libnm-client-public/nm-device-ipvlan.h b/src/libnm-client-public/nm-device-ipvlan.h
new file mode 100644
index 000000000..768abc80a
--- /dev/null
+++ b/src/libnm-client-public/nm-device-ipvlan.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024 Red Hat, Inc.
+ */
+
+#ifndef __NM_DEVICE_IPVLAN_H__
+#define __NM_DEVICE_IPVLAN_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_IPVLAN (nm_device_ipvlan_get_type())
+#define NM_DEVICE_IPVLAN(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_IPVLAN, NMDeviceIpvlan))
+#define NM_DEVICE_IPVLAN_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_IPVLAN, NMDeviceIpvlanClass))
+#define NM_IS_DEVICE_IPVLAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_IPVLAN))
+#define NM_IS_DEVICE_IPVLAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_IPVLAN))
+#define NM_DEVICE_IPVLAN_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_IPVLAN, NMDeviceIpvlanClass))
+
+#define NM_DEVICE_IPVLAN_PARENT "parent"
+#define NM_DEVICE_IPVLAN_MODE "mode"
+#define NM_DEVICE_IPVLAN_PRIVATE "private"
+#define NM_DEVICE_IPVLAN_VEPA "vepa"
+
+/**
+ * NMDeviceIpvlan:
+ *
+ * Since: 1.52
+ */
+typedef struct _NMDeviceIpvlan NMDeviceIpvlan;
+typedef struct _NMDeviceIpvlanClass NMDeviceIpvlanClass;
+
+NM_AVAILABLE_IN_1_52
+GType nm_device_ipvlan_get_type(void);
+
+NM_AVAILABLE_IN_1_52
+NMDevice *nm_device_ipvlan_get_parent(NMDeviceIpvlan *device);
+NM_AVAILABLE_IN_1_52
+const char *nm_device_ipvlan_get_mode(NMDeviceIpvlan *device);
+NM_AVAILABLE_IN_1_52
+gboolean nm_device_ipvlan_get_private(NMDeviceIpvlan *device);
+NM_AVAILABLE_IN_1_52
+gboolean nm_device_ipvlan_get_vepa(NMDeviceIpvlan *device);
+
+G_END_DECLS
+
+#endif /* __NM_DEVICE_IPVLAN_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 6d2b92541..0b03d3628 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
@@ -1865,6 +1865,26 @@
gprop-type="gchararray"
/>
+
+
+
+
+
+
diff --git a/src/libnm-core-impl/meson.build b/src/libnm-core-impl/meson.build
index e1f11f323..e068d6bd3 100644
--- a/src/libnm-core-impl/meson.build
+++ b/src/libnm-core-impl/meson.build
@@ -25,6 +25,7 @@ libnm_core_settings_sources = files(
'nm-setting-ip-tunnel.c',
'nm-setting-ip4-config.c',
'nm-setting-ip6-config.c',
+ 'nm-setting-ipvlan.c',
'nm-setting-link.c',
'nm-setting-loopback.c',
'nm-setting-macsec.c',
diff --git a/src/libnm-core-impl/nm-connection.c b/src/libnm-core-impl/nm-connection.c
index 6dace2b73..24c28e815 100644
--- a/src/libnm-core-impl/nm-connection.c
+++ b/src/libnm-core-impl/nm-connection.c
@@ -3176,6 +3176,7 @@ nm_connection_is_virtual(NMConnection *connection)
NM_SETTING_DUMMY_SETTING_NAME,
NM_SETTING_HSR_SETTING_NAME,
NM_SETTING_IP_TUNNEL_SETTING_NAME,
+ NM_SETTING_IPVLAN_SETTING_NAME,
NM_SETTING_MACSEC_SETTING_NAME,
NM_SETTING_MACVLAN_SETTING_NAME,
NM_SETTING_OVS_BRIDGE_SETTING_NAME,
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 34a7d22e7..c8b77bf32 100644
--- a/src/libnm-core-impl/nm-meta-setting-base-impl.c
+++ b/src/libnm-core-impl/nm-meta-setting-base-impl.c
@@ -35,6 +35,7 @@
#include "nm-setting-ip-tunnel.h"
#include "nm-setting-ip4-config.h"
#include "nm-setting-ip6-config.h"
+#include "nm-setting-ipvlan.h"
#include "nm-setting-link.h"
#include "nm-setting-loopback.h"
#include "nm-setting-macsec.h"
@@ -371,6 +372,13 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = {
.setting_name = NM_SETTING_IP_TUNNEL_SETTING_NAME,
.get_setting_gtype = nm_setting_ip_tunnel_get_type,
},
+ [NM_META_SETTING_TYPE_IPVLAN] =
+ {
+ .meta_type = NM_META_SETTING_TYPE_IPVLAN,
+ .setting_priority = NM_SETTING_PRIORITY_HW_BASE,
+ .setting_name = NM_SETTING_IPVLAN_SETTING_NAME,
+ .get_setting_gtype = nm_setting_ipvlan_get_type,
+ },
[NM_META_SETTING_TYPE_LINK] =
{
.meta_type = NM_META_SETTING_TYPE_LINK,
@@ -643,6 +651,7 @@ const NMMetaSettingType nm_meta_setting_types_by_priority[] = {
NM_META_SETTING_TYPE_HSR,
NM_META_SETTING_TYPE_INFINIBAND,
NM_META_SETTING_TYPE_IP_TUNNEL,
+ NM_META_SETTING_TYPE_IPVLAN,
NM_META_SETTING_TYPE_LOOPBACK,
NM_META_SETTING_TYPE_MACSEC,
NM_META_SETTING_TYPE_MACVLAN,
diff --git a/src/libnm-core-impl/nm-setting-ipvlan.c b/src/libnm-core-impl/nm-setting-ipvlan.c
new file mode 100644
index 000000000..fafa37b6e
--- /dev/null
+++ b/src/libnm-core-impl/nm-setting-ipvlan.c
@@ -0,0 +1,290 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024 Red Hat, Inc.
+ */
+
+#include "libnm-core-impl/nm-default-libnm-core.h"
+
+#include "nm-setting-ipvlan.h"
+
+#include "nm-connection-private.h"
+#include "nm-utils.h"
+#include "nm-utils-private.h"
+
+/**
+ * SECTION:nm-setting-ipvlan
+ * @short_description: Describes connection properties for IPVLAN interfaces
+ *
+ * The #NMSettingIpvlan object is a #NMSetting subclass that describes properties
+ * necessary for connection to IPVLAN interfaces.
+ **/
+
+/*****************************************************************************/
+
+NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_PARENT, PROP_MODE, PROP_PRIVATE, PROP_VEPA, );
+
+typedef struct {
+ char *parent;
+ guint32 mode;
+ bool private_flag;
+ bool vepa;
+} NMSettingIpvlanPrivate;
+
+/**
+ * NMSettingIpvlan:
+ *
+ * IPVLAN Settings
+ */
+struct _NMSettingIpvlan {
+ NMSetting parent;
+ NMSettingIpvlanPrivate _priv;
+};
+
+struct _NMSettingIpvlanClass {
+ NMSettingClass parent;
+};
+
+G_DEFINE_TYPE(NMSettingIpvlan, nm_setting_ipvlan, NM_TYPE_SETTING)
+
+#define NM_SETTING_IPVLAN_GET_PRIVATE(o) \
+ _NM_GET_PRIVATE(o, NMSettingIpvlan, NM_IS_SETTING_IPVLAN, NMSetting)
+
+/*****************************************************************************/
+
+/**
+ * nm_setting_ipvlan_get_parent:
+ * @setting: the #NMSettingIpvlan
+ *
+ * Returns: the #NMSettingIpvlan:parent property of the setting
+ *
+ * Since: 1.52
+ **/
+const char *
+nm_setting_ipvlan_get_parent(NMSettingIpvlan *setting)
+{
+ g_return_val_if_fail(NM_IS_SETTING_IPVLAN(setting), NULL);
+
+ return NM_SETTING_IPVLAN_GET_PRIVATE(setting)->parent;
+}
+
+/**
+ * nm_setting_ipvlan_get_mode:
+ * @setting: the #NMSettingIpvlan
+ *
+ * Returns: the #NMSettingIpvlan:mode property of the setting
+ *
+ * Since: 1.52
+ **/
+NMSettingIpvlanMode
+nm_setting_ipvlan_get_mode(NMSettingIpvlan *setting)
+{
+ g_return_val_if_fail(NM_IS_SETTING_IPVLAN(setting), NM_SETTING_IPVLAN_MODE_UNKNOWN);
+
+ return NM_SETTING_IPVLAN_GET_PRIVATE(setting)->mode;
+}
+
+/**
+ * nm_setting_ipvlan_get_private:
+ * @setting: the #NMSettingIpvlan
+ *
+ * Returns: the #NMSettingIpvlan:private property of the setting
+ *
+ * Since: 1.52
+ **/
+gboolean
+nm_setting_ipvlan_get_private(NMSettingIpvlan *setting)
+{
+ g_return_val_if_fail(NM_IS_SETTING_IPVLAN(setting), FALSE);
+
+ return NM_SETTING_IPVLAN_GET_PRIVATE(setting)->private_flag;
+}
+
+/**
+ * nm_setting_ipvlan_get_vepa:
+ * @setting: the #NMSettingIpvlan
+ *
+ * Returns: the #NMSettingIpvlan:vepa property of the setting
+ *
+ * Since: 1.52
+ **/
+gboolean
+nm_setting_ipvlan_get_vepa(NMSettingIpvlan *setting)
+{
+ g_return_val_if_fail(NM_IS_SETTING_IPVLAN(setting), FALSE);
+
+ return NM_SETTING_IPVLAN_GET_PRIVATE(setting)->vepa;
+}
+
+/*****************************************************************************/
+
+static gboolean
+verify(NMSetting *setting, NMConnection *connection, GError **error)
+{
+ NMSettingIpvlanPrivate *priv = NM_SETTING_IPVLAN_GET_PRIVATE(setting);
+ NMSettingWired *s_wired = NULL;
+
+ if (connection)
+ s_wired = nm_connection_get_setting_wired(connection);
+
+ if (priv->parent) {
+ if (!nm_utils_is_uuid(priv->parent) && !nm_utils_ifname_valid_kernel(priv->parent, NULL)) {
+ g_set_error(error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("'%s' is neither an UUID nor an interface name"),
+ priv->parent);
+ g_prefix_error(error,
+ "%s.%s: ",
+ NM_SETTING_IPVLAN_SETTING_NAME,
+ NM_SETTING_IPVLAN_PARENT);
+ return FALSE;
+ }
+ } else {
+ /* If parent is NULL, the parent must be specified via NMSettingWired:mac-address. */
+ if (connection && (!s_wired || !nm_setting_wired_get_mac_address(s_wired))) {
+ g_set_error(error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_MISSING_PROPERTY,
+ _("property is not specified and neither is '%s:%s'"),
+ NM_SETTING_WIRED_SETTING_NAME,
+ NM_SETTING_WIRED_MAC_ADDRESS);
+ g_prefix_error(error,
+ "%s.%s: ",
+ NM_SETTING_IPVLAN_SETTING_NAME,
+ NM_SETTING_IPVLAN_PARENT);
+ return FALSE;
+ }
+ }
+
+ if (priv->private_flag && priv->vepa) {
+ g_set_error(error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("private and VEPA cannot be enabled at the same time"));
+ g_prefix_error(error, "%s: ", NM_SETTING_IPVLAN_SETTING_NAME);
+ return FALSE;
+ }
+
+ if (!_nm_connection_verify_required_interface_name(connection, error))
+ return FALSE;
+
+ return TRUE;
+}
+
+/*****************************************************************************/
+
+static void
+nm_setting_ipvlan_init(NMSettingIpvlan *self)
+{}
+
+/**
+ * nm_setting_ipvlan_new:
+ *
+ * Creates a new #NMSettingIpvlan object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingIpvlan object
+ *
+ * Since: 1.52
+ **/
+NMSetting *
+nm_setting_ipvlan_new(void)
+{
+ return g_object_new(NM_TYPE_SETTING_IPVLAN, NULL);
+}
+
+static void
+nm_setting_ipvlan_class_init(NMSettingIpvlanClass *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;
+
+ /**
+ * NMSettingIpvlan:parent:
+ *
+ * If given, specifies the parent interface name or parent connection UUID
+ * from which this IPVLAN interface should be created. If this property is
+ * not specified, the connection must contain an #NMSettingWired setting
+ * with a #NMSettingWired:mac-address property.
+ *
+ * Since: 1.52
+ **/
+ _nm_setting_property_define_direct_string(properties_override,
+ obj_properties,
+ NM_SETTING_IPVLAN_PARENT,
+ PROP_PARENT,
+ NM_SETTING_PARAM_INFERRABLE,
+ NMSettingIpvlanPrivate,
+ parent,
+ .direct_string_allow_empty = TRUE);
+
+ /**
+ * NMSettingIpvlan:mode:
+ *
+ * The IPVLAN mode. Valid values: %NM_SETTING_IPVLAN_MODE_L2,
+ * %NM_SETTING_IPVLAN_MODE_L3 and %NM_SETTING_IPVLAN_MODE_L3S.
+ *
+ * Since: 1.52
+ **/
+ /* ---nmcli---
+ * property: mode
+ * description:
+ * The IPVLAN mode. Valid values: l2 (1), l3 (2), l3s (3)
+ * ---end---
+ */
+ _nm_setting_property_define_direct_uint32(properties_override,
+ obj_properties,
+ NM_SETTING_IPVLAN_MODE,
+ PROP_MODE,
+ 0,
+ G_MAXUINT32,
+ NM_SETTING_IPVLAN_MODE_UNKNOWN,
+ NM_SETTING_PARAM_INFERRABLE,
+ NMSettingIpvlanPrivate,
+ mode);
+
+ /**
+ * NMSettingIpvlan:private:
+ *
+ * Whether the interface should be put in private mode.
+ *
+ * Since: 1.52
+ **/
+ _nm_setting_property_define_direct_boolean(properties_override,
+ obj_properties,
+ NM_SETTING_IPVLAN_PRIVATE,
+ PROP_PRIVATE,
+ FALSE,
+ NM_SETTING_PARAM_INFERRABLE,
+ NMSettingIpvlanPrivate,
+ private_flag);
+
+ /**
+ * NMSettingIpvlan:vepa:
+ *
+ * Whether the interface should be put in VEPA mode.
+ *
+ * Since: 1.52
+ **/
+ _nm_setting_property_define_direct_boolean(properties_override,
+ obj_properties,
+ NM_SETTING_IPVLAN_VEPA,
+ PROP_VEPA,
+ FALSE,
+ NM_SETTING_PARAM_INFERRABLE,
+ NMSettingIpvlanPrivate,
+ vepa);
+
+ g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+
+ _nm_setting_class_commit(setting_class,
+ NM_META_SETTING_TYPE_IPVLAN,
+ NULL,
+ properties_override,
+ G_STRUCT_OFFSET(NMSettingIpvlan, _priv));
+}
diff --git a/src/libnm-core-intern/nm-core-internal.h b/src/libnm-core-intern/nm-core-internal.h
index 4677fb163..69a435ea1 100644
--- a/src/libnm-core-intern/nm-core-internal.h
+++ b/src/libnm-core-intern/nm-core-internal.h
@@ -44,6 +44,7 @@
#include "nm-setting-ip-tunnel.h"
#include "nm-setting-ip4-config.h"
#include "nm-setting-ip6-config.h"
+#include "nm-setting-ipvlan.h"
#include "nm-setting-link.h"
#include "nm-setting-loopback.h"
#include "nm-setting-macsec.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 9226183fe..c03285ebf 100644
--- a/src/libnm-core-intern/nm-meta-setting-base-impl.h
+++ b/src/libnm-core-intern/nm-meta-setting-base-impl.h
@@ -128,6 +128,7 @@ typedef enum _nm_packed {
NM_META_SETTING_TYPE_IP_TUNNEL,
NM_META_SETTING_TYPE_IP4_CONFIG,
NM_META_SETTING_TYPE_IP6_CONFIG,
+ NM_META_SETTING_TYPE_IPVLAN,
NM_META_SETTING_TYPE_LINK,
NM_META_SETTING_TYPE_LOOPBACK,
NM_META_SETTING_TYPE_MACSEC,
diff --git a/src/libnm-core-public/meson.build b/src/libnm-core-public/meson.build
index b5ed71e8c..97888467e 100644
--- a/src/libnm-core-public/meson.build
+++ b/src/libnm-core-public/meson.build
@@ -30,6 +30,7 @@ libnm_core_headers = files(
'nm-setting-ip-tunnel.h',
'nm-setting-ip4-config.h',
'nm-setting-ip6-config.h',
+ 'nm-setting-ipvlan.h',
'nm-setting-link.h',
'nm-setting-loopback.h',
'nm-setting-macsec.h',
diff --git a/src/libnm-core-public/nm-core-types.h b/src/libnm-core-public/nm-core-types.h
index d9a8225e8..a0d6bc82d 100644
--- a/src/libnm-core-public/nm-core-types.h
+++ b/src/libnm-core-public/nm-core-types.h
@@ -35,6 +35,7 @@ typedef struct _NMSettingIP4Config NMSettingIP4Config;
typedef struct _NMSettingIP6Config NMSettingIP6Config;
typedef struct _NMSettingIPConfig NMSettingIPConfig;
typedef struct _NMSettingIPTunnel NMSettingIPTunnel;
+typedef struct _NMSettingIpvlan NMSettingIpvlan;
typedef struct _NMSettingInfiniband NMSettingInfiniband;
typedef struct _NMSettingLink NMSettingLink;
typedef struct _NMSettingLoopback NMSettingLoopback;
diff --git a/src/libnm-core-public/nm-dbus-interface.h b/src/libnm-core-public/nm-dbus-interface.h
index 5eedd7da3..64136161d 100644
--- a/src/libnm-core-public/nm-dbus-interface.h
+++ b/src/libnm-core-public/nm-dbus-interface.h
@@ -40,6 +40,7 @@
#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_IPVLAN NM_DBUS_INTERFACE_DEVICE ".Ipvlan"
#define NM_DBUS_INTERFACE_DEVICE_LOOPBACK NM_DBUS_INTERFACE_DEVICE ".Loopback"
#define NM_DBUS_INTERFACE_DEVICE_MACSEC NM_DBUS_INTERFACE_DEVICE ".Macsec"
#define NM_DBUS_INTERFACE_DEVICE_MACVLAN NM_DBUS_INTERFACE_DEVICE ".Macvlan"
@@ -236,6 +237,7 @@ typedef enum {
* @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.
+ * @NM_DEVICE_TYPE_IPVLAN: A IPVLAN device. Since: 1.52.
*
* #NMDeviceType values indicate the type of hardware represented by a
* device object.
@@ -275,6 +277,7 @@ typedef enum {
NM_DEVICE_TYPE_VRF = 31,
NM_DEVICE_TYPE_LOOPBACK = 32,
NM_DEVICE_TYPE_HSR = 33,
+ NM_DEVICE_TYPE_IPVLAN = 34,
} NMDeviceType;
/**
diff --git a/src/libnm-core-public/nm-setting-ipvlan.h b/src/libnm-core-public/nm-setting-ipvlan.h
new file mode 100644
index 000000000..e332585b0
--- /dev/null
+++ b/src/libnm-core-public/nm-setting-ipvlan.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024 Red Hat, Inc.
+ */
+
+#ifndef __NM_SETTING_IPVLAN_H__
+#define __NM_SETTING_IPVLAN_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_IPVLAN (nm_setting_ipvlan_get_type())
+#define NM_SETTING_IPVLAN(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SETTING_IPVLAN, NMSettingIpvlan))
+#define NM_IS_SETTING_IPVLAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_SETTING_IPVLAN))
+#define NM_IS_SETTING_IPVLAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_SETTING_IPVLAN))
+#define NM_SETTING_IPVLAN_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_SETTING_IPVLAN, NMSettingIpvlanClass))
+
+#define NM_SETTING_IPVLAN_SETTING_NAME "ipvlan"
+
+#define NM_SETTING_IPVLAN_PARENT "parent"
+#define NM_SETTING_IPVLAN_MODE "mode"
+#define NM_SETTING_IPVLAN_PRIVATE "private"
+#define NM_SETTING_IPVLAN_VEPA "vepa"
+
+typedef struct _NMSettingIpvlanClass NMSettingIpvlanClass;
+
+/**
+ * NMSettingIpvlanMode:
+ * @NM_SETTING_IPVLAN_MODE_UNKNOWN: unknown/unset mode
+ * @NM_SETTING_IPVLAN_MODE_L2: L2 mode, device receives and responds to ARP.
+ * @NM_SETTING_IPVLAN_MODE_L3: L3 mode, device process only L3 traffic and above.
+ * @NM_SETTING_IPVLAN_MODE_L3S: L3S mode, same way as L3 mode but egress and ingress
+ * lands on netfilter chain.
+ *
+ * Since: 1.52
+ **/
+typedef enum {
+ NM_SETTING_IPVLAN_MODE_UNKNOWN = 0,
+ NM_SETTING_IPVLAN_MODE_L2 = 1,
+ NM_SETTING_IPVLAN_MODE_L3 = 2,
+ NM_SETTING_IPVLAN_MODE_L3S = 3,
+ _NM_SETTING_IPVLAN_MODE_NUM, /*< skip >*/
+ NM_SETTING_IPVLAN_MODE_LAST = _NM_SETTING_IPVLAN_MODE_NUM - 1, /*< skip >*/
+} NMSettingIpvlanMode;
+
+NM_AVAILABLE_IN_1_52
+GType nm_setting_ipvlan_get_type(void);
+NM_AVAILABLE_IN_1_52
+NMSetting *nm_setting_ipvlan_new(void);
+
+NM_AVAILABLE_IN_1_52
+const char *nm_setting_ipvlan_get_parent(NMSettingIpvlan *setting);
+NM_AVAILABLE_IN_1_52
+NMSettingIpvlanMode nm_setting_ipvlan_get_mode(NMSettingIpvlan *setting);
+NM_AVAILABLE_IN_1_52
+gboolean nm_setting_ipvlan_get_private(NMSettingIpvlan *setting);
+NM_AVAILABLE_IN_1_52
+gboolean nm_setting_ipvlan_get_vepa(NMSettingIpvlan *setting);
+
+G_END_DECLS
+
+#endif /* __NM_SETTING_IPVLAN_H__ */
diff --git a/src/libnm-glib-aux/nm-shared-utils.h b/src/libnm-glib-aux/nm-shared-utils.h
index 1dbd50232..93be743fb 100644
--- a/src/libnm-glib-aux/nm-shared-utils.h
+++ b/src/libnm-glib-aux/nm-shared-utils.h
@@ -137,6 +137,7 @@ typedef enum {
NM_LINK_TYPE_IP6GRE,
NM_LINK_TYPE_IP6GRETAP,
NM_LINK_TYPE_IPIP,
+ NM_LINK_TYPE_IPVLAN,
NM_LINK_TYPE_LOOPBACK,
NM_LINK_TYPE_MACSEC,
NM_LINK_TYPE_MACVLAN,
diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c
index bd495fe27..a738f9d9e 100644
--- a/src/libnm-platform/nm-linux-platform.c
+++ b/src/libnm-platform/nm-linux-platform.c
@@ -861,6 +861,7 @@ static const LinkDesc link_descs[] = {
[NM_LINK_TYPE_IP6GRE] = {"ip6gre", "ip6gre", NULL},
[NM_LINK_TYPE_IP6GRETAP] = {"ip6gretap", "ip6gretap", NULL},
[NM_LINK_TYPE_IPIP] = {"ipip", "ipip", NULL},
+ [NM_LINK_TYPE_IPVLAN] = {"ipvlan", "ipvlan", NULL},
[NM_LINK_TYPE_LOOPBACK] = {"loopback", NULL, NULL},
[NM_LINK_TYPE_MACSEC] = {"macsec", "macsec", NULL},
[NM_LINK_TYPE_MACVLAN] = {"macvlan", "macvlan", NULL},
@@ -908,6 +909,7 @@ _link_type_from_rtnl_type(const char *name)
NM_LINK_TYPE_IP6GRETAP, /* "ip6gretap" */
NM_LINK_TYPE_IP6TNL, /* "ip6tnl" */
NM_LINK_TYPE_IPIP, /* "ipip" */
+ NM_LINK_TYPE_IPVLAN, /* "ipvlan" */
NM_LINK_TYPE_MACSEC, /* "macsec" */
NM_LINK_TYPE_MACVLAN, /* "macvlan" */
NM_LINK_TYPE_MACVTAP, /* "macvtap" */
@@ -2106,6 +2108,40 @@ _parse_lnk_ipip(const char *kind, struct nlattr *info_data)
/*****************************************************************************/
+static NMPObject *
+_parse_lnk_ipvlan(const char *kind, struct nlattr *info_data)
+{
+ static const struct nla_policy policy[] = {
+ [IFLA_IPVLAN_MODE] = {.type = NLA_U16},
+ [IFLA_IPVLAN_FLAGS] = {.type = NLA_U16},
+ };
+ NMPlatformLnkIpvlan *props;
+ struct nlattr *tb[G_N_ELEMENTS(policy)];
+ NMPObject *obj;
+
+ if (!info_data || !kind)
+ return NULL;
+
+ if (nla_parse_nested_arr(tb, info_data, policy) < 0)
+ return NULL;
+
+ if (!tb[IFLA_IPVLAN_MODE])
+ return NULL;
+
+ obj = nmp_object_new(NMP_OBJECT_TYPE_LNK_IPVLAN, NULL);
+ props = &obj->lnk_ipvlan;
+ props->mode = nla_get_u16(tb[IFLA_IPVLAN_MODE]);
+
+ if (tb[IFLA_IPVLAN_FLAGS]) {
+ props->private_flag = NM_FLAGS_HAS(nla_get_u16(tb[IFLA_IPVLAN_FLAGS]), IPVLAN_F_PRIVATE);
+ props->vepa = NM_FLAGS_HAS(nla_get_u16(tb[IFLA_IPVLAN_FLAGS]), IPVLAN_F_VEPA);
+ }
+
+ return obj;
+}
+
+/*****************************************************************************/
+
static NMPObject *
_parse_lnk_macvlan(const char *kind, struct nlattr *info_data)
{
@@ -3670,6 +3706,9 @@ _new_from_nl_link(NMPlatform *platform,
case NM_LINK_TYPE_IPIP:
lnk_data = _parse_lnk_ipip(nl_info_kind, nl_info_data);
break;
+ case NM_LINK_TYPE_IPVLAN:
+ lnk_data = _parse_lnk_ipvlan(nl_info_kind, nl_info_data);
+ break;
case NM_LINK_TYPE_MACSEC:
lnk_data = _parse_lnk_macsec(nl_info_kind, nl_info_data);
break;
@@ -5248,6 +5287,26 @@ _nl_msg_new_link_set_linkinfo(struct nl_msg *msg, NMLinkType link_type, gconstpo
NLA_PUT_U8(msg, IFLA_IPTUN_PMTUDISC, !!props->path_mtu_discovery);
break;
}
+ case NM_LINK_TYPE_IPVLAN:
+ {
+ const NMPlatformLnkIpvlan *props = extra_data;
+ guint16 flags = 0;
+
+ nm_assert(props);
+
+ if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
+ goto nla_put_failure;
+
+ if (props->private_flag)
+ flags |= IPVLAN_F_PRIVATE;
+
+ if (props->vepa)
+ flags |= IPVLAN_F_VEPA;
+
+ NLA_PUT_U16(msg, IFLA_IPVLAN_MODE, props->mode);
+ NLA_PUT_U16(msg, IFLA_IPVLAN_FLAGS, flags);
+ break;
+ }
case NM_LINK_TYPE_MACSEC:
{
const NMPlatformLnkMacsec *props = extra_data;
diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c
index af04f29fa..a751aeeb3 100644
--- a/src/libnm-platform/nm-platform.c
+++ b/src/libnm-platform/nm-platform.c
@@ -1418,6 +1418,12 @@ nm_platform_link_add(NMPlatform *self,
buf_p,
buf_len);
break;
+ case NM_LINK_TYPE_IPVLAN:
+ nm_strbuf_append_str(&buf_p, &buf_len, ", ");
+ nm_platform_lnk_ipvlan_to_string((const NMPlatformLnkIpvlan *) extra_data,
+ buf_p,
+ buf_len);
+ break;
case NM_LINK_TYPE_MACSEC:
nm_strbuf_append_str(&buf_p, &buf_len, ", ");
nm_platform_lnk_macsec_to_string((const NMPlatformLnkMacsec *) extra_data,
@@ -2604,6 +2610,12 @@ nm_platform_link_get_lnk_ipip(NMPlatform *self, int ifindex, const NMPlatformLin
return _link_get_lnk(self, ifindex, NM_LINK_TYPE_IPIP, out_link);
}
+const NMPlatformLnkIpvlan *
+nm_platform_link_get_lnk_ipvlan(NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
+{
+ return _link_get_lnk(self, ifindex, NM_LINK_TYPE_IPVLAN, out_link);
+}
+
const NMPlatformLnkMacsec *
nm_platform_link_get_lnk_macsec(NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
@@ -6670,6 +6682,21 @@ nm_platform_lnk_macvlan_to_string(const NMPlatformLnkMacvlan *lnk, char *buf, gs
return buf;
}
+const char *
+nm_platform_lnk_ipvlan_to_string(const NMPlatformLnkIpvlan *lnk, char *buf, gsize len)
+{
+ if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len))
+ return buf;
+
+ g_snprintf(buf,
+ len,
+ "mode %u%s%s",
+ lnk->mode,
+ lnk->private_flag ? " private" : "",
+ lnk->vepa ? " vepa" : "");
+ return buf;
+}
+
const char *
nm_platform_lnk_sit_to_string(const NMPlatformLnkSit *lnk, char *buf, gsize len)
{
@@ -8557,6 +8584,22 @@ nm_platform_lnk_macvlan_cmp(const NMPlatformLnkMacvlan *a, const NMPlatformLnkMa
return 0;
}
+void
+nm_platform_lnk_ipvlan_hash_update(const NMPlatformLnkIpvlan *obj, NMHashState *h)
+{
+ nm_hash_update_vals(h, obj->mode, NM_HASH_COMBINE_BOOLS(guint8, obj->private_flag, obj->vepa));
+}
+
+int
+nm_platform_lnk_ipvlan_cmp(const NMPlatformLnkIpvlan *a, const NMPlatformLnkIpvlan *b)
+{
+ NM_CMP_SELF(a, b);
+ NM_CMP_FIELD(a, b, mode);
+ NM_CMP_FIELD_UNSAFE(a, b, private_flag);
+ NM_CMP_FIELD_UNSAFE(a, b, vepa);
+ return 0;
+}
+
void
nm_platform_lnk_sit_hash_update(const NMPlatformLnkSit *obj, NMHashState *h)
{
diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h
index e33be8135..97dac246f 100644
--- a/src/libnm-platform/nm-platform.h
+++ b/src/libnm-platform/nm-platform.h
@@ -879,6 +879,12 @@ typedef struct {
bool path_mtu_discovery : 1;
} _nm_alignas(NMPlatformObject) NMPlatformLnkIpIp;
+typedef struct {
+ guint16 mode;
+ bool private_flag : 1;
+ bool vepa : 1;
+} _nm_alignas(NMPlatformObject) NMPlatformLnkIpvlan;
+
typedef struct {
int parent_ifindex;
in_addr_t local;
@@ -1935,6 +1941,27 @@ nm_platform_link_macvlan_add(NMPlatform *self,
out_link);
}
+static inline int
+nm_platform_link_ipvlan_add(NMPlatform *self,
+ const char *name,
+ int parent,
+ const NMPlatformLnkIpvlan *props,
+ const NMPlatformLink **out_link)
+{
+ g_return_val_if_fail(props, -NME_BUG);
+ g_return_val_if_fail(parent > 0, -NME_BUG);
+
+ return nm_platform_link_add(self,
+ NM_LINK_TYPE_IPVLAN,
+ name,
+ parent,
+ NULL,
+ 0,
+ 0,
+ props,
+ out_link);
+}
+
gboolean nm_platform_link_delete(NMPlatform *self, int ifindex);
gboolean nm_platform_link_set_netns(NMPlatform *self, int ifindex, int netns_fd);
@@ -2117,6 +2144,8 @@ const NMPlatformLnkMacsec *
nm_platform_link_get_lnk_macsec(NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkMacvlan *
nm_platform_link_get_lnk_macvlan(NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
+const NMPlatformLnkIpvlan *
+nm_platform_link_get_lnk_ipvlan(NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkMacvlan *
nm_platform_link_get_lnk_macvtap(NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkSit *
@@ -2431,6 +2460,7 @@ const char *nm_platform_lnk_ipip_to_string(const NMPlatformLnkIpIp *lnk, char *b
const char *nm_platform_lnk_macsec_to_string(const NMPlatformLnkMacsec *lnk, char *buf, gsize len);
const char *
nm_platform_lnk_macvlan_to_string(const NMPlatformLnkMacvlan *lnk, char *buf, gsize len);
+const char *nm_platform_lnk_ipvlan_to_string(const NMPlatformLnkIpvlan *lnk, char *buf, gsize len);
const char *nm_platform_lnk_sit_to_string(const NMPlatformLnkSit *lnk, char *buf, gsize len);
const char *nm_platform_lnk_tun_to_string(const NMPlatformLnkTun *lnk, char *buf, gsize len);
const char *nm_platform_lnk_vlan_to_string(const NMPlatformLnkVlan *lnk, char *buf, gsize len);
@@ -2483,6 +2513,7 @@ int nm_platform_lnk_infiniband_cmp(const NMPlatformLnkInfiniband *a,
int nm_platform_lnk_ip6tnl_cmp(const NMPlatformLnkIp6Tnl *a, const NMPlatformLnkIp6Tnl *b);
int nm_platform_lnk_ipip_cmp(const NMPlatformLnkIpIp *a, const NMPlatformLnkIpIp *b);
int nm_platform_lnk_macsec_cmp(const NMPlatformLnkMacsec *a, const NMPlatformLnkMacsec *b);
+int nm_platform_lnk_ipvlan_cmp(const NMPlatformLnkIpvlan *a, const NMPlatformLnkIpvlan *b);
int nm_platform_lnk_macvlan_cmp(const NMPlatformLnkMacvlan *a, const NMPlatformLnkMacvlan *b);
int nm_platform_lnk_sit_cmp(const NMPlatformLnkSit *a, const NMPlatformLnkSit *b);
int nm_platform_lnk_tun_cmp(const NMPlatformLnkTun *a, const NMPlatformLnkTun *b);
@@ -2555,6 +2586,7 @@ void nm_platform_lnk_ip6tnl_hash_update(const NMPlatformLnkIp6Tnl *obj, NMHashSt
void nm_platform_lnk_ipip_hash_update(const NMPlatformLnkIpIp *obj, NMHashState *h);
void nm_platform_lnk_macsec_hash_update(const NMPlatformLnkMacsec *obj, NMHashState *h);
void nm_platform_lnk_macvlan_hash_update(const NMPlatformLnkMacvlan *obj, NMHashState *h);
+void nm_platform_lnk_ipvlan_hash_update(const NMPlatformLnkIpvlan *obj, NMHashState *h);
void nm_platform_lnk_sit_hash_update(const NMPlatformLnkSit *obj, NMHashState *h);
void nm_platform_lnk_tun_hash_update(const NMPlatformLnkTun *obj, NMHashState *h);
void nm_platform_lnk_vlan_hash_update(const NMPlatformLnkVlan *obj, NMHashState *h);
diff --git a/src/libnm-platform/nmp-base.h b/src/libnm-platform/nmp-base.h
index c7d487e23..4f675a81b 100644
--- a/src/libnm-platform/nmp-base.h
+++ b/src/libnm-platform/nmp-base.h
@@ -174,6 +174,7 @@ typedef enum _nm_packed {
NMP_OBJECT_TYPE_LNK_IP6GRE,
NMP_OBJECT_TYPE_LNK_IP6GRETAP,
NMP_OBJECT_TYPE_LNK_IPIP,
+ NMP_OBJECT_TYPE_LNK_IPVLAN,
NMP_OBJECT_TYPE_LNK_MACSEC,
NMP_OBJECT_TYPE_LNK_MACVLAN,
NMP_OBJECT_TYPE_LNK_MACVTAP,
diff --git a/src/libnm-platform/nmp-object.c b/src/libnm-platform/nmp-object.c
index 1fdaa2755..f41cc95ab 100644
--- a/src/libnm-platform/nmp-object.c
+++ b/src/libnm-platform/nmp-object.c
@@ -3565,6 +3565,18 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_ipip_hash_update,
.cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_ipip_cmp,
},
+ [NMP_OBJECT_TYPE_LNK_IPVLAN - 1] =
+ {
+ .parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
+ .obj_type = NMP_OBJECT_TYPE_LNK_IPVLAN,
+ .sizeof_data = sizeof(NMPObjectLnkIpvlan),
+ .sizeof_public = sizeof(NMPlatformLnkIpvlan),
+ .obj_type_name = "ipvlan",
+ .lnk_link_type = NM_LINK_TYPE_IPVLAN,
+ .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_lnk_ipvlan_to_string,
+ .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_ipvlan_hash_update,
+ .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_ipvlan_cmp,
+ },
[NMP_OBJECT_TYPE_LNK_MACSEC - 1] =
{
.parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
diff --git a/src/libnm-platform/nmp-object.h b/src/libnm-platform/nmp-object.h
index cd1793d45..b526fc3be 100644
--- a/src/libnm-platform/nmp-object.h
+++ b/src/libnm-platform/nmp-object.h
@@ -270,6 +270,10 @@ typedef struct {
NMPlatformLnkIpIp _public;
} NMPObjectLnkIpIp;
+typedef struct {
+ NMPlatformLnkIpvlan _public;
+} NMPObjectLnkIpvlan;
+
typedef struct {
NMPlatformLnkMacsec _public;
} NMPObjectLnkMacsec;
@@ -394,6 +398,9 @@ struct _NMPObject {
NMPlatformLnkIp6Tnl lnk_ip6tnl;
NMPObjectLnkIp6Tnl _lnk_ip6tnl;
+ NMPlatformLnkIpvlan lnk_ipvlan;
+ NMPObjectLnkIpvlan _lnk_ipvlan;
+
NMPlatformLnkMacsec lnk_macsec;
NMPObjectLnkMacsec _lnk_macsec;
@@ -544,6 +551,7 @@ _NMP_OBJECT_TYPE_IS_OBJ_WITH_IFINDEX(NMPObjectType obj_type)
case NMP_OBJECT_TYPE_LNK_IP6GRE:
case NMP_OBJECT_TYPE_LNK_IP6GRETAP:
case NMP_OBJECT_TYPE_LNK_IPIP:
+ case NMP_OBJECT_TYPE_LNK_IPVLAN:
case NMP_OBJECT_TYPE_LNK_MACSEC:
case NMP_OBJECT_TYPE_LNK_MACVLAN:
case NMP_OBJECT_TYPE_LNK_MACVTAP:
diff --git a/src/libnmc-setting/nm-meta-setting-base-impl.c b/src/libnmc-setting/nm-meta-setting-base-impl.c
index 34a7d22e7..c8b77bf32 100644
--- a/src/libnmc-setting/nm-meta-setting-base-impl.c
+++ b/src/libnmc-setting/nm-meta-setting-base-impl.c
@@ -35,6 +35,7 @@
#include "nm-setting-ip-tunnel.h"
#include "nm-setting-ip4-config.h"
#include "nm-setting-ip6-config.h"
+#include "nm-setting-ipvlan.h"
#include "nm-setting-link.h"
#include "nm-setting-loopback.h"
#include "nm-setting-macsec.h"
@@ -371,6 +372,13 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = {
.setting_name = NM_SETTING_IP_TUNNEL_SETTING_NAME,
.get_setting_gtype = nm_setting_ip_tunnel_get_type,
},
+ [NM_META_SETTING_TYPE_IPVLAN] =
+ {
+ .meta_type = NM_META_SETTING_TYPE_IPVLAN,
+ .setting_priority = NM_SETTING_PRIORITY_HW_BASE,
+ .setting_name = NM_SETTING_IPVLAN_SETTING_NAME,
+ .get_setting_gtype = nm_setting_ipvlan_get_type,
+ },
[NM_META_SETTING_TYPE_LINK] =
{
.meta_type = NM_META_SETTING_TYPE_LINK,
@@ -643,6 +651,7 @@ const NMMetaSettingType nm_meta_setting_types_by_priority[] = {
NM_META_SETTING_TYPE_HSR,
NM_META_SETTING_TYPE_INFINIBAND,
NM_META_SETTING_TYPE_IP_TUNNEL,
+ NM_META_SETTING_TYPE_IPVLAN,
NM_META_SETTING_TYPE_LOOPBACK,
NM_META_SETTING_TYPE_MACSEC,
NM_META_SETTING_TYPE_MACVLAN,
diff --git a/src/libnmc-setting/nm-meta-setting-base-impl.h b/src/libnmc-setting/nm-meta-setting-base-impl.h
index 9226183fe..c03285ebf 100644
--- a/src/libnmc-setting/nm-meta-setting-base-impl.h
+++ b/src/libnmc-setting/nm-meta-setting-base-impl.h
@@ -128,6 +128,7 @@ typedef enum _nm_packed {
NM_META_SETTING_TYPE_IP_TUNNEL,
NM_META_SETTING_TYPE_IP4_CONFIG,
NM_META_SETTING_TYPE_IP6_CONFIG,
+ NM_META_SETTING_TYPE_IPVLAN,
NM_META_SETTING_TYPE_LINK,
NM_META_SETTING_TYPE_LOOPBACK,
NM_META_SETTING_TYPE_MACSEC,
diff --git a/src/libnmc-setting/nm-meta-setting-desc.c b/src/libnmc-setting/nm-meta-setting-desc.c
index b3a51ba00..01aa271db 100644
--- a/src/libnmc-setting/nm-meta-setting-desc.c
+++ b/src/libnmc-setting/nm-meta-setting-desc.c
@@ -6077,7 +6077,6 @@ static const NMMetaPropertyInfo *const property_infos_HSR[] = {
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[] = {
@@ -6799,6 +6798,37 @@ static const NMMetaPropertyInfo *const property_infos_IP_TUNNEL[] = {
NULL
};
+#undef _CURRENT_NM_META_SETTING_TYPE
+#define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_IPVLAN
+static const NMMetaPropertyInfo *const property_infos_IPVLAN[] = {
+ PROPERTY_INFO_WITH_DESC (NM_SETTING_IPVLAN_PARENT,
+ .is_cli_option = TRUE,
+ .property_alias = "dev",
+ .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD,
+ .prompt = N_("IPVLAN parent device or connection UUID"),
+ .property_type = &_pt_gobject_devices,
+ ),
+ PROPERTY_INFO_WITH_DESC (NM_SETTING_IPVLAN_MODE,
+ .is_cli_option = TRUE,
+ .property_alias = "mode",
+ .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD,
+ .prompt = NM_META_TEXT_PROMPT_IPVLAN_MODE,
+ .property_type = &_pt_gobject_enum,
+ .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_enum,
+ .get_gtype = nm_setting_ipvlan_mode_get_type,
+ .min = NM_SETTING_IPVLAN_MODE_UNKNOWN + 1,
+ .max = G_MAXINT,
+ ),
+ ),
+ PROPERTY_INFO_WITH_DESC (NM_SETTING_IPVLAN_PRIVATE,
+ .property_type = &_pt_gobject_bool,
+ ),
+ PROPERTY_INFO_WITH_DESC (NM_SETTING_IPVLAN_VEPA,
+ .property_type = &_pt_gobject_bool,
+ ),
+ NULL
+};
+
#undef _CURRENT_NM_META_SETTING_TYPE
#define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_LOOPBACK
static const NMMetaPropertyInfo *const property_infos_LOOPBACK[] = {
@@ -8713,6 +8743,7 @@ _setting_init_fcn_wireless (ARGS_SETTING_INIT_FCN)
#define SETTING_PRETTY_NAME_IP4_CONFIG N_("IPv4 protocol")
#define SETTING_PRETTY_NAME_IP6_CONFIG N_("IPv6 protocol")
#define SETTING_PRETTY_NAME_IP_TUNNEL N_("IP-tunnel settings")
+#define SETTING_PRETTY_NAME_IPVLAN N_("IPVLAN settings")
#define SETTING_PRETTY_NAME_LINK N_("Link settings")
#define SETTING_PRETTY_NAME_LOOPBACK N_("Loopback settings")
#define SETTING_PRETTY_NAME_MACSEC N_("MACsec connection")
@@ -8881,6 +8912,14 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
NM_META_SETTING_VALID_PART_ITEM (ETHTOOL, FALSE),
),
),
+ SETTING_INFO (IPVLAN,
+ .valid_parts = NM_META_SETTING_VALID_PARTS (
+ NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE),
+ NM_META_SETTING_VALID_PART_ITEM (IPVLAN, TRUE),
+ NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE),
+ NM_META_SETTING_VALID_PART_ITEM (ETHTOOL, FALSE),
+ ),
+ ),
SETTING_INFO (LINK),
SETTING_INFO (LOOPBACK,
.valid_parts = NM_META_SETTING_VALID_PARTS (
diff --git a/src/libnmc-setting/nm-meta-setting-desc.h b/src/libnmc-setting/nm-meta-setting-desc.h
index 21d913826..e867f628c 100644
--- a/src/libnmc-setting/nm-meta-setting-desc.h
+++ b/src/libnmc-setting/nm-meta-setting-desc.h
@@ -69,6 +69,8 @@ struct _NMDevice;
#define NM_META_TEXT_PROMPT_IP_TUNNEL_MODE N_("IP Tunnel mode")
+#define NM_META_TEXT_PROMPT_IPVLAN_MODE N_("IPVLAN mode")
+
#define NM_META_TEXT_PROMPT_MACVLAN_MODE N_("MACVLAN mode")
#define NM_META_TEXT_PROMPT_MACSEC_MODE N_("MACsec mode")
diff --git a/src/libnmc-setting/settings-docs.h.in b/src/libnmc-setting/settings-docs.h.in
index 02b5d5fb3..8198caa45 100644
--- a/src/libnmc-setting/settings-docs.h.in
+++ b/src/libnmc-setting/settings-docs.h.in
@@ -249,6 +249,10 @@
#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_REMOTE N_("The remote endpoint of the tunnel; the value must contain an IPv4 or IPv6 address.")
#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_TOS N_("The type of service (IPv4) or traffic class (IPv6) field to be set on tunneled packets.")
#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_TTL N_("The TTL to assign to tunneled packets. 0 is a special value meaning that packets inherit the TTL value.")
+#define DESCRIBE_DOC_NM_SETTING_IPVLAN_MODE N_("The IPVLAN mode. Valid values: l2 (1), l3 (2), l3s (3)")
+#define DESCRIBE_DOC_NM_SETTING_IPVLAN_PARENT N_("If given, specifies the parent interface name or parent connection UUID from which this IPVLAN interface should be created. If this property is not specified, the connection must contain an \"802-3-ethernet\" setting with a \"mac-address\" property.")
+#define DESCRIBE_DOC_NM_SETTING_IPVLAN_PRIVATE N_("Whether the interface should be put in private mode.")
+#define DESCRIBE_DOC_NM_SETTING_IPVLAN_VEPA N_("Whether the interface should be put in VEPA mode.")
#define DESCRIBE_DOC_NM_SETTING_MACSEC_ENCRYPT N_("Whether the transmitted traffic must be encrypted.")
#define DESCRIBE_DOC_NM_SETTING_MACSEC_MKA_CAK N_("The pre-shared CAK (Connectivity Association Key) for MACsec Key Agreement. Must be a string of 32 hexadecimal characters.")
#define DESCRIBE_DOC_NM_SETTING_MACSEC_MKA_CAK_FLAGS N_("Flags indicating how to handle the \"mka-cak\" property.")
diff --git a/src/nmcli/connections.c b/src/nmcli/connections.c
index 002dd4027..1d9b9e39d 100644
--- a/src/nmcli/connections.c
+++ b/src/nmcli/connections.c
@@ -1075,7 +1075,7 @@ const NmcMetaGenericInfo
"," 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_HSR_SETTING_NAME
+ "," NM_SETTING_HSR_SETTING_NAME "," NM_SETTING_IPVLAN_SETTING_NAME
/* NM_SETTING_DUMMY_SETTING_NAME NM_SETTING_WIMAX_SETTING_NAME */
const NmcMetaGenericInfo *const nmc_fields_con_active_details_groups[] = {
diff --git a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in
index ca90b4107..e6018a8ad 100644
--- a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in
+++ b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in
@@ -629,7 +629,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, 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" />
+ values="6lowpan, 802-11-olpc-mesh, 802-11-wireless, 802-3-ethernet, adsl, bluetooth, bond, bridge, cdma, dummy, generic, gsm, hsr, infiniband, ip-tunnel, ipvlan, 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" />
+
+
+
+
+
+