core: move virtual interface name handling into device plugins

Instead of having a bunch of logic in the Manager for determining the
VLAN and Infiniband virtual interface names, move the type-specific
logic into the plugins themselves.
This commit is contained in:
Dan Williams 2014-09-18 17:50:47 -05:00
parent 42b272b604
commit 179d56c73c
5 changed files with 285 additions and 202 deletions

View file

@ -160,61 +160,92 @@ nm_device_factory_create_virtual_device_for_connection (NMDeviceFactory *factory
return interface->create_virtual_device_for_connection (factory, connection, parent, error);
}
const char *
nm_device_factory_get_connection_parent (NMDeviceFactory *factory,
NMConnection *connection)
{
g_return_val_if_fail (factory != NULL, NULL);
g_return_val_if_fail (connection != NULL, NULL);
if (!nm_connection_is_virtual (connection))
return NULL;
if (NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_connection_parent)
return NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_connection_parent (factory, connection);
return NULL;
}
static char *
get_virtual_iface_name (NMDeviceFactory *factory,
NMConnection *connection,
const char *parent_iface)
{
const char *iface;
/* For any other virtual connection, NMSettingConnection:interface-name is
* the virtual device name.
*/
iface = nm_connection_get_interface_name (connection);
g_return_val_if_fail (iface != NULL, NULL);
return g_strdup (iface);
}
char *
nm_device_factory_get_virtual_iface_name (NMDeviceFactory *factory,
NMConnection *connection,
const char *parent_iface)
{
g_return_val_if_fail (factory != NULL, NULL);
g_return_val_if_fail (connection != NULL, NULL);
if (!nm_connection_is_virtual (connection))
return NULL;
if (NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_virtual_iface_name)
return NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_virtual_iface_name (factory, connection, parent_iface);
return NULL;
}
/*******************************************************************/
static void
interface_init (gpointer g_iface)
default_init (NMDeviceFactory *factory_iface)
{
GType iface_type = G_TYPE_FROM_INTERFACE (g_iface);
static gboolean initialized = FALSE;
if (G_LIKELY (initialized))
return;
factory_iface->get_virtual_iface_name = get_virtual_iface_name;
/* Signals */
signals[DEVICE_ADDED] = g_signal_new (NM_DEVICE_FACTORY_DEVICE_ADDED,
iface_type,
NM_TYPE_DEVICE_FACTORY,
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMDeviceFactory, device_added),
NULL, NULL, NULL,
G_TYPE_NONE, 1, NM_TYPE_DEVICE);
signals[COMPONENT_ADDED] = g_signal_new (NM_DEVICE_FACTORY_COMPONENT_ADDED,
iface_type,
NM_TYPE_DEVICE_FACTORY,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NMDeviceFactory, component_added),
g_signal_accumulator_true_handled, NULL, NULL,
G_TYPE_BOOLEAN, 1, G_TYPE_OBJECT);
initialized = TRUE;
}
GType
nm_device_factory_get_type (void)
{
static GType device_factory_type = 0;
if (!device_factory_type) {
const GTypeInfo device_factory_info = {
sizeof (NMDeviceFactory), /* class_size */
interface_init, /* base_init */
NULL, /* base_finalize */
NULL,
NULL, /* class_finalize */
NULL, /* class_data */
0,
0, /* n_preallocs */
NULL
};
device_factory_type = g_type_register_static (G_TYPE_INTERFACE,
"NMDeviceFactory",
&device_factory_info,
0);
g_type_interface_add_prerequisite (device_factory_type, G_TYPE_OBJECT);
static volatile gsize g_define_type_id__volatile = 0;
if (g_once_init_enter (&g_define_type_id__volatile)) {
GType g_define_type_id =
g_type_register_static_simple (G_TYPE_INTERFACE,
g_intern_static_string ("NMDeviceFactory"),
sizeof (NMDeviceFactory),
(GClassInitFunc) default_init,
0,
(GInstanceInitFunc) NULL,
(GTypeFlags) 0);
g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_OBJECT);
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
}
return device_factory_type;
return g_define_type_id__volatile;
}
/*******************************************************************/

