summary refs log tree commit diff
path: root/src/libnm-core-impl
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2024-02-22 17:21:11 +0100
committerMichael Biebl <biebl@debian.org>2024-02-22 17:21:11 +0100
commitbba2e4b4de668db525cbfdfc35292e5a0b51671a (patch)
tree38d20cddfcc6f71572b9e169deefab5fa96e8d0c /src/libnm-core-impl
parent6681f77b757bbc42ce5c8868ee9142b7ebc8c059 (diff)
New upstream version 1.46.0 upstream/1.46.0
Diffstat (limited to 'src/libnm-core-impl')
-rw-r--r--src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in22
-rw-r--r--src/libnm-core-impl/nm-connection.c7
-rw-r--r--src/libnm-core-impl/nm-setting-connection.c22
-rw-r--r--src/libnm-core-impl/nm-setting-generic.c128
-rw-r--r--src/libnm-core-impl/nm-setting-ip-config.c6
-rw-r--r--src/libnm-core-impl/nm-setting-ip6-config.c22
-rw-r--r--src/libnm-core-impl/nm-setting-macsec.c49
-rw-r--r--src/libnm-core-impl/nm-setting-private.h96
-rw-r--r--src/libnm-core-impl/nm-setting-sriov.c133
-rw-r--r--src/libnm-core-impl/nm-setting-wireguard.c3
-rw-r--r--src/libnm-core-impl/nm-setting.c153
-rw-r--r--src/libnm-core-impl/tests/test-setting.c37
12 files changed, 603 insertions, 75 deletions
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 84220043..146f9282 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
@@ -769,7 +769,7 @@
                   />
         <property name="autoconnect-ports"
                   dbus-type="i"
-                  gprop-type="NMTernary"
+                  gprop-type="gint"
                   />
         <property name="autoconnect-priority"
                   dbus-type="i"
@@ -1331,6 +1331,10 @@
     <setting name="generic"
              gtype="NMSettingGeneric"
              >
+        <property name="device-handler"
+                  dbus-type="s"
+                  gprop-type="gchararray"
+                  />
     </setting>
     <setting name="gsm"
              gtype="NMSettingGsm"
@@ -1876,6 +1880,10 @@
                   dbus-type="i"
                   gprop-type="gint"
                   />
+        <property name="offload"
+                  dbus-type="i"
+                  gprop-type="gint"
+                  />
         <property name="parent"
                   dbus-type="s"
                   gprop-type="gchararray"
@@ -2198,6 +2206,18 @@
                   dbus-type="i"
                   gprop-type="NMTernary"
                   />
+        <property name="eswitch-encap-mode"
+                  dbus-type="i"
+                  gprop-type="gint"
+                  />
+        <property name="eswitch-inline-mode"
+                  dbus-type="i"
+                  gprop-type="gint"
+                  />
+        <property name="eswitch-mode"
+                  dbus-type="i"
+                  gprop-type="gint"
+                  />
         <property name="total-vfs"
                   dbus-type="u"
                   gprop-type="guint"
diff --git a/src/libnm-core-impl/nm-connection.c b/src/libnm-core-impl/nm-connection.c
index a23dc113..33360d04 100644
--- a/src/libnm-core-impl/nm-connection.c
+++ b/src/libnm-core-impl/nm-connection.c
@@ -3207,6 +3207,13 @@ nm_connection_is_virtual(NMConnection *connection)
         return !!nm_setting_pppoe_get_parent(s_pppoe);
     }
 
+    if (nm_streq(type, NM_SETTING_GENERIC_SETTING_NAME)) {
+        NMSettingGeneric *s_generic;
+
+        s_generic = nm_connection_get_setting_generic(connection);
+        return !!nm_setting_generic_get_device_handler(s_generic);
+    }
+
     return FALSE;
 }
 
diff --git a/src/libnm-core-impl/nm-setting-connection.c b/src/libnm-core-impl/nm-setting-connection.c
index 616a3e5e..7c58c84f 100644
--- a/src/libnm-core-impl/nm-setting-connection.c
+++ b/src/libnm-core-impl/nm-setting-connection.c
@@ -2655,7 +2655,7 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass)
      *   when this connection is activated.
      * ---end---
      */
