diff --git a/NEWS b/NEWS index bd7d24718..f08d3187c 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,9 @@ USE AT YOUR OWN RISK. NOT RECOMMENDED FOR PRODUCTION USE! * Add systemd services to provide networking in the initrd. * Introduce a new "ovs-dpdk.lsc-interrupt" property to configure the Link State Change (LSC) detection mode for OVS DPDK interfaces. +* Add a new "prefix-delegation" setting containing a "subnet-id" + property that specifies the subnet to choose on the downstream + interface when using IPv6 prefix delegation. ============================================= NetworkManager-1.52 diff --git a/docs/libnm/libnm-docs.xml b/docs/libnm/libnm-docs.xml index 4ed079393..39f62417d 100644 --- a/docs/libnm/libnm-docs.xml +++ b/docs/libnm/libnm-docs.xml @@ -341,6 +341,7 @@ print ("NetworkManager version " + client.get_version())]]> + diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index 3ddd5ffe4..6e798aaf1 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -11355,6 +11355,13 @@ _dev_ipdhcpx_notify(NMDhcpClient *client, const NMDhcpClientNotifyData *notify_d switch (notify_data->notify_type) { case NM_DHCP_CLIENT_NOTIFY_TYPE_PREFIX_DELEGATED: nm_assert(!IS_IPv4); + if (notify_data->prefix_delegated.prefix->plen == 0 + || notify_data->prefix_delegated.prefix->plen > 64) { + _LOGW_ipdhcp(addr_family, + "ignoring invalid prefix-delegation with length %u", + notify_data->prefix_delegated.prefix->plen); + return; + } /* Just re-emit. The device just contributes the prefix to the * pool in NMPolicy, which decides about subnet allocation * on the shared devices. */ @@ -13457,6 +13464,8 @@ _dev_ipsharedx_cleanup(NMDevice *self, int addr_family) nm_clear_l3cd(&priv->ipshared_data_4.v4.l3cd); _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_SHARED_4, NULL, FALSE); + } else { + _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_PD_6, NULL, FALSE); } _dev_ipsharedx_set_state(self, addr_family, NM_DEVICE_IP_STATE_NONE); diff --git a/src/core/nm-policy.c b/src/core/nm-policy.c index 4be796d24..fbcee40df 100644 --- a/src/core/nm-policy.c +++ b/src/core/nm-policy.c @@ -155,17 +155,15 @@ static gboolean hostname_retry_cb(gpointer user_data); typedef struct { NMPlatformIP6Address prefix; - NMDevice *device; /* The requesting ("uplink") device */ - guint64 next_subnet; /* Cache of the next subnet number to be - * assigned from this prefix */ - GHashTable *subnets; /* ifindex -> NMPlatformIP6Address */ + NMDevice *device; /* The requesting ("uplink") device */ + GHashTable *map_subnet_id_to_ifindex; /* (guint64 *) subnet_id -> int ifindex */ + GHashTable *map_ifindex_to_subnet; /* int ifindex -> (NMPlatformIP6Address *) prefix */ } IP6PrefixDelegation; static void -_clear_ip6_subnet(gpointer key, gpointer value, gpointer user_data) +clear_ip6_subnet(int ifindex, NMPlatformIP6Address *subnet) { - NMPlatformIP6Address *subnet = value; - NMDevice *device = nm_manager_get_device_by_ifindex(NM_MANAGER_GET, GPOINTER_TO_INT(key)); + NMDevice *device = nm_manager_get_device_by_ifindex(NM_MANAGER_GET, ifindex); if (device) { /* We can not remove a subnet we already started announcing. @@ -176,6 +174,12 @@ _clear_ip6_subnet(gpointer key, gpointer value, gpointer user_data) g_slice_free(NMPlatformIP6Address, subnet); } +static void +clear_ip6_subnet_entry(gpointer key, gpointer value, gpointer user_data) +{ + clear_ip6_subnet(GPOINTER_TO_INT(key), value); +} + static void clear_ip6_prefix_delegation(gpointer data) { @@ -187,8 +191,9 @@ clear_ip6_prefix_delegation(gpointer data) nm_inet6_ntop(&delegation->prefix.address, sbuf), delegation->prefix.plen); - g_hash_table_foreach(delegation->subnets, _clear_ip6_subnet, NULL); - g_hash_table_destroy(delegation->subnets); + g_hash_table_foreach(delegation->map_ifindex_to_subnet, clear_ip6_subnet_entry, NULL); + g_hash_table_destroy(delegation->map_ifindex_to_subnet); + g_hash_table_destroy(delegation->map_subnet_id_to_ifindex); } static void @@ -215,46 +220,112 @@ expire_ip6_delegations(NMPolicy *self) static gboolean ip6_subnet_from_delegation(IP6PrefixDelegation *delegation, NMDevice *device) { - NMPlatformIP6Address *subnet; - int ifindex = nm_device_get_ifindex(device); - char sbuf[NM_INET_ADDRSTRLEN]; + NMPlatformIP6Address *subnet; + int ifindex = nm_device_get_ifindex(device); + char sbuf[NM_INET_ADDRSTRLEN]; + NMSettingPrefixDelegation *s_pd; + gint64 wanted_subnet_id = -1; + guint64 num_subnets; + guint64 old_subnet_id; - subnet = g_hash_table_lookup(delegation->subnets, GINT_TO_POINTER(ifindex)); - if (!subnet) { - /* Check for out-of-prefixes condition. */ - if (delegation->next_subnet >= (1 << (64 - delegation->prefix.plen))) { - _LOGD(LOGD_IP6, - "ipv6-pd: no more prefixes in %s/%d", - nm_inet6_ntop(&delegation->prefix.address, sbuf), - delegation->prefix.plen); - return FALSE; - } + nm_assert(delegation->prefix.plen > 0 && delegation->prefix.plen <= 64); - /* Allocate a new subnet. */ - subnet = g_slice_new0(NMPlatformIP6Address); - g_hash_table_insert(delegation->subnets, GINT_TO_POINTER(ifindex), subnet); - - subnet->plen = 64; - subnet->address.s6_addr32[0] = - delegation->prefix.address.s6_addr32[0] | htonl(delegation->next_subnet >> 32); - subnet->address.s6_addr32[1] = - delegation->prefix.address.s6_addr32[1] | htonl(delegation->next_subnet); - - /* Out subnet pool management is pretty unsophisticated. We only add - * the subnets and index them by ifindex. That keeps the implementation - * simple and the dead entries make it easy to reuse the same subnet on - * subsequent activations. On the other hand they may waste the subnet - * space. */ - delegation->next_subnet++; + s_pd = nm_device_get_applied_setting(device, NM_TYPE_SETTING_PREFIX_DELEGATION); + if (s_pd) { + wanted_subnet_id = nm_setting_prefix_delegation_get_subnet_id(s_pd); } + /* Try to use the cached subnet assigned to the interface */ + subnet = g_hash_table_lookup(delegation->map_ifindex_to_subnet, GINT_TO_POINTER(ifindex)); + if (subnet) { + old_subnet_id = nm_ip6_addr_get_subnet_id(&subnet->address, delegation->prefix.plen); + if (wanted_subnet_id != -1 && wanted_subnet_id != old_subnet_id) { + /* The device had a subnet assigned before, but now wants a + * different subnet-id. Release the old subnet and continue below + * to get a new one. */ + clear_ip6_subnet(ifindex, subnet); + subnet = NULL; + g_hash_table_remove(delegation->map_ifindex_to_subnet, GINT_TO_POINTER(ifindex)); + g_hash_table_remove(delegation->map_subnet_id_to_ifindex, &old_subnet_id); + } else { + goto subnet_found; + } + } + + /* Check for out-of-prefixes condition */ + num_subnets = 1 << (64 - delegation->prefix.plen); + if (nm_g_hash_table_size(delegation->map_subnet_id_to_ifindex) >= num_subnets) { + _LOGD(LOGD_IP6, + "ipv6-pd: no more prefixes in %s/%u", + nm_inet6_ntop(&delegation->prefix.address, sbuf), + delegation->prefix.plen); + return FALSE; + } + + /* Try to honor the "prefix-delegation.subnet-id" property */ + if (wanted_subnet_id >= 0) { + gpointer value; + NMDevice *other_device; + + if (g_hash_table_lookup_extended(delegation->map_subnet_id_to_ifindex, + &wanted_subnet_id, + NULL, + &value)) { + other_device = nm_manager_get_device_by_ifindex(NM_MANAGER_GET, GPOINTER_TO_INT(value)); + _LOGW(LOGD_IP6, + "ipv6-pd: subnet-id 0x%" G_GINT64_MODIFIER + "x wanted by device %s is already in use by " + "device %s (ifindex %d)", + (guint64) wanted_subnet_id, + nm_device_get_iface(device), + other_device ? nm_device_get_ip_iface(other_device) : NULL, + GPOINTER_TO_INT(value)); + wanted_subnet_id = -1; + } + } + + /* If we don't have a subnet-id yet, find the first one available */ + if (wanted_subnet_id < 0) { + guint64 i; + + for (i = 0; i < num_subnets; i++) { + if (!g_hash_table_lookup_extended(delegation->map_subnet_id_to_ifindex, + &i, + NULL, + NULL)) { + wanted_subnet_id = (gint64) i; + break; + } + } + + if (wanted_subnet_id < 0) { + /* We already verified that there are available subnets, this should not happen */ + return nm_assert_unreachable_val(FALSE); + } + } + + /* Allocate a new subnet */ + subnet = g_slice_new0(NMPlatformIP6Address); + g_hash_table_insert(delegation->map_ifindex_to_subnet, GINT_TO_POINTER(ifindex), subnet); + g_hash_table_insert(delegation->map_subnet_id_to_ifindex, + nm_memdup(&wanted_subnet_id, sizeof(guint64)), + GINT_TO_POINTER(ifindex)); + + subnet->plen = 64; + subnet->address.s6_addr32[0] = + delegation->prefix.address.s6_addr32[0] | htonl(wanted_subnet_id >> 32); + subnet->address.s6_addr32[1] = + delegation->prefix.address.s6_addr32[1] | htonl(wanted_subnet_id); + +subnet_found: subnet->timestamp = delegation->prefix.timestamp; subnet->lifetime = delegation->prefix.lifetime; subnet->preferred = delegation->prefix.preferred; _LOGD(LOGD_IP6, - "ipv6-pd: %s allocated from a /%d prefix on %s", + "ipv6-pd: %s/64 (subnet-id 0x%" G_GINT64_MODIFIER "x) allocated from a /%d prefix on %s", nm_inet6_ntop(&subnet->address, sbuf), + (guint64) wanted_subnet_id, delegation->prefix.plen, nm_device_get_iface(device)); @@ -345,8 +416,9 @@ device_ip6_prefix_delegated(NMDevice *device, if (i == priv->ip6_prefix_delegations->len) { /* Allocate a delegation for new prefix. */ delegation = nm_g_array_append_new(priv->ip6_prefix_delegations, IP6PrefixDelegation); - delegation->subnets = g_hash_table_new(nm_direct_hash, NULL); - delegation->next_subnet = 0; + delegation->map_subnet_id_to_ifindex = + g_hash_table_new_full(nm_puint64_hash, nm_puint64_equal, g_free, NULL); + delegation->map_ifindex_to_subnet = g_hash_table_new(nm_direct_hash, NULL); } delegation->device = device; diff --git a/src/libnm-client-impl/libnm.ver b/src/libnm-client-impl/libnm.ver index 920caa4ef..bfcf7f399 100644 --- a/src/libnm-client-impl/libnm.ver +++ b/src/libnm-client-impl/libnm.ver @@ -2055,4 +2055,7 @@ global: nm_setting_ip_config_get_forwarding; nm_setting_ovs_dpdk_get_lsc_interrupt; nm_setting_ovs_dpdk_lsc_interrupt_get_type; + nm_setting_prefix_delegation_get_subnet_id; + nm_setting_prefix_delegation_get_type; + nm_setting_prefix_delegation_new; } libnm_1_52_0; diff --git a/src/libnm-client-public/NetworkManager.h b/src/libnm-client-public/NetworkManager.h index 3608168f9..9e9a4eb83 100644 --- a/src/libnm-client-public/NetworkManager.h +++ b/src/libnm-client-public/NetworkManager.h @@ -59,6 +59,7 @@ #include "nm-setting-ovs-port.h" #include "nm-setting-ppp.h" #include "nm-setting-pppoe.h" +#include "nm-setting-prefix-delegation.h" #include "nm-setting-proxy.h" #include "nm-setting-serial.h" #include "nm-setting-sriov.h" diff --git a/src/libnm-client-public/nm-autoptr.h b/src/libnm-client-public/nm-autoptr.h index 0f6e59c4a..f4321ad3a 100644 --- a/src/libnm-client-public/nm-autoptr.h +++ b/src/libnm-client-public/nm-autoptr.h @@ -104,6 +104,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingOvsPatch, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingOvsPort, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingPpp, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingPppoe, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingPrefixDelegation, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingProxy, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingSerial, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingSriov, g_object_unref) 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 44e338bb9..d16595717 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 @@ -2315,6 +2315,14 @@ gprop-type="gchararray" /> + + + diff --git a/src/libnm-core-impl/meson.build b/src/libnm-core-impl/meson.build index e068d6bd3..610e22792 100644 --- a/src/libnm-core-impl/meson.build +++ b/src/libnm-core-impl/meson.build @@ -41,6 +41,7 @@ libnm_core_settings_sources = files( 'nm-setting-ovs-port.c', 'nm-setting-ppp.c', 'nm-setting-pppoe.c', + 'nm-setting-prefix-delegation.c', 'nm-setting-proxy.c', 'nm-setting-serial.c', 'nm-setting-sriov.c', 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 37cb61f17..d625c4e8c 100644 --- a/src/libnm-core-impl/nm-meta-setting-base-impl.c +++ b/src/libnm-core-impl/nm-meta-setting-base-impl.c @@ -51,6 +51,7 @@ #include "nm-setting-ovs-port.h" #include "nm-setting-ppp.h" #include "nm-setting-pppoe.h" +#include "nm-setting-prefix-delegation.h" #include "nm-setting-proxy.h" #include "nm-setting-serial.h" #include "nm-setting-tc-config.h" @@ -484,6 +485,13 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = { .setting_name = NM_SETTING_PPP_SETTING_NAME, .get_setting_gtype = nm_setting_ppp_get_type, }, + [NM_META_SETTING_TYPE_PREFIX_DELEGATION] = + { + .meta_type = NM_META_SETTING_TYPE_PREFIX_DELEGATION, + .setting_priority = NM_SETTING_PRIORITY_IP, + .setting_name = NM_SETTING_PREFIX_DELEGATION_SETTING_NAME, + .get_setting_gtype = nm_setting_prefix_delegation_get_type, + }, [NM_META_SETTING_TYPE_PROXY] = { .meta_type = NM_META_SETTING_TYPE_PROXY, @@ -698,6 +706,7 @@ const NMMetaSettingType nm_meta_setting_types_by_priority[] = { NM_META_SETTING_TYPE_HOSTNAME, NM_META_SETTING_TYPE_IP4_CONFIG, NM_META_SETTING_TYPE_IP6_CONFIG, + NM_META_SETTING_TYPE_PREFIX_DELEGATION, NM_META_SETTING_TYPE_PROXY, NM_META_SETTING_TYPE_TC_CONFIG, diff --git a/src/libnm-core-impl/nm-setting-prefix-delegation.c b/src/libnm-core-impl/nm-setting-prefix-delegation.c new file mode 100644 index 000000000..100d31530 --- /dev/null +++ b/src/libnm-core-impl/nm-setting-prefix-delegation.c @@ -0,0 +1,118 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "libnm-core-impl/nm-default-libnm-core.h" + +#include "nm-setting-prefix-delegation.h" + +#include "nm-connection-private.h" +#include "nm-setting-connection.h" +#include "nm-setting-private.h" + +/** + * SECTION:nm-setting-prefix-delegation + * @short_description: Describes connection properties related to IPv6 prefix delegation + * + * The #NMSettingPrefixDelegation object is a #NMSetting subclass that describes the + * configuration of downstream interfaces using IPv6 prefix delegation. + **/ + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_SUBNET_ID, ); + +/** + * NMSettingPrefixDelegation: + * + * IPv6 prefix delegation settings + * + * Since: 1.54 + */ +struct _NMSettingPrefixDelegation { + NMSetting parent; + gint64 subnet_id; +}; + +struct _NMSettingPrefixDelegationClass { + NMSettingClass parent; +}; + +G_DEFINE_TYPE(NMSettingPrefixDelegation, nm_setting_prefix_delegation, NM_TYPE_SETTING) + +/*****************************************************************************/ + +/** + * nm_setting_prefix_delegation_get_subnet_id: + * @setting: the #NMSettingPrefixDelegation + * + * Returns: the subnet ID for prefix delegation + * + * Since: 1.54 + **/ +gint64 +nm_setting_prefix_delegation_get_subnet_id(NMSettingPrefixDelegation *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_PREFIX_DELEGATION(setting), 0); + + return setting->subnet_id; +} + +/*****************************************************************************/ + +static void +nm_setting_prefix_delegation_init(NMSettingPrefixDelegation *setting) +{} + +/** + * nm_setting_prefix_delegation_new: + * + * Creates a new #NMSettingPrefixDelegation object with default values. + * + * Returns: (transfer full): the new empty #NMSettingPrefixDelegation object + * + * Since: 1.54 + **/ +NMSetting * +nm_setting_prefix_delegation_new(void) +{ + return g_object_new(NM_TYPE_SETTING_PREFIX_DELEGATION, NULL); +} + +static void +nm_setting_prefix_delegation_class_init(NMSettingPrefixDelegationClass *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; + + /** + * NMSettingPrefixDelegation:subnet-id: + * + * The subnet ID to use on the interface from the prefix delegation received via + * an upstream interface. Set to a value between 0 and 0xffffffff (2^32 - 1) + * to indicate a specific subnet ID; or set to -1 to automatically choose + * an available subnet ID. + * + * Since: 1.54 + **/ + _nm_setting_property_define_direct_int64(properties_override, + obj_properties, + NM_SETTING_PREFIX_DELEGATION_SUBNET_ID, + PROP_SUBNET_ID, + -1, + G_MAXUINT32, + -1, + NM_SETTING_PARAM_NONE, + NMSettingPrefixDelegation, + subnet_id); + + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + _nm_setting_class_commit(setting_class, + NM_META_SETTING_TYPE_PREFIX_DELEGATION, + NULL, + properties_override, + 0); +} diff --git a/src/libnm-core-intern/nm-core-internal.h b/src/libnm-core-intern/nm-core-internal.h index aa96c5268..8b23dd44c 100644 --- a/src/libnm-core-intern/nm-core-internal.h +++ b/src/libnm-core-intern/nm-core-internal.h @@ -58,6 +58,7 @@ #include "nm-setting-ovs-port.h" #include "nm-setting-ppp.h" #include "nm-setting-pppoe.h" +#include "nm-setting-prefix-delegation.h" #include "nm-setting-proxy.h" #include "nm-setting-serial.h" #include "nm-setting-sriov.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 c03285ebf..d1535e5e1 100644 --- a/src/libnm-core-intern/nm-meta-setting-base-impl.h +++ b/src/libnm-core-intern/nm-meta-setting-base-impl.h @@ -143,6 +143,7 @@ typedef enum _nm_packed { NM_META_SETTING_TYPE_OVS_PORT, NM_META_SETTING_TYPE_PPP, NM_META_SETTING_TYPE_PPPOE, + NM_META_SETTING_TYPE_PREFIX_DELEGATION, NM_META_SETTING_TYPE_PROXY, NM_META_SETTING_TYPE_SERIAL, NM_META_SETTING_TYPE_SRIOV, diff --git a/src/libnm-core-public/meson.build b/src/libnm-core-public/meson.build index 97888467e..086801d96 100644 --- a/src/libnm-core-public/meson.build +++ b/src/libnm-core-public/meson.build @@ -46,6 +46,7 @@ libnm_core_headers = files( 'nm-setting-ovs-port.h', 'nm-setting-ppp.h', 'nm-setting-pppoe.h', + 'nm-setting-prefix-delegation.h', 'nm-setting-proxy.h', 'nm-setting-serial.h', 'nm-setting-sriov.h', diff --git a/src/libnm-core-public/nm-core-types.h b/src/libnm-core-public/nm-core-types.h index a0d6bc82d..617d6b741 100644 --- a/src/libnm-core-public/nm-core-types.h +++ b/src/libnm-core-public/nm-core-types.h @@ -52,6 +52,7 @@ typedef struct _NMSettingOvsPatch NMSettingOvsPatch; typedef struct _NMSettingOvsPort NMSettingOvsPort; typedef struct _NMSettingPpp NMSettingPpp; typedef struct _NMSettingPppoe NMSettingPppoe; +typedef struct _NMSettingPrefixDelegation NMSettingPrefixDelegation; typedef struct _NMSettingProxy NMSettingProxy; typedef struct _NMSettingSerial NMSettingSerial; typedef struct _NMSettingSriov NMSettingSriov; diff --git a/src/libnm-core-public/nm-setting-prefix-delegation.h b/src/libnm-core-public/nm-setting-prefix-delegation.h new file mode 100644 index 000000000..5361d7c69 --- /dev/null +++ b/src/libnm-core-public/nm-setting-prefix-delegation.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#ifndef __NM_SETTING_PREFIX_DELEGATION_H__ +#define __NM_SETTING_PREFIX_DELEGATION_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_PREFIX_DELEGATION (nm_setting_prefix_delegation_get_type()) +#define NM_SETTING_PREFIX_DELEGATION(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SETTING_PREFIX_DELEGATION, NMSettingVrf)) +#define NM_SETTING_PREFIX_DELEGATION_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_SETTING_PREFIX_DELEGATIONCONFIG, NMSettingVrfClass)) +#define NM_IS_SETTING_PREFIX_DELEGATION(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_SETTING_PREFIX_DELEGATION)) +#define NM_IS_SETTING_PREFIX_DELEGATION_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_SETTING_PREFIX_DELEGATION)) +#define NM_SETTING_PREFIX_DELEGATION_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_SETTING_PREFIX_DELEGATION, NMSettingVrfClass)) + +#define NM_SETTING_PREFIX_DELEGATION_SETTING_NAME "prefix-delegation" + +#define NM_SETTING_PREFIX_DELEGATION_SUBNET_ID "subnet-id" + +typedef struct _NMSettingPrefixDelegationClass NMSettingPrefixDelegationClass; + +NM_AVAILABLE_IN_1_54 +GType nm_setting_prefix_delegation_get_type(void); +NM_AVAILABLE_IN_1_54 +NMSetting *nm_setting_prefix_delegation_new(void); +NM_AVAILABLE_IN_1_54 +gint64 nm_setting_prefix_delegation_get_subnet_id(NMSettingPrefixDelegation *setting); + +G_END_DECLS + +#endif /* __NM_SETTING_PREFIX_DELEGATION_H__ */ diff --git a/src/libnm-glib-aux/nm-hash-utils.c b/src/libnm-glib-aux/nm-hash-utils.c index 973422a19..7f25e9ac3 100644 --- a/src/libnm-glib-aux/nm-hash-utils.c +++ b/src/libnm-glib-aux/nm-hash-utils.c @@ -190,6 +190,27 @@ nm_pint_equal(gconstpointer a, gconstpointer b) return s1 == s2 || (s1 && s2 && *s1 == *s2); } +/* GHashFunc for GHashTable keys that are a pointer to a guint64 */ +guint +nm_puint64_hash(gconstpointer p) +{ + const guint64 *s = p; + + if (!s) + return nm_hash_static(298377461u); + return nm_hash_val(1208815757u, *s); +} + +/* GEqualFunc for GHashTable keys that are a pointer to a guint64 */ +gboolean +nm_puint64_equal(gconstpointer a, gconstpointer b) +{ + const guint64 *s1 = a; + const guint64 *s2 = a; + + return s1 == s2 || (s1 && s2 && *s1 == *s2); +} + guint nm_pdirect_hash(gconstpointer p) { diff --git a/src/libnm-glib-aux/nm-hash-utils.h b/src/libnm-glib-aux/nm-hash-utils.h index 6d7cc271b..34690eabc 100644 --- a/src/libnm-glib-aux/nm-hash-utils.h +++ b/src/libnm-glib-aux/nm-hash-utils.h @@ -266,6 +266,9 @@ gboolean nm_pstr_equal(gconstpointer a, gconstpointer b); guint nm_pint_hash(gconstpointer p); gboolean nm_pint_equal(gconstpointer a, gconstpointer b); +guint nm_puint64_hash(gconstpointer p); +gboolean nm_puint64_equal(gconstpointer a, gconstpointer b); + G_STATIC_ASSERT(sizeof(int) == sizeof(guint32)); #define nm_puint32_hash nm_pint_hash #define nm_puint32_equal nm_pint_equal diff --git a/src/libnm-glib-aux/nm-inet-utils.c b/src/libnm-glib-aux/nm-inet-utils.c index 2ee73ad5e..f4f418cf1 100644 --- a/src/libnm-glib-aux/nm-inet-utils.c +++ b/src/libnm-glib-aux/nm-inet-utils.c @@ -238,6 +238,42 @@ nm_ip6_addr_clear_host_address(struct in6_addr *dst, const struct in6_addr *src, return dst; } +/** + * nm_ip6_addr_get_subnet_id: + * @addr: the IPv6 address + * @plen: the prefix length + * + * Given an IPv6 address and a prefix length, returns the subnet ID, + * defined as follows: + * + * | plen bits | (64 - plen) bits | 64 bits | + * +-----------------+------------------+-------------------------------+ + * | prefix | subnet ID | interface ID | + * +-----------------+------------------+-------------------------------+ + * + * The prefix length must be a value between 0 and 64. + */ +guint64 +nm_ip6_addr_get_subnet_id(struct in6_addr *addr, guint8 plen) +{ + int nbits = 64 - plen; + guint64 res = 0; + guint64 tmp; + guint64 i; + + g_return_val_if_fail(addr, 0); + g_return_val_if_fail(plen <= 64, 0); + + for (i = 0; i < 2 && nbits > 0; i++, nbits -= 32) { + tmp = htonl(addr->s6_addr32[1 - i]); + tmp = tmp & ((1ULL << NM_MIN(32U, (guint) nbits)) - 1); + tmp = tmp << (32 * i); + res += tmp; + } + + return res; +} + int nm_ip6_addr_same_prefix_cmp(const struct in6_addr *addr_a, const struct in6_addr *addr_b, diff --git a/src/libnm-glib-aux/nm-inet-utils.h b/src/libnm-glib-aux/nm-inet-utils.h index 489d21dde..999519f89 100644 --- a/src/libnm-glib-aux/nm-inet-utils.h +++ b/src/libnm-glib-aux/nm-inet-utils.h @@ -218,6 +218,8 @@ nm_ip4_addr_clear_host_address(in_addr_t addr, guint32 plen) const struct in6_addr * nm_ip6_addr_clear_host_address(struct in6_addr *dst, const struct in6_addr *src, guint32 plen); +guint64 nm_ip6_addr_get_subnet_id(struct in6_addr *addr, guint8 plen); + /*****************************************************************************/ static inline int diff --git a/src/libnm-glib-aux/tests/test-shared-general.c b/src/libnm-glib-aux/tests/test-shared-general.c index 2f09a5490..931c25c66 100644 --- a/src/libnm-glib-aux/tests/test-shared-general.c +++ b/src/libnm-glib-aux/tests/test-shared-general.c @@ -397,6 +397,53 @@ test_nm_ip4_addr_netmask_from_prefix(void) /*****************************************************************************/ +static void +test_nm_ip6_addr_get_subnet_id(void) +{ +#define check_subnet_id(_addrstr, _plen, _subnet_id) \ + { \ + struct in6_addr addr; \ + \ + addr = nmtst_inet6_from_string(_addrstr); \ + g_assert_cmpint(nm_ip6_addr_get_subnet_id(&addr, _plen), ==, _subnet_id); \ + } + + check_subnet_id("aaaa:bbbb:cccc:ffff::", 64, 0); + check_subnet_id("aaaa:bbbb:cccc:fffe::", 63, 0); + check_subnet_id("aaaa:bbbb:cccc:ffff::", 63, 1); + check_subnet_id("aaaa:bbbb:cccc:fffc::", 62, 0); + check_subnet_id("aaaa:bbbb:cccc:fffd::", 62, 1); + check_subnet_id("aaaa:bbbb:cccc:fffe::", 62, 2); + check_subnet_id("aaaa:bbbb:cccc:ffff::", 62, 3); + check_subnet_id("aaaa:bbbb:cccc:fff8::", 61, 0); + check_subnet_id("aaaa:bbbb:cccc:ffff::", 61, 7); + check_subnet_id("aaaa:bbbb:cccc:fff0::", 60, 0); + check_subnet_id("aaaa:bbbb:cccc:fff2::", 60, 2); + check_subnet_id("aaaa:bbbb:cccc:ffff::", 60, 15); + check_subnet_id("aaaa:bbbb:cccc:0000::", 48, 0); + check_subnet_id("aaaa:bbbb:cccc:f000::", 48, 61440); + check_subnet_id("aaaa:bbbb:cccc:ffff::", 48, 65535); + check_subnet_id("aaaa:bbbb:cccc:0000::", 46, 0); + check_subnet_id("aaaa:bbbb:cccc:0001::", 46, 1); + check_subnet_id("aaaa:bbbb:ccce:5555::", 46, 152917); + check_subnet_id("aaaa:bbbb:0000:0000::", 32, 0); + check_subnet_id("aaaa:bbbb:0000:0001::", 32, 1); + check_subnet_id("aaaa:bbbb:0001:0001::", 32, 65537); + check_subnet_id("aaaa:bbbb:ffff:ffff::", 32, 0xffffffff); + check_subnet_id("aaaa:bbb8:0000:0000::", 30, 0); + check_subnet_id("aaaa:bbb8:0000:0001::", 30, 1); + check_subnet_id("aaaa:bbb8:0001:0001::", 30, 65537); + check_subnet_id("aaaa:bbbb:0000:0000::", 30, 0x300000000ULL); + check_subnet_id("aaaa:bbbb:0001:0001::", 30, 0x300010001ULL); + check_subnet_id("aaaa:bbbb:0001:0001::", 8, 0xAABBBB00010001ULL); + check_subnet_id("abaa:bbbb:0001:0001::", 7, 0x1AABBBB00010001ULL); + check_subnet_id("abaa:bbbb:0001:0001::", 0, 0xABAABBBB00010001ULL); + check_subnet_id("abaa:bbbb:0001:0001:5555:5555:5555:5555", 0, 0xABAABBBB00010001ULL); + check_subnet_id("::", 0, 0); +} + +/*****************************************************************************/ + static void test_unaligned(void) { @@ -2864,6 +2911,7 @@ main(int argc, char **argv) g_test_add_func("/general/test_nm_ip4_addr_is_loopback", test_nm_ip4_addr_is_loopback); g_test_add_func("/general/test_nm_ip4_addr_netmask_from_prefix", test_nm_ip4_addr_netmask_from_prefix); + g_test_add_func("/general/test_nm_ip6_addr_get_subnet_id", test_nm_ip6_addr_get_subnet_id); g_test_add_func("/general/test_unaligned", test_unaligned); g_test_add_func("/general/test_strv_cmp", test_strv_cmp); g_test_add_func("/general/test_strstrip_avoid_copy", test_strstrip_avoid_copy); diff --git a/src/libnmc-setting/nm-meta-setting-base-impl.c b/src/libnmc-setting/nm-meta-setting-base-impl.c index 37cb61f17..d625c4e8c 100644 --- a/src/libnmc-setting/nm-meta-setting-base-impl.c +++ b/src/libnmc-setting/nm-meta-setting-base-impl.c @@ -51,6 +51,7 @@ #include "nm-setting-ovs-port.h" #include "nm-setting-ppp.h" #include "nm-setting-pppoe.h" +#include "nm-setting-prefix-delegation.h" #include "nm-setting-proxy.h" #include "nm-setting-serial.h" #include "nm-setting-tc-config.h" @@ -484,6 +485,13 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = { .setting_name = NM_SETTING_PPP_SETTING_NAME, .get_setting_gtype = nm_setting_ppp_get_type, }, + [NM_META_SETTING_TYPE_PREFIX_DELEGATION] = + { + .meta_type = NM_META_SETTING_TYPE_PREFIX_DELEGATION, + .setting_priority = NM_SETTING_PRIORITY_IP, + .setting_name = NM_SETTING_PREFIX_DELEGATION_SETTING_NAME, + .get_setting_gtype = nm_setting_prefix_delegation_get_type, + }, [NM_META_SETTING_TYPE_PROXY] = { .meta_type = NM_META_SETTING_TYPE_PROXY, @@ -698,6 +706,7 @@ const NMMetaSettingType nm_meta_setting_types_by_priority[] = { NM_META_SETTING_TYPE_HOSTNAME, NM_META_SETTING_TYPE_IP4_CONFIG, NM_META_SETTING_TYPE_IP6_CONFIG, + NM_META_SETTING_TYPE_PREFIX_DELEGATION, NM_META_SETTING_TYPE_PROXY, NM_META_SETTING_TYPE_TC_CONFIG, diff --git a/src/libnmc-setting/nm-meta-setting-base-impl.h b/src/libnmc-setting/nm-meta-setting-base-impl.h index c03285ebf..d1535e5e1 100644 --- a/src/libnmc-setting/nm-meta-setting-base-impl.h +++ b/src/libnmc-setting/nm-meta-setting-base-impl.h @@ -143,6 +143,7 @@ typedef enum _nm_packed { NM_META_SETTING_TYPE_OVS_PORT, NM_META_SETTING_TYPE_PPP, NM_META_SETTING_TYPE_PPPOE, + NM_META_SETTING_TYPE_PREFIX_DELEGATION, NM_META_SETTING_TYPE_PROXY, NM_META_SETTING_TYPE_SERIAL, NM_META_SETTING_TYPE_SRIOV, diff --git a/src/libnmc-setting/nm-meta-setting-desc.c b/src/libnmc-setting/nm-meta-setting-desc.c index b234504a0..2cae19ba8 100644 --- a/src/libnmc-setting/nm-meta-setting-desc.c +++ b/src/libnmc-setting/nm-meta-setting-desc.c @@ -1005,8 +1005,16 @@ _get_fcn_gobject_int(ARGS_GET_FCN) case 16: if (is_uint64) return_str = g_strdup_printf("0x%" G_GINT64_MODIFIER "x", v.u64); - else - return_str = g_strdup_printf("0x%" G_GINT64_MODIFIER "x", (guint64) v.i64); + else { + if (property_info->property_typ_data + && property_info->property_typ_data->subtype.gobject_int + .print_hex_negative_as_base10 + && v.i64 < 0) { + return_str = g_strdup_printf("%" G_GINT64_FORMAT, v.i64); + } else { + return_str = g_strdup_printf("0x%" G_GINT64_MODIFIER "x", (guint64) v.i64); + } + } break; default: return_str = NULL; @@ -1422,6 +1430,11 @@ _set_fcn_gobject_int(ARGS_SET_FCN) nm_meta_property_int_get_range(property_info, &min, &max); + /* See the comment on "print_hex_negative_as_base10" */ + nm_assert(!property_info->property_typ_data + || !property_info->property_typ_data->subtype.gobject_int.print_hex_negative_as_base10 + || (!is_uint64 && min.i64 > -10)); + if (is_uint64) v.u64 = _nm_utils_ascii_str_to_uint64(value, base, min.u64, max.u64, 0); else @@ -7481,6 +7494,19 @@ static const NMMetaPropertyInfo *const property_infos_PPPOE[] = { NULL }; +#undef _CURRENT_NM_META_SETTING_TYPE +#define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_PREFIX_DELEGATION +static const NMMetaPropertyInfo *const property_infos_PREFIX_DELEGATION[] = { + PROPERTY_INFO_WITH_DESC (NM_SETTING_PREFIX_DELEGATION_SUBNET_ID, + .property_type = &_pt_gobject_int, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int, + .base = 16, + .print_hex_negative_as_base10 = TRUE, + ), + ), + NULL +}; + #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_PROXY static const NMMetaPropertyInfo *const property_infos_PROXY[] = { @@ -8938,6 +8964,7 @@ _setting_init_fcn_wireless (ARGS_SETTING_INIT_FCN) #define SETTING_PRETTY_NAME_OVS_PORT N_("Open vSwitch port settings") #define SETTING_PRETTY_NAME_PPP N_("PPP settings") #define SETTING_PRETTY_NAME_PPPOE N_("PPPoE") +#define SETTING_PRETTY_NAME_PREFIX_DELEGATION N_("Prefix delegation settings") #define SETTING_PRETTY_NAME_PROXY N_("Proxy") #define SETTING_PRETTY_NAME_SERIAL N_("Serial settings") #define SETTING_PRETTY_NAME_SRIOV N_("SR-IOV settings") @@ -9155,6 +9182,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = { NM_META_SETTING_VALID_PART_ITEM (OVS_PATCH, FALSE), NM_META_SETTING_VALID_PART_ITEM (IP4_CONFIG, FALSE), NM_META_SETTING_VALID_PART_ITEM (IP6_CONFIG, FALSE), + NM_META_SETTING_VALID_PART_ITEM (PREFIX_DELEGATION, FALSE), NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE), NM_META_SETTING_VALID_PART_ITEM (ETHTOOL, FALSE), ), @@ -9185,6 +9213,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = { ), ), SETTING_INFO (PPP), + SETTING_INFO (PREFIX_DELEGATION), SETTING_INFO (PROXY, .setting_init_fcn = _setting_init_fcn_proxy, ), @@ -9313,6 +9342,7 @@ static const NMMetaSettingValidPartItem *const valid_settings_noport[] = { NM_META_SETTING_VALID_PART_ITEM(MATCH, FALSE), NM_META_SETTING_VALID_PART_ITEM(IP4_CONFIG, FALSE), NM_META_SETTING_VALID_PART_ITEM(IP6_CONFIG, FALSE), + NM_META_SETTING_VALID_PART_ITEM(PREFIX_DELEGATION, FALSE), NM_META_SETTING_VALID_PART_ITEM(HOSTNAME, FALSE), NM_META_SETTING_VALID_PART_ITEM(LINK, FALSE), NM_META_SETTING_VALID_PART_ITEM(TC_CONFIG, FALSE), diff --git a/src/libnmc-setting/nm-meta-setting-desc.h b/src/libnmc-setting/nm-meta-setting-desc.h index 46b7f6500..0294b1f70 100644 --- a/src/libnmc-setting/nm-meta-setting-desc.h +++ b/src/libnmc-setting/nm-meta-setting-desc.h @@ -293,9 +293,21 @@ struct _NMMetaPropertyTypData { int value); } gobject_enum; struct { - NMMetaSignUnsignInt64 min; - NMMetaSignUnsignInt64 max; - guint base; + NMMetaSignUnsignInt64 min; + NMMetaSignUnsignInt64 max; + guint base; + + /* Normally, when a property has "base = 16", it is printed + * as unsigned even if the gtype is signed. For some properties, + * we want to print the hexadecimal representation for positive + * values, and the base10 representation with minus sign for negative + * values. A typical use case is to encode the default value as + * "-1" and use positive values as a hexadecimal number. To avoid + * ambiguity when setting the value via nmcli, the property minimum + * allowed value should not be <= -10. + */ + bool print_hex_negative_as_base10; + const NMMetaUtilsIntValueInfo *value_infos; } gobject_int; struct { diff --git a/src/libnmc-setting/settings-docs.h.in b/src/libnmc-setting/settings-docs.h.in index 25aed3cfa..814ca1929 100644 --- a/src/libnmc-setting/settings-docs.h.in +++ b/src/libnmc-setting/settings-docs.h.in @@ -503,4 +503,5 @@ #define DESCRIBE_DOC_NM_SETTING_LOOPBACK_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple Ethernet frames.") #define DESCRIBE_DOC_NM_SETTING_OVS_EXTERNAL_IDS_DATA N_("A dictionary of key/value pairs with external-ids for OVS.") #define DESCRIBE_DOC_NM_SETTING_OVS_OTHER_CONFIG_DATA N_("A dictionary of key/value pairs with other_config settings for OVS. See also \"other_config\" in the \"ovs-vswitchd.conf.db\" manual for the keys that OVS supports.") +#define DESCRIBE_DOC_NM_SETTING_PREFIX_DELEGATION_SUBNET_ID N_("The subnet ID to use on the interface from the prefix delegation received via an upstream interface. Set to a value between 0 and 0xffffffff (2^32 - 1) to indicate a specific subnet ID; or set to -1 to automatically choose an available subnet ID.") #define DESCRIBE_DOC_NM_SETTING_VETH_PEER N_("This property specifies the peer interface name of the veth. This property is mandatory.") diff --git a/src/nmcli/connections.c b/src/nmcli/connections.c index 505be6d15..580fab66d 100644 --- a/src/nmcli/connections.c +++ b/src/nmcli/connections.c @@ -1055,27 +1055,28 @@ const NmcMetaGenericInfo "," NM_SETTING_VETH_SETTING_NAME "," NM_SETTING_802_1X_SETTING_NAME \ "," NM_SETTING_WIRELESS_SETTING_NAME "," NM_SETTING_WIRELESS_SECURITY_SETTING_NAME \ "," NM_SETTING_IP4_CONFIG_SETTING_NAME "," NM_SETTING_IP6_CONFIG_SETTING_NAME \ - "," NM_SETTING_SERIAL_SETTING_NAME "," NM_SETTING_WIFI_P2P_SETTING_NAME \ - "," NM_SETTING_PPP_SETTING_NAME "," NM_SETTING_PPPOE_SETTING_NAME \ - "," NM_SETTING_ADSL_SETTING_NAME "," NM_SETTING_GSM_SETTING_NAME \ - "," NM_SETTING_CDMA_SETTING_NAME "," NM_SETTING_BLUETOOTH_SETTING_NAME \ - "," NM_SETTING_OLPC_MESH_SETTING_NAME "," NM_SETTING_VPN_SETTING_NAME \ - "," NM_SETTING_INFINIBAND_SETTING_NAME "," NM_SETTING_BOND_SETTING_NAME \ - "," NM_SETTING_BOND_PORT_SETTING_NAME "," NM_SETTING_VLAN_SETTING_NAME \ - "," NM_SETTING_BRIDGE_SETTING_NAME "," NM_SETTING_BRIDGE_PORT_SETTING_NAME \ - "," NM_SETTING_TEAM_SETTING_NAME "," NM_SETTING_TEAM_PORT_SETTING_NAME \ - "," NM_SETTING_OVS_BRIDGE_SETTING_NAME "," NM_SETTING_OVS_INTERFACE_SETTING_NAME \ - "," NM_SETTING_OVS_PATCH_SETTING_NAME "," NM_SETTING_OVS_PORT_SETTING_NAME \ - "," NM_SETTING_GENERIC_SETTING_NAME "," NM_SETTING_DCB_SETTING_NAME \ - "," NM_SETTING_TUN_SETTING_NAME "," NM_SETTING_IP_TUNNEL_SETTING_NAME \ - "," NM_SETTING_MACSEC_SETTING_NAME "," NM_SETTING_MACVLAN_SETTING_NAME \ - "," NM_SETTING_VXLAN_SETTING_NAME "," NM_SETTING_VRF_SETTING_NAME \ - "," NM_SETTING_WPAN_SETTING_NAME "," NM_SETTING_6LOWPAN_SETTING_NAME \ - "," NM_SETTING_WIREGUARD_SETTING_NAME "," NM_SETTING_LINK_SETTING_NAME \ - "," NM_SETTING_PROXY_SETTING_NAME "," NM_SETTING_TC_CONFIG_SETTING_NAME \ - "," NM_SETTING_SRIOV_SETTING_NAME "," NM_SETTING_ETHTOOL_SETTING_NAME \ - "," NM_SETTING_OVS_DPDK_SETTING_NAME "," NM_SETTING_HOSTNAME_SETTING_NAME \ - "," NM_SETTING_HSR_SETTING_NAME "," NM_SETTING_IPVLAN_SETTING_NAME + "," NM_SETTING_PREFIX_DELEGATION_SETTING_NAME "," NM_SETTING_SERIAL_SETTING_NAME \ + "," NM_SETTING_WIFI_P2P_SETTING_NAME "," NM_SETTING_PPP_SETTING_NAME \ + "," NM_SETTING_PPPOE_SETTING_NAME "," NM_SETTING_ADSL_SETTING_NAME \ + "," NM_SETTING_GSM_SETTING_NAME "," NM_SETTING_CDMA_SETTING_NAME \ + "," NM_SETTING_BLUETOOTH_SETTING_NAME "," NM_SETTING_OLPC_MESH_SETTING_NAME \ + "," NM_SETTING_VPN_SETTING_NAME "," NM_SETTING_INFINIBAND_SETTING_NAME \ + "," NM_SETTING_BOND_SETTING_NAME "," NM_SETTING_BOND_PORT_SETTING_NAME \ + "," NM_SETTING_VLAN_SETTING_NAME "," NM_SETTING_BRIDGE_SETTING_NAME \ + "," NM_SETTING_BRIDGE_PORT_SETTING_NAME "," NM_SETTING_TEAM_SETTING_NAME \ + "," NM_SETTING_TEAM_PORT_SETTING_NAME "," NM_SETTING_OVS_BRIDGE_SETTING_NAME \ + "," NM_SETTING_OVS_INTERFACE_SETTING_NAME "," NM_SETTING_OVS_PATCH_SETTING_NAME \ + "," NM_SETTING_OVS_PORT_SETTING_NAME "," NM_SETTING_GENERIC_SETTING_NAME \ + "," NM_SETTING_DCB_SETTING_NAME "," NM_SETTING_TUN_SETTING_NAME \ + "," NM_SETTING_IP_TUNNEL_SETTING_NAME "," NM_SETTING_MACSEC_SETTING_NAME \ + "," NM_SETTING_MACVLAN_SETTING_NAME "," NM_SETTING_VXLAN_SETTING_NAME \ + "," NM_SETTING_VRF_SETTING_NAME "," NM_SETTING_WPAN_SETTING_NAME \ + "," NM_SETTING_6LOWPAN_SETTING_NAME "," NM_SETTING_WIREGUARD_SETTING_NAME \ + "," NM_SETTING_LINK_SETTING_NAME "," NM_SETTING_PROXY_SETTING_NAME \ + "," NM_SETTING_TC_CONFIG_SETTING_NAME "," NM_SETTING_SRIOV_SETTING_NAME \ + "," NM_SETTING_ETHTOOL_SETTING_NAME "," NM_SETTING_OVS_DPDK_SETTING_NAME \ + "," NM_SETTING_HOSTNAME_SETTING_NAME "," NM_SETTING_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 cf902a7e5..5b3ba3e7d 100644 --- a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in +++ b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in @@ -1912,6 +1912,12 @@ format="flags (NMSettingSecretFlags)" values="none (0x0), agent-owned (0x1), not-saved (0x2), not-required (0x4)" /> + + +