diff --git a/Makefile.am b/Makefile.am index 9c18709083..2b8e423995 100644 --- a/Makefile.am +++ b/Makefile.am @@ -393,6 +393,7 @@ libnm_core_lib_h_pub_real = \ libnm-core/nm-setting-macsec.h \ libnm-core/nm-setting-macvlan.h \ libnm-core/nm-setting-olpc-mesh.h \ + libnm-core/nm-setting-ovs-interface.h \ libnm-core/nm-setting-ovs-patch.h \ libnm-core/nm-setting-ppp.h \ libnm-core/nm-setting-pppoe.h \ @@ -475,6 +476,7 @@ libnm_core_lib_c_real = \ libnm-core/nm-setting-macsec.c \ libnm-core/nm-setting-macvlan.c \ libnm-core/nm-setting-olpc-mesh.c \ + libnm-core/nm-setting-ovs-interface.c \ libnm-core/nm-setting-ovs-patch.c \ libnm-core/nm-setting-ppp.c \ libnm-core/nm-setting-pppoe.c \ diff --git a/clients/common/settings-docs.c.in b/clients/common/settings-docs.c.in index 7228c7fb83..34e1683659 100644 --- a/clients/common/settings-docs.c.in +++ b/clients/common/settings-docs.c.in @@ -262,6 +262,8 @@ #define DESCRIBE_DOC_NM_SETTING_MACVLAN_PARENT N_("If given, specifies the parent interface name or parent connection UUID from which this MAC-VLAN interface should be created. If this property is not specified, the connection must contain an \"802-3-ethernet\" setting with a \"mac-address\" property.") #define DESCRIBE_DOC_NM_SETTING_MACVLAN_PROMISCUOUS N_("Whether the interface should be put in promiscuous mode.") #define DESCRIBE_DOC_NM_SETTING_MACVLAN_TAP N_("Whether the interface should be a MACVTAP.") +#define DESCRIBE_DOC_NM_SETTING_OVS_INTERFACE_NAME N_("The setting's name, which uniquely identifies the setting within the connection. Each setting type has a name unique to that type, for example \"ppp\" or \"wireless\" or \"wired\".") +#define DESCRIBE_DOC_NM_SETTING_OVS_INTERFACE_TYPE N_("The interface type. Either \"internal\", or empty.") #define DESCRIBE_DOC_NM_SETTING_OVS_PATCH_NAME N_("The setting's name, which uniquely identifies the setting within the connection. Each setting type has a name unique to that type, for example \"ppp\" or \"wireless\" or \"wired\".") #define DESCRIBE_DOC_NM_SETTING_OVS_PATCH_PEER N_("Specifies the unicast destination IP address of a remote OpenVSwitch bridge port to connect to.") #define DESCRIBE_DOC_NM_SETTING_PPP_BAUD N_("If non-zero, instruct pppd to set the serial port to the specified baudrate. This value should normally be left as 0 to automatically choose the speed.") diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index 607852e26a..43a5356133 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -1095,6 +1095,35 @@ _normalize_bluetooth_type (NMConnection *self, GHashTable *parameters) return FALSE; } +static gboolean +_normalize_ovs_interface_type (NMConnection *self, GHashTable *parameters) +{ + NMSettingOvsInterface *s_ovs_interface = nm_connection_get_setting_ovs_interface (self); + const char *interface_type; + + if (strcmp (nm_connection_get_connection_type (self), NM_SETTING_OVS_INTERFACE_SETTING_NAME) == 0) { + /* OpenVSwitch managed interface. */ + if (nm_connection_get_setting_ovs_patch (self)) + interface_type = "patch"; + else + interface_type = "internal"; + } else { + /* Something else. */ + return FALSE; + } + + if (!s_ovs_interface) { + s_ovs_interface = NM_SETTING_OVS_INTERFACE (nm_setting_ovs_interface_new ()); + nm_connection_add_setting (self, NM_SETTING (s_ovs_interface)); + } + + g_object_set (s_ovs_interface, + NM_SETTING_OVS_INTERFACE_TYPE, interface_type, + NULL); + + return TRUE; +} + static gboolean _normalize_required_settings (NMConnection *self, GHashTable *parameters) { @@ -1397,6 +1426,7 @@ nm_connection_normalize (NMConnection *connection, was_modified |= _normalize_team_config (connection, parameters); was_modified |= _normalize_team_port_config (connection, parameters); was_modified |= _normalize_bluetooth_type (connection, parameters); + was_modified |= _normalize_ovs_interface_type (connection, parameters); /* Verify anew. */ success = _nm_connection_verify (connection, error); @@ -1983,6 +2013,7 @@ nm_connection_is_virtual (NMConnection *connection) || !strcmp (type, NM_SETTING_IP_TUNNEL_SETTING_NAME) || !strcmp (type, NM_SETTING_MACSEC_SETTING_NAME) || !strcmp (type, NM_SETTING_MACVLAN_SETTING_NAME) + || !strcmp (type, NM_SETTING_OVS_INTERFACE_SETTING_NAME) || !strcmp (type, NM_SETTING_VXLAN_SETTING_NAME)) return TRUE; @@ -2335,6 +2366,22 @@ nm_connection_get_setting_olpc_mesh (NMConnection *connection) return _connection_get_setting_check (connection, NM_TYPE_SETTING_OLPC_MESH); } +/** + * nm_connection_get_setting_ovs_interface: + * @connection: the #NMConnection + * + * A shortcut to return any #NMSettingOvsInterface the connection might contain. + * + * Returns: (transfer none): an #NMSettingOvsInterface if the connection contains one, otherwise %NULL + * + * Since: 1.10 + **/ +NMSettingOvsInterface * +nm_connection_get_setting_ovs_interface (NMConnection *connection) +{ + return _connection_get_setting_check (connection, NM_TYPE_SETTING_OVS_INTERFACE); +} + /** * nm_connection_get_setting_ovs_patch: * @connection: the #NMConnection diff --git a/libnm-core/nm-connection.h b/libnm-core/nm-connection.h index dc664c6939..6d49c3a3d9 100644 --- a/libnm-core/nm-connection.h +++ b/libnm-core/nm-connection.h @@ -214,6 +214,7 @@ NM_AVAILABLE_IN_1_2 NMSettingMacvlan * nm_connection_get_setting_macvlan (NMConnection *connection); NMSettingOlpcMesh * nm_connection_get_setting_olpc_mesh (NMConnection *connection); NM_AVAILABLE_IN_1_10 +NMSettingOvsInterface * nm_connection_get_setting_ovs_interface (NMConnection *connection); NMSettingOvsPatch * nm_connection_get_setting_ovs_patch (NMConnection *connection); NMSettingPpp * nm_connection_get_setting_ppp (NMConnection *connection); NMSettingPppoe * nm_connection_get_setting_pppoe (NMConnection *connection); diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index a379d8e781..550a08d1a5 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -56,6 +56,7 @@ #include "nm-setting-macsec.h" #include "nm-setting-macvlan.h" #include "nm-setting-olpc-mesh.h" +#include "nm-setting-ovs-interface.h" #include "nm-setting-ovs-patch.h" #include "nm-setting-ppp.h" #include "nm-setting-pppoe.h" diff --git a/libnm-core/nm-core-types.h b/libnm-core/nm-core-types.h index 2599717b50..4026f9e3f9 100644 --- a/libnm-core/nm-core-types.h +++ b/libnm-core/nm-core-types.h @@ -50,6 +50,7 @@ typedef struct _NMSettingIP6Config NMSettingIP6Config; typedef struct _NMSettingMacsec NMSettingMacsec; typedef struct _NMSettingMacvlan NMSettingMacvlan; typedef struct _NMSettingOlpcMesh NMSettingOlpcMesh; +typedef struct _NMSettingOvsInterface NMSettingOvsInterface; typedef struct _NMSettingOvsPatch NMSettingOvsPatch; typedef struct _NMSettingPpp NMSettingPpp; typedef struct _NMSettingPppoe NMSettingPppoe; diff --git a/libnm-core/nm-setting-ovs-interface.c b/libnm-core/nm-setting-ovs-interface.c new file mode 100644 index 0000000000..b9e749ba96 --- /dev/null +++ b/libnm-core/nm-setting-ovs-interface.c @@ -0,0 +1,229 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2017 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-setting-ovs-interface.h" + +#include "nm-connection-private.h" +#include "nm-setting-connection.h" +#include "nm-setting-private.h" + +/** + * SECTION:nm-setting-ovs-interface + * @short_description: Describes connection properties for OpenVSwitch interfaces. + * + * The #NMSettingOvsInterface object is a #NMSetting subclass that describes properties + * necessary for OpenVSwitch interfaces. + **/ + +enum { + PROP_0, + PROP_TYPE, + LAST_PROP +}; + +/** + * NMSettingOvsInterface: + * + * OpenVSwitch Interface Settings + */ +struct _NMSettingOvsInterface { + NMSetting parent; + + char *type; +}; + +struct _NMSettingOvsInterfaceClass { + NMSettingClass parent; +}; + +G_DEFINE_TYPE_WITH_CODE (NMSettingOvsInterface, nm_setting_ovs_interface, NM_TYPE_SETTING, + _nm_register_setting (OVS_INTERFACE, NM_SETTING_PRIORITY_HW_BASE)) +NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_OVS_INTERFACE) + +/*****************************************************************************/ + +/** + * nm_setting_ovs_interface_get_interface_type: + * @self: the #NMSettingOvsInterface + * + * Returns: the #NMSettingOvsInterface:type property of the setting + * + * Since: 1.10 + **/ +const char * +nm_setting_ovs_interface_get_interface_type (NMSettingOvsInterface *self) +{ + g_return_val_if_fail (NM_IS_SETTING_OVS_INTERFACE (self), NULL); + + return self->type; +} + +/*****************************************************************************/ + +static int +verify (NMSetting *setting, NMConnection *connection, GError **error) +{ + NMSettingOvsInterface *self = NM_SETTING_OVS_INTERFACE (setting); + + if (connection) { + NMSettingConnection *s_con; + + s_con = nm_connection_get_setting_connection (connection); + if (!s_con) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_SETTING, + _("missing setting")); + g_prefix_error (error, "%s: ", NM_SETTING_CONNECTION_SETTING_NAME); + return FALSE; + } + + if (!nm_setting_connection_get_master (s_con)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("A connection with a '%s' setting must have a master."), + NM_SETTING_OVS_INTERFACE_SETTING_NAME); + g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_MASTER); + return FALSE; + } + } + + if (!NM_IN_STRSET (self->type, "internal", "system", "patch", "", NULL)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid interface type"), + self->type); + g_prefix_error (error, "%s.%s: ", NM_SETTING_OVS_INTERFACE_SETTING_NAME, NM_SETTING_OVS_INTERFACE_TYPE); + return FALSE; + } + + if (connection) { + if ( g_strcmp0 (self->type, "patch") == 0 + && !nm_connection_get_setting_ovs_patch (connection)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("A connection of 'patch' interface type needs a '%s' setting."), + NM_SETTING_OVS_PATCH_SETTING_NAME); + g_prefix_error (error, "%s.%s: ", NM_SETTING_OVS_INTERFACE_SETTING_NAME, NM_SETTING_OVS_INTERFACE_TYPE); + return FALSE; + } + } + + return TRUE; +} + +/*****************************************************************************/ + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMSettingOvsInterface *self = NM_SETTING_OVS_INTERFACE (object); + + switch (prop_id) { + case PROP_TYPE: + g_value_set_string (value, self->type); + 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) +{ + NMSettingOvsInterface *self = NM_SETTING_OVS_INTERFACE (object); + + switch (prop_id) { + case PROP_TYPE: + g_free (self->type); + self->type = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/*****************************************************************************/ + +static void +nm_setting_ovs_interface_init (NMSettingOvsInterface *self) +{ +} + +/** + * nm_setting_ovs_interface_new: + * + * Creates a new #NMSettingOvsInterface object with default values. + * + * Returns: (transfer full): the new empty #NMSettingOvsInterface object + * + * Since: 1.10 + **/ +NMSetting * +nm_setting_ovs_interface_new (void) +{ + return (NMSetting *) g_object_new (NM_TYPE_SETTING_OVS_INTERFACE, NULL); +} + +static void +finalize (GObject *object) +{ + NMSettingOvsInterface *self = NM_SETTING_OVS_INTERFACE (object); + + g_free (self->type); + + G_OBJECT_CLASS (nm_setting_ovs_interface_parent_class)->finalize (object); +} + +static void +nm_setting_ovs_interface_class_init (NMSettingOvsInterfaceClass *setting_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (setting_class); + NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class); + + object_class->set_property = set_property; + object_class->get_property = get_property; + object_class->finalize = finalize; + parent_class->verify = verify; + + /** + * NMSettingOvsInterface:type: + * + * The interface type. Either "internal", or empty. + * + * Since: 1.10 + **/ + g_object_class_install_property + (object_class, PROP_TYPE, + g_param_spec_string (NM_SETTING_OVS_INTERFACE_TYPE, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/libnm-core/nm-setting-ovs-interface.h b/libnm-core/nm-setting-ovs-interface.h new file mode 100644 index 0000000000..7261cfd8c9 --- /dev/null +++ b/libnm-core/nm-setting-ovs-interface.h @@ -0,0 +1,54 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2017 Red Hat, Inc. + */ + +#ifndef __NM_SETTING_OVS_INTERFACE_H__ +#define __NM_SETTING_OVS_INTERFACE_H__ + +#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION) +#error "Only can be included directly." +#endif + +#include "nm-setting.h" + +G_BEGIN_DECLS + +#define NM_TYPE_SETTING_OVS_INTERFACE (nm_setting_ovs_interface_get_type ()) +#define NM_SETTING_OVS_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_OVS_INTERFACE, NMSettingOvsInterface)) +#define NM_SETTING_OVS_INTERFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTING_OVS_INTERFACECONFIG, NMSettingOvsInterfaceClass)) +#define NM_IS_SETTING_OVS_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTING_OVS_INTERFACE)) +#define NM_IS_SETTING_OVS_INTERFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SETTING_OVS_INTERFACE)) +#define NM_SETTING_OVS_INTERFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTING_OVS_INTERFACE, NMSettingOvsInterfaceClass)) + +#define NM_SETTING_OVS_INTERFACE_SETTING_NAME "ovs-interface" + +#define NM_SETTING_OVS_INTERFACE_TYPE "type" + +typedef struct _NMSettingOvsInterfaceClass NMSettingOvsInterfaceClass; + +NM_AVAILABLE_IN_1_10 +GType nm_setting_ovs_interface_get_type (void); +NM_AVAILABLE_IN_1_10 +NMSetting *nm_setting_ovs_interface_new (void); + +NM_AVAILABLE_IN_1_10 +const char *nm_setting_ovs_interface_get_interface_type (NMSettingOvsInterface *self); + +G_END_DECLS + +#endif /* __NM_SETTING_OVS_INTERFACE_H__ */ diff --git a/libnm-core/nm-setting-ovs-patch.c b/libnm-core/nm-setting-ovs-patch.c index 9e38091474..fb1412bf4a 100644 --- a/libnm-core/nm-setting-ovs-patch.c +++ b/libnm-core/nm-setting-ovs-patch.c @@ -115,6 +115,37 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } + + if (connection) { + NMSettingOvsInterface *s_ovs_interface; + const char *interface_type = NULL; + + s_ovs_interface = nm_connection_get_setting_ovs_interface (connection); + if (s_ovs_interface) + interface_type = nm_setting_ovs_interface_get_interface_type (s_ovs_interface); + + if (interface_type && strcmp (interface_type, "patch") != 0) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("A connection with '%s' setting needs to be of 'patch' interface type, not '%s'"), + NM_SETTING_OVS_PATCH_SETTING_NAME, + interface_type); + g_prefix_error (error, "%s.%s: ", NM_SETTING_OVS_INTERFACE_SETTING_NAME, NM_SETTING_OVS_INTERFACE_TYPE); + return FALSE; + } + + if (!interface_type) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("A connection with '%s' setting needs to be of 'patch' interface type"), + NM_SETTING_OVS_PATCH_SETTING_NAME); + g_prefix_error (error, "%s.%s: ", NM_SETTING_OVS_INTERFACE_SETTING_NAME, NM_SETTING_OVS_INTERFACE_TYPE); + return NM_SETTING_VERIFY_NORMALIZABLE_ERROR; + } + } + return TRUE; } diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c index 2f282db6aa..f103727ce9 100644 --- a/libnm-core/nm-setting.c +++ b/libnm-core/nm-setting.c @@ -258,6 +258,8 @@ _nm_setting_slave_type_is_valid (const char *slave_type, const char **out_port_t ; else if (!strcmp (slave_type, NM_SETTING_BRIDGE_SETTING_NAME)) port_type = NM_SETTING_BRIDGE_PORT_SETTING_NAME; + else if (!strcmp (slave_type, NM_SETTING_OVS_INTERFACE_SETTING_NAME)) + ; else if (!strcmp (slave_type, NM_SETTING_TEAM_SETTING_NAME)) port_type = NM_SETTING_TEAM_PORT_SETTING_NAME; else diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 18b318c716..5045a2a9e6 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1190,6 +1190,9 @@ global: nm_ip_route_equal_full; nm_setting_bridge_get_group_forward_mask; nm_setting_ip_config_get_route_table; + nm_setting_ovs_interface_get_interface_type; + nm_setting_ovs_interface_get_type; + nm_setting_ovs_interface_new; nm_setting_ovs_patch_get_peer; nm_setting_ovs_patch_get_type; nm_setting_ovs_patch_new; diff --git a/po/POTFILES.in b/po/POTFILES.in index 21da33f0aa..e5b50a780e 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -75,6 +75,7 @@ libnm-core/nm-setting-ip-tunnel.c libnm-core/nm-setting-macsec.c libnm-core/nm-setting-macvlan.c libnm-core/nm-setting-olpc-mesh.c +libnm-core/nm-setting-ovs-interface.c libnm-core/nm-setting-ovs-patch.c libnm-core/nm-setting-ppp.c libnm-core/nm-setting-pppoe.c