-    prop_idx = _nm_setting_property_define_direct_enum(
+    prop_idx = _nm_setting_property_define_direct_real_enum(
         properties_override,
         obj_properties,
         NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES,
@@ -2776,16 +2776,16 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass)
      * example: CONNECTION_METERED=yes
      * ---end---
      */
-    _nm_setting_property_define_direct_enum(properties_override,
-                                            obj_properties,
-                                            NM_SETTING_CONNECTION_METERED,
-                                            PROP_METERED,
-                                            NM_TYPE_METERED,
-                                            NM_METERED_UNKNOWN,
-                                            NM_SETTING_PARAM_REAPPLY_IMMEDIATELY,
-                                            NULL,
-                                            NMSettingConnectionPrivate,
-                                            metered);
+    _nm_setting_property_define_direct_real_enum(properties_override,
+                                                 obj_properties,
+                                                 NM_SETTING_CONNECTION_METERED,
+                                                 PROP_METERED,
+                                                 NM_TYPE_METERED,
+                                                 NM_METERED_UNKNOWN,
+                                                 NM_SETTING_PARAM_REAPPLY_IMMEDIATELY,
+                                                 NULL,
+                                                 NMSettingConnectionPrivate,
+                                                 metered);
 
     /**
      * NMSettingConnection:lldp:
diff --git a/src/libnm-core-impl/nm-setting-generic.c b/src/libnm-core-impl/nm-setting-generic.c
index 6623e71f..8a38118a 100644
--- a/src/libnm-core-impl/nm-setting-generic.c
+++ b/src/libnm-core-impl/nm-setting-generic.c
@@ -23,13 +23,20 @@
 
 /*****************************************************************************/
 
+NM_GOBJECT_PROPERTIES_DEFINE(NMSettingGeneric, PROP_DEVICE_HANDLER, );
+
+typedef struct {
+    char *device_handler;
+} NMSettingGenericPrivate;
+
 /**
  * NMSettingGeneric:
  *
  * Generic Link Settings
  */
 struct _NMSettingGeneric {
-    NMSetting parent;
+    NMSetting               parent;
+    NMSettingGenericPrivate _priv;
 };
 
 struct _NMSettingGenericClass {
@@ -38,6 +45,82 @@ struct _NMSettingGenericClass {
 
 G_DEFINE_TYPE(NMSettingGeneric, nm_setting_generic, NM_TYPE_SETTING)
 
+#define NM_SETTING_GENERIC_GET_PRIVATE(self) \
+    _NM_GET_PRIVATE(self, NMSettingGeneric, NM_IS_SETTING_GENERIC, NMSetting)
+
+/*****************************************************************************/
+
+/**
+ * nm_setting_generic_get_device_handler:
+ * @setting: the #NMSettingGeneric
+ *
+ * Returns the #NMSettingGeneric:device-handler property of the connection.
+ *
+ * Returns: the device handler name, or %NULL if no device handler is set
+ *
+ * Since: 1.46
+ **/
+const char *
+nm_setting_generic_get_device_handler(NMSettingGeneric *setting)
+{
+    g_return_val_if_fail(NM_IS_SETTING_GENERIC(setting), NULL);
+
+    return NM_SETTING_GENERIC_GET_PRIVATE(setting)->device_handler;
+}
+
+static gboolean
+verify(NMSetting *setting, NMConnection *connection, GError **error)
+{
+    NMSettingGenericPrivate *priv = NM_SETTING_GENERIC_GET_PRIVATE(setting);
+
+    if (priv->device_handler) {
+        if (NM_IN_SET(priv->device_handler[0], '\0', '.')
+            || !NM_STRCHAR_ALL(priv->device_handler,
+                               ch,
+                               g_ascii_isalnum(ch) || NM_IN_SET(ch, '-', '_', '.'))) {
+            g_set_error_literal(error,
+                                NM_CONNECTION_ERROR,
+                                NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                                _("property is invalid"));
+            g_prefix_error(error,
+                           "%s.%s: ",
+                           NM_SETTING_GENERIC_SETTING_NAME,
+                           NM_SETTING_GENERIC_DEVICE_HANDLER);
+            return FALSE;
+        }
+
+        if (connection) {
+            NMSettingConnection *s_con;
+
+            s_con = nm_connection_get_setting_connection(connection);
+            if (!s_con) {
+                g_set_error(error,
+                            NM_CONNECTION_ERROR,
+                            NM_CONNECTION_ERROR_MISSING_SETTING,
+                            _("missing setting"));
+                g_prefix_error(error, "%s: ", NM_SETTING_CONNECTION_SETTING_NAME);
+                return FALSE;
+            }
+
+            if (!nm_setting_connection_get_interface_name(s_con)) {
+                g_set_error(error,
+                            NM_CONNECTION_ERROR,
+                            NM_CONNECTION_ERROR_MISSING_PROPERTY,
+                            _("the property is required when %s.%s is set"),
+                            NM_SETTING_GENERIC_SETTING_NAME,
+                            NM_SETTING_GENERIC_DEVICE_HANDLER);
+                g_prefix_error(error,
+                               "%s.%s: ",
+                               NM_SETTING_CONNECTION_SETTING_NAME,
+                               NM_SETTING_CONNECTION_INTERFACE_NAME);
+                return FALSE;
+            }
+        }
+    }
+
+    return TRUE;
+}
+
 /*****************************************************************************/
 
 static void
@@ -60,7 +143,46 @@ nm_setting_generic_new(void)
 static void
 nm_setting_generic_class_init(NMSettingGenericClass *klass)
 {
-    NMSettingClass *setting_class = NM_SETTING_CLASS(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;
+
+    /**
+     * NMSettingGeneric:device-handler:
+     *
+     * Name of the device handler that will be invoked to add and delete
+     * the device for this connection. The name can only contain ASCII
+     * alphanumeric characters and '-', '_', '.'. It cannot start with '.'.
+     *
+     * See the NetworkManager-dispatcher(8) man page for more details
+     * about how to write the device handler.
+     *
+     * By setting this property the generic connection becomes "virtual",
+     * meaning that it can be activated without an existing device; the device
+     * will be created at the time the connection is started by invoking the
+     * device-handler.
+     *
+     * Since: 1.46
+     **/
+    _nm_setting_property_define_direct_string(properties_override,
+                                              obj_properties,
+                                              NM_SETTING_GENERIC_DEVICE_HANDLER,
+                                              PROP_DEVICE_HANDLER,
+                                              NM_SETTING_PARAM_FUZZY_IGNORE
+                                                  | NM_SETTING_PARAM_INFERRABLE,
+                                              NMSettingGeneric,
+                                              _priv.device_handler);
+
+    g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
-    _nm_setting_class_commit(setting_class, NM_META_SETTING_TYPE_GENERIC, NULL, NULL, 0);
+    _nm_setting_class_commit(setting_class,
+                             NM_META_SETTING_TYPE_GENERIC,
+                             NULL,
+                             properties_override,
+                             0);
 }
diff --git a/src/libnm-core-impl/nm-setting-ip-config.c b/src/libnm-core-impl/nm-setting-ip-config.c
index 8165cb2f..02334b54 100644
--- a/src/libnm-core-impl/nm-setting-ip-config.c
+++ b/src/libnm-core-impl/nm-setting-ip-config.c
@@ -6139,14 +6139,16 @@ _nm_sett_info_property_override_create_array_ip_config(int addr_family)
         obj_properties[PROP_AUTO_ROUTE_EXT_GW],
         &nm_sett_info_propert_type_direct_enum,
         .direct_offset =
-            NM_STRUCT_OFFSET_ENSURE_TYPE(int, NMSettingIPConfigPrivate, auto_route_ext_gw));
+            NM_STRUCT_OFFSET_ENSURE_TYPE(int, NMSettingIPConfigPrivate, auto_route_ext_gw),
+        .direct_data.enum_gtype = NM_TYPE_TERNARY);
 
     _nm_properties_override_gobj(
         properties_override,
         obj_properties[PROP_REPLACE_LOCAL_RULE],
         &nm_sett_info_propert_type_direct_enum,
         .direct_offset =
-            NM_STRUCT_OFFSET_ENSURE_TYPE(int, NMSettingIPConfigPrivate, replace_local_rule));
+            NM_STRUCT_OFFSET_ENSURE_TYPE(int, NMSettingIPConfigPrivate, replace_local_rule),
+        .direct_data.enum_gtype = NM_TYPE_TERNARY);
 
     _nm_properties_override_gobj(
         properties_override,
diff --git a/src/libnm-core-impl/nm-setting-ip6-config.c b/src/libnm-core-impl/nm-setting-ip6-config.c
index fc0744ad..42bb2571 100644
--- a/src/libnm-core-impl/nm-setting-ip6-config.c
+++ b/src/libnm-core-impl/nm-setting-ip6-config.c
@@ -941,16 +941,16 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass)
      * example: IPV6_PRIVACY=rfc3041 IPV6_PRIVACY_PREFER_PUBLIC_IP=yes
      * ---end---
      */
-    _nm_setting_property_define_direct_enum(properties_override,
-                                            obj_properties,
-                                            NM_SETTING_IP6_CONFIG_IP6_PRIVACY,
-                                            PROP_IP6_PRIVACY,
-                                            NM_TYPE_SETTING_IP6_CONFIG_PRIVACY,
-                                            NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN,
-                                            NM_SETTING_PARAM_NONE,
-                                            NULL,
-                                            NMSettingIP6ConfigPrivate,
-                                            ip6_privacy);
+    _nm_setting_property_define_direct_real_enum(properties_override,
+                                                 obj_properties,
+                                                 NM_SETTING_IP6_CONFIG_IP6_PRIVACY,
+                                                 PROP_IP6_PRIVACY,
+                                                 NM_TYPE_SETTING_IP6_CONFIG_PRIVACY,
+                                                 NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN,
+                                                 NM_SETTING_PARAM_NONE,
+                                                 NULL,
+                                                 NMSettingIP6ConfigPrivate,
+                                                 ip6_privacy);
 
     /**
      * NMSettingIP6Config:addr-gen-mode:
@@ -1215,7 +1215,7 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass)
                                               NM_SETTING_PARAM_NONE,
                                               NMSettingIP6ConfigPrivate,
                                               dhcp_pd_hint,
-                                              .direct_set_fcn.set_string =
+                                              .direct_data.set_string =
                                                   _set_string_fcn_dhcp_pd_hint,
                                               .direct_string_allow_empty = TRUE);
 
diff --git a/src/libnm-core-impl/nm-setting-macsec.c b/src/libnm-core-impl/nm-setting-macsec.c
index f66fc52a..763d306b 100644
--- a/src/libnm-core-impl/nm-setting-macsec.c
+++ b/src/libnm-core-impl/nm-setting-macsec.c
@@ -35,7 +35,8 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_PARENT,
                                   PROP_MKA_CKN,
                                   PROP_PORT,
                                   PROP_VALIDATION,
-                                  PROP_SEND_SCI, );
+                                  PROP_SEND_SCI,
+                                  PROP_OFFLOAD, );
 
 typedef struct {
     char  *parent;
@@ -47,6 +48,7 @@ typedef struct {
     gint32 port;
     bool   encrypt;
     bool   send_sci;
+    gint32 offload;
 } NMSettingMacsecPrivate;
 
 /**
@@ -212,6 +214,22 @@ nm_setting_macsec_get_send_sci(NMSettingMacsec *setting)
     return NM_SETTING_MACSEC_GET_PRIVATE(setting)->send_sci;
 }
 
+/**
+ * nm_setting_macsec_get_offload:
+ * @setting: the #NMSettingMacsec
+ *
+ * Returns: the #NMSettingMacsec:offload property of the setting
+ *
+ * Since: 1.46
+ **/
+NMSettingMacsecOffload
+nm_setting_macsec_get_offload(NMSettingMacsec *setting)
+{
+    g_return_val_if_fail(NM_IS_SETTING_MACSEC(setting), NM_SETTING_MACSEC_OFFLOAD_DEFAULT);
+
+    return NM_SETTING_MACSEC_GET_PRIVATE(setting)->offload;
+}
+
 static GPtrArray *
 need_secrets(NMSetting *setting, gboolean check_rerequest)
 {
@@ -597,6 +615,35 @@ nm_setting_macsec_class_init(NMSettingMacsecClass *klass)
                                                NMSettingMacsecPrivate,
                                                send_sci);
 
+    /**
+     * NMSettingMacsec:offload:
+     *
+     * Specifies the MACsec offload mode.
+     *
+     * %NM_SETTING_MACSEC_OFFLOAD_OFF disables MACsec offload.
+     *
+     * %NM_SETTING_MACSEC_OFFLOAD_PHY and %NM_SETTING_MACSEC_OFFLOAD_MAC request offload
+     * respectively to the PHY or to the MAC; if the selected mode is not available, the
+     * connection will fail.
+     *
+     * %NM_SETTING_MACSEC_OFFLOAD_DEFAULT uses the global default value specified in
+     * NetworkManager configuration; if no global default is defined, the built-in
+     * default is %NM_SETTING_MACSEC_OFFLOAD_OFF.
+     *
+     * Since: 1.46
+     **/
+    _nm_setting_property_define_direct_enum(properties_override,
+                                            obj_properties,
+                                            NM_SETTING_MACSEC_OFFLOAD,
+                                            PROP_OFFLOAD,
+                                            NM_TYPE_SETTING_MACSEC_OFFLOAD,
+                                            NM_SETTING_MACSEC_OFFLOAD_DEFAULT,
+                                            NM_SETTING_PARAM_INFERRABLE
+                                                | NM_SETTING_PARAM_FUZZY_IGNORE,
+                                            NULL,
+                                            NMSettingMacsecPrivate,
+                                            offload);
+
     g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
     _nm_setting_class_commit(setting_class,
diff --git a/src/libnm-core-impl/nm-setting-private.h b/src/libnm-core-impl/nm-setting-private.h
index 6bad516e..1276c903 100644
--- a/src/libnm-core-impl/nm-setting-private.h
+++ b/src/libnm-core-impl/nm-setting-private.h
@@ -904,6 +904,13 @@ _nm_properties_override(GArray *properties_override, const NMSettInfoProperty *p
 
 /*****************************************************************************/
 
+/* Define a direct property of type enum, but using `int` as type in the underlying
+ * GObject property. This is the preferred way to define enum properties because using
+ * real enums it is not possible to maintain backwards compatibility with clients
+ * using an old libnm (glib asserts against new values of the enum not being valid).
+ * The main difference from define_direct_real_enum is that this will accept any
+ * integer value, and we'll check that it's valid in #NMSetting::verify, as doing
+ * 'verify' is optional for clients. */
 #define _nm_setting_property_define_direct_enum(properties_override,                             \
                                                 obj_properties,                                  \
                                                 prop_name,                                       \
@@ -924,6 +931,58 @@ _nm_properties_override(GArray *properties_override, const NMSettInfoProperty *p
                           ~(NM_SETTING_PARAM_REAPPLY_IMMEDIATELY | NM_SETTING_PARAM_FUZZY_IGNORE \
                             | NM_SETTING_PARAM_INFERRABLE)));                                    \
                                                                                                  \
+        nm_assert(G_TYPE_IS_ENUM(gtype_enum));                                                   \
+                                                                                                 \
+        _param_spec = g_param_spec_int("" prop_name "",                                          \
+                                       "",                                                       \
+                                       "",                                                       \
+                                       G_MININT32,                                               \
+                                       G_MAXINT32,                                               \
+                                       (default_value),                                          \
+                                       G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY               \
+                                           | G_PARAM_STATIC_STRINGS | (param_flags));            \
+                                                                                                 \
+        (obj_properties)[(prop_id)] = _param_spec;                                               \
+        _property_type              = (property_type) ?: &nm_sett_info_propert_type_direct_enum; \
+                                                                                                 \
+        _nm_properties_override_gobj(                                                            \
+            (properties_override),                                                               \
+            _param_spec,                                                                         \
+            _property_type,                                                                      \
+            .direct_offset =                                                                     \
+                NM_STRUCT_OFFSET_ENSURE_TYPE(int, private_struct_type, private_struct_field),    \
+            .direct_data.enum_gtype = (gtype_enum),                                              \
+            __VA_ARGS__);                                                                        \
+    })
+
+/*****************************************************************************/
+
+/* Define an enum property using real enums in the GObject, not integers. Note that
+ * this is not backwards compatible because clients with old libnm will reject
+ * newer values of the enum. Generally you want to use define_direct_enum and use this
+ * one only for properties that already existed as real enums */
+#define _nm_setting_property_define_direct_real_enum(properties_override,                        \
+                                                     obj_properties,                             \
+                                                     prop_name,                                  \
+                                                     prop_id,                                    \
+                                                     gtype_enum,                                 \
+                                                     default_value,                              \
+                                                     param_flags,                                \
+                                                     property_type,                              \
+                                                     private_struct_type,                        \
+                                                     private_struct_field,                       \
+                                                     ... /* extra NMSettInfoProperty fields */)  \
+    ({                                                                                           \
+        GParamSpec                  *_param_spec;                                                \
+        const NMSettInfoPropertType *_property_type;                                             \
+                                                                                                 \
+        G_STATIC_ASSERT(                                                                         \
+            !NM_FLAGS_ANY((param_flags),                                                         \
+                          ~(NM_SETTING_PARAM_REAPPLY_IMMEDIATELY | NM_SETTING_PARAM_FUZZY_IGNORE \
+                            | NM_SETTING_PARAM_INFERRABLE)));                                    \
+                                                                                                 \
+        nm_assert(G_TYPE_IS_ENUM(gtype_enum));                                                   \
+                                                                                                 \
         _param_spec = g_param_spec_enum("" prop_name "",                                         \
                                         "",                                                      \
                                         "",                                                      \
@@ -941,11 +1000,26 @@ _nm_properties_override(GArray *properties_override, const NMSettInfoProperty *p
             _property_type,                                                                      \
             .direct_offset =                                                                     \
                 NM_STRUCT_OFFSET_ENSURE_TYPE(int, private_struct_type, private_struct_field),    \
+            .direct_data.enum_gtype = (gtype_enum),                                              \
             __VA_ARGS__);                                                                        \
     })
 
 /*****************************************************************************/
 
+#define _nm_setting_property_is_valid_direct_enum(property_info)                               \
+    ({                                                                                         \
+        const NMSettInfoProperty *_property_info = (property_info);                            \
+        NMValueType               direct_nmtype  = _property_info->property_type->direct_type; \
+        GType                     direct_gtype   = _property_info->direct_data.enum_gtype;     \
+        GParamSpec               *spec           = _property_info->param_spec;                 \
+        GType                     spec_gtype     = spec ? spec->value_type : G_TYPE_INVALID;   \
+                                                                                               \
+        direct_nmtype == NM_VALUE_TYPE_ENUM &&direct_gtype &&G_TYPE_IS_ENUM(direct_gtype)      \
+            && NM_IN_SET(spec_gtype, G_TYPE_INT, direct_gtype);                                \
+    })
+
+/*****************************************************************************/
+
 #define _nm_setting_property_define_direct_ternary_enum(properties_override,  \
                                                         obj_properties,       \
                                                         prop_name,            \
@@ -954,17 +1028,17 @@ _nm_properties_override(GArray *properties_override, const NMSettInfoProperty *p
                                                         private_struct_type,  \
                                                         private_struct_field, \
                                                         ...)                  \
-    _nm_setting_property_define_direct_enum((properties_override),            \
-                                            (obj_properties),                 \
-                                            prop_name,                        \
-                                            (prop_id),                        \
-                                            NM_TYPE_TERNARY,                  \
-                                            NM_TERNARY_DEFAULT,               \
-                                            (param_flags),                    \
-                                            NULL,                             \
-                                            private_struct_type,              \
-                                            private_struct_field,             \
-                                            __VA_ARGS__)
+    _nm_setting_property_define_direct_real_enum((properties_override),       \
+                                                 (obj_properties),            \
+                                                 prop_name,                   \
+                                                 (prop_id),                   \
+                                                 NM_TYPE_TERNARY,             \
+                                                 NM_TERNARY_DEFAULT,          \
+                                                 (param_flags),               \
+                                                 NULL,                        \
+                                                 private_struct_type,         \
+                                                 private_struct_field,        \
+                                                 __VA_ARGS__)
 
 /*****************************************************************************/
 
diff --git a/src/libnm-core-impl/nm-setting-sriov.c b/src/libnm-core-impl/nm-setting-sriov.c
index b9faad56..145c2b14 100644
--- a/src/libnm-core-impl/nm-setting-sriov.c
+++ b/src/libnm-core-impl/nm-setting-sriov.c
@@ -9,6 +9,7 @@
 
 #include "nm-setting-private.h"
 #include "nm-utils-private.h"
+#include "nm-core-enum-types.h"
 
 /**
  * SECTION:nm-setting-sriov
@@ -18,7 +19,13 @@
 
 /*****************************************************************************/
 
-NM_GOBJECT_PROPERTIES_DEFINE(NMSettingSriov, PROP_TOTAL_VFS, PROP_VFS, PROP_AUTOPROBE_DRIVERS, );
+NM_GOBJECT_PROPERTIES_DEFINE(NMSettingSriov,
+                             PROP_TOTAL_VFS,
+                             PROP_VFS,
+                             PROP_AUTOPROBE_DRIVERS,
+                             PROP_ESWITCH_MODE,
+                             PROP_ESWITCH_INLINE_MODE,
+                             PROP_ESWITCH_ENCAP_MODE, );
 
 /**
  * NMSettingSriov:
@@ -32,6 +39,9 @@ struct _NMSettingSriov {
     GPtrArray *vfs;
     int        autoprobe_drivers;
     guint32    total_vfs;
+    int        eswitch_mode;
+    int        eswitch_inline_mode;
+    int        eswitch_encap_mode;
 };
 
 struct _NMSettingSriovClass {
@@ -835,6 +845,54 @@ nm_setting_sriov_get_autoprobe_drivers(NMSettingSriov *setting)
     return setting->autoprobe_drivers;
 }
 
+/**
+ * nm_setting_sriov_get_eswitch_mode:
+ * @setting: the #NMSettingSriov
+ *
+ * Returns: the value contained in the #NMSettingSriov:eswitch-mode property.
+ *
+ * Since: 1.46
+ */
+NMSriovEswitchMode
+nm_setting_sriov_get_eswitch_mode(NMSettingSriov *setting)
+{
+    g_return_val_if_fail(NM_IS_SETTING_SRIOV(setting), NM_SRIOV_ESWITCH_MODE_PRESERVE);
+
+    return setting->eswitch_mode;
+}
+
+/**
+ * nm_setting_sriov_get_eswitch_inline_mode:
+ * @setting: the #NMSettingSriov
+ *
+ * Returns: the value contained in the #NMSettingSriov:eswitch-inline-mode property.
+ *
+ * Since: 1.46
+ */
+NMSriovEswitchInlineMode
+nm_setting_sriov_get_eswitch_inline_mode(NMSettingSriov *setting)
+{
+    g_return_val_if_fail(NM_IS_SETTING_SRIOV(setting), NM_SRIOV_ESWITCH_INLINE_MODE_PRESERVE);
+
+    return setting->eswitch_inline_mode;
+}
+
+/**
+ * nm_setting_sriov_get_eswitch_encap_mode:
+ * @setting: the #NMSettingSriov
+ *
+ * Returns: the value contained in the #NMSettingSriov:eswitch-encap-mode property.
+ *
+ * Since: 1.46
+ */
+NMSriovEswitchEncapMode
+nm_setting_sriov_get_eswitch_encap_mode(NMSettingSriov *setting)
+{
+    g_return_val_if_fail(NM_IS_SETTING_SRIOV(setting), NM_SRIOV_ESWITCH_ENCAP_MODE_PRESERVE);
+
+    return setting->eswitch_encap_mode;
+}
+
 static int
 vf_index_compare(gconstpointer a, gconstpointer b)
 {
@@ -1331,6 +1389,79 @@ nm_setting_sriov_class_init(NMSettingSriovClass *klass)
                                                     NMSettingSriov,
                                                     autoprobe_drivers);
 
+    /**
+     * NMSettingSriov:eswitch-mode
+     *
+     * Select the eswitch mode of the device. Currently it's only supported for
+     * PCI PF devices, and only if the eswitch device is managed from the same
+     * PCI address than the PF.
+     *
+     * If set to %NM_SRIOV_ESWITCH_MODE_PRESERVE (default) the eswitch mode won't be
+     * modified by NetworkManager.
+     *
+     * Since: 1.46
+     */
+    _nm_setting_property_define_direct_enum(properties_override,
+                                            obj_properties,
+                                            NM_SETTING_SRIOV_ESWITCH_MODE,
+                                            PROP_ESWITCH_MODE,
+                                            NM_TYPE_SRIOV_ESWITCH_MODE,
+                                            NM_SRIOV_ESWITCH_MODE_PRESERVE,
+                                            NM_SETTING_PARAM_FUZZY_IGNORE,
+                                            NULL,
+                                            NMSettingSriov,
+                                            eswitch_mode);
+
+    /**
+     * NMSettingSriov:eswitch-inline-mode
+     *
+     * Select the eswitch inline-mode of the device. Some HWs need the VF driver to put
+     * part of the packet headers on the TX descriptor so the e-switch can do proper
+     * matching and steering.
+     *
+     * Currently it's only supported for PCI PF devices, and only if the eswitch device
+     * is managed from the same PCI address than the PF.
+     *
+     * If set to %NM_SRIOV_ESWITCH_INLINE_MODE_PRESERVE (default) the eswitch inline-mode
+     * won't be modified by NetworkManager.
+     *
+     * Since: 1.46
+     */
+    _nm_setting_property_define_direct_enum(properties_override,
+                                            obj_properties,
+                                            NM_SETTING_SRIOV_ESWITCH_INLINE_MODE,
+                                            PROP_ESWITCH_INLINE_MODE,
+                                            NM_TYPE_SRIOV_ESWITCH_INLINE_MODE,
+                                            NM_SRIOV_ESWITCH_INLINE_MODE_PRESERVE,
+                                            NM_SETTING_PARAM_FUZZY_IGNORE,
+                                            NULL,
+                                            NMSettingSriov,
+                                            eswitch_inline_mode);
+
+    /**
+     * NMSettingSriov:eswitch-encap-mode
+     *
+     * Select the eswitch encapsulation support.
+     *
+     * Currently it's only supported for PCI PF devices, and only if the eswitch device
+     * is managed from the same PCI address than the PF.
+     *
+     * If set to %NM_SRIOV_ESWITCH_ENCAP_MODE_PRESERVE (default) the eswitch encap-mode
+     * won't be modified by NetworkManager.
+     *
+     * Since: 1.46
+     */
+    _nm_setting_property_define_direct_enum(properties_override,
+                                            obj_properties,
+                                            NM_SETTING_SRIOV_ESWITCH_ENCAP_MODE,
+                                            PROP_ESWITCH_ENCAP_MODE,
+                                            NM_TYPE_SRIOV_ESWITCH_ENCAP_MODE,
+                                            NM_SRIOV_ESWITCH_ENCAP_MODE_PRESERVE,
+                                            NM_SETTING_PARAM_FUZZY_IGNORE,
+                                            NULL,
+                                            NMSettingSriov,
+                                            eswitch_encap_mode);
+
     g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
     _nm_setting_class_commit(setting_class,
diff --git a/src/libnm-core-impl/nm-setting-wireguard.c b/src/libnm-core-impl/nm-setting-wireguard.c
index c313d22c..4f96f742 100644
--- a/src/libnm-core-impl/nm-setting-wireguard.c
+++ b/src/libnm-core-impl/nm-setting-wireguard.c
@@ -2361,8 +2361,7 @@ nm_setting_wireguard_class_init(NMSettingWireGuardClass *klass)
                                               NM_SETTING_PARAM_SECRET,
                                               NMSettingWireGuard,
                                               _priv.private_key,
-                                              .direct_set_fcn.set_string =
-                                                  _set_string_fcn_public_key,
+                                              .direct_data.set_string = _set_string_fcn_public_key,
                                               .direct_string_allow_empty = TRUE);
 
     /**
diff --git a/src/libnm-core-impl/nm-setting.c b/src/libnm-core-impl/nm-setting.c
index e6e4d23b..8bc7b4bf 100644
--- a/src/libnm-core-impl/nm-setting.c
+++ b/src/libnm-core-impl/nm-setting.c
@@ -682,10 +682,10 @@ _property_direct_set_string(const NMSettInfoSetting  *sett_info,
                + (!!property_info->direct_string_is_refstr)
                + (property_info->direct_set_string_mac_address_len > 0)
                + (property_info->direct_set_string_ip_address_addr_family != 0))
-              <= (property_info->direct_set_fcn.set_string ? 0 : 1));
+              <= (property_info->direct_data.set_string ? 0 : 1));
 
-    if (property_info->direct_set_fcn.set_string) {
-        return property_info->direct_set_fcn.set_string(sett_info, property_info, setting, src);
+    if (property_info->direct_data.set_string) {
+        return property_info->direct_data.set_string(sett_info, property_info, setting, src);
     }
 
     dst = _nm_setting_get_private_field(setting, sett_info, property_info);
@@ -805,7 +805,13 @@ _nm_setting_property_get_property_direct(GObject    *object,
     {
         const int *p_val = _nm_setting_get_private_field(setting, sett_info, property_info);
 
-        g_value_set_enum(value, *p_val);
+        nm_assert(_nm_setting_property_is_valid_direct_enum(property_info));
+
+        if (G_TYPE_IS_ENUM(pspec->value_type))
+            g_value_set_enum(value, *p_val);
+        else
+            g_value_set_int(value, *p_val);
+
         return;
     }
     case NM_VALUE_TYPE_FLAGS:
@@ -940,7 +946,13 @@ _nm_setting_property_set_property_direct(GObject      *object,
         int *p_val = _nm_setting_get_private_field(setting, sett_info, property_info);
         int  v;
 
-        v = g_value_get_enum(value);
+        nm_assert(_nm_setting_property_is_valid_direct_enum(property_info));
+
+        if (G_TYPE_IS_ENUM(pspec->value_type))
+            v = g_value_get_enum(value);
+        else
+            v = g_value_get_int(value);
+
         if (*p_val == v)
             return;
         *p_val = v;
@@ -1076,7 +1088,13 @@ _init_direct(NMSetting *setting)
             int *p_val = _nm_setting_get_private_field(setting, sett_info, property_info);
             int  def_val;
 
-            def_val = NM_G_PARAM_SPEC_GET_DEFAULT_ENUM(property_info->param_spec);
+            nm_assert(_nm_setting_property_is_valid_direct_enum(property_info));
+
+            if (G_TYPE_IS_ENUM(property_info->param_spec->value_type))
+                def_val = NM_G_PARAM_SPEC_GET_DEFAULT_ENUM(property_info->param_spec);
+            else
+                def_val = NM_G_PARAM_SPEC_GET_DEFAULT_INT(property_info->param_spec);
+
             nm_assert(NM_IN_SET(*p_val, 0, property_info->direct_is_aliased_field ? def_val : 0));
             *p_val = def_val;
             break;
@@ -1234,10 +1252,22 @@ _nm_setting_property_to_dbus_fcn_direct(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_
     {
         int val;
 
+        nm_assert(_nm_setting_property_is_valid_direct_enum(property_info));
+
         val = *((int *) _nm_setting_get_private_field(setting, sett_info, property_info));
-        if (!property_info->to_dbus_including_default
-            && val == NM_G_PARAM_SPEC_GET_DEFAULT_ENUM(property_info->param_spec))
-            return NULL;
+
+        if (!property_info->to_dbus_including_default) {
+            int default_value;
+
+            if (G_TYPE_IS_ENUM(property_info->param_spec->value_type))
+                default_value = NM_G_PARAM_SPEC_GET_DEFAULT_ENUM(property_info->param_spec);
+            else
+                default_value = NM_G_PARAM_SPEC_GET_DEFAULT_INT(property_info->param_spec);
+
+            if (val == default_value)
+                return NULL;
+        }
+
         return nm_g_variant_maybe_singleton_i(val);
     }
     case NM_VALUE_TYPE_FLAGS:
@@ -1413,7 +1443,10 @@ _nm_setting_property_from_dbus_fcn_direct(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS
         GVariant                       *_value         = (value);                      \
         gboolean                        _success       = FALSE;                        \
                                                                                        \
-        nm_assert(_property_info->param_spec->value_type == _gtype);                   \
+        nm_assert(_property_info->param_spec->value_type == _gtype                     \
+                  || (_property_info->property_type->direct_type == NM_VALUE_TYPE_ENUM \
+                      && _property_info->direct_data.enum_gtype == _gtype));           \
+                                                                                       \
         if (_property_info->property_type->from_dbus_direct_allow_transform) {         \
             nm_auto_unset_gvalue GValue _gvalue = G_VALUE_INIT;                        \
                                                                                        \
@@ -1564,21 +1597,20 @@ _nm_setting_property_from_dbus_fcn_direct(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS
     }
     case NM_VALUE_TYPE_ENUM:
     {
-        const GParamSpecEnum *param_spec;
-        int                  *p_val;
-        int                   v;
+        int *p_val;
+        int  v;
 
-        param_spec = NM_G_PARAM_SPEC_CAST_ENUM(property_info->param_spec);
+        nm_assert(_nm_setting_property_is_valid_direct_enum(property_info));
 
         if (g_variant_is_of_type(value, G_VARIANT_TYPE_INT32)) {
             G_STATIC_ASSERT(sizeof(int) >= sizeof(gint32));
             v = g_variant_get_int32(value);
         } else {
-            if (!_variant_get_value_transform(property_info,
-                                              value,
-                                              G_TYPE_FROM_CLASS(param_spec->enum_class),
-                                              g_value_get_flags,
-                                              &v))
+            GType gtype = G_TYPE_IS_ENUM(property_info->param_spec->value_type)
+                              ? property_info->param_spec->value_type
+                              : G_TYPE_INT;
+
+            if (!_variant_get_value_transform(property_info, value, gtype, g_value_get_flags, &v))
                 goto out_error_wrong_dbus_type;
         }
 
@@ -1586,8 +1618,18 @@ _nm_setting_property_from_dbus_fcn_direct(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS
         if (*p_val == v)
             goto out_unchanged;
 
-        if (!g_enum_get_value(param_spec->enum_class, v))
-            goto out_error_param_spec_validation;
+        /* To avoid that clients with old libnm fails setting a newer value received
+         * from the daemon, do not validate here if the value is within range or not.
+         * Instead, do it in 'verify' that the client can ignore.
+         * However, some properties are implemented as real enums, mostly those that
+         * were originally implemented as such. Maintain the old behaviour on them. */
+        if (G_TYPE_IS_ENUM(property_info->param_spec->value_type)) {
+            const GParamSpecEnum *enum_spec = NM_G_PARAM_SPEC_CAST_ENUM(property_info->param_spec);
+
+            if (!g_enum_get_value(enum_spec->enum_class, v))
+                goto out_error_param_spec_validation;
+        }
+
         *p_val = v;
         goto out_notify;
     }