View file

@ -128,6 +128,34 @@ struct _NMDeviceFactory {
NMDevice *parent,
GError **error);
/**
* get_connection_parent:
* @factory: the #NMDeviceFactory
* @connection: the #NMConnection to return the parent name for, if supported
*
* Given a connection, returns the a parent interface name, parent connection
* UUID, or parent device hardware address for @connection.
*
* Returns: the parent interface name, parent connection UUID, parent
* device hardware address, or %NULL
*/
const char * (*get_connection_parent) (NMDeviceFactory *factory,
NMConnection *connection);
/**
* get_virtual_iface_name:
* @factory: the #NMDeviceFactory
* @connection: the #NMConnection to return the virtual interface name for
* @parent_iface: parent interface name
*
* Given a connection, returns the interface name that a device activating
* that connection would have.
*
* Returns: the interface name, or %NULL
*/
char * (*get_virtual_iface_name) (NMDeviceFactory *factory,
NMConnection *connection,
const char *parent_iface);
/* Signals */
@ -162,6 +190,13 @@ void nm_device_factory_get_supported_types (NMDeviceFactory *factory,
const NMLinkType **out_link_types,
const char ***out_setting_types);
const char *nm_device_factory_get_connection_parent (NMDeviceFactory *factory,
NMConnection *connection);
char * nm_device_factory_get_virtual_iface_name (NMDeviceFactory *factory,
NMConnection *connection,
const char *parent_iface);
void nm_device_factory_start (NMDeviceFactory *factory);
NMDevice * nm_device_factory_new_link (NMDeviceFactory *factory,

View file

@ -345,10 +345,42 @@ create_virtual_device_for_connection (NMDeviceFactory *factory,
NULL);
}
static const char *
get_connection_parent (NMDeviceFactory *factory, NMConnection *connection)
{
NMSettingInfiniband *s_infiniband;
g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME), NULL);
s_infiniband = nm_connection_get_setting_infiniband (connection);
g_assert (s_infiniband);
return nm_setting_infiniband_get_parent (s_infiniband);
}
static char *
get_virtual_iface_name (NMDeviceFactory *factory,
NMConnection *connection,
const char *parent_iface)
{
NMSettingInfiniband *s_infiniband;
g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME), NULL);
s_infiniband = nm_connection_get_setting_infiniband (connection);
g_assert (s_infiniband);
g_return_val_if_fail (g_strcmp0 (parent_iface, nm_setting_infiniband_get_parent (s_infiniband)) == 0, NULL);
return g_strdup (nm_setting_infiniband_get_virtual_interface_name (s_infiniband));
}
NM_DEVICE_FACTORY_DEFINE_INTERNAL (INFINIBAND, Infiniband, infiniband,
NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_INFINIBAND)
NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_INFINIBAND_SETTING_NAME),
factory_iface->new_link = new_link;
factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection;
factory_iface->get_connection_parent = get_connection_parent;
factory_iface->get_virtual_iface_name = get_virtual_iface_name;
)

View file

@ -743,10 +743,63 @@ create_virtual_device_for_connection (NMDeviceFactory *factory,
return device;
}
static const char *
get_connection_parent (NMDeviceFactory *factory, NMConnection *connection)
{
NMSettingVlan *s_vlan;
NMSettingWired *s_wired;
const char *parent = NULL;
g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME), NULL);
s_vlan = nm_connection_get_setting_vlan (connection);
g_assert (s_vlan);
parent = nm_setting_vlan_get_parent (s_vlan);
if (parent)
return parent;
/* Try the hardware address from the VLAN connection's hardware setting */
s_wired = nm_connection_get_setting_wired (connection);
if (s_wired)
return nm_setting_wired_get_mac_address (s_wired);
return NULL;
}
static char *
get_virtual_iface_name (NMDeviceFactory *factory,
NMConnection *connection,
const char *parent_iface)
{
const char *ifname;
NMSettingVlan *s_vlan;
g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME), NULL);
s_vlan = nm_connection_get_setting_vlan (connection);
g_assert (s_vlan);
if (!parent_iface)
return NULL;
ifname = nm_connection_get_interface_name (connection);
if (ifname)
return g_strdup (ifname);
/* If the connection doesn't specify the interface name for the VLAN
* device, we create one for it using the VLAN ID and the parent
* interface's name.
*/
return nm_utils_new_vlan_name (parent_iface, nm_setting_vlan_get_id (s_vlan));
}
NM_DEVICE_FACTORY_DEFINE_INTERNAL (VLAN, Vlan, vlan,
NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_VLAN)
NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_VLAN_SETTING_NAME),
factory_iface->new_link = new_link;
factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection;
factory_iface->get_connection_parent = get_connection_parent;
factory_iface->get_virtual_iface_name = get_virtual_iface_name;
)

