diff --git a/NEWS b/NEWS index 65260a14dc..ffd9dc43d9 100644 --- a/NEWS +++ b/NEWS @@ -47,6 +47,7 @@ USE AT YOUR OWN RISK. NOT RECOMMENDED FOR PRODUCTION USE! * WIFI connections using wpa-psk respect the setting connection.auth-retry and only prompt for new secrets during the last authentication attempt before failing. +* Add support for GENEVE interface. ============================================= NetworkManager-1.56 diff --git a/docs/api/network-manager-docs.xml b/docs/api/network-manager-docs.xml index caff6fa4fc..9916427399 100644 --- a/docs/api/network-manager-docs.xml +++ b/docs/api/network-manager-docs.xml @@ -183,6 +183,7 @@ + diff --git a/docs/libnm/libnm-docs.xml b/docs/libnm/libnm-docs.xml index 39f62417d1..719d8998a1 100644 --- a/docs/libnm/libnm-docs.xml +++ b/docs/libnm/libnm-docs.xml @@ -317,6 +317,7 @@ print ("NetworkManager version " + client.get_version())]]> + @@ -377,6 +378,7 @@ print ("NetworkManager version " + client.get_version())]]> + diff --git a/introspection/meson.build b/introspection/meson.build index 16bb5ed423..7703b46983 100644 --- a/introspection/meson.build +++ b/introspection/meson.build @@ -15,6 +15,7 @@ ifaces = [ 'org.freedesktop.NetworkManager.Device.Bridge', 'org.freedesktop.NetworkManager.Device.Dummy', 'org.freedesktop.NetworkManager.Device.Generic', + 'org.freedesktop.NetworkManager.Device.Geneve', 'org.freedesktop.NetworkManager.Device.Hsr', 'org.freedesktop.NetworkManager.Device.IPTunnel', 'org.freedesktop.NetworkManager.Device.Infiniband', diff --git a/introspection/org.freedesktop.NetworkManager.Device.Geneve.xml b/introspection/org.freedesktop.NetworkManager.Device.Geneve.xml new file mode 100644 index 0000000000..8d24c5a578 --- /dev/null +++ b/introspection/org.freedesktop.NetworkManager.Device.Geneve.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/po/POTFILES.in b/po/POTFILES.in index 20bd8f253a..b66ca45263 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -11,6 +11,7 @@ src/core/devices/nm-device-bridge.c src/core/devices/nm-device-dummy.c src/core/devices/nm-device-ethernet-utils.c src/core/devices/nm-device-ethernet.c +src/core/devices/nm-device-geneve.c src/core/devices/nm-device-infiniband.c src/core/devices/nm-device-ip-tunnel.c src/core/devices/nm-device-loopback.c @@ -46,6 +47,7 @@ src/libnm-client-impl/nm-device-bt.c src/libnm-client-impl/nm-device-dummy.c src/libnm-client-impl/nm-device-ethernet.c src/libnm-client-impl/nm-device-generic.c +src/libnm-client-impl/nm-device-geneve.c src/libnm-client-impl/nm-device-hsr.c src/libnm-client-impl/nm-device-infiniband.c src/libnm-client-impl/nm-device-ip-tunnel.c @@ -90,6 +92,7 @@ src/libnm-core-impl/nm-setting-connection.c src/libnm-core-impl/nm-setting-dcb.c src/libnm-core-impl/nm-setting-ethtool.c src/libnm-core-impl/nm-setting-generic.c +src/libnm-core-impl/nm-setting-geneve.c src/libnm-core-impl/nm-setting-gsm.c src/libnm-core-impl/nm-setting-hsr.c src/libnm-core-impl/nm-setting-infiniband.c diff --git a/src/core/devices/nm-device-factory.c b/src/core/devices/nm-device-factory.c index 1585836281..24755a5f00 100644 --- a/src/core/devices/nm-device-factory.c +++ b/src/core/devices/nm-device-factory.c @@ -412,6 +412,7 @@ nm_device_factory_manager_load_factories(NMDeviceFactoryManagerFactoryFunc callb _ADD_INTERNAL(nm_dummy_device_factory_get_type); _ADD_INTERNAL(nm_ethernet_device_factory_get_type); _ADD_INTERNAL(nm_generic_device_factory_get_type); + _ADD_INTERNAL(nm_geneve_device_factory_get_type); _ADD_INTERNAL(nm_hsr_device_factory_get_type); _ADD_INTERNAL(nm_infiniband_device_factory_get_type); _ADD_INTERNAL(nm_ip_tunnel_device_factory_get_type); diff --git a/src/core/devices/nm-device-geneve.c b/src/core/devices/nm-device-geneve.c new file mode 100644 index 0000000000..0968a2fb9b --- /dev/null +++ b/src/core/devices/nm-device-geneve.c @@ -0,0 +1,487 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2026 Red Hat, Inc. + */ + +#include "src/core/nm-default-daemon.h" + +#include "nm-manager.h" +#include "nm-device-geneve.h" + +#include "libnm-core-intern/nm-core-internal.h" +#include "nm-act-request.h" +#include "nm-device-private.h" +#include "nm-setting-geneve.h" +#include "libnm-platform/nm-platform.h" +#include "nm-device-factory.h" + +#define _NMLOG_DEVICE_TYPE NMDeviceGeneve +#include "nm-device-logging.h" + +NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceGeneve, + PROP_ID, + PROP_REMOTE, + PROP_TOS, + PROP_TTL, + PROP_DF, + PROP_DST_PORT, ); + +typedef struct { + NMPlatformLnkGeneve props; +} NMDeviceGenevePrivate; + +struct _NMDeviceGeneve { + NMDevice parent; + NMDeviceGenevePrivate _priv; +}; + +struct _NMDeviceGeneveClass { + NMDeviceClass parent; +}; + +G_DEFINE_TYPE(NMDeviceGeneve, nm_device_geneve, NM_TYPE_DEVICE) + +#define NM_DEVICE_GENEVE_GET_PRIVATE(self) \ + _NM_GET_PRIVATE(self, NMDeviceGeneve, NM_IS_DEVICE_GENEVE, NMDevice) + +/*****************************************************************************/ + +static NMDeviceCapabilities +get_generic_capabilities(NMDevice *dev) +{ + return NM_DEVICE_CAP_IS_SOFTWARE; +} + +static void +update_properties(NMDevice *device) +{ + NMDeviceGeneve *self; + NMDeviceGenevePrivate *priv; + const NMPlatformLink *plink; + const NMPlatformLnkGeneve *props; + int ifindex; + + g_return_if_fail(NM_IS_DEVICE_GENEVE(device)); + self = NM_DEVICE_GENEVE(device); + priv = NM_DEVICE_GENEVE_GET_PRIVATE(self); + + ifindex = nm_device_get_ifindex(device); + g_return_if_fail(ifindex > 0); + props = nm_platform_link_get_lnk_geneve(nm_device_get_platform(device), ifindex, &plink); + + if (!props) { + _LOGW(LOGD_PLATFORM, "could not get GENEVE properties"); + return; + } + + g_object_freeze_notify((GObject *) device); + +#define CHECK_PROPERTY_CHANGED(field, prop) \ + G_STMT_START \ + { \ + if (priv->props.field != props->field) { \ + priv->props.field = props->field; \ + _notify(self, prop); \ + } \ + } \ + G_STMT_END + +#define CHECK_PROPERTY_CHANGED_IN6ADDR(field, prop) \ + G_STMT_START \ + { \ + if (memcmp(&priv->props.field, &props->field, sizeof(props->field)) != 0) { \ + priv->props.field = props->field; \ + _notify(self, prop); \ + } \ + } \ + G_STMT_END + + CHECK_PROPERTY_CHANGED(id, PROP_ID); + CHECK_PROPERTY_CHANGED(remote, PROP_REMOTE); + CHECK_PROPERTY_CHANGED_IN6ADDR(remote6, PROP_REMOTE); + CHECK_PROPERTY_CHANGED(tos, PROP_TOS); + CHECK_PROPERTY_CHANGED(ttl, PROP_TTL); + CHECK_PROPERTY_CHANGED(df, PROP_DF); + CHECK_PROPERTY_CHANGED(dst_port, PROP_DST_PORT); + + g_object_thaw_notify((GObject *) device); +} + +static void +link_changed(NMDevice *device, const NMPlatformLink *pllink) +{ + NM_DEVICE_CLASS(nm_device_geneve_parent_class)->link_changed(device, pllink); + update_properties(device); +} + +static void +unrealize_notify(NMDevice *device) +{ + NMDeviceGeneve *self = NM_DEVICE_GENEVE(device); + NMDeviceGenevePrivate *priv = NM_DEVICE_GENEVE_GET_PRIVATE(self); + guint i; + + NM_DEVICE_CLASS(nm_device_geneve_parent_class)->unrealize_notify(device); + + memset(&priv->props, 0, sizeof(NMPlatformLnkGeneve)); + + for (i = 1; i < _PROPERTY_ENUMS_LAST; i++) + g_object_notify_by_pspec(G_OBJECT(self), obj_properties[i]); +} + +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); + NMPlatformLnkGeneve props = {}; + NMSettingGeneve *s_geneve; + const char *str; + int r; + + s_geneve = nm_connection_get_setting_geneve(connection); + g_return_val_if_fail(s_geneve, FALSE); + + props.id = nm_setting_geneve_get_id(s_geneve); + + str = nm_setting_geneve_get_remote(s_geneve); + if (!nm_inet_parse_bin(AF_INET, str, NULL, &props.remote) + && !nm_inet_parse_bin(AF_INET6, str, NULL, &props.remote6)) { + return nm_assert_unreachable_val(FALSE); + } + props.tos = nm_setting_geneve_get_tos(s_geneve); + props.ttl = nm_setting_geneve_get_ttl(s_geneve); + props.df = nm_setting_geneve_get_df(s_geneve); + props.dst_port = nm_setting_geneve_get_destination_port(s_geneve); + + r = nm_platform_link_geneve_add(nm_device_get_platform(device), iface, &props, out_plink); + if (r < 0) { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create geneve interface '%s' for '%s': %s", + iface, + nm_connection_get_id(connection), + nm_strerror(r)); + return FALSE; + } + + return TRUE; +} + +static gboolean +address_matches(const char *candidate, in_addr_t addr4, struct in6_addr *addr6) +{ + NMIPAddr candidate_addr; + int addr_family; + + if (!candidate) + return addr4 == 0u && IN6_IS_ADDR_UNSPECIFIED(addr6); + + if (!nm_inet_parse_bin(AF_UNSPEC, candidate, &addr_family, &candidate_addr)) + return FALSE; + + if (!nm_ip_addr_equal(addr_family, + &candidate_addr, + NM_IS_IPv4(addr_family) ? (gpointer) &addr4 : addr6)) + return FALSE; + + if (NM_IS_IPv4(addr_family)) + return IN6_IS_ADDR_UNSPECIFIED(addr6); + else + return addr4 == 0u; +} + +static gboolean +check_connection_compatible(NMDevice *device, + NMConnection *connection, + gboolean check_properties, + GError **error) +{ + NMDeviceGenevePrivate *priv = NM_DEVICE_GENEVE_GET_PRIVATE(device); + NMSettingGeneve *s_geneve; + + if (!NM_DEVICE_CLASS(nm_device_geneve_parent_class) + ->check_connection_compatible(device, connection, check_properties, error)) + return FALSE; + + if (check_properties && nm_device_is_real(device)) { + s_geneve = nm_connection_get_setting_geneve(connection); + + if (priv->props.id != nm_setting_geneve_get_id(s_geneve)) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "geneve id mismatches"); + return FALSE; + } + + if (!address_matches(nm_setting_geneve_get_remote(s_geneve), + priv->props.remote, + &priv->props.remote6)) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "geneve remote address mismatches"); + return FALSE; + } + + if (priv->props.dst_port != nm_setting_geneve_get_destination_port(s_geneve)) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "geneve destination port mismatches"); + return FALSE; + } + + if (priv->props.tos != nm_setting_geneve_get_tos(s_geneve)) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "geneve TOS mismatches"); + return FALSE; + } + + if (priv->props.ttl != nm_setting_geneve_get_ttl(s_geneve)) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "geneve TTL mismatches"); + return FALSE; + } + + if (priv->props.df != nm_setting_geneve_get_df(s_geneve)) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "geneve DF mismatches"); + return FALSE; + } + } + + return TRUE; +} + +static gboolean +complete_connection(NMDevice *device, + NMConnection *connection, + const char *specific_object, + NMConnection *const *existing_connections, + GError **error) +{ + NMSettingGeneve *s_geneve; + + nm_utils_complete_generic(nm_device_get_platform(device), + connection, + NM_SETTING_GENEVE_SETTING_NAME, + existing_connections, + NULL, + _("Geneve connection"), + NULL, + NULL); + + s_geneve = nm_connection_get_setting_geneve(connection); + if (!s_geneve) { + g_set_error_literal(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_CONNECTION, + "A 'geneve' setting is required."); + return FALSE; + } + + return TRUE; +} + +static void +update_connection(NMDevice *device, NMConnection *connection) +{ + NMDeviceGenevePrivate *priv = NM_DEVICE_GENEVE_GET_PRIVATE(device); + NMSettingGeneve *s_geneve = _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_GENEVE); + char sbuf[NM_INET_ADDRSTRLEN]; + + if (priv->props.id != nm_setting_geneve_get_id(s_geneve)) + g_object_set(G_OBJECT(s_geneve), NM_SETTING_GENEVE_ID, priv->props.id, NULL); + + /* Handle remote (IPv4 or IPv6) */ + if (priv->props.remote) { + g_object_set(s_geneve, + NM_SETTING_GENEVE_REMOTE, + nm_inet4_ntop(priv->props.remote, sbuf), + NULL); + } else if (memcmp(&priv->props.remote6, &in6addr_any, sizeof(in6addr_any))) { + g_object_set(s_geneve, + NM_SETTING_GENEVE_REMOTE, + nm_inet6_ntop(&priv->props.remote6, sbuf), + NULL); + } + + if (priv->props.dst_port != nm_setting_geneve_get_destination_port(s_geneve)) + g_object_set(G_OBJECT(s_geneve), + NM_SETTING_GENEVE_DESTINATION_PORT, + priv->props.dst_port, + NULL); + + if (priv->props.tos != nm_setting_geneve_get_tos(s_geneve)) + g_object_set(G_OBJECT(s_geneve), NM_SETTING_GENEVE_TOS, priv->props.tos, NULL); + + if (priv->props.ttl != nm_setting_geneve_get_ttl(s_geneve)) + g_object_set(G_OBJECT(s_geneve), NM_SETTING_GENEVE_TTL, priv->props.ttl, NULL); + + if (priv->props.df != nm_setting_geneve_get_df(s_geneve)) + g_object_set(G_OBJECT(s_geneve), NM_SETTING_GENEVE_DF, priv->props.df, NULL); +} + +static void +get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + NMDeviceGenevePrivate *priv = NM_DEVICE_GENEVE_GET_PRIVATE(object); + + switch (prop_id) { + case PROP_ID: + g_value_set_uint(value, priv->props.id); + break; + case PROP_REMOTE: + if (priv->props.remote) + g_value_take_string(value, nm_inet4_ntop_dup(priv->props.remote)); + else if (!IN6_IS_ADDR_UNSPECIFIED(&priv->props.remote6)) + g_value_take_string(value, nm_inet6_ntop_dup(&priv->props.remote6)); + break; + case PROP_TOS: + g_value_set_uchar(value, priv->props.tos); + break; + case PROP_TTL: + g_value_set_uchar(value, priv->props.ttl); + break; + case PROP_DF: + g_value_set_uint(value, priv->props.df); + break; + case PROP_DST_PORT: + g_value_set_uint(value, priv->props.dst_port); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +/*****************************************************************************/ + +static void +nm_device_geneve_init(NMDeviceGeneve *self) +{} + +static const NMDBusInterfaceInfoExtended interface_info_device_geneve = { + .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( + NM_DBUS_INTERFACE_DEVICE_GENEVE, + .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Id", "u", NM_DEVICE_GENEVE_ID), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Remote", "s", NM_DEVICE_GENEVE_REMOTE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Tos", "y", NM_DEVICE_GENEVE_TOS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Ttl", "y", NM_DEVICE_GENEVE_TTL), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Df", "u", NM_DEVICE_GENEVE_DF), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("DstPort", + "q", + NM_DEVICE_GENEVE_DST_PORT), ), ), +}; + +static void +nm_device_geneve_class_init(NMDeviceGeneveClass *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_geneve); + + device_class->connection_type_supported = NM_SETTING_GENEVE_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_GENEVE_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_GENEVE); + + device_class->link_changed = link_changed; + device_class->unrealize_notify = unrealize_notify; + device_class->create_and_realize = create_and_realize; + device_class->check_connection_compatible = check_connection_compatible; + device_class->complete_connection = complete_connection; + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->update_connection = update_connection; + + obj_properties[PROP_ID] = g_param_spec_uint(NM_DEVICE_GENEVE_ID, + "", + "", + 0, + G_MAXUINT32, + 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_REMOTE] = g_param_spec_string(NM_DEVICE_GENEVE_REMOTE, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_TOS] = g_param_spec_uchar(NM_DEVICE_GENEVE_TOS, + "", + "", + 0, + 255, + 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_TTL] = g_param_spec_uchar(NM_DEVICE_GENEVE_TTL, + "", + "", + 0, + 255, + 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_DF] = g_param_spec_uint(NM_DEVICE_GENEVE_DF, + "", + "", + 0, + 2, + 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_DST_PORT] = g_param_spec_uint(NM_DEVICE_GENEVE_DST_PORT, + "", + "", + 0, + 65535, + 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); +} + +/*****************************************************************************/ + +#define NM_TYPE_GENEVE_DEVICE_FACTORY (nm_geneve_device_factory_get_type()) +#define NM_GENEVE_DEVICE_FACTORY(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_GENEVE_DEVICE_FACTORY, NMGeneveDeviceFactory)) + +static NMDevice * +create_device(NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) +{ + return g_object_new(NM_TYPE_DEVICE_GENEVE, + NM_DEVICE_IFACE, + iface, + NM_DEVICE_TYPE_DESC, + "Geneve", + NM_DEVICE_DEVICE_TYPE, + NM_DEVICE_TYPE_GENEVE, + NM_DEVICE_LINK_TYPE, + NM_LINK_TYPE_GENEVE, + NULL); +} + +NM_DEVICE_FACTORY_DEFINE_INTERNAL( + GENEVE, + Geneve, + geneve, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_GENEVE) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_GENEVE_SETTING_NAME), + factory_class->create_device = create_device;); diff --git a/src/core/devices/nm-device-geneve.h b/src/core/devices/nm-device-geneve.h new file mode 100644 index 0000000000..d0a44e9dbb --- /dev/null +++ b/src/core/devices/nm-device-geneve.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2026 Red Hat, Inc. + */ + +#ifndef __NETWORKMANAGER_DEVICE_GENEVE_H__ +#define __NETWORKMANAGER_DEVICE_GENEVE_H__ + +#include "nm-device.h" + +#define NM_TYPE_DEVICE_GENEVE (nm_device_geneve_get_type()) +#define NM_DEVICE_GENEVE(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_GENEVE, NMDeviceGeneve)) +#define NM_DEVICE_GENEVE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_GENEVE, NMDeviceGeneveClass)) +#define NM_IS_DEVICE_GENEVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_GENEVE)) +#define NM_IS_DEVICE_GENEVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_GENEVE)) +#define NM_DEVICE_GENEVE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_GENEVE, NMDeviceGeneveClass)) + +#define NM_DEVICE_GENEVE_ID "id" +#define NM_DEVICE_GENEVE_REMOTE "remote" +#define NM_DEVICE_GENEVE_TOS "tos" +#define NM_DEVICE_GENEVE_TTL "ttl" +#define NM_DEVICE_GENEVE_DF "df" +#define NM_DEVICE_GENEVE_DST_PORT "dst-port" + +typedef struct _NMDeviceGeneve NMDeviceGeneve; +typedef struct _NMDeviceGeneveClass NMDeviceGeneveClass; + +GType nm_device_geneve_get_type(void); + +#endif /* __NETWORKMANAGER_DEVICE_GENEVE_H__ */ diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index 434683d6b4..f3f09db18c 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -5962,7 +5962,6 @@ nm_device_get_route_metric_default(NMDeviceType device_type) * in some aspects a VPN. */ case NM_DEVICE_TYPE_WIREGUARD: return NM_VPN_ROUTE_METRIC_DEFAULT; - case NM_DEVICE_TYPE_ETHERNET: case NM_DEVICE_TYPE_VETH: return 100; @@ -5996,6 +5995,8 @@ nm_device_get_route_metric_default(NMDeviceType device_type) return 470; case NM_DEVICE_TYPE_VXLAN: return 500; + case NM_DEVICE_TYPE_GENEVE: + return 525; case NM_DEVICE_TYPE_DUMMY: return 550; case NM_DEVICE_TYPE_WIFI: @@ -19567,7 +19568,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_IPVLAN); + nm_assert(priv->type <= NM_DEVICE_TYPE_GENEVE); break; case PROP_LINK_TYPE: /* construct-only */ diff --git a/src/core/meson.build b/src/core/meson.build index 26d27f96e2..4a3dfd8e11 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -111,6 +111,7 @@ libNetworkManager = static_library( 'devices/nm-device-ethernet-utils.c', 'devices/nm-device-factory.c', 'devices/nm-device-generic.c', + 'devices/nm-device-geneve.c', 'devices/nm-device-hsr.c', 'devices/nm-device-infiniband.c', 'devices/nm-device-ip-tunnel.c', diff --git a/src/core/nm-ip-config.c b/src/core/nm-ip-config.c index 51a069f801..4616f2e4a3 100644 --- a/src/core/nm-ip-config.c +++ b/src/core/nm-ip-config.c @@ -56,7 +56,7 @@ G_DEFINE_ABSTRACT_TYPE(NMIPConfig, nm_ip_config, NM_TYPE_DBUS_OBJECT) /*****************************************************************************/ -static void _handle_platform_change(NMIPConfig *self, guint32 obj_type_flags, gboolean is_init); +static void _handle_platform_change(NMIPConfig *self, guint64 obj_type_flags, gboolean is_init); static void _handle_l3cd_changed(NMIPConfig *self, const NML3ConfigData *l3cd); /*****************************************************************************/ @@ -77,7 +77,7 @@ static void _notify_platform_handle(NMIPConfig *self, gint64 now_msec) { NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self); - guint32 obj_type_flags; + guint64 obj_type_flags; nm_clear_g_source_inst(&priv->notify_platform_timeout_source); @@ -98,7 +98,7 @@ _notify_platform_cb(gpointer user_data) } static void -_notify_platform(NMIPConfig *self, guint32 obj_type_flags) +_notify_platform(NMIPConfig *self, guint64 obj_type_flags) { const int addr_family = nm_ip_config_get_addr_family(self); const int IS_IPv4 = NM_IS_IPv4(addr_family); @@ -953,7 +953,7 @@ _handle_l3cd_changed(NMIPConfig *self, const NML3ConfigData *l3cd) } static void -_handle_platform_change(NMIPConfig *self, guint32 obj_type_flags, gboolean is_init) +_handle_platform_change(NMIPConfig *self, guint64 obj_type_flags, gboolean is_init) { const int addr_family = nm_ip_config_get_addr_family(self); const int IS_IPv4 = NM_IS_IPv4(addr_family); diff --git a/src/core/nm-ip-config.h b/src/core/nm-ip-config.h index 47a40bd223..02d654c4fd 100644 --- a/src/core/nm-ip-config.h +++ b/src/core/nm-ip-config.h @@ -35,7 +35,7 @@ struct _NMIPConfigPrivate { GSource *notify_platform_timeout_source; gint64 notify_platform_rlimited_until_msec; gulong l3cfg_notify_id; - guint32 notify_platform_obj_type_flags; + guint64 notify_platform_obj_type_flags; }; struct _NMIPConfig { diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c index 9bb272df10..59fc6e4d7f 100644 --- a/src/core/nm-l3cfg.c +++ b/src/core/nm-l3cfg.c @@ -657,7 +657,7 @@ _l3_config_notify_data_to_string(const NML3ConfigNotifyData *notify_data, case NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE: nm_strbuf_append(&s, &l, - ", obj-type-flags=0x%x", + ", obj-type-flags=0x%" G_GINT64_MODIFIER "x", notify_data->platform_change_on_idle.obj_type_flags); break; case NM_L3_CONFIG_NOTIFY_TYPE_IPV4LL_EVENT: @@ -1604,7 +1604,7 @@ _load_link(NML3Cfg *self, gboolean initial) /*****************************************************************************/ void -_nm_l3cfg_notify_platform_change_on_idle(NML3Cfg *self, guint32 obj_type_flags) +_nm_l3cfg_notify_platform_change_on_idle(NML3Cfg *self, guint64 obj_type_flags) { NML3ConfigNotifyData notify_data; diff --git a/src/core/nm-l3cfg.h b/src/core/nm-l3cfg.h index 5f0721da3c..c103c9f233 100644 --- a/src/core/nm-l3cfg.h +++ b/src/core/nm-l3cfg.h @@ -178,7 +178,7 @@ typedef struct { } platform_change; struct { - guint32 obj_type_flags; + guint64 obj_type_flags; } platform_change_on_idle; struct { @@ -207,7 +207,7 @@ struct _NML3Cfg { * NML3Cfg instance. We track some per-l3cfg-data that is only * relevant to NMNetns here. */ struct { - guint32 signal_pending_obj_type_flags; + guint64 signal_pending_obj_type_flags; CList signal_pending_lst; CList ecmp_track_ifindex_lst_head; } internal_netns; @@ -223,7 +223,7 @@ NML3Cfg *nm_l3cfg_new(NMNetns *netns, int ifindex); gboolean nm_l3cfg_is_ready(NML3Cfg *self); -void _nm_l3cfg_notify_platform_change_on_idle(NML3Cfg *self, guint32 obj_type_flags); +void _nm_l3cfg_notify_platform_change_on_idle(NML3Cfg *self, guint64 obj_type_flags); void _nm_l3cfg_notify_platform_change(NML3Cfg *self, NMPlatformSignalChangeType change_type, diff --git a/src/core/platform/tests/test-common.c b/src/core/platform/tests/test-common.c index 91445b30f8..f1f7caee7a 100644 --- a/src/core/platform/tests/test-common.c +++ b/src/core/platform/tests/test-common.c @@ -1230,7 +1230,7 @@ out: } gboolean -nmtstp_check_platform_full(NMPlatform *platform, guint32 obj_type_flags, gboolean do_assert) +nmtstp_check_platform_full(NMPlatform *platform, guint64 obj_type_flags, gboolean do_assert) { static const NMPObjectType obj_types[] = { NMP_OBJECT_TYPE_IP4_ADDRESS, @@ -1265,7 +1265,7 @@ nmtstp_check_platform_full(NMPlatform *platform, guint32 obj_type_flags, gboolea for (i_obj_types = 0; i_obj_types < (int) G_N_ELEMENTS(obj_types); i_obj_types++) { const NMPObjectType obj_type = obj_types[i_obj_types]; - const guint32 i_obj_type_flags = nmp_object_type_to_flags(obj_type); + const guint64 i_obj_type_flags = nmp_object_type_to_flags(obj_type); gs_unref_ptrarray GPtrArray *arr1 = NULL; gs_unref_ptrarray GPtrArray *arr2 = NULL; NMPLookup lookup; @@ -1408,7 +1408,7 @@ nmtstp_check_platform_full(NMPlatform *platform, guint32 obj_type_flags, gboolea } void -nmtstp_check_platform(NMPlatform *platform, guint32 obj_type_flags) +nmtstp_check_platform(NMPlatform *platform, guint64 obj_type_flags) { if (!nmtstp_check_platform_full(platform, obj_type_flags, FALSE)) { /* It's unclear why this failure sometimes happens. It happens @@ -2393,6 +2393,61 @@ nmtstp_link_dummy_add(NMPlatform *platform, int external_command, const char *na return pllink; } +const NMPlatformLink * +nmtstp_link_geneve_add(NMPlatform *platform, + int external_command, + const char *name, + const NMPlatformLnkGeneve *lnk) +{ + const NMPlatformLink *pllink = NULL; + int success; + + g_assert(nm_utils_ifname_valid_kernel(name, NULL)); + g_assert(lnk->remote || !IN6_IS_ADDR_UNSPECIFIED(&lnk->remote6)); + + external_command = nmtstp_run_command_check_external(external_command); + + _init_platform(&platform, external_command); + + if (external_command) { + char remote[NM_INET_ADDRSTRLEN]; + char remote6[NM_INET_ADDRSTRLEN]; + char str_ttl[30]; + + if (lnk->remote) + nm_inet4_ntop(lnk->remote, remote); + else + remote[0] = '\0'; + + if (memcmp(&lnk->remote6, &in6addr_any, sizeof(in6addr_any))) + nm_inet6_ntop(&lnk->remote6, remote6); + else + remote6[0] = '\0'; + + success = !nmtstp_run_command( + "ip link add %s type geneve id %u remote %s %s tos %02x dstport %u%s", + name, + lnk->id, + remote[0] ? remote : remote6, + lnk->ttl > 0 ? nm_sprintf_buf(str_ttl, "ttl %u", lnk->ttl & 0xff) + : lnk->ttl == 0 ? "ttl auto" + : "ttl inherit", + lnk->tos, + lnk->dst_port, + lnk->df == 1 ? " df set " + : lnk->df == 2 ? " df inherit " + : ""); + + if (success) + pllink = nmtstp_assert_wait_for_link(platform, name, NM_LINK_TYPE_GENEVE, 100); + } else + success = NMTST_NM_ERR_SUCCESS(nm_platform_link_geneve_add(platform, name, lnk, &pllink)); + + _assert_pllink(platform, success, pllink, name, NM_LINK_TYPE_GENEVE); + + return pllink; +} + const NMPlatformLink * nmtstp_link_gre_add(NMPlatform *platform, int external_command, @@ -3024,8 +3079,6 @@ nmtstp_link_vxlan_add(NMPlatform *platform, return pllink; } -/*****************************************************************************/ - const NMPlatformLink * nmtstp_link_get_typed(NMPlatform *platform, int ifindex, const char *name, NMLinkType link_type) { diff --git a/src/core/platform/tests/test-common.h b/src/core/platform/tests/test-common.h index 85ed79615b..251fa51090 100644 --- a/src/core/platform/tests/test-common.h +++ b/src/core/platform/tests/test-common.h @@ -140,9 +140,9 @@ int nmtstp_run_command(const char *format, ...) _nm_printf(1, 2); /*****************************************************************************/ gboolean -nmtstp_check_platform_full(NMPlatform *platform, guint32 obj_type_flags, gboolean do_assert); +nmtstp_check_platform_full(NMPlatform *platform, guint64 obj_type_flags, gboolean do_assert); -void nmtstp_check_platform(NMPlatform *platform, guint32 obj_type_flags); +void nmtstp_check_platform(NMPlatform *platform, guint64 obj_type_flags); /*****************************************************************************/ @@ -474,6 +474,10 @@ const NMPlatformLink *nmtstp_link_veth_add(NMPlatform *platform, const char *peer); const NMPlatformLink * nmtstp_link_dummy_add(NMPlatform *platform, int external_command, const char *name); +const NMPlatformLink *nmtstp_link_geneve_add(NMPlatform *platform, + int external_command, + const char *name, + const NMPlatformLnkGeneve *lnk); const NMPlatformLink *nmtstp_link_gre_add(NMPlatform *platform, int external_command, const char *name, diff --git a/src/core/platform/tests/test-link.c b/src/core/platform/tests/test-link.c index 77e7e64121..5618308f80 100644 --- a/src/core/platform/tests/test-link.c +++ b/src/core/platform/tests/test-link.c @@ -1388,10 +1388,11 @@ test_software_detect(gconstpointer user_data) const gboolean ext = test_data->external_command; NMPlatformLnkBridge lnk_bridge = {}; NMPlatformLnkTun lnk_tun; - NMPlatformLnkGre lnk_gre = {}; - NMPlatformLnkVti lnk_vti = {}; - NMPlatformLnkVti6 lnk_vti6 = {}; - nm_auto_close int tun_fd = -1; + NMPlatformLnkGeneve lnk_geneve = {}; + NMPlatformLnkGre lnk_gre = {}; + NMPlatformLnkVti lnk_vti = {}; + NMPlatformLnkVti6 lnk_vti6 = {}; + nm_auto_close int tun_fd = -1; gboolean module_loaded; nmtstp_run_command_check("ip link add %s type dummy", PARENT_NAME); @@ -1434,6 +1435,31 @@ test_software_detect(gconstpointer user_data) g_error("Failed adding Bridge interface"); break; + case NM_LINK_TYPE_GENEVE: + { + switch (test_data->test_mode) { + case 0: + lnk_geneve.id = 42; + lnk_geneve.remote = nmtst_inet4_from_string("192.168.1.100"); + lnk_geneve.ttl = 64; + lnk_geneve.tos = 0; + lnk_geneve.dst_port = 6081; + lnk_geneve.df = 0; + break; + case 1: + lnk_geneve.id = 12345; + lnk_geneve.remote6 = nmtst_inet6_from_string("2001:db8::1"); + lnk_geneve.ttl = 128; + lnk_geneve.tos = 16; + lnk_geneve.dst_port = 6082; + lnk_geneve.df = 1; + break; + } + + g_assert(nmtstp_link_geneve_add(NULL, ext, DEVICE_NAME, &lnk_geneve)); + break; + } + case NM_LINK_TYPE_GRE: module_loaded = nmtstp_ensure_module("ip_gre"); @@ -2208,6 +2234,34 @@ test_software_detect(gconstpointer user_data) } break; } + case NM_LINK_TYPE_GENEVE: + { + const NMPlatformLnkGeneve *plnk = &lnk->lnk_geneve; + + g_assert(plnk == nm_platform_link_get_lnk_geneve(NM_PLATFORM_GET, ifindex, NULL)); + + switch (test_data->test_mode) { + case 0: + g_assert_cmpint(plnk->id, ==, 42); + nmtst_assert_ip4_address(plnk->remote, "192.168.1.100"); + nmtst_assert_ip6_address(&plnk->remote6, "::"); + g_assert_cmpint(plnk->ttl, ==, 64); + g_assert_cmpint(plnk->tos, ==, 0); + g_assert_cmpint(plnk->dst_port, ==, 6081); + g_assert_cmpint(plnk->df, ==, 0); + break; + case 1: + g_assert_cmpint(plnk->id, ==, 12345); + nmtst_assert_ip4_address(plnk->remote, "0.0.0.0"); + nmtst_assert_ip6_address(&plnk->remote6, "2001:db8::1"); + g_assert_cmpint(plnk->ttl, ==, 128); + g_assert_cmpint(plnk->tos, ==, 16); + g_assert_cmpint(plnk->dst_port, ==, 6082); + g_assert_cmpint(plnk->df, ==, 1); + break; + } + break; + } case NM_LINK_TYPE_WIREGUARD: { const NMPlatformLnkWireGuard *plnk = &lnk->lnk_wireguard; @@ -4143,6 +4197,8 @@ _nmtstp_setup_tests(void) g_test_add_func("/link/external", test_external); test_software_detect_add("/link/software/detect/bridge", NM_LINK_TYPE_BRIDGE, 0); + test_software_detect_add("/link/software/detect/geneve/0", NM_LINK_TYPE_GENEVE, 0); + test_software_detect_add("/link/software/detect/geneve/1", NM_LINK_TYPE_GENEVE, 1); test_software_detect_add("/link/software/detect/gre", NM_LINK_TYPE_GRE, 0); test_software_detect_add("/link/software/detect/gretap", NM_LINK_TYPE_GRETAP, 0); test_software_detect_add("/link/software/detect/ip6tnl/0", NM_LINK_TYPE_IP6TNL, 0); diff --git a/src/libnm-client-impl/libnm.ver b/src/libnm-client-impl/libnm.ver index 5678a90d09..e9850ea6e5 100644 --- a/src/libnm-client-impl/libnm.ver +++ b/src/libnm-client-impl/libnm.ver @@ -2106,8 +2106,25 @@ global: libnm_1_58_0 { global: + nm_connection_get_setting_geneve; + nm_device_geneve_get_df; + nm_device_geneve_get_dst_port; + nm_device_geneve_get_id; + nm_device_geneve_get_remote; + nm_device_geneve_get_tos; + nm_device_geneve_get_ttl; + nm_device_geneve_get_type; nm_ip_config_get_clat_address; nm_ip_config_get_clat_pref64; + nm_setting_geneve_df_get_type; + nm_setting_geneve_get_destination_port; + nm_setting_geneve_get_df; + nm_setting_geneve_get_id; + nm_setting_geneve_get_remote; + nm_setting_geneve_get_tos; + nm_setting_geneve_get_ttl; + nm_setting_geneve_get_type; + nm_setting_geneve_new; nm_setting_ip4_config_clat_get_type; nm_setting_ip4_config_get_clat; nm_utils_wifi_6ghz_freqs; diff --git a/src/libnm-client-impl/meson.build b/src/libnm-client-impl/meson.build index b49366292f..3352ebfee0 100644 --- a/src/libnm-client-impl/meson.build +++ b/src/libnm-client-impl/meson.build @@ -16,6 +16,7 @@ libnm_client_impl_sources = files( 'nm-device-bt.c', 'nm-device-dummy.c', 'nm-device-ethernet.c', + 'nm-device-geneve.c', 'nm-device-generic.c', 'nm-device-hsr.c', 'nm-device-infiniband.c', diff --git a/src/libnm-client-impl/nm-client.c b/src/libnm-client-impl/nm-client.c index b81ac6e506..f13835269e 100644 --- a/src/libnm-client-impl/nm-client.c +++ b/src/libnm-client-impl/nm-client.c @@ -29,6 +29,7 @@ #include "nm-device-dummy.h" #include "nm-device-ethernet.h" #include "nm-device-generic.h" +#include "nm-device-geneve.h" #include "nm-device-hsr.h" #include "nm-device-infiniband.h" #include "nm-device-ip-tunnel.h" diff --git a/src/libnm-client-impl/nm-device-geneve.c b/src/libnm-client-impl/nm-device-geneve.c new file mode 100644 index 0000000000..415e978d16 --- /dev/null +++ b/src/libnm-client-impl/nm-device-geneve.c @@ -0,0 +1,344 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2026 Red Hat, Inc. + */ + +#include "libnm-client-impl/nm-default-libnm.h" + +#include "nm-device-geneve.h" + +#include "nm-setting-connection.h" +#include "nm-setting-geneve.h" +#include "nm-utils.h" +#include "nm-object-private.h" + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_ID, + PROP_REMOTE, + PROP_TOS, + PROP_TTL, + PROP_DST_PORT, + PROP_DF, ); + +typedef struct { + char *remote; + guint32 id; + gint32 ttl; + guint16 dst_port; + guint8 df; + guint8 tos; +} NMDeviceGenevePrivate; + +struct _NMDeviceGeneve { + NMDevice parent; + NMDeviceGenevePrivate _priv; +}; + +struct _NMDeviceGeneveClass { + NMDeviceClass parent; +}; + +G_DEFINE_TYPE(NMDeviceGeneve, nm_device_geneve, NM_TYPE_DEVICE) + +#define NM_DEVICE_GENEVE_GET_PRIVATE(self) \ + _NM_GET_PRIVATE(self, NMDeviceGeneve, NM_IS_DEVICE_GENEVE, NMObject, NMDevice) + +/*****************************************************************************/ + +/** + * nm_device_geneve_get_id: + * @device: a #NMDeviceGeneve + * + * Returns: the device's GENEVE ID. + * + * Since: 1.58 + **/ +guint +nm_device_geneve_get_id(NMDeviceGeneve *device) +{ + g_return_val_if_fail(NM_IS_DEVICE_GENEVE(device), 0); + + return NM_DEVICE_GENEVE_GET_PRIVATE(device)->id; +} + +/** + * nm_device_geneve_get_remote: + * @device: a #NMDeviceGeneve + * + * Returns: the IP address of the remote tunnel endpoint + * + * Since: 1.58 + **/ +const char * +nm_device_geneve_get_remote(NMDeviceGeneve *device) +{ + g_return_val_if_fail(NM_IS_DEVICE_GENEVE(device), NULL); + + return _nml_coerce_property_str_not_empty(NM_DEVICE_GENEVE_GET_PRIVATE(device)->remote); +} + +/** + * nm_device_geneve_get_dst_port: + * @device: a #NMDeviceGeneve + * + * Returns: the UDP destination port + * + * Since: 1.58 + **/ +guint +nm_device_geneve_get_dst_port(NMDeviceGeneve *device) +{ + g_return_val_if_fail(NM_IS_DEVICE_GENEVE(device), 0); + + return NM_DEVICE_GENEVE_GET_PRIVATE(device)->dst_port; +} + +/** + * nm_device_geneve_get_tos: + * @device: a #NMDeviceGeneve + * + * Returns: the TOS value to use in outgoing packets + * + * Since: 1.58 + **/ +guint +nm_device_geneve_get_tos(NMDeviceGeneve *device) +{ + g_return_val_if_fail(NM_IS_DEVICE_GENEVE(device), 0); + + return NM_DEVICE_GENEVE_GET_PRIVATE(device)->tos; +} + +/** + * nm_device_geneve_get_ttl: + * @device: a #NMDeviceGeneve + * + * Returns: the time-to-live value to use in outgoing packets + * + * Since: 1.58 + **/ +guint +nm_device_geneve_get_ttl(NMDeviceGeneve *device) +{ + g_return_val_if_fail(NM_IS_DEVICE_GENEVE(device), 0); + + return NM_DEVICE_GENEVE_GET_PRIVATE(device)->ttl; +} + +/** + * nm_device_geneve_get_df: + * @device: a #NMDeviceGeneve + * + * Returns: the Don't Fragment (DF) bit to set in outgoing packets + * + * Since: 1.58 + **/ +guint +nm_device_geneve_get_df(NMDeviceGeneve *device) +{ + g_return_val_if_fail(NM_IS_DEVICE_GENEVE(device), 0); + + return NM_DEVICE_GENEVE_GET_PRIVATE(device)->df; +} + +static gboolean +connection_compatible(NMDevice *device, NMConnection *connection, GError **error) +{ + NMSettingGeneve *s_geneve; + + if (!NM_DEVICE_CLASS(nm_device_geneve_parent_class) + ->connection_compatible(device, connection, error)) + return FALSE; + + if (!nm_connection_is_type(connection, NM_SETTING_GENEVE_SETTING_NAME)) { + g_set_error_literal(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, + _("The connection was not a GENEVE connection.")); + return FALSE; + } + + s_geneve = nm_connection_get_setting_geneve(connection); + if (nm_setting_geneve_get_id(s_geneve) != nm_device_geneve_get_id(NM_DEVICE_GENEVE(device))) { + g_set_error_literal( + error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, + _("The GENEVE identifiers of the device and the connection didn't match.")); + return FALSE; + } + + return TRUE; +} + +static GType +get_setting_type(NMDevice *device) +{ + return NM_TYPE_SETTING_GENEVE; +} + +/*****************************************************************************/ + +static void +get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + NMDeviceGeneve *device = NM_DEVICE_GENEVE(object); + + switch (prop_id) { + case PROP_ID: + g_value_set_uint(value, nm_device_geneve_get_id(device)); + break; + case PROP_REMOTE: + g_value_set_string(value, nm_device_geneve_get_remote(device)); + break; + case PROP_TOS: + g_value_set_uint(value, nm_device_geneve_get_tos(device)); + break; + case PROP_TTL: + g_value_set_int(value, nm_device_geneve_get_ttl(device)); + break; + case PROP_DST_PORT: + g_value_set_uint(value, nm_device_geneve_get_dst_port(device)); + break; + case PROP_DF: + g_value_set_uint(value, nm_device_geneve_get_df(device)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +nm_device_geneve_init(NMDeviceGeneve *device) +{} + +static void +finalize(GObject *object) +{ + NMDeviceGenevePrivate *priv = NM_DEVICE_GENEVE_GET_PRIVATE(object); + + g_free(priv->remote); + + G_OBJECT_CLASS(nm_device_geneve_parent_class)->finalize(object); +} + +const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_geneve = NML_DBUS_META_IFACE_INIT_PROP( + NM_DBUS_INTERFACE_DEVICE_GENEVE, + nm_device_geneve_get_type, + NML_DBUS_META_INTERFACE_PRIO_INSTANTIATE_30, + NML_DBUS_META_IFACE_DBUS_PROPERTIES( + NML_DBUS_META_PROPERTY_INIT_Y("Df", PROP_DF, NMDeviceGeneve, _priv.df), + NML_DBUS_META_PROPERTY_INIT_Q("DstPort", PROP_DST_PORT, NMDeviceGeneve, _priv.dst_port), + NML_DBUS_META_PROPERTY_INIT_U("Id", PROP_ID, NMDeviceGeneve, _priv.id), + NML_DBUS_META_PROPERTY_INIT_S("Remote", PROP_REMOTE, NMDeviceGeneve, _priv.remote), + NML_DBUS_META_PROPERTY_INIT_Y("Tos", PROP_TOS, NMDeviceGeneve, _priv.tos), + NML_DBUS_META_PROPERTY_INIT_I("Ttl", PROP_TTL, NMDeviceGeneve, _priv.ttl), ), ); + +static void +nm_device_geneve_class_init(NMDeviceGeneveClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + NMObjectClass *nm_object_class = NM_OBJECT_CLASS(klass); + NMDeviceClass *device_class = NM_DEVICE_CLASS(klass); + + object_class->get_property = get_property; + object_class->finalize = finalize; + + _NM_OBJECT_CLASS_INIT_PRIV_PTR_DIRECT(nm_object_class, NMDeviceGeneve); + + device_class->connection_compatible = connection_compatible; + device_class->get_setting_type = get_setting_type; + + /** + * NMDeviceGeneve:id: + * + * The device's GENEVE ID. + * + * Since: 1.58 + **/ + obj_properties[PROP_ID] = g_param_spec_uint(NM_DEVICE_GENEVE_ID, + "", + "", + 0, + (1 << 24) - 1, + 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + /** + * NMDeviceGeneve:remote: + * + * The IP address of the remote tunnel endpoint. + * + * Since: 1.58 + */ + obj_properties[PROP_REMOTE] = g_param_spec_string(NM_DEVICE_GENEVE_REMOTE, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + /** + * NMDeviceGeneve:tos: + * + * The TOS value to use in outgoing packets. + * + * Since: 1.58 + */ + obj_properties[PROP_TOS] = g_param_spec_uchar(NM_DEVICE_GENEVE_TOS, + "", + "", + 0, + 255, + 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + /** + * NMDeviceGeneve:ttl: + * + * The time-to-live value to use in outgoing packets. + * + * Since: 1.58 + */ + obj_properties[PROP_TTL] = g_param_spec_int(NM_DEVICE_GENEVE_TTL, + "", + "", + -1, + 255, + 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + /** + * NMDeviceGeneve:dst-port: + * + * The UDP destination port used to communicate with the remote GENEVE tunnel + * endpoint. + * + * Since: 1.58 + */ + obj_properties[PROP_DST_PORT] = g_param_spec_uint(NM_DEVICE_GENEVE_DST_PORT, + "", + "", + 0, + 65535, + 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + /** + * NMDeviceGeneve:df: + * + * The Don't Fragment (DF) bit to set in outgoing packets. + * + * Since: 1.58 + */ + obj_properties[PROP_DF] = g_param_spec_uchar(NM_DEVICE_GENEVE_DF, + "", + "", + 0, + 2, + 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + _nml_dbus_meta_class_init_with_properties(object_class, &_nml_dbus_meta_iface_nm_device_geneve); +} diff --git a/src/libnm-client-impl/nm-device.c b/src/libnm-client-impl/nm-device.c index 1712efa5bb..9203fd6f13 100644 --- a/src/libnm-client-impl/nm-device.c +++ b/src/libnm-client-impl/nm-device.c @@ -302,6 +302,7 @@ coerce_type(NMDeviceType type) case NM_DEVICE_TYPE_TUN: case NM_DEVICE_TYPE_VETH: case NM_DEVICE_TYPE_GENERIC: + case NM_DEVICE_TYPE_GENEVE: case NM_DEVICE_TYPE_UNUSED1: case NM_DEVICE_TYPE_UNUSED2: case NM_DEVICE_TYPE_UNKNOWN: @@ -1792,6 +1793,8 @@ get_type_name(NMDevice *device) return _("MACVLAN"); case NM_DEVICE_TYPE_VXLAN: return _("VXLAN"); + case NM_DEVICE_TYPE_GENEVE: + return _("GENEVE"); case NM_DEVICE_TYPE_IP_TUNNEL: return _("IPTunnel"); case NM_DEVICE_TYPE_TUN: diff --git a/src/libnm-client-impl/nm-libnm-utils.c b/src/libnm-client-impl/nm-libnm-utils.c index c2fa2addef..9f1b515c2e 100644 --- a/src/libnm-client-impl/nm-libnm-utils.c +++ b/src/libnm-client-impl/nm-libnm-utils.c @@ -789,6 +789,7 @@ const NMLDBusMetaIface *const _nml_dbus_meta_ifaces[] = { &_nml_dbus_meta_iface_nm_device_bridge, &_nml_dbus_meta_iface_nm_device_dummy, &_nml_dbus_meta_iface_nm_device_generic, + &_nml_dbus_meta_iface_nm_device_geneve, &_nml_dbus_meta_iface_nm_device_hsr, &_nml_dbus_meta_iface_nm_device_iptunnel, &_nml_dbus_meta_iface_nm_device_infiniband, diff --git a/src/libnm-client-impl/nm-libnm-utils.h b/src/libnm-client-impl/nm-libnm-utils.h index 7dcf8c18dc..27b77b6009 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[47]; +extern const NMLDBusMetaIface *const _nml_dbus_meta_ifaces[48]; extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm; extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_accesspoint; @@ -593,6 +593,7 @@ extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_bond; extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_bridge; extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_dummy; extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_generic; +extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_geneve; 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; diff --git a/src/libnm-client-public/NetworkManager.h b/src/libnm-client-public/NetworkManager.h index 9e9a4eb839..880bac6ed7 100644 --- a/src/libnm-client-public/NetworkManager.h +++ b/src/libnm-client-public/NetworkManager.h @@ -37,6 +37,7 @@ #include "nm-setting-dummy.h" #include "nm-setting-ethtool.h" #include "nm-setting-generic.h" +#include "nm-setting-geneve.h" #include "nm-setting-gsm.h" #include "nm-setting-hostname.h" #include "nm-setting-hsr.h" @@ -114,6 +115,7 @@ #include "nm-device-dummy.h" #include "nm-device-ethernet.h" #include "nm-device-generic.h" +#include "nm-device-geneve.h" #include "nm-device-hsr.h" #include "nm-device-infiniband.h" #include "nm-device-ip-tunnel.h" diff --git a/src/libnm-client-public/meson.build b/src/libnm-client-public/meson.build index b8ae9cce07..5aa6de2518 100644 --- a/src/libnm-client-public/meson.build +++ b/src/libnm-client-public/meson.build @@ -18,6 +18,7 @@ libnm_client_headers = files( 'nm-device-dummy.h', 'nm-device-ethernet.h', 'nm-device-generic.h', + 'nm-device-geneve.h', 'nm-device-hsr.h', 'nm-device-infiniband.h', 'nm-device-ip-tunnel.h', diff --git a/src/libnm-client-public/nm-autoptr.h b/src/libnm-client-public/nm-autoptr.h index f4321ad3a6..12379fe1aa 100644 --- a/src/libnm-client-public/nm-autoptr.h +++ b/src/libnm-client-public/nm-autoptr.h @@ -41,6 +41,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMDeviceBt, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMDeviceDummy, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMDeviceEthernet, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMDeviceGeneric, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMDeviceGeneve, 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) @@ -80,6 +81,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingDcb, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingDummy, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingEthtool, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingGeneric, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingGeneve, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingGsm, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingHostname, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(NMSettingHsr, g_object_unref) diff --git a/src/libnm-client-public/nm-device-geneve.h b/src/libnm-client-public/nm-device-geneve.h new file mode 100644 index 0000000000..5f7c92b30b --- /dev/null +++ b/src/libnm-client-public/nm-device-geneve.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2015 Red Hat, Inc. + */ + +#ifndef __NM_DEVICE_GENEVE_H__ +#define __NM_DEVICE_GENEVE_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_GENEVE (nm_device_geneve_get_type()) +#define NM_DEVICE_GENEVE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_GENEVE, NMDeviceGeneve)) +#define NM_DEVICE_GENEVE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_GENEVE, NMDeviceGeneveClass)) +#define NM_IS_DEVICE_GENEVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_GENEVE)) +#define NM_IS_DEVICE_GENEVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_GENEVE)) +#define NM_DEVICE_GENEVE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_GENEVE, NMDeviceGeneveClass)) + +#define NM_DEVICE_GENEVE_ID "id" +#define NM_DEVICE_GENEVE_REMOTE "remote" +#define NM_DEVICE_GENEVE_TOS "tos" +#define NM_DEVICE_GENEVE_TTL "ttl" +#define NM_DEVICE_GENEVE_DST_PORT "dst-port" +#define NM_DEVICE_GENEVE_DF "df" + +/** + * NMDeviceGeneve: + * + * Since: 1.58 + */ +typedef struct _NMDeviceGeneve NMDeviceGeneve; +typedef struct _NMDeviceGeneveClass NMDeviceGeneveClass; + +NM_AVAILABLE_IN_1_58 +GType nm_device_geneve_get_type(void); + +NM_AVAILABLE_IN_1_58 +guint nm_device_geneve_get_id(NMDeviceGeneve *device); +NM_AVAILABLE_IN_1_58 +const char *nm_device_geneve_get_remote(NMDeviceGeneve *device); +NM_AVAILABLE_IN_1_58 +guint nm_device_geneve_get_dst_port(NMDeviceGeneve *device); +NM_AVAILABLE_IN_1_58 +guint nm_device_geneve_get_tos(NMDeviceGeneve *device); +NM_AVAILABLE_IN_1_58 +guint nm_device_geneve_get_ttl(NMDeviceGeneve *device); +NM_AVAILABLE_IN_1_58 +guint nm_device_geneve_get_df(NMDeviceGeneve *device); + +G_END_DECLS + +#endif /* __NM_DEVICE_GENEVE_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 0131ba76bf..7308db4d64 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 @@ -1378,6 +1378,34 @@ gprop-type="gchararray" /> + + + + + + + + diff --git a/src/libnm-core-impl/meson.build b/src/libnm-core-impl/meson.build index 610e22792e..1eee3184e5 100644 --- a/src/libnm-core-impl/meson.build +++ b/src/libnm-core-impl/meson.build @@ -17,6 +17,7 @@ libnm_core_settings_sources = files( 'nm-setting-dummy.c', 'nm-setting-ethtool.c', 'nm-setting-generic.c', + 'nm-setting-geneve.c', 'nm-setting-gsm.c', 'nm-setting-hostname.c', 'nm-setting-hsr.c', diff --git a/src/libnm-core-impl/nm-connection.c b/src/libnm-core-impl/nm-connection.c index 0fbadfb85c..9ce72b4145 100644 --- a/src/libnm-core-impl/nm-connection.c +++ b/src/libnm-core-impl/nm-connection.c @@ -3272,6 +3272,7 @@ nm_connection_is_virtual(NMConnection *connection) NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BRIDGE_SETTING_NAME, NM_SETTING_DUMMY_SETTING_NAME, + NM_SETTING_GENEVE_SETTING_NAME, NM_SETTING_HSR_SETTING_NAME, NM_SETTING_IP_TUNNEL_SETTING_NAME, NM_SETTING_IPVLAN_SETTING_NAME, @@ -3526,6 +3527,22 @@ nm_connection_get_setting_generic(NMConnection *connection) return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_GENERIC); } +/** + * nm_connection_get_setting_geneve: + * @connection: the #NMConnection + * + * A shortcut to return any #NMSettingGeneve the connection might contain. + * + * Returns: (transfer none): an #NMSettingGeneve if the connection contains one, otherwise NULL + * + * Since: 1.58 + **/ +NMSettingGeneve * +nm_connection_get_setting_geneve(NMConnection *connection) +{ + return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_GENEVE); +} + /** * nm_connection_get_setting_gsm: * @connection: the #NMConnection 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 52af9ad259..d84490d238 100644 --- a/src/libnm-core-impl/nm-meta-setting-base-impl.c +++ b/src/libnm-core-impl/nm-meta-setting-base-impl.c @@ -27,6 +27,7 @@ #include "nm-setting-dummy.h" #include "nm-setting-ethtool.h" #include "nm-setting-generic.h" +#include "nm-setting-geneve.h" #include "nm-setting-gsm.h" #include "nm-setting-hostname.h" #include "nm-setting-hsr.h" @@ -324,6 +325,13 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = { .setting_name = NM_SETTING_GENERIC_SETTING_NAME, .get_setting_gtype = nm_setting_generic_get_type, }, + [NM_META_SETTING_TYPE_GENEVE] = + { + .meta_type = NM_META_SETTING_TYPE_GENEVE, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_GENEVE_SETTING_NAME, + .get_setting_gtype = nm_setting_geneve_get_type, + }, [NM_META_SETTING_TYPE_GSM] = { .meta_type = NM_META_SETTING_TYPE_GSM, @@ -655,6 +663,7 @@ const NMMetaSettingType nm_meta_setting_types_by_priority[] = { NM_META_SETTING_TYPE_CDMA, NM_META_SETTING_TYPE_DUMMY, NM_META_SETTING_TYPE_GENERIC, + NM_META_SETTING_TYPE_GENEVE, NM_META_SETTING_TYPE_GSM, NM_META_SETTING_TYPE_HSR, NM_META_SETTING_TYPE_INFINIBAND, diff --git a/src/libnm-core-impl/nm-setting-geneve.c b/src/libnm-core-impl/nm-setting-geneve.c new file mode 100644 index 0000000000..d6426a06ff --- /dev/null +++ b/src/libnm-core-impl/nm-setting-geneve.c @@ -0,0 +1,354 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2026 Red Hat, Inc. + */ + +#include "libnm-core-impl/nm-default-libnm-core.h" + +#include "nm-setting-geneve.h" + +#include + +#include "nm-utils.h" +#include "nm-setting-private.h" + +/** + * SECTION:nm-setting-geneve + * @short_description: Describes connection properties for GENEVE interfaces + * + * The #NMSettingGeneve object is a #NMSetting subclass that describes properties + * necessary for connection to GENEVE interfaces. + **/ + +#define DST_PORT_DEFAULT 6081 + +NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_ID, + PROP_REMOTE, + PROP_DESTINATION_PORT, + PROP_TOS, + PROP_TTL, + PROP_DF, ); + +typedef struct { + char *remote; + guint32 id; + guint32 destination_port; + guint32 tos; + gint32 ttl; + int df; +} NMSettingGenevePrivate; + +/** + * NMSettingGeneve: + * + * GENEVE Settings + */ +struct _NMSettingGeneve { + NMSetting parent; + NMSettingGenevePrivate _priv; +}; + +struct _NMSettingGeneveClass { + NMSettingClass parent; +}; + +G_DEFINE_TYPE(NMSettingGeneve, nm_setting_geneve, NM_TYPE_SETTING) + +#define NM_SETTING_GENEVE_GET_PRIVATE(o) \ + _NM_GET_PRIVATE(o, NMSettingGeneve, NM_IS_SETTING_GENEVE, NMSetting) + +/*****************************************************************************/ + +/** + * nm_setting_geneve_get_id: + * @setting: the #NMSettingGeneve + * + * Returns: the #NMSettingGeneve:id property of the setting + * + * Since: 1.58 + **/ +guint +nm_setting_geneve_get_id(NMSettingGeneve *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_GENEVE(setting), 0); + + return NM_SETTING_GENEVE_GET_PRIVATE(setting)->id; +} + +/** + * nm_setting_geneve_get_remote: + * @setting: the #NMSettingGeneve + * + * Returns: the #NMSettingGeneve:remote property of the setting + * + * Since: 1.58 + **/ +const char * +nm_setting_geneve_get_remote(NMSettingGeneve *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_GENEVE(setting), NULL); + + return NM_SETTING_GENEVE_GET_PRIVATE(setting)->remote; +} + +/** + * nm_setting_geneve_get_destination_port: + * @setting: the #NMSettingGeneve + * + * Returns: the #NMSettingGeneve:destination-port property of the setting + * + * Since: 1.58 + **/ +guint +nm_setting_geneve_get_destination_port(NMSettingGeneve *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_GENEVE(setting), DST_PORT_DEFAULT); + + return NM_SETTING_GENEVE_GET_PRIVATE(setting)->destination_port; +} + +/** + * nm_setting_geneve_get_tos: + * @setting: the #NMSettingGeneve + * + * Returns: the #NMSettingGeneve:tos property of the setting + * + * Since: 1.58 + **/ +guint +nm_setting_geneve_get_tos(NMSettingGeneve *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_GENEVE(setting), 0); + + return NM_SETTING_GENEVE_GET_PRIVATE(setting)->tos; +} + +/** + * nm_setting_geneve_get_ttl: + * @setting: the #NMSettingGeneve + * + * Returns: the #NMSettingGeneve:ttl property of the setting + * + * Since: 1.58 + **/ +guint +nm_setting_geneve_get_ttl(NMSettingGeneve *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_GENEVE(setting), 0); + + return NM_SETTING_GENEVE_GET_PRIVATE(setting)->ttl; +} + +/** + * nm_setting_geneve_get_df: + * @setting: the #NMSettingGeneve + * + * Returns: the #NMSettingGeneve:df property of the setting + * + * Since: 1.58 + **/ +NMSettingGeneveDf +nm_setting_geneve_get_df(NMSettingGeneve *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_GENEVE(setting), NM_SETTING_GENEVE_DF_UNSET); + + return NM_SETTING_GENEVE_GET_PRIVATE(setting)->df; +} + +/*****************************************************************************/ + +static gboolean +verify(NMSetting *setting, NMConnection *connection, GError **error) +{ + NMSettingGenevePrivate *priv = NM_SETTING_GENEVE_GET_PRIVATE(setting); + + if (priv->id == 0) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_PROPERTY, + _("property is required")); + g_prefix_error(error, "%s.%s: ", NM_SETTING_GENEVE_SETTING_NAME, NM_SETTING_GENEVE_ID); + return FALSE; + } + + if (!priv->remote) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_PROPERTY, + _("property is required")); + g_prefix_error(error, "%s.%s: ", NM_SETTING_GENEVE_SETTING_NAME, NM_SETTING_GENEVE_REMOTE); + return FALSE; + } + + if (!nm_inet_parse_bin(AF_UNSPEC, priv->remote, NULL, NULL)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid IP address"), + priv->remote); + g_prefix_error(error, "%s.%s: ", NM_SETTING_GENEVE_SETTING_NAME, NM_SETTING_GENEVE_REMOTE); + return FALSE; + } + + return TRUE; +} + +/*****************************************************************************/ + +static void +nm_setting_geneve_init(NMSettingGeneve *self) +{} + +/** + * nm_setting_geneve_new: + * + * Creates a new #NMSettingGeneve object with default values. + * + * Returns: (transfer full): the new empty #NMSettingGeneve object + * + * Since: 1.58 + **/ +NMSetting * +nm_setting_geneve_new(void) +{ + return g_object_new(NM_TYPE_SETTING_GENEVE, NULL); +} + +static void +nm_setting_geneve_class_init(NMSettingGeneveClass *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; + + /** + * NMSettingGeneve:id: + * + * Specifies the GENEVE Network Identifier (or GENEVE Segment Identifier) to + * use. + * + * Since: 1.58 + **/ + _nm_setting_property_define_direct_uint32(properties_override, + obj_properties, + NM_SETTING_GENEVE_ID, + PROP_ID, + 0, + (1 << 24) - 1, + 0, + NM_SETTING_PARAM_INFERRABLE, + NMSettingGenevePrivate, + id); + + /** + * NMSettingGeneve:remote: + * + * Specifies the unicast destination IP address to use in outgoing packets + * when communicating with the remote GENEVE tunnel endpoint. + * + * Since: 1.58 + **/ + _nm_setting_property_define_direct_string(properties_override, + obj_properties, + NM_SETTING_GENEVE_REMOTE, + PROP_REMOTE, + NM_SETTING_PARAM_REQUIRED, + NMSettingGenevePrivate, + remote, + .direct_set_string_ip_address_addr_family = + AF_UNSPEC + 1, + .direct_string_allow_empty = TRUE); + + /** + * NMSettingGeneve:destination-port: + * + * Specifies the UDP destination port to communicate to the remote GENEVE + * tunnel endpoint. + * + * Since: 1.58 + **/ + _nm_setting_property_define_direct_uint32(properties_override, + obj_properties, + NM_SETTING_GENEVE_DESTINATION_PORT, + PROP_DESTINATION_PORT, + 0, + G_MAXUINT16, + DST_PORT_DEFAULT, + NM_SETTING_PARAM_INFERRABLE, + NMSettingGenevePrivate, + destination_port); + + /** + * NMSettingGeneve:tos: + * + * Specifies the TOS value to use in outgoing packets. + * The special value "inherit" (1) means inherit from outer packet. + * + * Since: 1.58 + **/ + _nm_setting_property_define_direct_uint32(properties_override, + obj_properties, + NM_SETTING_GENEVE_TOS, + PROP_TOS, + 0, + 255, + 0, + NM_SETTING_PARAM_INFERRABLE, + NMSettingGenevePrivate, + tos); + + /** + * NMSettingGeneve:ttl: + * + * Specifies the time-to-live value to use in outgoing packets. + * The special value "inherit" (-1) means inherit from outer packet, 0 means auto, 1-255 are fixed values. + * + * Since: 1.58 + **/ + _nm_setting_property_define_direct_int32(properties_override, + obj_properties, + NM_SETTING_GENEVE_TTL, + PROP_TTL, + -1, + 255, + 0, + NM_SETTING_PARAM_INFERRABLE, + NMSettingGenevePrivate, + ttl); + + /** + * NMSettingGeneve:df: + * + * Specifies how the Don't Fragment (DF) flag should be handled in the outer IP + * header of GENEVE tunnel packets. + * + * %NM_SETTING_GENEVE_DF_UNSET (0): Don't set the DF flag, packets may be fragmented. + * %NM_SETTING_GENEVE_DF_SET (1): Always set the DF flag, packets will not be fragmented. + * %NM_SETTING_GENEVE_DF_INHERIT (2): Inherit the DF flag from the inner IP header. + * + * Since: 1.58 + **/ + _nm_setting_property_define_direct_enum(properties_override, + obj_properties, + NM_SETTING_GENEVE_DF, + PROP_DF, + NM_TYPE_SETTING_GENEVE_DF, + NM_SETTING_GENEVE_DF_UNSET, + NM_SETTING_PARAM_INFERRABLE, + NULL, + NMSettingGenevePrivate, + df); + + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + _nm_setting_class_commit(setting_class, + NM_META_SETTING_TYPE_GENEVE, + NULL, + properties_override, + G_STRUCT_OFFSET(NMSettingGeneve, _priv)); +} diff --git a/src/libnm-core-intern/nm-core-internal.h b/src/libnm-core-intern/nm-core-internal.h index f1fc76a563..9a7633281e 100644 --- a/src/libnm-core-intern/nm-core-internal.h +++ b/src/libnm-core-intern/nm-core-internal.h @@ -37,6 +37,7 @@ #include "nm-setting-dcb.h" #include "nm-setting-dummy.h" #include "nm-setting-generic.h" +#include "nm-setting-geneve.h" #include "nm-setting-gsm.h" #include "nm-setting-hsr.h" #include "nm-setting-hostname.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 d1535e5e1f..8f512d09c6 100644 --- a/src/libnm-core-intern/nm-meta-setting-base-impl.h +++ b/src/libnm-core-intern/nm-meta-setting-base-impl.h @@ -121,6 +121,7 @@ typedef enum _nm_packed { NM_META_SETTING_TYPE_DUMMY, NM_META_SETTING_TYPE_ETHTOOL, NM_META_SETTING_TYPE_GENERIC, + NM_META_SETTING_TYPE_GENEVE, NM_META_SETTING_TYPE_GSM, NM_META_SETTING_TYPE_HOSTNAME, NM_META_SETTING_TYPE_HSR, diff --git a/src/libnm-core-public/meson.build b/src/libnm-core-public/meson.build index 086801d96d..2a4f143f75 100644 --- a/src/libnm-core-public/meson.build +++ b/src/libnm-core-public/meson.build @@ -22,6 +22,7 @@ libnm_core_headers = files( 'nm-setting-dummy.h', 'nm-setting-ethtool.h', 'nm-setting-generic.h', + 'nm-setting-geneve.h', 'nm-setting-gsm.h', 'nm-setting-hsr.h', 'nm-setting-hostname.h', diff --git a/src/libnm-core-public/nm-connection.h b/src/libnm-core-public/nm-connection.h index ff3e0f924a..db73711f69 100644 --- a/src/libnm-core-public/nm-connection.h +++ b/src/libnm-core-public/nm-connection.h @@ -206,8 +206,10 @@ NMSettingCdma *nm_connection_get_setting_cdma(NMConnection *connection); NMSettingConnection *nm_connection_get_setting_connection(NMConnection *connection); NMSettingDcb *nm_connection_get_setting_dcb(NMConnection *connection); NM_AVAILABLE_IN_1_8 -NMSettingDummy *nm_connection_get_setting_dummy(NMConnection *connection); -NMSettingGeneric *nm_connection_get_setting_generic(NMConnection *connection); +NMSettingDummy *nm_connection_get_setting_dummy(NMConnection *connection); +NMSettingGeneric *nm_connection_get_setting_generic(NMConnection *connection); +NM_AVAILABLE_IN_1_58 +NMSettingGeneve *nm_connection_get_setting_geneve(NMConnection *connection); NMSettingGsm *nm_connection_get_setting_gsm(NMConnection *connection); NMSettingInfiniband *nm_connection_get_setting_infiniband(NMConnection *connection); NM_AVAILABLE_IN_1_2 diff --git a/src/libnm-core-public/nm-core-types.h b/src/libnm-core-public/nm-core-types.h index 617d6b7415..81743e31d7 100644 --- a/src/libnm-core-public/nm-core-types.h +++ b/src/libnm-core-public/nm-core-types.h @@ -27,6 +27,7 @@ typedef struct _NMSettingConnection NMSettingConnection; typedef struct _NMSettingDcb NMSettingDcb; typedef struct _NMSettingDummy NMSettingDummy; typedef struct _NMSettingEthtool NMSettingEthtool; +typedef struct _NMSettingGeneve NMSettingGeneve; typedef struct _NMSettingGeneric NMSettingGeneric; typedef struct _NMSettingGsm NMSettingGsm; typedef struct _NMSettingHostname NMSettingHostname; diff --git a/src/libnm-core-public/nm-dbus-interface.h b/src/libnm-core-public/nm-dbus-interface.h index 42bff04ae0..8d34066f0e 100644 --- a/src/libnm-core-public/nm-dbus-interface.h +++ b/src/libnm-core-public/nm-dbus-interface.h @@ -36,6 +36,7 @@ #define NM_DBUS_INTERFACE_DEVICE_BRIDGE NM_DBUS_INTERFACE_DEVICE ".Bridge" #define NM_DBUS_INTERFACE_DEVICE_DUMMY NM_DBUS_INTERFACE_DEVICE ".Dummy" #define NM_DBUS_INTERFACE_DEVICE_GENERIC NM_DBUS_INTERFACE_DEVICE ".Generic" +#define NM_DBUS_INTERFACE_DEVICE_GENEVE NM_DBUS_INTERFACE_DEVICE ".Geneve" #define NM_DBUS_INTERFACE_DEVICE_GRE NM_DBUS_INTERFACE_DEVICE ".Gre" #define NM_DBUS_INTERFACE_DEVICE_HSR NM_DBUS_INTERFACE_DEVICE ".Hsr" #define NM_DBUS_INTERFACE_DEVICE_INFINIBAND NM_DBUS_INTERFACE_DEVICE ".Infiniband" @@ -250,6 +251,7 @@ typedef enum { * @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. + * @NM_DEVICE_TYPE_GENEVE: A GENEVE device. Since: 1.58. * * #NMDeviceType values indicate the type of hardware represented by a * device object. @@ -290,6 +292,7 @@ typedef enum { NM_DEVICE_TYPE_LOOPBACK = 32, NM_DEVICE_TYPE_HSR = 33, NM_DEVICE_TYPE_IPVLAN = 34, + NM_DEVICE_TYPE_GENEVE = 35, } NMDeviceType; /** diff --git a/src/libnm-core-public/nm-setting-geneve.h b/src/libnm-core-public/nm-setting-geneve.h new file mode 100644 index 0000000000..bff8fba1b2 --- /dev/null +++ b/src/libnm-core-public/nm-setting-geneve.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2026 Red Hat, Inc. + */ + +#ifndef __NM_SETTING_GENEVE_H__ +#define __NM_SETTING_GENEVE_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_GENEVE (nm_setting_geneve_get_type()) +#define NM_SETTING_GENEVE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SETTING_GENEVE, NMSettingGeneve)) +#define NM_SETTING_GENEVE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_SETTING_GENEVE, NMSettingGeneveClass)) +#define NM_IS_SETTING_GENEVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_SETTING_GENEVE)) +#define NM_IS_SETTING_GENEVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_SETTING_GENEVE)) +#define NM_SETTING_GENEVE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_SETTING_GENEVE, NMSettingGeneveClass)) + +#define NM_SETTING_GENEVE_SETTING_NAME "geneve" + +#define NM_SETTING_GENEVE_ID "id" +#define NM_SETTING_GENEVE_REMOTE "remote" +#define NM_SETTING_GENEVE_DESTINATION_PORT "destination-port" +#define NM_SETTING_GENEVE_TOS "tos" +#define NM_SETTING_GENEVE_TTL "ttl" +#define NM_SETTING_GENEVE_DF "df" + +/** + * NMSettingGeneveDf: + * @NM_SETTING_GENEVE_DF_UNSET: Don't set the DF flag, packets may be fragmented. + * @NM_SETTING_GENEVE_DF_SET: Always set the DF flag, packets will not be fragmented. + * @NM_SETTING_GENEVE_DF_INHERIT: Inherit the DF flag from the inner IP header. + * + * #NMSettingGeneveDf values indicate how the Don't Fragment (DF) flag should be handled + * in the outer IP header of GENEVE tunnel packets. + * + * Since: 1.58 + */ +typedef enum { + NM_SETTING_GENEVE_DF_UNSET = 0, + NM_SETTING_GENEVE_DF_SET = 1, + NM_SETTING_GENEVE_DF_INHERIT = 2, +} NMSettingGeneveDf; + +typedef struct _NMSettingGeneveClass NMSettingGeneveClass; + +NM_AVAILABLE_IN_1_58 +GType nm_setting_geneve_get_type(void); +NM_AVAILABLE_IN_1_58 +NMSetting *nm_setting_geneve_new(void); +NM_AVAILABLE_IN_1_58 +guint nm_setting_geneve_get_id(NMSettingGeneve *setting); +NM_AVAILABLE_IN_1_58 +const char *nm_setting_geneve_get_remote(NMSettingGeneve *setting); +NM_AVAILABLE_IN_1_58 +guint nm_setting_geneve_get_destination_port(NMSettingGeneve *setting); +NM_AVAILABLE_IN_1_58 +guint nm_setting_geneve_get_tos(NMSettingGeneve *setting); +NM_AVAILABLE_IN_1_58 +guint nm_setting_geneve_get_ttl(NMSettingGeneve *setting); +NM_AVAILABLE_IN_1_58 +NMSettingGeneveDf nm_setting_geneve_get_df(NMSettingGeneve *setting); + +G_END_DECLS + +#endif /* __NM_SETTING_GENEVE_H__ */ diff --git a/src/libnm-glib-aux/nm-shared-utils.h b/src/libnm-glib-aux/nm-shared-utils.h index 1fca6015d8..0bc6e29495 100644 --- a/src/libnm-glib-aux/nm-shared-utils.h +++ b/src/libnm-glib-aux/nm-shared-utils.h @@ -130,6 +130,7 @@ typedef enum { #define _NM_LINK_TYPE_SW_FIRST NM_LINK_TYPE_BNEP NM_LINK_TYPE_BNEP, /* Bluetooth Ethernet emulation */ NM_LINK_TYPE_DUMMY, + NM_LINK_TYPE_GENEVE, NM_LINK_TYPE_GRE, NM_LINK_TYPE_GRETAP, NM_LINK_TYPE_IFB, diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index cc5b99e095..cde96326ca 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -862,6 +862,7 @@ static const LinkDesc link_descs[] = { [NM_LINK_TYPE_BNEP] = {"bluetooth", NULL, "bluetooth"}, [NM_LINK_TYPE_DUMMY] = {"dummy", "dummy", NULL}, + [NM_LINK_TYPE_GENEVE] = {"geneve", "geneve", "geneve"}, [NM_LINK_TYPE_GRE] = {"gre", "gre", NULL}, [NM_LINK_TYPE_GRETAP] = {"gretap", "gretap", NULL}, [NM_LINK_TYPE_IFB] = {"ifb", "ifb", NULL}, @@ -909,6 +910,7 @@ _link_type_from_rtnl_type(const char *name) NM_LINK_TYPE_BOND, /* "bond" */ NM_LINK_TYPE_BRIDGE, /* "bridge" */ NM_LINK_TYPE_DUMMY, /* "dummy" */ + NM_LINK_TYPE_GENEVE, /* "geneve" */ NM_LINK_TYPE_GRE, /* "gre" */ NM_LINK_TYPE_GRETAP, /* "gretap" */ NM_LINK_TYPE_HSR, /* "hsr" */ @@ -987,6 +989,7 @@ _link_type_from_devtype(const char *name) NM_LINK_TYPE_BNEP, /* "bluetooth" */ NM_LINK_TYPE_BOND, /* "bond" */ NM_LINK_TYPE_BRIDGE, /* "bridge" */ + NM_LINK_TYPE_GENEVE, /* "geneve" */ NM_LINK_TYPE_HSR, /* "hsr" */ NM_LINK_TYPE_PPP, /* "ppp" */ NM_LINK_TYPE_VLAN, /* "vlan" */ @@ -1856,6 +1859,57 @@ _parse_lnk_gre(const char *kind, struct nlattr *info_data) /*****************************************************************************/ +static NMPObject * +_parse_lnk_geneve(const char *kind, struct nlattr *info_data) +{ + static const struct nla_policy policy[] = { + [IFLA_GENEVE_ID] = {.type = NLA_U32}, + [IFLA_GENEVE_REMOTE] = {.type = NLA_U32}, + [IFLA_GENEVE_REMOTE6] = {.type = NLA_UNSPEC, .minlen = sizeof(struct in6_addr)}, + [IFLA_GENEVE_TTL] = {.type = NLA_U8}, + [IFLA_GENEVE_TOS] = {.type = NLA_U8}, + [IFLA_GENEVE_TTL_INHERIT] = {.type = NLA_U8}, + [IFLA_GENEVE_PORT] = {.type = NLA_U16}, + [IFLA_GENEVE_DF] = {.type = NLA_U8}, + }; + + struct nlattr *tb[G_N_ELEMENTS(policy)]; + NMPObject *obj; + NMPlatformLnkGeneve *props; + + if (!info_data || !nm_streq0(kind, "geneve")) + return NULL; + + if (nla_parse_nested_arr(tb, info_data, policy) < 0) + return NULL; + + obj = nmp_object_new(NMP_OBJECT_TYPE_LNK_GENEVE, NULL); + props = &obj->lnk_geneve; + + if (tb[IFLA_GENEVE_ID]) + props->id = nla_get_u32(tb[IFLA_GENEVE_ID]); + if (tb[IFLA_GENEVE_REMOTE]) + props->remote = nla_get_u32(tb[IFLA_GENEVE_REMOTE]); + if (tb[IFLA_GENEVE_REMOTE6]) + props->remote6 = *nla_data_as(struct in6_addr, tb[IFLA_GENEVE_REMOTE6]); + + if (tb[IFLA_GENEVE_TTL_INHERIT] && nla_get_u8(tb[IFLA_GENEVE_TTL_INHERIT])) + props->ttl = -1; + else if (tb[IFLA_GENEVE_TTL]) + props->ttl = nla_get_u8(tb[IFLA_GENEVE_TTL]); + + if (tb[IFLA_GENEVE_TOS]) + props->tos = nla_get_u8(tb[IFLA_GENEVE_TOS]); + if (tb[IFLA_GENEVE_PORT]) + props->dst_port = ntohs(nla_get_u16(tb[IFLA_GENEVE_PORT])); + if (tb[IFLA_GENEVE_DF]) + props->df = nla_get_u8(tb[IFLA_GENEVE_DF]); + + return obj; +} + +/*****************************************************************************/ + static NMPObject * _parse_lnk_hsr(const char *kind, struct nlattr *info_data) { @@ -3694,6 +3748,9 @@ _new_from_nl_link(NMPlatform *platform, case NM_LINK_TYPE_BOND: lnk_data = _parse_lnk_bond(nl_info_kind, nl_info_data); break; + case NM_LINK_TYPE_GENEVE: + lnk_data = _parse_lnk_geneve(nl_info_kind, nl_info_data); + break; case NM_LINK_TYPE_GRE: case NM_LINK_TYPE_GRETAP: lnk_data = _parse_lnk_gre(nl_info_kind, nl_info_data); @@ -5182,6 +5239,35 @@ _nl_msg_new_link_set_linkinfo(struct nl_msg *msg, NMLinkType link_type, gconstpo nla_nest_end(msg, info_peer); break; } + case NM_LINK_TYPE_GENEVE: + { + const NMPlatformLnkGeneve *props = extra_data; + + nm_assert(props); + + if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) + goto nla_put_failure; + + NLA_PUT_U32(msg, IFLA_GENEVE_ID, props->id); + + if (props->remote) { + NLA_PUT_U32(msg, IFLA_GENEVE_REMOTE, props->remote); + } else if (!IN6_IS_ADDR_UNSPECIFIED(&props->remote6)) { + NLA_PUT(msg, IFLA_GENEVE_REMOTE6, sizeof(props->remote6), &props->remote6); + } + NLA_PUT_U16(msg, IFLA_GENEVE_PORT, htons(props->dst_port)); + if (props->ttl == -1) { + NLA_PUT_U8(msg, IFLA_GENEVE_TTL_INHERIT, 1); + } else { + /* When you want to specify a TTL value, + * don't add TTL_INHERIT to the message */ + NLA_PUT_U8(msg, IFLA_GENEVE_TTL, props->ttl & 0xff); + } + NLA_PUT_U8(msg, IFLA_GENEVE_TOS, props->tos); + NLA_PUT_U8(msg, IFLA_GENEVE_DF, props->df); + break; + } + case NM_LINK_TYPE_GRE: case NM_LINK_TYPE_GRETAP: { diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index 853157d204..1f98a9a9c3 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -1388,6 +1388,12 @@ nm_platform_link_add(NMPlatform *self, case NM_LINK_TYPE_VETH: nm_sprintf_buf(buf, ", veth-peer \"%s\"", (const char *) extra_data); break; + case NM_LINK_TYPE_GENEVE: + nm_strbuf_append_str(&buf_p, &buf_len, ", "); + nm_platform_lnk_geneve_to_string((const NMPlatformLnkGeneve *) extra_data, + buf_p, + buf_len); + break; case NM_LINK_TYPE_GRE: case NM_LINK_TYPE_GRETAP: nm_strbuf_append_str(&buf_p, &buf_len, ", "); @@ -2565,6 +2571,12 @@ nm_platform_link_get_lnk_bridge(NMPlatform *self, int ifindex, const NMPlatformL return _link_get_lnk(self, ifindex, NM_LINK_TYPE_BRIDGE, out_link); } +const NMPlatformLnkGeneve * +nm_platform_link_get_lnk_geneve(NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk(self, ifindex, NM_LINK_TYPE_GENEVE, out_link); +} + const NMPlatformLnkGre * nm_platform_link_get_lnk_gre(NMPlatform *self, int ifindex, const NMPlatformLink **out_link) { @@ -6494,6 +6506,52 @@ nm_platform_lnk_bond_to_string(const NMPlatformLnkBond *lnk, char *buf, gsize le return buf; } +const char * +nm_platform_lnk_geneve_to_string(const NMPlatformLnkGeneve *lnk, char *buf, gsize len) +{ + char str_remote[NM_INET_ADDRSTRLEN]; + char str_remote1[30 + NM_INET_ADDRSTRLEN]; + char str_remote6[NM_INET_ADDRSTRLEN]; + char str_remote6_1[30 + NM_INET_ADDRSTRLEN]; + char str_ttl[30]; + char str_tos[30]; + char str_id[30]; + char str_dstport[30]; + + if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len)) + return buf; + + g_snprintf( + buf, + len, + "geneve" + "%s" /* id */ + "%s" /* remote */ + "%s" /* remote6 */ + "%s" /* dst_port */ + "%s" /* ttl */ + "%s" /* tos */ + "%s" /* df */ + "", + lnk->id ? nm_sprintf_buf(str_id, " id %u", lnk->id) : "", + lnk->remote + ? nm_sprintf_buf(str_remote, " remote %s", nm_inet4_ntop(lnk->remote, str_remote1)) + : "", + !IN6_IS_ADDR_UNSPECIFIED(&lnk->remote6) + ? nm_sprintf_buf(str_remote6, " remote %s", nm_inet6_ntop(&lnk->remote6, str_remote6_1)) + : "", + lnk->dst_port ? nm_sprintf_buf(str_dstport, " dstport %u", lnk->dst_port) : "", + lnk->ttl > 0 ? nm_sprintf_buf(str_ttl, " ttl %u", lnk->ttl & 0xff) + : lnk->ttl == 0 ? "ttl auto" + : "ttl inherit", + lnk->tos ? (lnk->tos == 1 ? " tos inherit" : nm_sprintf_buf(str_tos, " tos 0x%x", lnk->tos)) + : "", + lnk->df == 1 ? " df set " + : lnk->df == 2 ? " df inherit " + : ""); + return buf; +} + const char * nm_platform_lnk_gre_to_string(const NMPlatformLnkGre *lnk, char *buf, gsize len) { @@ -8491,6 +8549,27 @@ nm_platform_lnk_gre_cmp(const NMPlatformLnkGre *a, const NMPlatformLnkGre *b) return 0; } +void +nm_platform_lnk_geneve_hash_update(const NMPlatformLnkGeneve *obj, NMHashState *h) +{ + nm_hash_update_vals(h, obj->id, obj->remote, obj->dst_port, obj->ttl, obj->tos, obj->df); + nm_hash_update_mem(h, &obj->remote6, sizeof(obj->remote6)); +} + +int +nm_platform_lnk_geneve_cmp(const NMPlatformLnkGeneve *a, const NMPlatformLnkGeneve *b) +{ + NM_CMP_SELF(a, b); + NM_CMP_FIELD(a, b, id); + NM_CMP_FIELD(a, b, remote); + NM_CMP_FIELD_MEMCMP(a, b, remote6); + NM_CMP_FIELD(a, b, ttl); + NM_CMP_FIELD(a, b, tos); + NM_CMP_FIELD(a, b, dst_port); + NM_CMP_FIELD(a, b, df); + return 0; +} + void nm_platform_lnk_hsr_hash_update(const NMPlatformLnkHsr *obj, NMHashState *h) { diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index 033dc51541..1cdd160114 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -835,6 +835,16 @@ typedef struct { bool use_carrier : 1; } _nm_alignas(NMPlatformObject) NMPlatformLnkBond; +typedef struct { + struct in6_addr remote6; + in_addr_t remote; + guint32 id; + gint32 ttl; + guint16 dst_port; + guint8 tos; + guint8 df; +} _nm_alignas(NMPlatformObject) NMPlatformLnkGeneve; + typedef struct { int parent_ifindex; in_addr_t local; @@ -1858,6 +1868,15 @@ nm_platform_link_vxlan_add(NMPlatform *self, return nm_platform_link_add(self, NM_LINK_TYPE_VXLAN, name, 0, NULL, 0, 0, props, out_link); } +static inline int +nm_platform_link_geneve_add(NMPlatform *self, + const char *name, + const NMPlatformLnkGeneve *props, + const NMPlatformLink **out_link) +{ + return nm_platform_link_add(self, NM_LINK_TYPE_GENEVE, name, 0, NULL, 0, 0, props, out_link); +} + static inline int nm_platform_link_6lowpan_add(NMPlatform *self, const char *name, @@ -2143,6 +2162,8 @@ const NMPlatformLnkBond * nm_platform_link_get_lnk_bond(NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkBridge * nm_platform_link_get_lnk_bridge(NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkGeneve * +nm_platform_link_get_lnk_geneve(NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkGre * nm_platform_link_get_lnk_gre(NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkGre * @@ -2482,6 +2503,7 @@ gboolean nm_platform_tc_sync(NMPlatform *self, const char *nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len); const char *nm_platform_lnk_bond_to_string(const NMPlatformLnkBond *lnk, char *buf, gsize len); const char *nm_platform_lnk_bridge_to_string(const NMPlatformLnkBridge *lnk, char *buf, gsize len); +const char *nm_platform_lnk_geneve_to_string(const NMPlatformLnkGeneve *lnk, char *buf, gsize len); const char *nm_platform_lnk_gre_to_string(const NMPlatformLnkGre *lnk, char *buf, gsize len); const char *nm_platform_lnk_hsr_to_string(const NMPlatformLnkHsr *lnk, char *buf, gsize len); const char * @@ -2537,6 +2559,7 @@ nm_platform_mptcp_addr_to_string(const NMPlatformMptcpAddr *mptcp_addr, char *bu int nm_platform_link_cmp(const NMPlatformLink *a, const NMPlatformLink *b); int nm_platform_lnk_bond_cmp(const NMPlatformLnkBond *a, const NMPlatformLnkBond *b); int nm_platform_lnk_bridge_cmp(const NMPlatformLnkBridge *a, const NMPlatformLnkBridge *b); +int nm_platform_lnk_geneve_cmp(const NMPlatformLnkGeneve *a, const NMPlatformLnkGeneve *b); int nm_platform_lnk_gre_cmp(const NMPlatformLnkGre *a, const NMPlatformLnkGre *b); int nm_platform_lnk_hsr_cmp(const NMPlatformLnkHsr *a, const NMPlatformLnkHsr *b); int nm_platform_lnk_infiniband_cmp(const NMPlatformLnkInfiniband *a, @@ -2612,6 +2635,7 @@ void nm_platform_routing_rule_hash_update(const NMPlatformRoutingRule *obj, NMHashState *h); void nm_platform_lnk_bond_hash_update(const NMPlatformLnkBond *obj, NMHashState *h); void nm_platform_lnk_bridge_hash_update(const NMPlatformLnkBridge *obj, NMHashState *h); +void nm_platform_lnk_geneve_hash_update(const NMPlatformLnkGeneve *obj, NMHashState *h); void nm_platform_lnk_gre_hash_update(const NMPlatformLnkGre *obj, NMHashState *h); void nm_platform_lnk_hsr_hash_update(const NMPlatformLnkHsr *obj, NMHashState *h); void nm_platform_lnk_infiniband_hash_update(const NMPlatformLnkInfiniband *obj, NMHashState *h); diff --git a/src/libnm-platform/nmp-base.h b/src/libnm-platform/nmp-base.h index f665629645..ae538f5bad 100644 --- a/src/libnm-platform/nmp-base.h +++ b/src/libnm-platform/nmp-base.h @@ -166,6 +166,7 @@ typedef enum _nm_packed { NMP_OBJECT_TYPE_TFILTER, NMP_OBJECT_TYPE_LNK_BRIDGE, + NMP_OBJECT_TYPE_LNK_GENEVE, NMP_OBJECT_TYPE_LNK_GRE, NMP_OBJECT_TYPE_LNK_GRETAP, NMP_OBJECT_TYPE_LNK_HSR, @@ -194,15 +195,15 @@ typedef enum _nm_packed { NMP_OBJECT_TYPE_MAX = __NMP_OBJECT_TYPE_LAST - 1, } NMPObjectType; -static inline guint32 +static inline guint64 nmp_object_type_to_flags(NMPObjectType obj_type) { - G_STATIC_ASSERT_EXPR(NMP_OBJECT_TYPE_MAX < 32); + G_STATIC_ASSERT_EXPR(NMP_OBJECT_TYPE_MAX < 64); nm_assert(_NM_INT_NOT_NEGATIVE(obj_type)); nm_assert(obj_type < NMP_OBJECT_TYPE_MAX); - return ((guint32) 1u) << obj_type; + return ((guint64) 1u) << obj_type; } /*****************************************************************************/ diff --git a/src/libnm-platform/nmp-object.c b/src/libnm-platform/nmp-object.c index 56533c99c5..d73eb641f1 100644 --- a/src/libnm-platform/nmp-object.c +++ b/src/libnm-platform/nmp-object.c @@ -3469,6 +3469,18 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_bridge_hash_update, .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_bridge_cmp, }, + [NMP_OBJECT_TYPE_LNK_GENEVE - 1] = + { + .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), + .obj_type = NMP_OBJECT_TYPE_LNK_GENEVE, + .sizeof_data = sizeof(NMPObjectLnkGeneve), + .sizeof_public = sizeof(NMPlatformLnkGeneve), + .obj_type_name = "geneve", + .lnk_link_type = NM_LINK_TYPE_GENEVE, + .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_lnk_geneve_to_string, + .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_geneve_hash_update, + .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_geneve_cmp, + }, [NMP_OBJECT_TYPE_LNK_GRE - 1] = { .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), diff --git a/src/libnm-platform/nmp-object.h b/src/libnm-platform/nmp-object.h index b526fc3bec..a960c528c7 100644 --- a/src/libnm-platform/nmp-object.h +++ b/src/libnm-platform/nmp-object.h @@ -250,6 +250,10 @@ typedef struct { NMPlatformLnkBond _public; } NMPObjectLnkBond; +typedef struct { + NMPlatformLnkGeneve _public; +} NMPObjectLnkGeneve; + typedef struct { NMPlatformLnkGre _public; } NMPObjectLnkGre; @@ -383,6 +387,9 @@ struct _NMPObject { NMPlatformLnkBond lnk_bond; NMPObjectLnkBond _lnk_bond; + NMPlatformLnkGeneve lnk_geneve; + NMPObjectLnkGeneve _lnk_geneve; + NMPlatformLnkGre lnk_gre; NMPObjectLnkGre _lnk_gre; @@ -543,6 +550,7 @@ _NMP_OBJECT_TYPE_IS_OBJ_WITH_IFINDEX(NMPObjectType obj_type) case NMP_OBJECT_TYPE_LNK_BRIDGE: case NMP_OBJECT_TYPE_LNK_BOND: + case NMP_OBJECT_TYPE_LNK_GENEVE: case NMP_OBJECT_TYPE_LNK_GRE: case NMP_OBJECT_TYPE_LNK_GRETAP: case NMP_OBJECT_TYPE_LNK_HSR: diff --git a/src/libnm-platform/tests/test-nm-platform.c b/src/libnm-platform/tests/test-nm-platform.c index 22148f8c64..d087d66f38 100644 --- a/src/libnm-platform/tests/test-nm-platform.c +++ b/src/libnm-platform/tests/test-nm-platform.c @@ -19,6 +19,7 @@ G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectIP6Route)) G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLink)); G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLnkBond)); G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLnkBridge)); +G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLnkGeneve)); G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLnkGre)); G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLnkInfiniband)); G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPObjectLnkIp6Tnl)); @@ -49,6 +50,7 @@ G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformIPXRoute) G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLink)); G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLnkBond)); G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLnkBridge)); +G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLnkGeneve)); G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLnkGre)); G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLnkInfiniband)); G_STATIC_ASSERT(_nm_alignof(NMPlatformObject) == _nm_alignof(NMPlatformLnkIp6Tnl)); diff --git a/src/libnmc-setting/nm-meta-setting-base-impl.c b/src/libnmc-setting/nm-meta-setting-base-impl.c index 52af9ad259..d84490d238 100644 --- a/src/libnmc-setting/nm-meta-setting-base-impl.c +++ b/src/libnmc-setting/nm-meta-setting-base-impl.c @@ -27,6 +27,7 @@ #include "nm-setting-dummy.h" #include "nm-setting-ethtool.h" #include "nm-setting-generic.h" +#include "nm-setting-geneve.h" #include "nm-setting-gsm.h" #include "nm-setting-hostname.h" #include "nm-setting-hsr.h" @@ -324,6 +325,13 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = { .setting_name = NM_SETTING_GENERIC_SETTING_NAME, .get_setting_gtype = nm_setting_generic_get_type, }, + [NM_META_SETTING_TYPE_GENEVE] = + { + .meta_type = NM_META_SETTING_TYPE_GENEVE, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_GENEVE_SETTING_NAME, + .get_setting_gtype = nm_setting_geneve_get_type, + }, [NM_META_SETTING_TYPE_GSM] = { .meta_type = NM_META_SETTING_TYPE_GSM, @@ -655,6 +663,7 @@ const NMMetaSettingType nm_meta_setting_types_by_priority[] = { NM_META_SETTING_TYPE_CDMA, NM_META_SETTING_TYPE_DUMMY, NM_META_SETTING_TYPE_GENERIC, + NM_META_SETTING_TYPE_GENEVE, NM_META_SETTING_TYPE_GSM, NM_META_SETTING_TYPE_HSR, NM_META_SETTING_TYPE_INFINIBAND, diff --git a/src/libnmc-setting/nm-meta-setting-base-impl.h b/src/libnmc-setting/nm-meta-setting-base-impl.h index d1535e5e1f..8f512d09c6 100644 --- a/src/libnmc-setting/nm-meta-setting-base-impl.h +++ b/src/libnmc-setting/nm-meta-setting-base-impl.h @@ -121,6 +121,7 @@ typedef enum _nm_packed { NM_META_SETTING_TYPE_DUMMY, NM_META_SETTING_TYPE_ETHTOOL, NM_META_SETTING_TYPE_GENERIC, + NM_META_SETTING_TYPE_GENEVE, NM_META_SETTING_TYPE_GSM, NM_META_SETTING_TYPE_HOSTNAME, NM_META_SETTING_TYPE_HSR, diff --git a/src/libnmc-setting/nm-meta-setting-desc.c b/src/libnmc-setting/nm-meta-setting-desc.c index 5ce86e8bcb..6c9a5c0c1b 100644 --- a/src/libnmc-setting/nm-meta-setting-desc.c +++ b/src/libnmc-setting/nm-meta-setting-desc.c @@ -6112,6 +6112,57 @@ static const NMMetaPropertyInfo *const property_infos_GENERIC[] = { NULL }; +#undef _CURRENT_NM_META_SETTING_TYPE +#define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_GENEVE +static const NMMetaPropertyInfo *const property_infos_GENEVE[] = { + PROPERTY_INFO_WITH_DESC (NM_SETTING_GENEVE_ID, + .is_cli_option = TRUE, + .property_alias = "id", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = N_("GENEVE ID"), + .property_type = &_pt_gobject_int, + ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_GENEVE_REMOTE, + .is_cli_option = TRUE, + .property_alias = "remote", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = N_("Remote"), + .property_type = &_pt_gobject_string, + ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_GENEVE_DESTINATION_PORT, + .is_cli_option = TRUE, + .property_alias = "destination-port", + .prompt = N_("Destination port"), + .property_type = &_pt_gobject_int, + ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_GENEVE_TOS, + .property_type = &_pt_gobject_int, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int, + .value_infos = INT_VALUE_INFOS ( + { + .value.u64 = 1, + .nick = "inherit", + }, + ), + ), + ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_GENEVE_TTL, + .property_type = &_pt_gobject_int, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int, + .value_infos = INT_VALUE_INFOS ( + { + .value.i64 = -1, + .nick = "inherit", + }, + ), + ), + ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_GENEVE_DF, + .property_type = &_pt_gobject_enum, + ), + NULL +}; + #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_GSM static const NMMetaPropertyInfo *const property_infos_GSM[] = { @@ -9018,6 +9069,7 @@ _setting_init_fcn_wireless (ARGS_SETTING_INIT_FCN) #define SETTING_PRETTY_NAME_DUMMY N_("Dummy settings") #define SETTING_PRETTY_NAME_ETHTOOL N_("Ethtool settings") #define SETTING_PRETTY_NAME_GENERIC N_("Generic settings") +#define SETTING_PRETTY_NAME_GENEVE N_("Geneve settings") #define SETTING_PRETTY_NAME_GSM N_("GSM mobile broadband connection") #define SETTING_PRETTY_NAME_HOSTNAME N_("Hostname settings") #define SETTING_PRETTY_NAME_HSR N_("HSR settings") @@ -9156,6 +9208,14 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = { NM_META_SETTING_VALID_PART_ITEM (GENERIC, TRUE), ), ), + SETTING_INFO (GENEVE, + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (GENEVE, TRUE), + NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE), + NM_META_SETTING_VALID_PART_ITEM (ETHTOOL, FALSE), + ), + ), SETTING_INFO (GSM, .valid_parts = NM_META_SETTING_VALID_PARTS ( NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), diff --git a/src/libnmc-setting/settings-docs.h.in b/src/libnmc-setting/settings-docs.h.in index e02a93e43d..97848c8a67 100644 --- a/src/libnmc-setting/settings-docs.h.in +++ b/src/libnmc-setting/settings-docs.h.in @@ -499,6 +499,12 @@ #define DESCRIBE_DOC_NM_SETTING_WPAN_SHORT_ADDRESS N_("Short IEEE 802.15.4 address to be used within a restricted environment.") #define DESCRIBE_DOC_NM_SETTING_BOND_PORT_PRIO N_("The port priority for bond active port re-selection during failover. A higher number means a higher priority in selection. The primary port has the highest priority. This option is only compatible with active-backup, balance-tlb and balance-alb modes.") #define DESCRIBE_DOC_NM_SETTING_BOND_PORT_QUEUE_ID N_("The queue ID of this bond port. The maximum value of queue ID is the number of TX queues currently active in device.") +#define DESCRIBE_DOC_NM_SETTING_GENEVE_DESTINATION_PORT N_("Specifies the UDP destination port to communicate to the remote GENEVE tunnel endpoint.") +#define DESCRIBE_DOC_NM_SETTING_GENEVE_DF N_("Specifies how the Don't Fragment (DF) flag should be handled in the outer IP header of GENEVE tunnel packets. \"unset\" (0) (0): Don't set the DF flag, packets may be fragmented. \"set\" (1) (1): Always set the DF flag, packets will not be fragmented. \"inherit\" (2) (2): Inherit the DF flag from the inner IP header.") +#define DESCRIBE_DOC_NM_SETTING_GENEVE_ID N_("Specifies the GENEVE Network Identifier (or GENEVE Segment Identifier) to use.") +#define DESCRIBE_DOC_NM_SETTING_GENEVE_REMOTE N_("Specifies the unicast destination IP address to use in outgoing packets when communicating with the remote GENEVE tunnel endpoint.") +#define DESCRIBE_DOC_NM_SETTING_GENEVE_TOS N_("Specifies the TOS value to use in outgoing packets. The special value \"inherit\" (1) means inherit from outer packet.") +#define DESCRIBE_DOC_NM_SETTING_GENEVE_TTL N_("Specifies the time-to-live value to use in outgoing packets. The special value \"inherit\" (-1) means inherit from outer packet, 0 means auto, 1-255 are fixed values.") #define DESCRIBE_DOC_NM_SETTING_HOSTNAME_FROM_DHCP N_("Whether the system hostname can be determined from DHCP on this connection. When set to \"default\" (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be \"true\" (1).") #define DESCRIBE_DOC_NM_SETTING_HOSTNAME_FROM_DNS_LOOKUP N_("Whether the system hostname can be determined from reverse DNS lookup of addresses on this device. When set to \"default\" (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be \"true\" (1).") #define DESCRIBE_DOC_NM_SETTING_HOSTNAME_ONLY_FROM_DEFAULT N_("If set to \"true\" (1), NetworkManager attempts to get the hostname via DHCPv4/DHCPv6 or reverse DNS lookup on this device only when the device has the default route for the given address family (IPv4/IPv6). If set to \"false\" (0), the hostname can be set from this device even if it doesn't have the default route. When set to \"default\" (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be \"false\" (0).") diff --git a/src/nmcli/connections.c b/src/nmcli/connections.c index d93e16f03c..a3b03efe31 100644 --- a/src/nmcli/connections.c +++ b/src/nmcli/connections.c @@ -4,6 +4,7 @@ */ #include "libnm-client-aux-extern/nm-default-client.h" +#include "nmcli.h" #include "connections.h" @@ -1070,13 +1071,13 @@ const NmcMetaGenericInfo "," 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_GENEVE_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[] = { @@ -1306,6 +1307,9 @@ usage_connection_add(void) " [source-port-min <0-65535>]\n" " [source-port-max <0-65535>]\n" " [destination-port <0-65535>]\n\n" + " geneve: id \n" + " remote \n" + " [destination-port <0-65535>]\n\n" " wpan: [short-addr <0x0000-0xffff>]\n" " [pan-id <0x0000-0xffff>]\n" " [page ]\n" diff --git a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in index 8733cc995b..8b98e95e24 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, ipvlan, loopback, macsec, macvlan, ovs-bridge, ovs-interface, 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, geneve, gsm, hsr, infiniband, ip-tunnel, ipvlan, loopback, macsec, macvlan, ovs-bridge, ovs-interface, ovs-port, pppoe, team, tun, veth, vlan, vpn, vrf, vxlan, wifi-p2p, wimax, wireguard, wpan" /> + + + + + + + +