core: move software device creation logic out of NMManager

Rather than having NMManager know how to parse various settings to
create each kind of software device, add a _new_for_connection()
constructor to each of them and let them call NMPlatform to create the
device correctly themselves.
This commit is contained in:
Dan Winship 2013-09-03 14:23:16 -04:00
parent 23d4973835
commit 2688ae4950
11 changed files with 244 additions and 112 deletions

View file

@ -378,10 +378,37 @@ release_slave (NMDevice *device, NMDevice *slave)
/******************************************************************/
NMDevice *
nm_device_bond_new (const char *iface)
nm_device_bond_new (NMPlatformLink *platform_device)
{
g_return_val_if_fail (platform_device != NULL, NULL);
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BOND,
NM_DEVICE_PLATFORM_DEVICE, platform_device,
NM_DEVICE_DRIVER, "bonding",
NM_DEVICE_TYPE_DESC, "Bond",
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BOND,
NM_DEVICE_IS_MASTER, TRUE,
NULL);
}
NMDevice *
nm_device_bond_new_for_connection (NMConnection *connection)
{
const char *iface;
g_return_val_if_fail (connection != NULL, NULL);
iface = nm_connection_get_virtual_iface_name (connection);
g_return_val_if_fail (iface != NULL, NULL);
if ( !nm_platform_bond_add (iface)
&& nm_platform_get_error () != NM_PLATFORM_ERROR_EXISTS) {
nm_log_warn (LOGD_DEVICE | LOGD_BOND, "(%s): failed to create bonding master interface for '%s': %s",
iface, nm_connection_get_id (connection),
nm_platform_get_error_msg ());
return NULL;
}
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BOND,
NM_DEVICE_IFACE, iface,
NM_DEVICE_DRIVER, "bonding",

View file

@ -54,7 +54,8 @@ typedef struct {
GType nm_device_bond_get_type (void);
NMDevice *nm_device_bond_new (const char *iface);
NMDevice *nm_device_bond_new (NMPlatformLink *platform_device);
NMDevice *nm_device_bond_new_for_connection (NMConnection *connection);
G_END_DECLS

View file

@ -324,10 +324,37 @@ release_slave (NMDevice *device, NMDevice *slave)
/******************************************************************/
NMDevice *
nm_device_bridge_new (const char *iface)
nm_device_bridge_new (NMPlatformLink *platform_device)
{
g_return_val_if_fail (platform_device != NULL, NULL);
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BRIDGE,
NM_DEVICE_PLATFORM_DEVICE, platform_device,
NM_DEVICE_DRIVER, "bridge",
NM_DEVICE_TYPE_DESC, "Bridge",
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BRIDGE,
NM_DEVICE_IS_MASTER, TRUE,
NULL);
}
NMDevice *
nm_device_bridge_new_for_connection (NMConnection *connection)
{
const char *iface;
g_return_val_if_fail (connection != NULL, NULL);
iface = nm_connection_get_virtual_iface_name (connection);
g_return_val_if_fail (iface != NULL, NULL);
if ( !nm_platform_bridge_add (iface)
&& nm_platform_get_error () != NM_PLATFORM_ERROR_EXISTS) {
nm_log_warn (LOGD_DEVICE | LOGD_BRIDGE, "(%s): failed to create bridge master interface for '%s': %s",
iface, nm_connection_get_id (connection),
nm_platform_get_error_msg ());
return NULL;
}
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BRIDGE,
NM_DEVICE_IFACE, iface,
NM_DEVICE_DRIVER, "bridge",

View file

@ -54,7 +54,8 @@ typedef struct {
GType nm_device_bridge_get_type (void);
NMDevice *nm_device_bridge_new (const char *iface);
NMDevice *nm_device_bridge_new (NMPlatformLink *platform_device);
NMDevice *nm_device_bridge_new_for_connection (NMConnection *connection);
G_END_DECLS

View file

@ -105,15 +105,34 @@ nm_device_infiniband_new (NMPlatformLink *platform_device)
}
NMDevice *
nm_device_infiniband_new_partition (const char *iface,
const char *driver)
nm_device_infiniband_new_partition (NMConnection *connection,
NMDevice *parent)
{
NMSettingInfiniband *s_infiniband;
int p_key, parent_ifindex;
const char *iface;
g_return_val_if_fail (connection != NULL, NULL);
g_return_val_if_fail (NM_IS_DEVICE_INFINIBAND (parent), NULL);
iface = nm_connection_get_virtual_iface_name (connection);
g_return_val_if_fail (iface != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
parent_ifindex = nm_device_get_ifindex (parent);
s_infiniband = nm_connection_get_setting_infiniband (connection);
p_key = nm_setting_infiniband_get_p_key (s_infiniband);
if ( !nm_platform_infiniband_partition_add (parent_ifindex, p_key)
&& nm_platform_get_error () != NM_PLATFORM_ERROR_EXISTS) {
nm_log_warn (LOGD_DEVICE | LOGD_INFINIBAND, "(%s): failed to add InfiniBand P_Key interface for '%s': %s",
iface, nm_connection_get_id (connection),
nm_platform_get_error_msg ());
return NULL;
}
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_INFINIBAND,
NM_DEVICE_IFACE, iface,
NM_DEVICE_DRIVER, driver,
NM_DEVICE_DRIVER, nm_device_get_driver (parent),
NM_DEVICE_TYPE_DESC, "InfiniBand",
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_INFINIBAND,
NULL);

View file

@ -53,8 +53,8 @@ typedef struct {
GType nm_device_infiniband_get_type (void);
NMDevice *nm_device_infiniband_new (NMPlatformLink *platform_device);
NMDevice *nm_device_infiniband_new_partition (const char *iface,
const char *driver);
NMDevice *nm_device_infiniband_new_partition (NMConnection *connection,
NMDevice *parent);
G_END_DECLS

View file

@ -590,10 +590,37 @@ release_slave (NMDevice *device, NMDevice *slave)
/******************************************************************/
NMDevice *
nm_device_team_new (const char *iface)
nm_device_team_new (NMPlatformLink *platform_device)
{
g_return_val_if_fail (platform_device != NULL, NULL);
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_TEAM,
NM_DEVICE_PLATFORM_DEVICE, platform_device,
NM_DEVICE_DRIVER, "team",
NM_DEVICE_TYPE_DESC, "Team",
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_TEAM,
NM_DEVICE_IS_MASTER, TRUE,
NULL);
}
NMDevice *
nm_device_team_new_for_connection (NMConnection *connection)
{
const char *iface;
g_return_val_if_fail (connection != NULL, NULL);
iface = nm_connection_get_virtual_iface_name (connection);
g_return_val_if_fail (iface != NULL, NULL);
if ( !nm_platform_team_add (iface)
&& nm_platform_get_error () != NM_PLATFORM_ERROR_EXISTS) {
nm_log_warn (LOGD_DEVICE | LOGD_TEAM, "(%s): failed to create team master interface for '%s': %s",
iface, nm_connection_get_id (connection),
nm_platform_get_error_msg ());
return NULL;
}
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_TEAM,
NM_DEVICE_IFACE, iface,
NM_DEVICE_DRIVER, "team",

View file

@ -54,7 +54,8 @@ typedef struct {
GType nm_device_team_get_type (void);
NMDevice *nm_device_team_new (const char *iface);
NMDevice *nm_device_team_new (NMPlatformLink *platform_device);
NMDevice *nm_device_team_new_for_connection (NMConnection *connection);
G_END_DECLS

View file

@ -47,6 +47,7 @@ G_DEFINE_TYPE (NMDeviceVlan, nm_device_vlan, NM_TYPE_DEVICE)
typedef struct {
gboolean disposed;
gboolean invalid;
NMDevice *parent;
guint parent_state_id;
@ -56,6 +57,7 @@ typedef struct {
enum {
PROP_0,
PROP_PARENT,
PROP_VLAN_ID,
LAST_PROP
@ -344,57 +346,69 @@ parent_state_changed (NMDevice *parent,
/******************************************************************/
NMDevice *
nm_device_vlan_new (const char *iface, NMDevice *parent)
nm_device_vlan_new (NMPlatformLink *platform_device, NMDevice *parent)
{
NMDevice *device;
g_return_val_if_fail (iface != NULL, NULL);
g_return_val_if_fail (parent != NULL, NULL);
g_return_val_if_fail (platform_device != NULL, NULL);
g_return_val_if_fail (NM_IS_DEVICE (parent), NULL);
device = (NMDevice *) g_object_new (NM_TYPE_DEVICE_VLAN,
NM_DEVICE_IFACE, iface,
NM_DEVICE_PLATFORM_DEVICE, platform_device,
NM_DEVICE_VLAN_PARENT, parent,
NM_DEVICE_DRIVER, "8021q",
NM_DEVICE_TYPE_DESC, "VLAN",
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_VLAN,
NULL);
if (device) {
NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device);
int ifindex = nm_device_get_ifindex (device);
int parent_ifindex = -1, itype;
int vlan_id;
if (NM_DEVICE_VLAN_GET_PRIVATE (device)->invalid) {
g_object_unref (device);
device = NULL;
}
itype = nm_platform_link_get_type (ifindex);
if (itype != NM_LINK_TYPE_VLAN) {
nm_log_err (LOGD_VLAN, "(%s): failed to get VLAN interface type.", iface);
g_object_unref (device);
return NULL;
}
return device;
}
if (!nm_platform_vlan_get_info (ifindex, &parent_ifindex, &vlan_id)) {
nm_log_warn (LOGD_VLAN, "(%s): failed to get VLAN interface info.", iface);
g_object_unref (device);
return NULL;
}
NMDevice *
nm_device_vlan_new_for_connection (NMConnection *connection, NMDevice *parent)
{
NMDevice *device;
NMSettingVlan *s_vlan;
char *iface;
if ( parent_ifindex < 0
|| parent_ifindex != nm_device_get_ip_ifindex (parent)
|| vlan_id < 0) {
nm_log_warn (LOGD_VLAN, "(%s): VLAN parent ifindex (%d) or VLAN ID (%d) invalid.",
iface, parent_ifindex, priv->vlan_id);
g_object_unref (device);
return NULL;
}
g_return_val_if_fail (connection != NULL, NULL);
g_return_val_if_fail (NM_IS_DEVICE (parent), NULL);
priv->vlan_id = vlan_id;
priv->parent = g_object_ref (parent);
priv->parent_state_id = g_signal_connect (priv->parent,
"state-changed",
G_CALLBACK (parent_state_changed),
device);
s_vlan = nm_connection_get_setting_vlan (connection);
g_return_val_if_fail (s_vlan != NULL, NULL);
nm_log_dbg (LOGD_HW | LOGD_ETHER, "(%s): kernel ifindex %d", iface, ifindex);
nm_log_info (LOGD_HW | LOGD_ETHER, "(%s): VLAN ID %d with parent %s",
iface, priv->vlan_id, nm_device_get_iface (parent));
iface = g_strdup (nm_connection_get_virtual_iface_name (connection));
if (!iface) {
iface = nm_utils_new_vlan_name (nm_device_get_ip_iface (parent),
nm_setting_vlan_get_id (s_vlan));
}
if ( !nm_platform_vlan_add (iface,
nm_device_get_ifindex (parent),
nm_setting_vlan_get_id (s_vlan),
nm_setting_vlan_get_flags (s_vlan))
&& nm_platform_get_error () != NM_PLATFORM_ERROR_EXISTS) {
nm_log_warn (LOGD_DEVICE | LOGD_VLAN, "(%s): failed to add VLAN interface for '%s'",
iface, nm_connection_get_id (connection));
g_free (iface);
return NULL;
}
device = (NMDevice *) g_object_new (NM_TYPE_DEVICE_VLAN,
NM_DEVICE_IFACE, iface,
NM_DEVICE_VLAN_PARENT, parent,
NM_DEVICE_DRIVER, "8021q",
NM_DEVICE_TYPE_DESC, "VLAN",
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_VLAN,
NULL);
g_free (iface);
if (NM_DEVICE_VLAN_GET_PRIVATE (device)->invalid) {
g_object_unref (device);
device = NULL;
}
return device;
@ -405,6 +419,53 @@ nm_device_vlan_init (NMDeviceVlan * self)
{
}
static void
constructed (GObject *object)
{
NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (object);
NMDevice *device = NM_DEVICE (object);
const char *iface = nm_device_get_iface (device);
int ifindex = nm_device_get_ifindex (device);
int parent_ifindex = -1, itype;
int vlan_id;
if (G_OBJECT_CLASS (nm_device_vlan_parent_class)->constructed)
G_OBJECT_CLASS (nm_device_vlan_parent_class)->constructed (object);
if (!priv->parent) {
nm_log_err (LOGD_VLAN, "(%s): no parent specified.", iface);
priv->invalid = TRUE;
return;
}
itype = nm_platform_link_get_type (ifindex);
if (itype != NM_LINK_TYPE_VLAN) {
nm_log_err (LOGD_VLAN, "(%s): failed to get VLAN interface type.", iface);
priv->invalid = TRUE;
return;
}
if (!nm_platform_vlan_get_info (ifindex, &parent_ifindex, &vlan_id)) {
nm_log_warn (LOGD_VLAN, "(%s): failed to get VLAN interface info.", iface);
priv->invalid = TRUE;
return;
}
if ( parent_ifindex < 0
|| parent_ifindex != nm_device_get_ip_ifindex (priv->parent)
|| vlan_id < 0) {
nm_log_warn (LOGD_VLAN, "(%s): VLAN parent ifindex (%d) or VLAN ID (%d) invalid.",
iface, parent_ifindex, priv->vlan_id);
priv->invalid = TRUE;
return;
}
priv->vlan_id = vlan_id;
nm_log_dbg (LOGD_HW | LOGD_VLAN, "(%s): kernel ifindex %d", iface, ifindex);
nm_log_info (LOGD_HW | LOGD_VLAN, "(%s): VLAN ID %d with parent %s",
iface, priv->vlan_id, nm_device_get_iface (priv->parent));
}
static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
@ -428,6 +489,13 @@ set_property (GObject *object, guint prop_id,
NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (object);
switch (prop_id) {
case PROP_PARENT:
priv->parent = g_value_dup_object (value);
priv->parent_state_id = g_signal_connect (priv->parent,
"state-changed",
G_CALLBACK (parent_state_changed),
object);
break;
case PROP_VLAN_ID:
priv->vlan_id = g_value_get_uint (value);
break;
@ -464,6 +532,7 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass)
g_type_class_add_private (object_class, sizeof (NMDeviceVlanPrivate));
/* virtual methods */
object_class->constructed = constructed;
object_class->get_property = get_property;
object_class->set_property = set_property;
object_class->dispose = dispose;
@ -477,6 +546,13 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass)
parent_class->match_l2_config = match_l2_config;
/* properties */
g_object_class_install_property
(object_class, PROP_PARENT,
g_param_spec_object (NM_DEVICE_VLAN_PARENT,
"Parent",
"Parent",
NM_TYPE_DEVICE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(object_class, PROP_VLAN_ID,
g_param_spec_uint (NM_DEVICE_VLAN_ID,

View file

@ -40,6 +40,7 @@ typedef enum {
NM_VLAN_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/
} NMVlanError;
#define NM_DEVICE_VLAN_PARENT "parent"
#define NM_DEVICE_VLAN_ID "vlan-id"
typedef struct {
@ -54,7 +55,10 @@ typedef struct {
GType nm_device_vlan_get_type (void);
NMDevice *nm_device_vlan_new (const char *iface, NMDevice *parent);
NMDevice *nm_device_vlan_new (NMPlatformLink *platform_link,
NMDevice *parent);
NMDevice *nm_device_vlan_new_for_connection (NMConnection *connection,
NMDevice *parent);
G_END_DECLS

View file

@ -1424,70 +1424,20 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
g_signal_handlers_block_by_func (nm_platform_get (), G_CALLBACK (platform_link_added_cb), self);
if (nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME)) {
if ( !nm_platform_bond_add (iface)
&& nm_platform_get_error () != NM_PLATFORM_ERROR_EXISTS) {
nm_log_warn (LOGD_DEVICE, "(%s): failed to add bonding master interface for '%s'",
iface, nm_connection_get_id (connection));
goto unblock;
}
device = nm_device_bond_new (iface);
device = nm_device_bond_new_for_connection (connection);
} else if (nm_connection_is_type (connection, NM_SETTING_TEAM_SETTING_NAME)) {
if (!nm_platform_team_add (iface)
&& nm_platform_get_error () != NM_PLATFORM_ERROR_EXISTS) {
nm_log_warn (LOGD_DEVICE, "(%s): failed to add team master interface for '%s'",
iface, nm_connection_get_id (connection));
goto unblock;
}
device = nm_device_team_new (iface);
device = nm_device_team_new_for_connection (connection);
} else if (nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME)) {
gboolean result;
result = nm_platform_bridge_add (iface);
if (!result && nm_platform_get_error () != NM_PLATFORM_ERROR_EXISTS) {
nm_log_warn (LOGD_DEVICE, "(%s): failed to add bridging interface for '%s'",
iface, nm_connection_get_id (connection));
goto unblock;
}
/* FIXME: remove when we handle bridges non-destructively */
if (!result && !bridge_created_by_nm (self, iface)) {
if (!nm_platform_link_get_ifindex (iface) > 0 && !bridge_created_by_nm (self, iface)) {
nm_log_warn (LOGD_DEVICE, "(%s): cannot use existing bridge for '%s'",
iface, nm_connection_get_id (connection));
goto unblock;
}
device = nm_device_bridge_new (iface);
} else
device = nm_device_bridge_new_for_connection (connection);
} else if (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME)) {
NMSettingVlan *s_vlan = nm_connection_get_setting_vlan (connection);
int ifindex = nm_device_get_ip_ifindex (parent);
if ( !nm_platform_vlan_add (iface, ifindex,
nm_setting_vlan_get_id (s_vlan),
nm_setting_vlan_get_flags (s_vlan))
&& nm_platform_get_error () != NM_PLATFORM_ERROR_EXISTS) {
nm_log_warn (LOGD_DEVICE, "(%s): failed to add VLAN interface for '%s'",
iface, nm_connection_get_id (connection));
goto unblock;
}
device = nm_device_vlan_new (iface, parent);
device = nm_device_vlan_new_for_connection (connection, parent);
} else if (nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME)) {
NMSettingInfiniband *s_infiniband = nm_connection_get_setting_infiniband (connection);
int p_key, parent_ifindex;
parent_ifindex = nm_device_get_ifindex (parent);
p_key = nm_setting_infiniband_get_p_key (s_infiniband);
if ( !nm_platform_infiniband_partition_add (parent_ifindex, p_key)
&& nm_platform_get_error () != NM_PLATFORM_ERROR_EXISTS) {
nm_log_warn (LOGD_DEVICE, "(%s): failed to add InfiniBand P_Key interface for '%s'",
iface, nm_connection_get_id (connection));
goto unblock;
}
device = nm_device_infiniband_new_partition (iface, nm_device_get_driver (parent));
device = nm_device_infiniband_new_partition (connection, parent);
}
if (device) {
@ -1495,7 +1445,6 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
add_device (self, device);
}
unblock:
g_signal_handlers_unblock_by_func (nm_platform_get (), G_CALLBACK (platform_link_added_cb), self);
out:
@ -2493,15 +2442,15 @@ platform_link_added_cb (NMPlatform *platform,
device = nm_device_wifi_new (link);
break;
case NM_LINK_TYPE_BOND:
device = nm_device_bond_new (link->name);
device = nm_device_bond_new (link);
break;
case NM_LINK_TYPE_TEAM:
device = nm_device_team_new (link->name);
device = nm_device_team_new (link);
break;
case NM_LINK_TYPE_BRIDGE:
/* FIXME: always create device when we handle bridges non-destructively */
if (bridge_created_by_nm (self, link->name))
device = nm_device_bridge_new (link->name);
device = nm_device_bridge_new (link);
else
nm_log_info (LOGD_BRIDGE, "(%s): ignoring bridge not created by NetworkManager", link->name);
break;
@ -2510,7 +2459,7 @@ platform_link_added_cb (NMPlatform *platform,
if (nm_platform_vlan_get_info (ifindex, &parent_ifindex, NULL)) {
parent = find_device_by_ifindex (self, parent_ifindex);
if (parent)
device = nm_device_vlan_new (link->name, parent);
device = nm_device_vlan_new (link, parent);
else {
/* If udev signaled the VLAN interface before it signaled
* the VLAN's parent at startup we may not know about the