View file

@ -514,23 +514,19 @@ nm_manager_get_device_by_ifindex (NMManager *manager, int ifindex)
}
static NMDevice *
get_device_from_hwaddr (NMManager *self, const char *setting_mac)
find_device_by_hw_addr (NMManager *manager, const char *hwaddr)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
const char *device_mac;
GSList *iter;
const char *device_addr;
if (!setting_mac)
return NULL;
g_return_val_if_fail (hwaddr != NULL, NULL);
for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
NMDevice *device = iter->data;
device_mac = nm_device_get_hw_address (iter->data);
if (!device_mac)
continue;
if (nm_utils_hwaddr_matches (setting_mac, -1, device_mac, -1))
return device;
if (nm_utils_hwaddr_valid (hwaddr, -1)) {
for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) {
device_addr = nm_device_get_hw_address (NM_DEVICE (iter->data));
if (device_addr && nm_utils_hwaddr_matches (hwaddr, -1, device_addr, -1))
return NM_DEVICE (iter->data);
}
}
return NULL;
}
@ -538,14 +534,13 @@ get_device_from_hwaddr (NMManager *self, const char *setting_mac)
static NMDevice *
find_device_by_ip_iface (NMManager *self, const gchar *iface)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GSList *iter;
for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
NMDevice *candidate = iter->data;
g_return_val_if_fail (iface != NULL, NULL);
if (g_strcmp0 (nm_device_get_ip_iface (candidate), iface) == 0)
return candidate;
for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = g_slist_next (iter)) {
if (g_strcmp0 (nm_device_get_ip_iface (NM_DEVICE (iter->data)), iface) == 0)
return NM_DEVICE (iter->data);
}
return NULL;
}
@ -873,87 +868,56 @@ nm_manager_get_state (NMManager *manager)
return NM_MANAGER_GET_PRIVATE (manager)->state;
}
/*******************************************************************/
/* Settings stuff via NMSettings */
/*******************************************************************/
/***************************/
static NMDevice *
find_vlan_parent (NMManager *self,
NMConnection *connection)
find_parent_device_for_connection (NMManager *self, NMConnection *connection)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMSettingVlan *s_vlan;
NMSettingWired *s_wired;
NMDeviceFactory *factory;
const char *parent_name = NULL;
NMConnection *parent_connection;
const char *parent_iface;
NMDevice *parent = NULL;
const char *setting_mac;
NMDevice *parent, *first_compatible = NULL;
GSList *iter;
/* The 'parent' property could be given by an interface name, a
* connection UUID, or the MAC address of an NMSettingWired.
factory = nm_device_factory_manager_find_factory_for_connection (connection);
if (!factory)
return NULL;
parent_name = nm_device_factory_get_connection_parent (factory, connection);
if (!parent_name)
return NULL;
/* Try as an interface name */
parent = find_device_by_ip_iface (self, parent_name);
if (parent)
return parent;
/* Maybe a hardware address */
parent = find_device_by_hw_addr (self, parent_name);
if (parent)
return parent;
/* Maybe a connection UUID */
parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (priv->settings, parent_name);
if (!parent_connection)
return NULL;
/* Check if the parent connection is currently activated or is comaptible
* with some known device.
*/
s_vlan = nm_connection_get_setting_vlan (connection);
g_return_val_if_fail (s_vlan != NULL, NULL);
for (iter = priv->devices; iter; iter = iter->next) {
NMDevice *candidate = iter->data;
s_wired = nm_connection_get_setting_wired (connection);
setting_mac = s_wired ? nm_setting_wired_get_mac_address (s_wired) : NULL;
if (nm_device_get_connection (candidate) == parent_connection)
return candidate;
parent_iface = nm_setting_vlan_get_parent (s_vlan);
if (parent_iface) {
parent = find_device_by_ip_iface (self, parent_iface);
if (parent)
return parent;
if (nm_utils_is_uuid (parent_iface)) {
/* Try as a connection UUID */
parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (priv->settings, parent_iface);
if (parent_connection) {
/* Check if the parent connection is activated on some device already */
for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
NMActRequest *req;
NMConnection *candidate;
req = nm_device_get_act_request (NM_DEVICE (iter->data));
if (req) {
candidate = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (req));
if (candidate == parent_connection)
return NM_DEVICE (iter->data);
}
}
/* Check the hardware address of the parent connection */
return get_device_from_hwaddr (self, setting_mac);
}
return NULL;
}
if ( !first_compatible
&& nm_device_check_connection_compatible (candidate, parent_connection))
first_compatible = candidate;
}
/* Try the hardware address from the VLAN connection's hardware setting */
return get_device_from_hwaddr (self, setting_mac);
}
static NMDevice *
find_infiniband_parent (NMManager *self,
NMConnection *connection)
{
NMSettingInfiniband *s_infiniband;
const char *parent_iface;
NMDevice *parent = NULL;
const char *setting_mac;
s_infiniband = nm_connection_get_setting_infiniband (connection);
g_return_val_if_fail (s_infiniband != NULL, NULL);
parent_iface = nm_setting_infiniband_get_parent (s_infiniband);
if (parent_iface) {
parent = find_device_by_ip_iface (self, parent_iface);
if (parent)
return parent;
}
setting_mac = nm_setting_infiniband_get_mac_address (s_infiniband);
return get_device_from_hwaddr (self, setting_mac);
return first_compatible;
}
/**
@ -961,86 +925,69 @@ find_infiniband_parent (NMManager *self,
* @self: the #NMManager
* @connection: the #NMConnection representing a virtual interface
* @out_parent: on success, the parent device if any
* @error: an error if determining the virtual interface name failed
*
* Given @connection, returns the interface name that the connection
* would represent. If the interface name is not given by the connection,
* this may require constructing it based on information in the connection
* and existing network interfaces.
* would represent if it is a virtual connection. %NULL is returned and
* @error is set if the connection is not virtual, or if the name could
* not be determined.
*
* Returns: the expected interface name (caller takes ownership), or %NULL
*/
static char *
get_virtual_iface_name (NMManager *self,
NMConnection *connection,
NMDevice **out_parent)
NMDevice **out_parent,
GError **error)
{
NMDeviceFactory *factory;
char *iface = NULL;
NMDevice *parent = NULL;
const char *ifname;
if (out_parent)
*out_parent = NULL;
if (!nm_connection_is_virtual (connection))
if (!nm_connection_is_virtual (connection)) {
g_set_error (error,
NM_MANAGER_ERROR,
NM_MANAGER_ERROR_FAILED,
"NetworkManager plugin for '%s' unavailable",
nm_connection_get_connection_type (connection));
return NULL;
ifname = nm_connection_get_interface_name (connection);
if (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME)) {
NMSettingVlan *s_vlan;
char *vname;
s_vlan = nm_connection_get_setting_vlan (connection);
g_return_val_if_fail (s_vlan != NULL, NULL);
parent = find_vlan_parent (self, connection);
if (!parent)
return NULL;
if (!nm_device_supports_vlans (parent)) {
nm_log_warn (LOGD_DEVICE, "(%s): No support for VLANs on interface %s of type %s",
ifname ? ifname : nm_connection_get_id (connection),
nm_device_get_ip_iface (parent),
nm_device_get_type_desc (parent));
return NULL;
}
/* If the connection doesn't specify the interface name for the VLAN
* device, we create one for it using the VLAN ID and the parent
* interface's name.
*/
if (ifname)
vname = g_strdup (ifname);
else {
vname = nm_utils_new_vlan_name (nm_device_get_ip_iface (parent),
nm_setting_vlan_get_id (s_vlan));
}
if (out_parent)
*out_parent = parent;
return vname;
}
if (nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME)) {
NMSettingInfiniband *s_infiniband;
parent = find_infiniband_parent (self, connection);
if (!parent)
return NULL;
s_infiniband = nm_connection_get_setting_infiniband (connection);
if (out_parent)
*out_parent = parent;
return g_strdup (nm_setting_infiniband_get_virtual_interface_name (s_infiniband));
factory = nm_device_factory_manager_find_factory_for_connection (connection);
if (!factory) {
nm_log_warn (LOGD_DEVICE, "(%s) NetworkManager plugin for '%s' unavailable",
nm_connection_get_id (connection),
nm_connection_get_connection_type (connection));
g_set_error (error,
NM_MANAGER_ERROR,
NM_MANAGER_ERROR_FAILED,
"NetworkManager plugin for '%s' unavailable",
nm_connection_get_connection_type (connection));
return NULL;
}
/* For any other virtual connection, NMSettingConnection:interface-name is
* the virtual device name.
*/
g_return_val_if_fail (ifname != NULL, NULL);
return g_strdup (ifname);
parent = find_parent_device_for_connection (self, connection);
iface = nm_device_factory_get_virtual_iface_name (factory,
connection,
parent ? nm_device_get_ip_iface (parent) : NULL);
if (!iface) {
nm_log_warn (LOGD_DEVICE, "(%s) failed to determine virtual interface name",
nm_connection_get_id (connection));
g_set_error_literal (error,
NM_MANAGER_ERROR,
NM_MANAGER_ERROR_UNKNOWN_DEVICE,
"failed to determine virtual interface name");
return NULL;
}
if (out_parent)
*out_parent = parent;
return iface;
}
/***************************/
/**
* system_create_virtual_device:
* @self: the #NMManager
@ -1066,16 +1013,9 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
iface = get_virtual_iface_name (self, connection, &parent);
if (!iface) {
nm_log_dbg (LOGD_DEVICE, "(%s) failed to determine virtual interface name",
nm_connection_get_id (connection));
g_set_error_literal (error,
NM_MANAGER_ERROR,
NM_MANAGER_ERROR_FAILED,
"failed to determine virtual interface name");
iface = get_virtual_iface_name (self, connection, &parent, error);
if (!iface)
return NULL;
}
/* Make sure we didn't create a device for this connection already */
for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
@ -2251,13 +2191,10 @@ find_master (NMManager *self,
NMConnection *candidate = iter->data;
char *vname;
if (nm_connection_is_virtual (candidate)) {
vname = get_virtual_iface_name (self, candidate, NULL);
if ( g_strcmp0 (master, vname) == 0
&& is_compatible_with_slave (candidate, connection))
master_connection = candidate;
g_free (vname);
}
vname = get_virtual_iface_name (self, connection, NULL, NULL);
if (g_strcmp0 (master, vname) == 0 && is_compatible_with_slave (candidate, connection))
master_connection = candidate;
g_free (vname);
}
g_slist_free (connections);
}
@ -2939,17 +2876,12 @@ validate_activation_request (NMManager *self,
}
if (is_software) {
/* Look for an existing device with the connection's interface name */
char *iface;
iface = get_virtual_iface_name (self, connection, NULL);
if (!iface) {
g_set_error_literal (error,
NM_MANAGER_ERROR,
NM_MANAGER_ERROR_UNKNOWN_DEVICE,
"Failed to determine connection's virtual interface name");
/* Look for an existing device with the connection's interface name */
iface = get_virtual_iface_name (self, connection, NULL, error);
if (!iface)
goto error;
}
device = find_device_by_ip_iface (self, iface);
g_free (iface);