@@ -2422,7 +2464,6 @@ _verify_properties(NMSetting *setting, GError **error)
         case NM_VALUE_TYPE_BOOL:
         case NM_VALUE_TYPE_BYTES:
         case NM_VALUE_TYPE_STRV:
-        case NM_VALUE_TYPE_ENUM:
         case NM_VALUE_TYPE_FLAGS:
         case NM_VALUE_TYPE_INT32:
         case NM_VALUE_TYPE_INT64:
@@ -2430,6 +2471,37 @@ _verify_properties(NMSetting *setting, GError **error)
         case NM_VALUE_TYPE_UINT32:
         case NM_VALUE_TYPE_UINT64:
             break;
+        case NM_VALUE_TYPE_ENUM:
+        {
+            nm_auto_unref_gtypeclass GEnumClass *enum_class = NULL;
+            int                                 *val;
+
+            nm_assert(_nm_setting_property_is_valid_direct_enum(property_info));
+
+            enum_class = g_type_class_ref(property_info->direct_data.enum_gtype);
+            val        = _nm_setting_get_private_field(setting, sett_info, property_info);
+
+            /* We validate here that the value is within the range of the enum, and not
+             * in the GObject property and/or DBus setters. This way, clients using an
+             * old libnm can accept new values added later to the enum, because clients
+             * are not required to 'verify' */
+            if (!g_enum_get_value(enum_class, *val)) {
+                g_set_error(error,
+                            NM_CONNECTION_ERROR,
+                            NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                            _("invalid value %d, expected %d-%d"),
+                            *val,
+                            enum_class->minimum,
+                            enum_class->maximum);
+                g_prefix_error(error,
+                               "%s.%s: ",
+                               klass->setting_info->setting_name,
+                               property_info->name);
+                return FALSE;
+            }
+
+            return TRUE;
+        }
         case NM_VALUE_TYPE_STRING:
         {
             const char *val;
@@ -4444,6 +4516,43 @@ nm_range_from_str(const char *str, GError **error)
     return nm_range_new(start, end);
 }
 
