summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2020-01-14 10:31:41 +0100
committerBeniamino Galvani <bgalvani@redhat.com>2020-01-14 10:31:41 +0100
commite6a9d5b99c7b674c3a932a5e16921eb9e3a7073c (patch)
treedb4cb3002a0517c5d2438a3f02dc06a2c81cf9f4
parent56e91b11a24f87e57ee0ae9535c081796e4bdeb9 (diff)
parent667568d1b2be54b03ce1dd078433a32c39a2a3eb (diff)
downloadNetworkManager-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
-rw-r--r--Makefile.am10
-rw-r--r--clients/cli/connections.c1
-rw-r--r--clients/common/nm-meta-setting-desc.c29
-rw-r--r--clients/common/settings-docs.h.in1
-rw-r--r--docs/api/network-manager-docs.xml1
-rw-r--r--docs/libnm/libnm-docs.xml2
-rw-r--r--introspection/meson.build1
-rw-r--r--introspection/org.freedesktop.NetworkManager.Device.Vrf.xml17
-rw-r--r--libnm-core/meson.build2
-rw-r--r--libnm-core/nm-connection.c5
-rw-r--r--libnm-core/nm-core-internal.h1
-rw-r--r--libnm-core/nm-core-types.h1
-rw-r--r--libnm-core/nm-dbus-interface.h3
-rw-r--r--libnm-core/nm-setting-vrf.c168
-rw-r--r--libnm-core/nm-setting-vrf.h36
-rw-r--r--libnm-core/nm-setting.c15
-rw-r--r--libnm/NetworkManager.h1
-rw-r--r--libnm/libnm.ver5
-rw-r--r--libnm/meson.build2
-rw-r--r--libnm/nm-device-vrf.c145
-rw-r--r--libnm/nm-device-vrf.h35
-rw-r--r--libnm/nm-device.c3
-rw-r--r--libnm/nm-libnm-utils.c1
-rw-r--r--libnm/nm-libnm-utils.h3
-rw-r--r--libnm/nm-types.h1
-rw-r--r--po/POTFILES.in3
-rw-r--r--shared/nm-meta-setting.c7
-rw-r--r--shared/nm-meta-setting.h1
-rw-r--r--src/devices/nm-device-bond.c2
-rw-r--r--src/devices/nm-device-factory.c1
-rw-r--r--src/devices/nm-device-vrf.c371
-rw-r--r--src/devices/nm-device-vrf.h22
-rw-r--r--src/devices/nm-device.c28
-rw-r--r--src/meson.build1
-rw-r--r--src/nm-types.h2
-rw-r--r--src/platform/nm-linux-platform.c44
-rw-r--r--src/platform/nm-platform.c39
-rw-r--r--src/platform/nm-platform.h17
-rw-r--r--src/platform/nmp-object.c12
-rw-r--r--src/platform/nmp-object.h7
-rw-r--r--src/platform/tests/test-common.c33
-rw-r--r--src/platform/tests/test-common.h4
-rw-r--r--src/platform/tests/test-link.c16
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c18
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c2
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h2
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c3
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));