diff options
author | Beniamino Galvani <bgalvani@redhat.com> | 2020-01-14 10:31:41 +0100 |
---|---|---|
committer | Beniamino Galvani <bgalvani@redhat.com> | 2020-01-14 10:31:41 +0100 |
commit | e6a9d5b99c7b674c3a932a5e16921eb9e3a7073c (patch) | |
tree | db4cb3002a0517c5d2438a3f02dc06a2c81cf9f4 | |
parent | 56e91b11a24f87e57ee0ae9535c081796e4bdeb9 (diff) | |
parent | 667568d1b2be54b03ce1dd078433a32c39a2a3eb (diff) | |
download | NetworkManager-e6a9d5b99c7b674c3a932a5e16921eb9e3a7073c.tar.gz |
merge: branch 'bg/vrf'
Add support for virtual routing and forwarding (VRF) interfaces.
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/375
47 files changed, 1113 insertions, 11 deletions
diff --git a/Makefile.am b/Makefile.am index 1673fc1fc3..ab4f8b8e3b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -693,6 +693,8 @@ introspection_sources = \ introspection/org.freedesktop.NetworkManager.Device.Veth.h \ introspection/org.freedesktop.NetworkManager.Device.Vlan.c \ introspection/org.freedesktop.NetworkManager.Device.Vlan.h \ + introspection/org.freedesktop.NetworkManager.Device.Vrf.c \ + introspection/org.freedesktop.NetworkManager.Device.Vrf.h \ introspection/org.freedesktop.NetworkManager.Device.Vxlan.c \ introspection/org.freedesktop.NetworkManager.Device.Vxlan.h \ introspection/org.freedesktop.NetworkManager.Device.WiMax.c \ @@ -764,6 +766,7 @@ DBUS_INTERFACE_DOCS = \ docs/api/dbus-org.freedesktop.NetworkManager.Device.Tun.xml \ docs/api/dbus-org.freedesktop.NetworkManager.Device.Veth.xml \ docs/api/dbus-org.freedesktop.NetworkManager.Device.Vlan.xml \ + docs/api/dbus-org.freedesktop.NetworkManager.Device.Vrf.xml \ docs/api/dbus-org.freedesktop.NetworkManager.Device.Vxlan.xml \ docs/api/dbus-org.freedesktop.NetworkManager.Device.WiMax.xml \ docs/api/dbus-org.freedesktop.NetworkManager.Device.WifiP2P.xml \ @@ -831,6 +834,7 @@ dbusinterfaces_DATA = \ introspection/org.freedesktop.NetworkManager.Device.Tun.xml \ introspection/org.freedesktop.NetworkManager.Device.Veth.xml \ introspection/org.freedesktop.NetworkManager.Device.Vlan.xml \ + introspection/org.freedesktop.NetworkManager.Device.Vrf.xml \ introspection/org.freedesktop.NetworkManager.Device.Vxlan.xml \ introspection/org.freedesktop.NetworkManager.Device.WiMax.xml \ introspection/org.freedesktop.NetworkManager.Device.WifiP2P.xml \ @@ -918,6 +922,7 @@ libnm_core_lib_h_pub_real = \ libnm-core/nm-setting-user.h \ libnm-core/nm-setting-vlan.h \ libnm-core/nm-setting-vpn.h \ + libnm-core/nm-setting-vrf.h \ libnm-core/nm-setting-vxlan.h \ libnm-core/nm-setting-wifi-p2p.h \ libnm-core/nm-setting-wimax.h \ @@ -990,6 +995,7 @@ libnm_core_lib_c_settings_real = \ libnm-core/nm-setting-user.c \ libnm-core/nm-setting-vlan.c \ libnm-core/nm-setting-vpn.c \ + libnm-core/nm-setting-vrf.c \ libnm-core/nm-setting-vxlan.c \ libnm-core/nm-setting-wifi-p2p.c \ libnm-core/nm-setting-wimax.c \ @@ -1317,6 +1323,7 @@ libnm_lib_h_pub_real = \ libnm/nm-device-team.h \ libnm/nm-device-tun.h \ libnm/nm-device-vlan.h \ + libnm/nm-device-vrf.h \ libnm/nm-device-vxlan.h \ libnm/nm-device-wifi-p2p.h \ libnm/nm-device-wifi.h \ @@ -1380,6 +1387,7 @@ libnm_lib_c_real = \ libnm/nm-device-team.c \ libnm/nm-device-tun.c \ libnm/nm-device-vlan.c \ + libnm/nm-device-vrf.c \ libnm/nm-device-vxlan.c \ libnm/nm-device-wifi-p2p.c \ libnm/nm-device-wifi.c \ @@ -2167,6 +2175,8 @@ src_libNetworkManager_la_SOURCES = \ src/devices/nm-device-veth.h \ src/devices/nm-device-vlan.c \ src/devices/nm-device-vlan.h \ + src/devices/nm-device-vrf.c \ + src/devices/nm-device-vrf.h \ src/devices/nm-device-vxlan.c \ src/devices/nm-device-vxlan.h \ src/devices/nm-device-wireguard.c \ diff --git a/clients/cli/connections.c b/clients/cli/connections.c index a4fbf6df3a..6e4e7fd964 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -855,6 +855,7 @@ const NmcMetaGenericInfo *const metagen_con_active_vpn[_NMC_GENERIC_INFO_TYPE_CO 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","\ diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index d28efa0753..c5b8bb3166 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -5127,7 +5127,8 @@ static const NMMetaPropertyInfo *const property_infos_CONNECTION[] = { NM_SETTING_BRIDGE_SETTING_NAME, NM_SETTING_OVS_BRIDGE_SETTING_NAME, NM_SETTING_OVS_PORT_SETTING_NAME, - NM_SETTING_TEAM_SETTING_NAME), + NM_SETTING_TEAM_SETTING_NAME, + NM_SETTING_VRF_SETTING_NAME), ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES, @@ -6915,6 +6916,20 @@ static const NMMetaPropertyInfo *const property_infos_VPN[] = { }; #undef _CURRENT_NM_META_SETTING_TYPE +#define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_VRF +static const NMMetaPropertyInfo *const property_infos_VRF[] = { + PROPERTY_INFO_WITH_DESC (NM_SETTING_VRF_TABLE, + .is_cli_option = TRUE, + .property_alias = "table", + .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, + .prompt = N_("Table [0]"), + .property_type = &_pt_gobject_int, + ), + NULL +}; + + +#undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_VXLAN static const NMMetaPropertyInfo *const property_infos_VXLAN[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_VXLAN_PARENT, @@ -7698,6 +7713,7 @@ _setting_init_fcn_wireless (ARGS_SETTING_INIT_FCN) #define SETTING_PRETTY_NAME_USER N_("User settings") #define SETTING_PRETTY_NAME_VLAN N_("VLAN connection") #define SETTING_PRETTY_NAME_VPN N_("VPN connection") +#define SETTING_PRETTY_NAME_VRF N_("VRF connection") #define SETTING_PRETTY_NAME_VXLAN N_("VXLAN connection") #define SETTING_PRETTY_NAME_WIFI_P2P N_("Wi-Fi P2P connection") #define SETTING_PRETTY_NAME_WIMAX N_("WiMAX connection") @@ -7938,6 +7954,13 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = { NM_META_SETTING_VALID_PART_ITEM (VPN, TRUE), ), ), + SETTING_INFO (VRF, + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (VRF, TRUE), + ), + ), + SETTING_INFO (VXLAN, .valid_parts = NM_META_SETTING_VALID_PARTS ( NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), @@ -8062,6 +8085,10 @@ nm_meta_setting_info_valid_parts_for_slave_type (const char *slave_type, const c NM_SET_OUT (out_slave_name, "team-slave"); return valid_settings_slave_team; } + if (nm_streq (slave_type, NM_SETTING_VRF_SETTING_NAME)) { + NM_SET_OUT (out_slave_name, "vrf-slave"); + return valid_settings_noslave; + } return NULL; } diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in index 57e9ab2a48..5ab0152222 100644 --- a/clients/common/settings-docs.h.in +++ b/clients/common/settings-docs.h.in @@ -354,6 +354,7 @@ #define DESCRIBE_DOC_NM_SETTING_VPN_SERVICE_TYPE N_("D-Bus service name of the VPN plugin that this setting uses to connect to its network. i.e. org.freedesktop.NetworkManager.vpnc for the vpnc plugin.") #define DESCRIBE_DOC_NM_SETTING_VPN_TIMEOUT N_("Timeout for the VPN service to establish the connection. Some services may take quite a long time to connect. Value of 0 means a default timeout, which is 60 seconds (unless overridden by vpn.timeout in configuration file). Values greater than zero mean timeout in seconds.") #define DESCRIBE_DOC_NM_SETTING_VPN_USER_NAME N_("If the VPN connection requires a user name for authentication, that name should be provided here. If the connection is available to more than one user, and the VPN requires each user to supply a different name, then leave this property empty. If this property is empty, NetworkManager will automatically supply the username of the user which requested the VPN connection.") +#define DESCRIBE_DOC_NM_SETTING_VRF_TABLE N_("The routing table for this VRF.") #define DESCRIBE_DOC_NM_SETTING_VXLAN_AGEING N_("Specifies the lifetime in seconds of FDB entries learnt by the kernel.") #define DESCRIBE_DOC_NM_SETTING_VXLAN_DESTINATION_PORT N_("Specifies the UDP destination port to communicate to the remote VXLAN tunnel endpoint.") #define DESCRIBE_DOC_NM_SETTING_VXLAN_ID N_("Specifies the VXLAN Network Identifier (or VXLAN Segment Identifier) to use.") diff --git a/docs/api/network-manager-docs.xml b/docs/api/network-manager-docs.xml index fd7a1c3ec4..883df41d78 100644 --- a/docs/api/network-manager-docs.xml +++ b/docs/api/network-manager-docs.xml @@ -202,6 +202,7 @@ <xi:include href="dbus-org.freedesktop.NetworkManager.Device.Tun.xml"/> <xi:include href="dbus-org.freedesktop.NetworkManager.Device.Veth.xml"/> <xi:include href="dbus-org.freedesktop.NetworkManager.Device.Vlan.xml"/> + <xi:include href="dbus-org.freedesktop.NetworkManager.Device.Vrf.xml"/> <xi:include href="dbus-org.freedesktop.NetworkManager.Device.Vxlan.xml"/> <xi:include href="dbus-org.freedesktop.NetworkManager.Device.WifiP2P.xml"/> <xi:include href="dbus-org.freedesktop.NetworkManager.Device.WireGuard.xml"/> diff --git a/docs/libnm/libnm-docs.xml b/docs/libnm/libnm-docs.xml index 357cfe16d0..b482207abb 100644 --- a/docs/libnm/libnm-docs.xml +++ b/docs/libnm/libnm-docs.xml @@ -350,6 +350,7 @@ print ("NetworkManager version " + client.get_version())]]></programlisting></in <xi:include href="xml/nm-setting-user.xml"/> <xi:include href="xml/nm-setting-vlan.xml"/> <xi:include href="xml/nm-setting-vpn.xml"/> + <xi:include href="xml/nm-setting-vrf.xml"/> <xi:include href="xml/nm-setting-vxlan.xml"/> <xi:include href="xml/nm-setting-wifi-p2p.xml"/> <xi:include href="xml/nm-setting-wimax.xml"/> @@ -386,6 +387,7 @@ print ("NetworkManager version " + client.get_version())]]></programlisting></in <xi:include href="xml/nm-device-team.xml"/> <xi:include href="xml/nm-device-tun.xml"/> <xi:include href="xml/nm-device-vlan.xml"/> + <xi:include href="xml/nm-device-vrf.xml"/> <xi:include href="xml/nm-device-vxlan.xml"/> <xi:include href="xml/nm-device-wifi-p2p.xml"/> <xi:include href="xml/nm-device-wifi.xml"/> diff --git a/introspection/meson.build b/introspection/meson.build index 3f8a1b1581..f25251fd78 100644 --- a/introspection/meson.build +++ b/introspection/meson.build @@ -33,6 +33,7 @@ ifaces = [ 'org.freedesktop.NetworkManager.Device.Tun', 'org.freedesktop.NetworkManager.Device.Veth', 'org.freedesktop.NetworkManager.Device.Vlan', + 'org.freedesktop.NetworkManager.Device.Vrf', 'org.freedesktop.NetworkManager.Device.Vxlan', 'org.freedesktop.NetworkManager.Device.WiMax', 'org.freedesktop.NetworkManager.Device.WifiP2P', diff --git a/introspection/org.freedesktop.NetworkManager.Device.Vrf.xml b/introspection/org.freedesktop.NetworkManager.Device.Vrf.xml new file mode 100644 index 0000000000..971d2b619d --- /dev/null +++ b/introspection/org.freedesktop.NetworkManager.Device.Vrf.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<node name="/"> + <!-- + org.freedesktop.NetworkManager.Device.Vrf: + @short_description: VRF Device + + --> + <interface name="org.freedesktop.NetworkManager.Device.Vrf"> + + <!-- + Table: + + The routing table of the VRF. + --> + <property name="Table" type="u" access="read"/> + </interface> +</node> diff --git a/libnm-core/meson.build b/libnm-core/meson.build index 4e1c93e778..27d6e2c8cc 100644 --- a/libnm-core/meson.build +++ b/libnm-core/meson.build @@ -56,6 +56,7 @@ libnm_core_headers = files( 'nm-setting-user.h', 'nm-setting-vlan.h', 'nm-setting-vpn.h', + 'nm-setting-vrf.h', 'nm-setting-vxlan.h', 'nm-setting-wifi-p2p.h', 'nm-setting-wimax.h', @@ -150,6 +151,7 @@ libnm_core_settings_sources = files( 'nm-setting-user.c', 'nm-setting-vlan.c', 'nm-setting-vpn.c', + 'nm-setting-vrf.c', 'nm-setting-vxlan.c', 'nm-setting-wifi-p2p.c', 'nm-setting-wimax.c', diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index bedf3003c7..7c62bea2f3 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -887,6 +887,7 @@ static gboolean _supports_addr_family (NMConnection *self, int family) { const char *connection_type = nm_connection_get_connection_type (self); + NMSettingConnection *s_con; g_return_val_if_fail (connection_type, TRUE); if (strcmp (connection_type, NM_SETTING_OVS_INTERFACE_SETTING_NAME) == 0) @@ -895,6 +896,9 @@ _supports_addr_family (NMConnection *self, int family) return FALSE; if (strcmp (connection_type, NM_SETTING_6LOWPAN_SETTING_NAME) == 0) return family == AF_INET6 || family == AF_UNSPEC; + if ( (s_con = nm_connection_get_setting_connection (self)) + && (nm_streq0 (nm_setting_connection_get_slave_type (s_con), NM_SETTING_VRF_SETTING_NAME))) + return TRUE; return !nm_setting_connection_get_master (nm_connection_get_setting_connection (self)); } @@ -2687,6 +2691,7 @@ nm_connection_is_virtual (NMConnection *connection) NM_SETTING_TEAM_SETTING_NAME, NM_SETTING_TUN_SETTING_NAME, NM_SETTING_VLAN_SETTING_NAME, + NM_SETTING_VRF_SETTING_NAME, NM_SETTING_VXLAN_SETTING_NAME, NM_SETTING_WIREGUARD_SETTING_NAME)) return TRUE; diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index 95cfc47f3d..bd65432eee 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -61,6 +61,7 @@ #include "nm-setting-tun.h" #include "nm-setting-vlan.h" #include "nm-setting-vpn.h" +#include "nm-setting-vrf.h" #include "nm-setting-vxlan.h" #include "nm-setting-wifi-p2p.h" #include "nm-setting-wimax.h" diff --git a/libnm-core/nm-core-types.h b/libnm-core/nm-core-types.h index d7c1b5b5b7..d1ce6310cd 100644 --- a/libnm-core/nm-core-types.h +++ b/libnm-core/nm-core-types.h @@ -54,6 +54,7 @@ typedef struct _NMSettingTun NMSettingTun; typedef struct _NMSettingUser NMSettingUser; typedef struct _NMSettingVlan NMSettingVlan; typedef struct _NMSettingVpn NMSettingVpn; +typedef struct _NMSettingVrf NMSettingVrf; typedef struct _NMSettingVxlan NMSettingVxlan; typedef struct _NMSettingWifiP2P NMSettingWifiP2P; typedef struct _NMSettingWimax NMSettingWimax; diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h index d5f17f1428..28ee89bfbe 100644 --- a/libnm-core/nm-dbus-interface.h +++ b/libnm-core/nm-dbus-interface.h @@ -52,6 +52,7 @@ #define NM_DBUS_INTERFACE_DEVICE_TUN NM_DBUS_INTERFACE_DEVICE ".Tun" #define NM_DBUS_INTERFACE_DEVICE_VETH NM_DBUS_INTERFACE_DEVICE ".Veth" #define NM_DBUS_INTERFACE_DEVICE_VLAN NM_DBUS_INTERFACE_DEVICE ".Vlan" +#define NM_DBUS_INTERFACE_DEVICE_VRF NM_DBUS_INTERFACE_DEVICE ".Vrf" #define NM_DBUS_INTERFACE_DEVICE_VXLAN NM_DBUS_INTERFACE_DEVICE ".Vxlan" #define NM_DBUS_INTERFACE_DEVICE_WIFI_P2P NM_DBUS_INTERFACE_DEVICE ".WifiP2P" #define NM_DBUS_INTERFACE_DEVICE_WIMAX NM_DBUS_INTERFACE_DEVICE ".WiMax" @@ -213,6 +214,7 @@ typedef enum { * @NM_DEVICE_TYPE_6LOWPAN: 6LoWPAN interface * @NM_DEVICE_TYPE_WIREGUARD: a WireGuard interface * @NM_DEVICE_TYPE_WIFI_P2P: an 802.11 Wi-Fi P2P device (Since: 1.16) + * @NM_DEVICE_TYPE_VRF: A VRF (Virtual Routing and Forwarding) interface (Since: 1.24) * * #NMDeviceType values indicate the type of hardware represented by a * device object. @@ -249,6 +251,7 @@ typedef enum { NM_DEVICE_TYPE_6LOWPAN = 28, NM_DEVICE_TYPE_WIREGUARD = 29, NM_DEVICE_TYPE_WIFI_P2P = 30, + NM_DEVICE_TYPE_VRF = 31, } NMDeviceType; /** diff --git a/libnm-core/nm-setting-vrf.c b/libnm-core/nm-setting-vrf.c new file mode 100644 index 0000000000..9a62e86493 --- /dev/null +++ b/libnm-core/nm-setting-vrf.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: LGPL-2.1+ + +#include "nm-default.h" + +#include "nm-setting-vrf.h" + +#include "nm-connection-private.h" +#include "nm-setting-connection.h" +#include "nm-setting-private.h" + +/** + * SECTION:nm-setting-vrf + * @short_description: Describes connection properties for vrf interfaces + * + * The #NMSettingVrf object is a #NMSetting subclass that describes properties + * necessary for connection to vrf devices + **/ + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE_BASE ( + PROP_TABLE, +); + +/** + * NMSettingVrf: + * + * VRF settings. + * + * Since: 1.24 + */ +struct _NMSettingVrf { + NMSetting parent; + guint32 table; +}; + +struct _NMSettingVrfClass { + NMSettingClass parent; +}; + +G_DEFINE_TYPE (NMSettingVrf, nm_setting_vrf, NM_TYPE_SETTING) + +/*****************************************************************************/ + +/** + * nm_setting_vrf_get_table: + * @setting: the #NMSettingVrf + * + * Returns: the routing table for the VRF + * + * Since: 1.24 + **/ +guint32 +nm_setting_vrf_get_table (NMSettingVrf *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_VRF (setting), 0); + + return setting->table; +} + +/*****************************************************************************/ + +static gboolean +verify (NMSetting *setting, NMConnection *connection, GError **error) +{ + NMSettingVrf *self = NM_SETTING_VRF (setting); + + if (!_nm_connection_verify_required_interface_name (connection, error)) + return FALSE; + + if (self->table == 0) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("table cannot be zero")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_VRF_SETTING_NAME, + NM_SETTING_VRF_TABLE); + return FALSE; + } + + return TRUE; +} + +/*****************************************************************************/ + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMSettingVrf *self = NM_SETTING_VRF (object); + + switch (prop_id) { + case PROP_TABLE: + g_value_set_uint (value, self->table); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMSettingVrf *self = NM_SETTING_VRF (object); + + switch (prop_id) { + case PROP_TABLE: + self->table = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/*****************************************************************************/ + +static void +nm_setting_vrf_init (NMSettingVrf *setting) +{ +} + +/** + * nm_setting_vrf_new: + * + * Creates a new #NMSettingVrf object with default values. + * + * Returns: (transfer full): the new empty #NMSettingVrf object + * + * Since: 1.24 + **/ +NMSetting * +nm_setting_vrf_new (void) +{ + return (NMSetting *) g_object_new (NM_TYPE_SETTING_VRF, NULL); +} + +static void +nm_setting_vrf_class_init (NMSettingVrfClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMSettingClass *setting_class = NM_SETTING_CLASS (klass); + + object_class->get_property = get_property; + object_class->set_property = set_property; + + setting_class->verify = verify; + + /** + * NMSettingVrf:table: + * + * The routing table for this VRF. + * + * Since: 1.24 + **/ + obj_properties[PROP_TABLE] = + g_param_spec_uint (NM_SETTING_VRF_TABLE, "", "", + 0, G_MAXUINT32, 0, + G_PARAM_READWRITE | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + _nm_setting_class_commit (setting_class, NM_META_SETTING_TYPE_VRF); +} diff --git a/libnm-core/nm-setting-vrf.h b/libnm-core/nm-setting-vrf.h new file mode 100644 index 0000000000..774a4824b7 --- /dev/null +++ b/libnm-core/nm-setting-vrf.h @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: LGPL-2.1+ + +#ifndef __NM_SETTING_VRF_H__ +#define __NM_SETTING_VRF_H__ + +#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION) +#error "Only <NetworkManager.h> can be included directly." +#endif + +#include "nm-setting.h" + +G_BEGIN_DECLS + +#define NM_TYPE_SETTING_VRF (nm_setting_vrf_get_type ()) +#define NM_SETTING_VRF(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_VRF, NMSettingVrf)) +#define NM_SETTING_VRF_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTING_VRFCONFIG, NMSettingVrfClass)) +#define NM_IS_SETTING_VRF(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTING_VRF)) +#define NM_IS_SETTING_VRF_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SETTING_VRF)) +#define NM_SETTING_VRF_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTING_VRF, NMSettingVrfClass)) + +#define NM_SETTING_VRF_SETTING_NAME "vrf" + +#define NM_SETTING_VRF_TABLE "table" + +typedef struct _NMSettingVrfClass NMSettingVrfClass; + +NM_AVAILABLE_IN_1_24 +GType nm_setting_vrf_get_type (void); +NM_AVAILABLE_IN_1_24 +NMSetting *nm_setting_vrf_new (void); +NM_AVAILABLE_IN_1_24 +guint32 nm_setting_vrf_get_table (NMSettingVrf *setting); + +G_END_DECLS + +#endif /* __NM_SETTING_VRF_H__ */ diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c index b7be9c657f..a75302f00f 100644 --- a/libnm-core/nm-setting.c +++ b/libnm-core/nm-setting.c @@ -151,15 +151,18 @@ _nm_setting_slave_type_is_valid (const char *slave_type, const char **out_port_t if (!slave_type) found = FALSE; - else if (!strcmp (slave_type, NM_SETTING_BOND_SETTING_NAME)) - ; - else if (!strcmp (slave_type, NM_SETTING_BRIDGE_SETTING_NAME)) + else if (NM_IN_STRSET (slave_type, + NM_SETTING_BOND_SETTING_NAME, + NM_SETTING_VRF_SETTING_NAME)) { + /* pass */ + } + else if (nm_streq (slave_type, NM_SETTING_BRIDGE_SETTING_NAME)) port_type = NM_SETTING_BRIDGE_PORT_SETTING_NAME; - else if (!strcmp (slave_type, NM_SETTING_OVS_BRIDGE_SETTING_NAME)) + else if (nm_streq (slave_type, NM_SETTING_OVS_BRIDGE_SETTING_NAME)) port_type = NM_SETTING_OVS_PORT_SETTING_NAME; - else if (!strcmp (slave_type, NM_SETTING_OVS_PORT_SETTING_NAME)) + else if (nm_streq (slave_type, NM_SETTING_OVS_PORT_SETTING_NAME)) port_type = NM_SETTING_OVS_INTERFACE_SETTING_NAME; - else if (!strcmp (slave_type, NM_SETTING_TEAM_SETTING_NAME)) + else if (nm_streq (slave_type, NM_SETTING_TEAM_SETTING_NAME)) port_type = NM_SETTING_TEAM_PORT_SETTING_NAME; else found = FALSE; diff --git a/libnm/NetworkManager.h b/libnm/NetworkManager.h index 6a0f117865..41f9354222 100644 --- a/libnm/NetworkManager.h +++ b/libnm/NetworkManager.h @@ -88,6 +88,7 @@ #include "nm-setting-user.h" #include "nm-setting-vlan.h" #include "nm-setting-vpn.h" +#include "nm-setting-vrf.h" #include "nm-setting-vxlan.h" #include "nm-setting-wimax.h" #include "nm-setting-wired.h" diff --git a/libnm/libnm.ver b/libnm/libnm.ver index d8e069f8ae..3ff469b0c5 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1664,5 +1664,10 @@ global: nm_client_get_object_by_path; nm_client_get_permissions_state; nm_client_instance_flags_get_type; + nm_device_vrf_get_table; + nm_device_vrf_get_type; nm_object_get_client; + nm_setting_vrf_get_table; + nm_setting_vrf_get_type; + nm_setting_vrf_new; } libnm_1_22_0; diff --git a/libnm/meson.build b/libnm/meson.build index 7680b9ebe0..29a21db76a 100644 --- a/libnm/meson.build +++ b/libnm/meson.build @@ -39,6 +39,7 @@ libnm_headers = files( 'nm-device-team.h', 'nm-device-tun.h', 'nm-device-vlan.h', + 'nm-device-vrf.h', 'nm-device-vxlan.h', 'nm-device-wifi-p2p.h', 'nm-device-wifi.h', @@ -104,6 +105,7 @@ libnm_sources = files( 'nm-device-team.c', 'nm-device-tun.c', 'nm-device-vlan.c', + 'nm-device-vrf.c', 'nm-device-vxlan.c', 'nm-device-wifi-p2p.c', 'nm-device-wifi.c', diff --git a/libnm/nm-device-vrf.c b/libnm/nm-device-vrf.c new file mode 100644 index 0000000000..2036e16f8c --- /dev/null +++ b/libnm/nm-device-vrf.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: LGPL-2.1+ + +#include "nm-default.h" + +#include "nm-device-vrf.h" + +#include "nm-setting-connection.h" +#include "nm-setting-vrf.h" +#include "nm-utils.h" +#include "nm-object-private.h" + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE_BASE ( + PROP_TABLE, +); + +typedef struct { + guint32 table; +} NMDeviceVrfPrivate; + +struct _NMDeviceVrf { + NMDevice parent; + NMDeviceVrfPrivate _priv; +}; + +struct _NMDeviceVrfClass { + NMDeviceClass parent; +}; + +G_DEFINE_TYPE (NMDeviceVrf, nm_device_vrf, NM_TYPE_DEVICE) + +#define NM_DEVICE_VRF_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMDeviceVrf, NM_IS_DEVICE_VRF, NMObject, NMDevice) + +/*****************************************************************************/ + +/** + * nm_device_vrf_get_table: + * @device: a #NMDeviceVrf + * + * Returns: the device's VRF routing table. + * + * Since: 1.24 + **/ +guint32 +nm_device_vrf_get_table (NMDeviceVrf *device) +{ + g_return_val_if_fail (NM_IS_DEVICE_VRF (device), 0); + + return NM_DEVICE_VRF_GET_PRIVATE (device)->table; +} + +static gboolean +connection_compatible (NMDevice *device, NMConnection *connection, GError **error) +{ + NMSettingVrf *s_vrf; + + if (!NM_DEVICE_CLASS (nm_device_vrf_parent_class)->connection_compatible (device, connection, error)) + return FALSE; + + if (!nm_connection_is_type (connection, NM_SETTING_VRF_SETTING_NAME)) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, + _("The connection was not a VRF connection.")); + return FALSE; + } + + s_vrf = (NMSettingVrf *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VRF); + if (nm_setting_vrf_get_table (s_vrf) != nm_device_vrf_get_table (NM_DEVICE_VRF (device))) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, + _("The VRF table of the device and the connection didn't match.")); + return FALSE; + } + + return TRUE; +} + +static GType +get_setting_type (NMDevice *device) +{ + return NM_TYPE_SETTING_VRF; +} + +/*****************************************************************************/ + +static void +get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NMDeviceVrf *device = NM_DEVICE_VRF (object); + + switch (prop_id) { + case PROP_TABLE: + g_value_set_uint (value, nm_device_vrf_get_table (device)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nm_device_vrf_init (NMDeviceVrf *device) +{ +} + +const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_vrf = NML_DBUS_META_IFACE_INIT_PROP ( + NM_DBUS_INTERFACE_DEVICE_VRF, + nm_device_vrf_get_type, + NML_DBUS_META_INTERFACE_PRIO_INSTANTIATE_HIGH, + NML_DBUS_META_IFACE_DBUS_PROPERTIES ( + NML_DBUS_META_PROPERTY_INIT_U ("Table", PROP_TABLE, NMDeviceVrf, _priv.table), + ), +); + +static void +nm_device_vrf_class_init (NMDeviceVrfClass *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; + + _NM_OBJECT_CLASS_INIT_PRIV_PTR_DIRECT (nm_object_class, NMDeviceVrf); + + device_class->connection_compatible = connection_compatible; + device_class->get_setting_type = get_setting_type; + + /** + * NMDeviceVrf:table: + * + * The device's VRF table. + * + * Since: 1.24 + **/ + obj_properties[PROP_TABLE] = + g_param_spec_uint (NM_DEVICE_VRF_TABLE, "", "", + 0, G_MAXUINT32, 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); + + _nml_dbus_meta_class_init_with_properties (object_class, &_nml_dbus_meta_iface_nm_device_vrf); +} diff --git a/libnm/nm-device-vrf.h b/libnm/nm-device-vrf.h new file mode 100644 index 0000000000..bf7499ca70 --- /dev/null +++ b/libnm/nm-device-vrf.h @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: LGPL-2.1+ + +#ifndef __NM_DEVICE_VRF_H__ +#define __NM_DEVICE_VRF_H__ + +#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION) +#error "Only <NetworkManager.h> can be included directly." +#endif + +#include "nm-device.h" + +G_BEGIN_DECLS + +#define NM_TYPE_DEVICE_VRF (nm_device_vrf_get_type ()) +#define NM_DEVICE_VRF(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_VRF, NMDeviceVrf)) +#define NM_DEVICE_VRF_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_VRF, NMDeviceVrfClass)) +#define NM_IS_DEVICE_VRF(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_VRF)) +#define NM_IS_DEVICE_VRF_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_VRF)) +#define NM_DEVICE_VRF_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_VRF, NMDeviceVrfClass)) + +#define NM_DEVICE_VRF_TABLE "table" + +/** + * NMDeviceVrf: + */ +typedef struct _NMDeviceVrfClass NMDeviceVrfClass; + +NM_AVAILABLE_IN_1_24 +GType nm_device_vrf_get_type (void); +NM_AVAILABLE_IN_1_24 +guint32 nm_device_vrf_get_table (NMDeviceVrf *device); + +G_END_DECLS + +#endif /* __NM_DEVICE_VRF_H__ */ diff --git a/libnm/nm-device.c b/libnm/nm-device.c index ade67b0474..77b7da6b09 100644 --- a/libnm/nm-device.c +++ b/libnm/nm-device.c @@ -296,6 +296,7 @@ coerce_type (NMDeviceType type) case NM_DEVICE_TYPE_6LOWPAN: case NM_DEVICE_TYPE_WIREGUARD: case NM_DEVICE_TYPE_WIFI_P2P: + case NM_DEVICE_TYPE_VRF: return type; } return NM_DEVICE_TYPE_UNKNOWN; @@ -1505,6 +1506,8 @@ get_type_name (NMDevice *device) return _("WireGuard"); case NM_DEVICE_TYPE_WIFI_P2P: return _("Wi-Fi P2P"); + case NM_DEVICE_TYPE_VRF: + return _("VRF"); case NM_DEVICE_TYPE_GENERIC: case NM_DEVICE_TYPE_UNUSED1: case NM_DEVICE_TYPE_UNUSED2: diff --git a/libnm/nm-libnm-utils.c b/libnm/nm-libnm-utils.c index 5f78f264f2..f04a7419f5 100644 --- a/libnm/nm-libnm-utils.c +++ b/libnm/nm-libnm-utils.c @@ -694,6 +694,7 @@ const NMLDBusMetaIface *const _nml_dbus_meta_ifaces[] = { &_nml_dbus_meta_iface_nm_device_tun, &_nml_dbus_meta_iface_nm_device_veth, &_nml_dbus_meta_iface_nm_device_vlan, + &_nml_dbus_meta_iface_nm_device_vrf, &_nml_dbus_meta_iface_nm_device_vxlan, &_nml_dbus_meta_iface_nm_device_wifip2p, &_nml_dbus_meta_iface_nm_device_wireguard, diff --git a/libnm/nm-libnm-utils.h b/libnm/nm-libnm-utils.h index db6f55ec0e..ec9f23ba8e 100644 --- a/libnm/nm-libnm-utils.h +++ b/libnm/nm-libnm-utils.h @@ -505,7 +505,7 @@ struct _NMLDBusMetaIface { NML_DBUS_META_IFACE_INIT (__VA_ARGS__ \ NML_DBUS_META_IFACE_OBJ_PROPERTIES ()) -extern const NMLDBusMetaIface *const _nml_dbus_meta_ifaces[43]; +extern const NMLDBusMetaIface *const _nml_dbus_meta_ifaces[44]; extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm; extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_accesspoint; @@ -535,6 +535,7 @@ extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_team; extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_tun; extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_veth; extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_vlan; +extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_vrf; extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_vxlan; extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_wifip2p; extern const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_wired; diff --git a/libnm/nm-types.h b/libnm/nm-types.h index 11e9f05570..d390e61a3b 100644 --- a/libnm/nm-types.h +++ b/libnm/nm-types.h @@ -37,6 +37,7 @@ typedef struct _NMDevicePpp NMDevicePpp; typedef struct _NMDeviceTeam NMDeviceTeam; typedef struct _NMDeviceTun NMDeviceTun; typedef struct _NMDeviceVlan NMDeviceVlan; +typedef struct _NMDeviceVrf NMDeviceVrf; typedef struct _NMDeviceVxlan NMDeviceVxlan; typedef struct _NMDeviceWifi NMDeviceWifi; typedef struct _NMDeviceWifiP2P NMDeviceWifiP2P; diff --git a/po/POTFILES.in b/po/POTFILES.in index d48d92a00e..9379fae271 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -90,6 +90,7 @@ libnm-core/nm-setting-team.c libnm-core/nm-setting-tun.c libnm-core/nm-setting-user.c libnm-core/nm-setting-vlan.c +libnm-core/nm-setting-vrf.c libnm-core/nm-setting-vpn.c libnm-core/nm-setting-vxlan.c libnm-core/nm-setting-wifi-p2p.c @@ -124,6 +125,7 @@ libnm/nm-device-ovs-port.c libnm/nm-device-team.c libnm/nm-device-tun.c libnm/nm-device-vlan.c +libnm/nm-device-vrf.c libnm/nm-device-vxlan.c libnm/nm-device-wifi-p2p.c libnm/nm-device-wifi.c @@ -160,6 +162,7 @@ src/devices/nm-device-ip-tunnel.c src/devices/nm-device-macvlan.c src/devices/nm-device-tun.c src/devices/nm-device-vlan.c +src/devices/nm-device-vrf.c src/devices/nm-device-vxlan.c src/devices/nm-device-wpan.c src/devices/team/nm-device-team.c diff --git a/shared/nm-meta-setting.c b/shared/nm-meta-setting.c index af5aa8429d..cf6309b168 100644 --- a/shared/nm-meta-setting.c +++ b/shared/nm-meta-setting.c @@ -46,6 +46,7 @@ #include "nm-setting-user.h" #include "nm-setting-vlan.h" #include "nm-setting-vpn.h" +#include "nm-setting-vrf.h" #include "nm-setting-vxlan.h" #include "nm-setting-wifi-p2p.h" #include "nm-setting-wimax.h" @@ -387,6 +388,12 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = { .setting_name = NM_SETTING_VPN_SETTING_NAME, .get_setting_gtype = nm_setting_vpn_get_type, }, + [NM_META_SETTING_TYPE_VRF] = { + .meta_type = NM_META_SETTING_TYPE_VRF, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_VRF_SETTING_NAME, + .get_setting_gtype = nm_setting_vrf_get_type, + }, [NM_META_SETTING_TYPE_VXLAN] = { .meta_type = NM_META_SETTING_TYPE_VXLAN, .setting_priority = NM_SETTING_PRIORITY_HW_BASE, diff --git a/shared/nm-meta-setting.h b/shared/nm-meta-setting.h index 3976bfe19b..8b0c7d35a5 100644 --- a/shared/nm-meta-setting.h +++ b/shared/nm-meta-setting.h @@ -142,6 +142,7 @@ typedef enum { NM_META_SETTING_TYPE_USER, NM_META_SETTING_TYPE_VLAN, NM_META_SETTING_TYPE_VPN, + NM_META_SETTING_TYPE_VRF, NM_META_SETTING_TYPE_VXLAN, NM_META_SETTING_TYPE_WIFI_P2P, NM_META_SETTING_TYPE_WIMAX, diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c index c6ecb2e85f..08a288601e 100644 --- a/src/devices/nm-device-bond.c +++ b/src/devices/nm-device-bond.c @@ -414,7 +414,7 @@ release_slave (NMDevice *device, ifindex_slave = nm_device_get_ip_ifindex (slave); if (ifindex_slave <= 0) - _LOGD (LOGD_TEAM, "bond slave %s is already released", nm_device_get_ip_iface (slave)); + _LOGD (LOGD_BOND, "bond slave %s is already released", nm_device_get_ip_iface (slave)); if (configure) { /* When the last slave is released the bond MAC will be set to a random diff --git a/src/devices/nm-device-factory.c b/src/devices/nm-device-factory.c index 232e69ef2c..0046785056 100644 --- a/src/devices/nm-device-factory.c +++ b/src/devices/nm-device-factory.c @@ -393,6 +393,7 @@ nm_device_factory_manager_load_factories (NMDeviceFactoryManagerFactoryFunc call _ADD_INTERNAL (nm_tun_device_factory_get_type); _ADD_INTERNAL (nm_veth_device_factory_get_type); _ADD_INTERNAL (nm_vlan_device_factory_get_type); + _ADD_INTERNAL (nm_vrf_device_factory_get_type); _ADD_INTERNAL (nm_vxlan_device_factory_get_type); _ADD_INTERNAL (nm_wireguard_device_factory_get_type); _ADD_INTERNAL (nm_wpan_device_factory_get_type); diff --git a/src/devices/nm-device-vrf.c b/src/devices/nm-device-vrf.c new file mode 100644 index 0000000000..05ee7a8c95 --- /dev/null +++ b/src/devices/nm-device-vrf.c @@ -0,0 +1,371 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include "nm-default.h" + +#include "nm-device-vrf.h" + +#include "nm-core-internal.h" +#include "nm-device-factory.h" +#include "nm-device-private.h" +#include "nm-manager.h" +#include "nm-setting-vrf.h" +#include "platform/nm-platform.h" +#include "settings/nm-settings.h" + +#include "nm-device-logging.h" +_LOG_DECLARE_SELF(NMDeviceVrf); + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceVrf, + PROP_TABLE, +); + +typedef struct { + NMPlatformLnkVrf props; +} NMDeviceVrfPrivate; + +struct _NMDeviceVrf { + NMDevice parent; + NMDeviceVrfPrivate _priv; +}; + +struct _NMDeviceVrfClass { + NMDeviceClass parent; +}; + +G_DEFINE_TYPE (NMDeviceVrf, nm_device_vrf, NM_TYPE_DEVICE) + +#define NM_DEVICE_VRF_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceVrf, NM_IS_DEVICE_VRF, NMDevice) + +/*****************************************************************************/ + +static void +do_update_properties (NMDeviceVrf *self, const NMPlatformLnkVrf *props) +{ + NMDeviceVrfPrivate *priv = NM_DEVICE_VRF_GET_PRIVATE (self); + GObject *object = G_OBJECT (self); + NMPlatformLnkVrf props_null; + + if (!props) { + props_null = (NMPlatformLnkVrf) { }; + props = &props_null; + } + + g_object_freeze_notify (object); + +#define CHECK_PROPERTY_CHANGED(field, prop) \ + G_STMT_START { \ + if (priv->props.field != props->field) { \ + priv->props.field = props->field; \ + _notify (self, prop); \ + } \ + } G_STMT_END + + CHECK_PROPERTY_CHANGED (table, PROP_TABLE); + + g_object_thaw_notify (object); +} + +static void +update_properties (NMDevice *device) +{ + NMDeviceVrf *self = NM_DEVICE_VRF (device); + const NMPlatformLnkVrf *props; + + props = nm_platform_link_get_lnk_vrf (nm_device_get_platform (device), nm_device_get_ifindex (device), NULL); + if (!props) { + _LOGW (LOGD_PLATFORM, "could not get vrf properties"); + return; + } + + do_update_properties (self, props); +} + +static NMDeviceCapabilities +get_generic_capabilities (NMDevice *dev) +{ + return NM_DEVICE_CAP_IS_SOFTWARE; +} + +static void +link_changed (NMDevice *device, + const NMPlatformLink *pllink) +{ + NM_DEVICE_CLASS (nm_device_vrf_parent_class)->link_changed (device, pllink); + update_properties (device); +} + +static void +unrealize_notify (NMDevice *device) +{ + NMDeviceVrf *self = NM_DEVICE_VRF (device); + + NM_DEVICE_CLASS (nm_device_vrf_parent_class)->unrealize_notify (device); + + do_update_properties (self, NULL); +} + +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); + NMPlatformLnkVrf props = { }; + NMSettingVrf *s_vrf; + int r; + + s_vrf = _nm_connection_get_setting (connection, NM_TYPE_SETTING_VRF); + nm_assert (s_vrf); + + props.table = nm_setting_vrf_get_table (s_vrf); + + r = nm_platform_link_vrf_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 VRF interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_strerror (r)); + return FALSE; + } + + return TRUE; +} + +static gboolean +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) +{ + NMDeviceVrfPrivate *priv = NM_DEVICE_VRF_GET_PRIVATE (device); + NMSettingVrf *s_vrf; + + if (!NM_DEVICE_CLASS (nm_device_vrf_parent_class)->check_connection_compatible (device, connection, error)) + return FALSE; + + if (nm_device_is_real (device)) { + s_vrf = _nm_connection_get_setting (connection, NM_TYPE_SETTING_VRF); + + if (priv->props.table != nm_setting_vrf_get_table (s_vrf)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vrf table mismatches"); + return FALSE; + } + } + + return TRUE; +} + +static gboolean +complete_connection (NMDevice *device, + NMConnection *connection, + const char *specific_object, + NMConnection *const*existing_connections, + GError **error) +{ + NMSettingVrf *s_vrf; + + nm_utils_complete_generic (nm_device_get_platform (device), + connection, + NM_SETTING_VRF_SETTING_NAME, + existing_connections, + NULL, + _("VRF connection"), + NULL, + NULL, + TRUE); + + s_vrf = _nm_connection_get_setting (connection, NM_TYPE_SETTING_VRF); + if (!s_vrf) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, + "A 'vrf' setting is required."); + return FALSE; + } + + return TRUE; +} + +static void +update_connection (NMDevice *device, NMConnection *connection) +{ + NMDeviceVrfPrivate *priv = NM_DEVICE_VRF_GET_PRIVATE (device); + NMSettingVrf *s_vrf = _nm_connection_get_setting (connection, NM_TYPE_SETTING_VRF); + + if (!s_vrf) { + s_vrf = (NMSettingVrf *) nm_setting_vrf_new (); + nm_connection_add_setting (connection, (NMSetting *) s_vrf); + } + + if (priv->props.table != nm_setting_vrf_get_table (s_vrf)) + g_object_set (G_OBJECT (s_vrf), NM_SETTING_VRF_TABLE, priv->props.table, NULL); +} + +static gboolean +enslave_slave (NMDevice *device, + NMDevice *slave, + NMConnection *connection, + gboolean configure) +{ + NMDeviceVrf *self = NM_DEVICE_VRF (device); + gboolean success = TRUE; + const char *slave_iface = nm_device_get_ip_iface (slave); + + nm_device_master_check_slave_physical_port (device, slave, LOGD_DEVICE); + + if (configure) { + nm_device_take_down (slave, TRUE); + success = nm_platform_link_enslave (nm_device_get_platform (device), + nm_device_get_ip_ifindex (device), + nm_device_get_ip_ifindex (slave)); + nm_device_bring_up (slave, TRUE, NULL); + + if (!success) + return FALSE; + + _LOGI (LOGD_DEVICE, "enslaved VRF slave %s", slave_iface); + } else + _LOGI (LOGD_BOND, "VRF slave %s was enslaved", slave_iface); + + return TRUE; +} + +static void +release_slave (NMDevice *device, + NMDevice *slave, + gboolean configure) +{ + NMDeviceVrf *self = NM_DEVICE_VRF (device); + gboolean success; + int ifindex_slave; + int ifindex; + + if (configure) { + ifindex = nm_device_get_ifindex (device); + if ( ifindex <= 0 + || !nm_platform_link_get (nm_device_get_platform (device), ifindex)) + configure = FALSE; + } + + ifindex_slave = nm_device_get_ip_ifindex (slave); + + if (ifindex_slave <= 0) + _LOGD (LOGD_DEVICE, "VRF slave %s is already released", nm_device_get_ip_iface (slave)); + + if (configure) { + if (ifindex_slave > 0) { + success = nm_platform_link_release (nm_device_get_platform (device), + nm_device_get_ip_ifindex (device), + ifindex_slave); + + if (success) { + _LOGI (LOGD_DEVICE, "released VRF slave %s", + nm_device_get_ip_iface (slave)); + } else { + _LOGW (LOGD_DEVICE, "failed to release VRF slave %s", + nm_device_get_ip_iface (slave)); + } + } + } else { + if (ifindex_slave > 0) { + _LOGI (LOGD_DEVICE, "VRF slave %s was released", + nm_device_get_ip_iface (slave)); + } + } +} + +/*****************************************************************************/ + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMDeviceVrfPrivate *priv = NM_DEVICE_VRF_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_TABLE: + g_value_set_uint (value, priv->props.table); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/*****************************************************************************/ + +static void +nm_device_vrf_init (NMDeviceVrf *self) +{ +} + +static const NMDBusInterfaceInfoExtended interface_info_device_vrf = { + .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( + NM_DBUS_INTERFACE_DEVICE_VRF, + .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Table", "u", NM_DEVICE_VRF_TABLE), + ), + ), +}; + +static void +nm_device_vrf_class_init (NMDeviceVrfClass *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_vrf); + + device_class->connection_type_supported = NM_SETTING_VRF_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_VRF_SETTING_NAME; + device_class->is_master = TRUE; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_VRF); + + device_class->enslave_slave = enslave_slave; + device_class->release_slave = release_slave; + 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_TABLE] = + g_param_spec_uint (NM_DEVICE_VRF_TABLE, "", "", + 0, G_MAXUINT32, 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); +} + +/*****************************************************************************/ + +#define NM_TYPE_VRF_DEVICE_FACTORY (nm_vrf_device_factory_get_type ()) +#define NM_VRF_DEVICE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VRF_DEVICE_FACTORY, NMVrfDeviceFactory)) + +static NMDevice * +create_device (NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) +{ + return g_object_new (NM_TYPE_DEVICE_VRF, + NM_DEVICE_IFACE, iface, + NM_DEVICE_TYPE_DESC, "Vrf", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_VRF, + NM_DEVICE_LINK_TYPE, NM_LINK_TYPE_VRF, + NULL); +} + +NM_DEVICE_FACTORY_DEFINE_INTERNAL (VRF, Vrf, vrf, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_VRF) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_VRF_SETTING_NAME), + factory_class->create_device = create_device; +); diff --git a/src/devices/nm-device-vrf.h b/src/devices/nm-device-vrf.h new file mode 100644 index 0000000000..89ab0f1300 --- /dev/null +++ b/src/devices/nm-device-vrf.h @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#ifndef __NETWORKMANAGER_DEVICE_VRF_H__ +#define __NETWORKMANAGER_DEVICE_VRF_H__ + +#include "nm-device-generic.h" + +#define NM_TYPE_DEVICE_VRF (nm_device_vrf_get_type ()) +#define NM_DEVICE_VRF(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_VRF, NMDeviceVrf)) +#define NM_DEVICE_VRF_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_VRF, NMDeviceVrfClass)) +#define NM_IS_DEVICE_VRF(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_VRF)) +#define NM_IS_DEVICE_VRF_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_VRF)) +#define NM_DEVICE_VRF_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_VRF, NMDeviceVrfClass)) + +#define NM_DEVICE_VRF_TABLE "table" + +typedef struct _NMDeviceVrf NMDeviceVrf; +typedef struct _NMDeviceVrfClass NMDeviceVrfClass; + +GType nm_device_vrf_get_type (void); + +#endif /* __NETWORKMANAGER_DEVICE_VRF_H__ */ diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 3898d1565a..22ab17c8fb 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -2109,6 +2109,8 @@ nm_device_get_route_metric_default (NMDeviceType device_type) return 450; case NM_DEVICE_TYPE_PPP: return 460; + case NM_DEVICE_TYPE_VRF: + return 470; case NM_DEVICE_TYPE_VXLAN: return 500; case NM_DEVICE_TYPE_DUMMY: @@ -2274,6 +2276,8 @@ _get_route_table (NMDevice *self, NMSettingIPConfig *s_ip; guint32 route_table = 0; gboolean is_user_config = TRUE; + NMSettingConnection *s_con; + NMSettingVrf *s_vrf; nm_assert_addr_family (addr_family); @@ -2310,6 +2314,28 @@ _get_route_table (NMDevice *self, } } + if ( route_table == 0u + && connection + && (s_con = nm_connection_get_setting_connection (connection)) + && (nm_streq0 (nm_setting_connection_get_slave_type (s_con), NM_SETTING_VRF_SETTING_NAME) + && priv->master + && nm_device_get_device_type (priv->master) == NM_DEVICE_TYPE_VRF)) { + const NMPlatformLnkVrf *lnk; + + lnk = nm_platform_link_get_lnk_vrf (nm_device_get_platform (self), + nm_device_get_ifindex (priv->master), + NULL); + + if (lnk) + route_table = lnk->table; + } + + if ( route_table == 0u + && connection + && (s_vrf = (NMSettingVrf *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VRF))) { + route_table = nm_setting_vrf_get_table (s_vrf); + } + klass = NM_DEVICE_GET_CLASS (self); if (klass->coerce_route_table) route_table = klass->coerce_route_table (self, addr_family, route_table, is_user_config); @@ -17152,7 +17178,7 @@ set_property (GObject *object, guint prop_id, 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_WIFI_P2P); + nm_assert (priv->type <= NM_DEVICE_TYPE_VRF); break; case PROP_LINK_TYPE: /* construct-only */ diff --git a/src/meson.build b/src/meson.build index 47acb4a686..bc816a8543 100644 --- a/src/meson.build +++ b/src/meson.build @@ -87,6 +87,7 @@ sources = files( 'devices/nm-device-tun.c', 'devices/nm-device-veth.c', 'devices/nm-device-vlan.c', + 'devices/nm-device-vrf.c', 'devices/nm-device-vxlan.c', 'devices/nm-device-wireguard.c', 'devices/nm-device-wpan.c', diff --git a/src/nm-types.h b/src/nm-types.h index 2f1ac2dcd5..43b931dad3 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -160,6 +160,7 @@ typedef enum { NM_LINK_TYPE_TUN, NM_LINK_TYPE_VETH, NM_LINK_TYPE_VLAN, + NM_LINK_TYPE_VRF, NM_LINK_TYPE_VXLAN, NM_LINK_TYPE_WIREGUARD, @@ -197,6 +198,7 @@ typedef enum { NMP_OBJECT_TYPE_LNK_SIT, NMP_OBJECT_TYPE_LNK_TUN, NMP_OBJECT_TYPE_LNK_VLAN, + NMP_OBJECT_TYPE_LNK_VRF, NMP_OBJECT_TYPE_LNK_VXLAN, NMP_OBJECT_TYPE_LNK_WIREGUARD, diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 4fc4a16f21..020db21ecd 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -656,6 +656,7 @@ static const LinkDesc linktypes[] = { { NM_LINK_TYPE_TUN, "tun", "tun", NULL }, { NM_LINK_TYPE_VETH, "veth", "veth", NULL }, { NM_LINK_TYPE_VLAN, "vlan", "vlan", "vlan" }, + { NM_LINK_TYPE_VRF, "vrf", "vrf", "vrf" }, { NM_LINK_TYPE_VXLAN, "vxlan", "vxlan", "vxlan" }, { NM_LINK_TYPE_WIREGUARD, "wireguard", "wireguard", "wireguard" }, @@ -1754,6 +1755,8 @@ _parse_lnk_vlan (const char *kind, struct nlattr *info_data) #undef IFLA_VXLAN_MAX #define IFLA_VXLAN_MAX IFLA_VXLAN_LOCAL6 +#define IFLA_VRF_TABLE 1 + /* older kernel header might not contain 'struct ifla_vxlan_port_range'. * Redefine it. */ struct nm_ifla_vxlan_port_range { @@ -1848,6 +1851,33 @@ _parse_lnk_vxlan (const char *kind, struct nlattr *info_data) return obj; } +static NMPObject * +_parse_lnk_vrf (const char *kind, struct nlattr *info_data) +{ + static const struct nla_policy policy[] = { + [IFLA_VRF_TABLE] = { .type = NLA_U32 }, + }; + NMPlatformLnkVrf *props; + struct nlattr *tb[G_N_ELEMENTS (policy)]; + NMPObject *obj; + + if ( !info_data + || !nm_streq0 (kind, "vrf")) + return NULL; + + if (nla_parse_nested_arr (tb, info_data, policy) < 0) + return NULL; + + obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_VRF, NULL); + + props = &obj->lnk_vrf; + + if (tb[IFLA_VRF_TABLE]) + props->table = nla_get_u32 (tb[IFLA_VRF_TABLE]); + + return obj; +} + /*****************************************************************************/ static gboolean @@ -2798,6 +2828,9 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr case NM_LINK_TYPE_VLAN: lnk_data = _parse_lnk_vlan (nl_info_kind, nl_info_data); break; + case NM_LINK_TYPE_VRF: + lnk_data = _parse_lnk_vrf (nl_info_kind, nl_info_data); + break; case NM_LINK_TYPE_VXLAN: lnk_data = _parse_lnk_vxlan (nl_info_kind, nl_info_data); break; @@ -3728,6 +3761,17 @@ _nl_msg_new_link_set_linkinfo (struct nl_msg *msg, } break; } + case NM_LINK_TYPE_VRF: { + const NMPlatformLnkVrf *props = extra_data; + + nm_assert (extra_data); + + if (!(data = nla_nest_start (msg, IFLA_INFO_DATA))) + goto nla_put_failure; + + NLA_PUT_U32 (msg, IFLA_VRF_TABLE, props->table); + break; + } case NM_LINK_TYPE_VXLAN: { const NMPlatformLnkVxlan *props = extra_data; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index fbb5e7e2fa..2065b1818e 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -1218,6 +1218,10 @@ nm_platform_link_add (NMPlatform *self, nm_utils_strbuf_append_str (&buf_p, &buf_len, ", "); nm_platform_lnk_vlan_to_string ((const NMPlatformLnkVlan *) extra_data, buf_p, buf_len); break; + case NM_LINK_TYPE_VRF: + nm_utils_strbuf_append_str (&buf_p, &buf_len, ", "); + nm_platform_lnk_vrf_to_string ((const NMPlatformLnkVrf *) extra_data, buf_p, buf_len); + break; case NM_LINK_TYPE_VXLAN: nm_utils_strbuf_append_str (&buf_p, &buf_len, ", "); nm_platform_lnk_vxlan_to_string ((const NMPlatformLnkVxlan *) extra_data, buf_p, buf_len); @@ -2252,6 +2256,12 @@ nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLi return _link_get_lnk (self, ifindex, NM_LINK_TYPE_VLAN, out_link); } +const NMPlatformLnkVrf * +nm_platform_link_get_lnk_vrf (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk (self, ifindex, NM_LINK_TYPE_VRF, out_link); +} + const NMPlatformLnkVxlan * nm_platform_link_get_lnk_vxlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) { @@ -5485,6 +5495,20 @@ nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize l } const char * +nm_platform_lnk_vrf_to_string (const NMPlatformLnkVrf *lnk, char *buf, gsize len) +{ + char *b; + + if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len)) + return buf; + + b = buf; + + nm_utils_strbuf_append (&b, &len, "table %u", lnk->table); + return buf; +} + +const char * nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize len) { char str_group[100]; @@ -6851,6 +6875,21 @@ nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b } void +nm_platform_lnk_vrf_hash_update (const NMPlatformLnkVrf *obj, NMHashState *h) +{ + nm_hash_update_vals (h, + obj->table); +} + +int +nm_platform_lnk_vrf_cmp (const NMPlatformLnkVrf *a, const NMPlatformLnkVrf *b) +{ + NM_CMP_SELF (a, b); + NM_CMP_FIELD (a, b, table); + return 0; +} + +void nm_platform_lnk_vxlan_hash_update (const NMPlatformLnkVxlan *obj, NMHashState *h) { nm_hash_update_vals (h, diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 8d1a3d3865..d18208081a 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -828,6 +828,10 @@ typedef struct { } NMPlatformLnkVlan; typedef struct { + guint32 table; +} NMPlatformLnkVrf; + +typedef struct { struct in6_addr group6; struct in6_addr local6; in_addr_t group; @@ -1431,6 +1435,15 @@ nm_platform_link_vlan_add (NMPlatform *self, } static inline int +nm_platform_link_vrf_add (NMPlatform *self, + const char *name, + const NMPlatformLnkVrf *props, + const NMPlatformLink **out_link) +{ + return nm_platform_link_add (self, NM_LINK_TYPE_VRF, name, 0, NULL, 0, props, out_link); +} + +static inline int nm_platform_link_vxlan_add (NMPlatform *self, const char *name, const NMPlatformLnkVxlan *props, @@ -1621,6 +1634,7 @@ const NMPlatformLnkMacvlan *nm_platform_link_get_lnk_macvtap (NMPlatform *self, const NMPlatformLnkSit *nm_platform_link_get_lnk_sit (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkTun *nm_platform_link_get_lnk_tun (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkVlan *nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkVrf *nm_platform_link_get_lnk_vrf (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkVxlan *nm_platform_link_get_lnk_vxlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkWireGuard *nm_platform_link_get_lnk_wireguard (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); @@ -1792,6 +1806,7 @@ const char *nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, const char *nm_platform_lnk_sit_to_string (const NMPlatformLnkSit *lnk, char *buf, gsize len); const char *nm_platform_lnk_tun_to_string (const NMPlatformLnkTun *lnk, char *buf, gsize len); const char *nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize len); +const char *nm_platform_lnk_vrf_to_string (const NMPlatformLnkVrf *lnk, char *buf, gsize len); const char *nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize len); const char *nm_platform_lnk_wireguard_to_string (const NMPlatformLnkWireGuard *lnk, char *buf, gsize len); const char *nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address, char *buf, gsize len); @@ -1824,6 +1839,7 @@ int nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatform int nm_platform_lnk_sit_cmp (const NMPlatformLnkSit *a, const NMPlatformLnkSit *b); int nm_platform_lnk_tun_cmp (const NMPlatformLnkTun *a, const NMPlatformLnkTun *b); int nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b); +int nm_platform_lnk_vrf_cmp (const NMPlatformLnkVrf *a, const NMPlatformLnkVrf *b); int nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *b); int nm_platform_lnk_wireguard_cmp (const NMPlatformLnkWireGuard *a, const NMPlatformLnkWireGuard *b); int nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b); @@ -1870,6 +1886,7 @@ void nm_platform_lnk_macvlan_hash_update (const NMPlatformLnkMacvlan *obj, NMHas void nm_platform_lnk_sit_hash_update (const NMPlatformLnkSit *obj, NMHashState *h); void nm_platform_lnk_tun_hash_update (const NMPlatformLnkTun *obj, NMHashState *h); void nm_platform_lnk_vlan_hash_update (const NMPlatformLnkVlan *obj, NMHashState *h); +void nm_platform_lnk_vrf_hash_update (const NMPlatformLnkVrf *obj, NMHashState *h); void nm_platform_lnk_vxlan_hash_update (const NMPlatformLnkVxlan *obj, NMHashState *h); void nm_platform_lnk_wireguard_hash_update (const NMPlatformLnkWireGuard *obj, NMHashState *h); diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 240c1e7d8a..12f90aee1c 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -3336,6 +3336,18 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_vlan_hash_update, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_vlan_cmp, }, + [NMP_OBJECT_TYPE_LNK_VRF - 1] = { + .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), + .obj_type = NMP_OBJECT_TYPE_LNK_VRF, + .sizeof_data = sizeof (NMPObjectLnkVrf), + .sizeof_public = sizeof (NMPlatformLnkVrf), + .obj_type_name = "vrf", + .lnk_link_type = NM_LINK_TYPE_VRF, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_vrf_to_string, + .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_vrf_hash_update, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_vrf_cmp, + }, + [NMP_OBJECT_TYPE_LNK_VXLAN - 1] = { .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), .obj_type = NMP_OBJECT_TYPE_LNK_VXLAN, diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index d52cc132d2..1cafc3abf8 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -287,6 +287,10 @@ typedef struct { } NMPObjectLnkVlan; typedef struct { + NMPlatformLnkVrf _public; +} NMPObjectLnkVrf; + +typedef struct { NMPlatformLnkVxlan _public; } NMPObjectLnkVxlan; @@ -366,6 +370,9 @@ struct _NMPObject { NMPlatformLnkVlan lnk_vlan; NMPObjectLnkVlan _lnk_vlan; + NMPlatformLnkVrf lnk_vrf; + NMPObjectLnkVrf _lnk_vrf; + NMPlatformLnkVxlan lnk_vxlan; NMPObjectLnkVxlan _lnk_vxlan; diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c index 906deeada6..2fbfb90d4c 100644 --- a/src/platform/tests/test-common.c +++ b/src/platform/tests/test-common.c @@ -1586,6 +1586,39 @@ nmtstp_link_tun_add (NMPlatform *platform, } const NMPlatformLink * +nmtstp_link_vrf_add (NMPlatform *platform, + gboolean external_command, + const char *name, + const NMPlatformLnkVrf *lnk) +{ + const NMPlatformLink *pllink = NULL; + int err; + int r; + + g_assert (nm_utils_is_valid_iface_name (name, NULL)); + + external_command = nmtstp_run_command_check_external (external_command); + + _init_platform (&platform, external_command); + + if (external_command) { + err = nmtstp_run_command ("ip link add %s type vrf table %u", + name, + lnk->table); + if (err == 0) + pllink = nmtstp_assert_wait_for_link (platform, name, NM_LINK_TYPE_VRF, 100); + } else { + r = nm_platform_link_vrf_add (platform, name, lnk, &pllink); + g_assert (NMTST_NM_ERR_SUCCESS (r)); + g_assert (pllink); + } + + g_assert_cmpint (pllink->type, ==, NM_LINK_TYPE_VRF); + g_assert_cmpstr (pllink->name, ==, name); + return pllink; +} + +const NMPlatformLink * nmtstp_link_vxlan_add (NMPlatform *platform, gboolean external_command, const char *name, diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h index 6f5a6cf62b..f392413eca 100644 --- a/src/platform/tests/test-common.h +++ b/src/platform/tests/test-common.h @@ -360,6 +360,10 @@ const NMPlatformLink *nmtstp_link_tun_add (NMPlatform *platform, const char *name, const NMPlatformLnkTun *lnk, int *out_fd); +const NMPlatformLink *nmtstp_link_vrf_add (NMPlatform *platform, + gboolean external_command, + const char *name, + const NMPlatformLnkVrf *lnk); const NMPlatformLink *nmtstp_link_vxlan_add (NMPlatform *platform, gboolean external_command, const char *name, diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index 4a54af2a19..2f7a503cee 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -1182,6 +1182,14 @@ test_software_detect (gconstpointer user_data) case NM_LINK_TYPE_VLAN: nmtstp_run_command_check ("ip link add name %s link %s type vlan id 1242", DEVICE_NAME, PARENT_NAME); break; + case NM_LINK_TYPE_VRF: { + NMPlatformLnkVrf lnk_vrf = { }; + + lnk_vrf.table = 9876; + + nmtstp_link_vrf_add (NULL, ext, DEVICE_NAME, &lnk_vrf); + break; + } case NM_LINK_TYPE_VXLAN: { NMPlatformLnkVxlan lnk_vxlan = { }; @@ -1444,6 +1452,13 @@ test_software_detect (gconstpointer user_data) g_assert_cmpint (plnk->id, ==, 1242); break; } + case NM_LINK_TYPE_VRF: { + const NMPlatformLnkVrf *plnk = &lnk->lnk_vrf; + + g_assert (plnk == nm_platform_link_get_lnk_vrf (NM_PLATFORM_GET, ifindex, NULL)); + g_assert_cmpint (plnk->table, ==, 9876); + break; + } case NM_LINK_TYPE_VXLAN: { const NMPlatformLnkVxlan *plnk = &lnk->lnk_vxlan; @@ -3313,6 +3328,7 @@ _nmtstp_setup_tests (void) test_software_detect_add ("/link/software/detect/sit", NM_LINK_TYPE_SIT, 0); test_software_detect_add ("/link/software/detect/tun", NM_LINK_TYPE_TUN, 0); test_software_detect_add ("/link/software/detect/vlan", NM_LINK_TYPE_VLAN, 0); + test_software_detect_add ("/link/software/detect/vrf", NM_LINK_TYPE_VRF, 0); test_software_detect_add ("/link/software/detect/vxlan/0", NM_LINK_TYPE_VXLAN, 0); test_software_detect_add ("/link/software/detect/vxlan/1", NM_LINK_TYPE_VXLAN, 1); test_software_detect_add ("/link/software/detect/wireguard/0", NM_LINK_TYPE_WIREGUARD, 0); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 8fc72822de..32364aed55 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -502,6 +502,24 @@ make_connection_setting (const char *file, } nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "VRF_UUID", &value); + if (!v) + v = svGetValueStr (ifcfg, "VRF", &value); + if (v) { + const char *old_value; + + if ((old_value = nm_setting_connection_get_master (s_con))) { + PARSE_WARNING ("Already configured as slave of %s. Ignoring VRF{_UUID}=\"%s\"", + old_value, v); + } else { + g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, v, NULL); + g_object_set (s_con, NM_SETTING_CONNECTION_SLAVE_TYPE, + NM_SETTING_VRF_SETTING_NAME, NULL); + } + } + + + nm_clear_g_free (&value); v = svGetValueStr (ifcfg, "GATEWAY_PING_TIMEOUT", &value); if (v) { gint64 tmp; diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c index 5027171931..a6a4d381ec 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c @@ -850,6 +850,8 @@ const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = { _KEY_TYPE ("VLAN_FLAGS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), _KEY_TYPE ("VLAN_ID", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), _KEY_TYPE ("VLAN_INGRESS_PRIORITY_MAP", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("VRF", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("VRF_UUID", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), _KEY_TYPE ("WEP_KEY_FLAGS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), _KEY_TYPE ("WPA_ALLOW_WPA", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), _KEY_TYPE ("WPA_ALLOW_WPA2", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h index 734a6a63c2..29c9df7af7 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h @@ -33,7 +33,7 @@ typedef struct { NMSIfcfgKeyTypeFlags key_flags; } NMSIfcfgKeyTypeInfo; -const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[225]; +const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[227]; const NMSIfcfgKeyTypeInfo *nms_ifcfg_well_known_key_find_info (const char *key, gssize *out_idx); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index 19de53ca81..7f26c3edf1 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -1851,6 +1851,9 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) } else if (nm_setting_connection_is_slave_type (s_con, NM_SETTING_OVS_PORT_SETTING_NAME)) { svSetValueStr (ifcfg, "OVS_PORT_UUID", master); svSetValueStr (ifcfg, "OVS_PORT", master_iface); + } else if (nm_setting_connection_is_slave_type (s_con, NM_SETTING_VRF_SETTING_NAME)) { + svSetValueStr (ifcfg, "VRF_UUID", master); + svSetValueStr (ifcfg, "VRF", master_iface); } else { _LOGW ("don't know how to set master for a %s slave", nm_setting_connection_get_slave_type (s_con)); |