+/**
+ * nm_setting_get_enum_property_type:
+ * @setting_type: the GType of the NMSetting instance
+ * @property_name: the name of the property
+ *
+ * Get the type of the enum that defines the values that the property accepts. It is only
+ * useful for properties configured to accept values from certain enum type, otherwise
+ * it will return %G_TYPE_INVALID. Note that flags (children of G_TYPE_FLAGS) are also
+ * considered enums.
+ *
+ * Note that the GObject property might be implemented as an integer, actually, and not
+ * as enum. Find out what underlying type is used, checking the #GParamSpec, before
+ * setting the GObject property.
+ *
+ * Returns: the enum's GType, or %G_TYPE_INVALID if the property is not of enum type
+ *
+ * Since: 1.46
+ */
+GType
+nm_setting_get_enum_property_type(GType setting_type, const char *property_name)
+{
+    nm_auto_unref_gtypeclass NMSettingClass *setting_class = g_type_class_ref(setting_type);
+    const NMSettInfoProperty                *property_info;
+    GParamSpec                              *spec;
+
+    g_return_val_if_fail(NM_IS_SETTING_CLASS(setting_class), G_TYPE_INVALID);
+
+    property_info = _nm_setting_class_get_property_info(setting_class, property_name);
+    spec          = property_info->param_spec;
+
+    if (spec && (G_TYPE_IS_ENUM(spec->value_type) || G_TYPE_IS_FLAGS(spec->value_type)))
+        return property_info->param_spec->value_type;
+    if (property_info->property_type->direct_type == NM_VALUE_TYPE_ENUM)
+        return property_info->direct_data.enum_gtype;
+    return G_TYPE_INVALID;
+}
+
 /*****************************************************************************/
 
 static void
diff --git a/src/libnm-core-impl/tests/test-setting.c b/src/libnm-core-impl/tests/test-setting.c
index 72b855a5..4b5a0b6f 100644
--- a/src/libnm-core-impl/tests/test-setting.c
+++ b/src/libnm-core-impl/tests/test-setting.c
@@ -4565,7 +4565,7 @@ test_setting_metadata(void)
             GArray                   *property_types_data;
             guint                     prop_idx_val;
             gboolean                  can_set_including_default = FALSE;
-            gboolean                  can_have_direct_set_fcn   = FALSE;
+            gboolean                  can_have_direct_data      = FALSE;
             int                       n_special_options;
 
             g_assert(sip->name);
@@ -4662,18 +4662,35 @@ test_setting_metadata(void)
 
                 can_set_including_default = TRUE;
             } else if (sip->property_type->direct_type == NM_VALUE_TYPE_ENUM) {
-                const GParamSpecEnum *pspec;
+                nm_auto_unref_gtypeclass GEnumClass *enum_class = NULL;
+                int                                  default_value;
 
+                g_assert(_nm_setting_property_is_valid_direct_enum(sip));
+                g_assert(G_TYPE_IS_ENUM(sip->direct_data.enum_gtype));
                 g_assert(g_variant_type_equal(sip->property_type->dbus_type, "i"));
                 g_assert(sip->param_spec);
-                g_assert(g_type_is_a(sip->param_spec->value_type, G_TYPE_ENUM));
-                g_assert(sip->param_spec->value_type != G_TYPE_ENUM);
 
-                pspec = NM_G_PARAM_SPEC_CAST_ENUM(sip->param_spec);
-                g_assert(G_TYPE_FROM_CLASS(pspec->enum_class) == sip->param_spec->value_type);
-                g_assert(g_enum_get_value(pspec->enum_class, pspec->default_value));
+                if (G_TYPE_IS_ENUM(sip->param_spec->value_type)) {
+                    const GParamSpecEnum *pspec = NM_G_PARAM_SPEC_CAST_ENUM(sip->param_spec);
+
+                    g_assert(sip->param_spec->value_type != G_TYPE_ENUM);
+                    g_assert(G_TYPE_FROM_CLASS(pspec->enum_class) == sip->param_spec->value_type);
+                    g_assert(sip->param_spec->value_type == sip->direct_data.enum_gtype);
+
+                    default_value = pspec->default_value;
+                } else if (sip->param_spec->value_type == G_TYPE_INT) {
+                    const GParamSpecInt *pspec = NM_G_PARAM_SPEC_CAST_INT(sip->param_spec);
+
+                    default_value = pspec->default_value;
+                } else {
+                    g_assert_not_reached();
+                }
+
+                enum_class = g_type_class_ref(sip->direct_data.enum_gtype);
+                g_assert(g_enum_get_value(enum_class, default_value));
 
                 can_set_including_default = TRUE;
+                can_have_direct_data      = TRUE;
             } else if (sip->property_type->direct_type == NM_VALUE_TYPE_FLAGS) {
                 const GParamSpecFlags *pspec;
 
@@ -4703,7 +4720,7 @@ test_setting_metadata(void)
                                        INFINIBAND_ALEN));
                 } else {
                     g_assert(g_variant_type_equal(sip->property_type->dbus_type, "s"));
-                    can_have_direct_set_fcn = TRUE;
+                    can_have_direct_data = TRUE;
                 }
                 g_assert(sip->param_spec);
                 g_assert(sip->param_spec->value_type == G_TYPE_STRING);
@@ -4744,8 +4761,8 @@ test_setting_metadata(void)
                 g_assert(sip->property_type->direct_type == NM_VALUE_TYPE_STRING);
             }
 
-            if (!can_have_direct_set_fcn)
-                g_assert(!sip->direct_set_fcn.set_string);
+            if (!can_have_direct_data)
+                g_assert(!sip->direct_data.set_string);
 
             if (sip->property_type->direct_type == NM_VALUE_TYPE_NONE)
                 g_assert(!sip->direct_also_notify);