core: add support for team device

Signed-off-by: Jiri Pirko <jiri@resnulli.us>
This commit is contained in:
Jiri Pirko 2013-07-25 15:36:45 +02:00 committed by Dan Williams
parent 64cdb1a7f0
commit 23836e8146
12 changed files with 510 additions and 29 deletions

View file

@ -51,6 +51,7 @@
#define NM_DBUS_INTERFACE_DHCP6_CONFIG NM_DBUS_INTERFACE ".DHCP6Config"
#define NM_DBUS_INTERFACE_DEVICE_INFINIBAND NM_DBUS_INTERFACE_DEVICE ".Infiniband"
#define NM_DBUS_INTERFACE_DEVICE_BOND NM_DBUS_INTERFACE_DEVICE ".Bond"
#define NM_DBUS_INTERFACE_DEVICE_TEAM NM_DBUS_INTERFACE_DEVICE ".Team"
#define NM_DBUS_INTERFACE_DEVICE_VLAN NM_DBUS_INTERFACE_DEVICE ".Vlan"
#define NM_DBUS_INTERFACE_DEVICE_BRIDGE NM_DBUS_INTERFACE_DEVICE ".Bridge"
#define NM_DBUS_INTERFACE_DEVICE_GENERIC NM_DBUS_INTERFACE_DEVICE ".Generic"
@ -118,6 +119,7 @@ typedef enum {
* @NM_DEVICE_TYPE_VLAN: an 802.1Q VLAN interface
* @NM_DEVICE_TYPE_ADSL: ADSL modem
* @NM_DEVICE_TYPE_BRIDGE: a bridge master interface
* @NM_DEVICE_TYPE_TEAM: a team master interface
*
* #NMDeviceType values indicate the type of hardware represented by
* an #NMDevice.
@ -138,6 +140,7 @@ typedef enum {
NM_DEVICE_TYPE_ADSL = 12,
NM_DEVICE_TYPE_BRIDGE = 13,
NM_DEVICE_TYPE_GENERIC = 14,
NM_DEVICE_TYPE_TEAM = 15,
} NMDeviceType;
/**

View file

@ -13,6 +13,7 @@ EXTRA_DIST = \
nm-device-wimax.xml \
nm-device-infiniband.xml \
nm-device-bond.xml \
nm-device-team.xml \
nm-device-bridge.xml \
nm-device-vlan.xml \
nm-device-generic.xml \

View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8" ?>
<node name="/" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
<interface name="org.freedesktop.NetworkManager.Device.Team">
<property name="HwAddress" type="s" access="read">
<tp:docstring>
Hardware address of the device.
</tp:docstring>
</property>
<property name="Carrier" type="b" access="read">
<tp:docstring>
Indicates whether the physical carrier is found (e.g. whether a cable is plugged in or not).
</tp:docstring>
</property>
<property name="Slaves" type="ao" access="read">
<tp:docstring>
Array of object paths representing devices which are currently
slaved to this device.
</tp:docstring>
</property>
<signal name="PropertiesChanged">
<arg name="properties" type="a{sv}" tp:type="String_Variant_Map">
<tp:docstring>
A dictionary mapping property names to variant boxed values
</tp:docstring>
</arg>
</signal>
</interface>
</node>

View file

@ -51,6 +51,7 @@ src/devices/nm-device-bt.c
src/devices/nm-device-ethernet.c
src/devices/nm-device-infiniband.c
src/devices/nm-device-olpc-mesh.c
src/devices/nm-device-team.c
src/devices/nm-device-vlan.c
src/nm-manager.c
src/nm-netlink-monitor.c

View file

@ -88,6 +88,8 @@ nm_sources = \
devices/nm-device-olpc-mesh.c \
devices/nm-device-olpc-mesh.h \
devices/nm-device-private.h \
devices/nm-device-team.c \
devices/nm-device-team.h \
devices/nm-device-tun.c \
devices/nm-device-tun.h \
devices/nm-device-veth.c \
@ -323,6 +325,7 @@ glue_sources = \
nm-device-macvlan-glue.h \
nm-device-modem-glue.h \
nm-device-olpc-mesh-glue.h \
nm-device-team-glue.h \
nm-device-tun-glue.h \
nm-device-veth-glue.h \
nm-device-vlan-glue.h \

View file

@ -0,0 +1,352 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* Copyright (C) 2013 Jiri Pirko <jiri@resnulli.us>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <glib.h>
#include <glib/gi18n.h>
#include <netinet/ether.h>
#include "nm-device-team.h"
#include "nm-logging.h"
#include "nm-utils.h"
#include "NetworkManagerUtils.h"
#include "nm-device-private.h"
#include "nm-platform.h"
#include "nm-dbus-glib-types.h"
#include "nm-dbus-manager.h"
#include "nm-enum-types.h"
#include "nm-device-team-glue.h"
G_DEFINE_TYPE (NMDeviceTeam, nm_device_team, NM_TYPE_DEVICE)
#define NM_DEVICE_TEAM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_TEAM, NMDeviceTeamPrivate))
#define NM_TEAM_ERROR (nm_team_error_quark ())
typedef struct {
int dummy;
} NMDeviceTeamPrivate;
enum {
PROP_0,
PROP_SLAVES,
LAST_PROP
};
/******************************************************************/
static GQuark
nm_team_error_quark (void)
{
static GQuark quark = 0;
if (!quark)
quark = g_quark_from_static_string ("nm-team-error");
return quark;
}
/******************************************************************/
static guint32
get_generic_capabilities (NMDevice *dev)
{
return NM_DEVICE_CAP_CARRIER_DETECT;
}
static gboolean
is_available (NMDevice *dev)
{
if (NM_DEVICE_GET_CLASS (dev)->is_up)
return NM_DEVICE_GET_CLASS (dev)->is_up (dev);
return FALSE;
}
static gboolean
check_connection_compatible (NMDevice *device,
NMConnection *connection,
GError **error)
{
const char *iface;
NMSettingTeam *s_team;
if (!NM_DEVICE_CLASS (nm_device_team_parent_class)->check_connection_compatible (device, connection, error))
return FALSE;
s_team = nm_connection_get_setting_team (connection);
if (!s_team || !nm_connection_is_type (connection, NM_SETTING_TEAM_SETTING_NAME)) {
g_set_error (error, NM_TEAM_ERROR, NM_TEAM_ERROR_CONNECTION_NOT_TEAM,
"The connection was not a team connection.");
return FALSE;
}
/* Team connections must specify the virtual interface name */
iface = nm_connection_get_virtual_iface_name (connection);
if (!iface || strcmp (nm_device_get_iface (device), iface)) {
g_set_error (error, NM_TEAM_ERROR, NM_TEAM_ERROR_CONNECTION_NOT_TEAM,
"The team connection virtual interface name did not match.");
return FALSE;
}
/* FIXME: match team properties like mode, etc? */
return TRUE;
}
static gboolean
complete_connection (NMDevice *device,
NMConnection *connection,
const char *specific_object,
const GSList *existing_connections,
GError **error)
{
NMSettingTeam *s_team, *tmp;
guint32 i = 0;
char *name;
const GSList *iter;
gboolean found;
nm_utils_complete_generic (connection,
NM_SETTING_TEAM_SETTING_NAME,
existing_connections,
_("Team connection %d"),
NULL,
TRUE);
s_team = nm_connection_get_setting_team (connection);
if (!s_team) {
s_team = (NMSettingTeam *) nm_setting_team_new ();
nm_connection_add_setting (connection, NM_SETTING (s_team));
}
/* Grab the first name that doesn't exist in either our connections
* or a device on the system.
*/
while (i < 500 && !nm_setting_team_get_interface_name (s_team)) {
name = g_strdup_printf ("team%u", i);
/* check interface names */
if (!nm_platform_link_exists (name)) {
/* check existing team connections */
for (iter = existing_connections, found = FALSE; iter; iter = g_slist_next (iter)) {
NMConnection *candidate = iter->data;
tmp = nm_connection_get_setting_team (candidate);
if (tmp && nm_connection_is_type (candidate, NM_SETTING_TEAM_SETTING_NAME)) {
if (g_strcmp0 (nm_setting_team_get_interface_name (tmp), name) == 0) {
found = TRUE;
break;
}
}
}
if (!found)
g_object_set (G_OBJECT (s_team), NM_SETTING_TEAM_INTERFACE_NAME, name, NULL);
}
g_free (name);
i++;
}
return TRUE;
}
static gboolean
match_l2_config (NMDevice *self, NMConnection *connection)
{
/* FIXME */
return TRUE;
}
/******************************************************************/
static NMActStageReturn
act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
{
NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
NMConnection *connection;
NMSettingTeam *s_team;
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
ret = NM_DEVICE_CLASS (nm_device_team_parent_class)->act_stage1_prepare (dev, reason);
if (ret == NM_ACT_STAGE_RETURN_SUCCESS) {
connection = nm_device_get_connection (dev);
g_assert (connection);
s_team = nm_connection_get_setting_team (connection);
g_assert (s_team);
}
return ret;
}
static gboolean
enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection)
{
gboolean success, no_firmware = FALSE;
const char *iface = nm_device_get_ip_iface (device);
const char *slave_iface = nm_device_get_ip_iface (slave);
nm_device_take_down (slave, TRUE);
success = nm_platform_link_enslave (nm_device_get_ip_ifindex (device),
nm_device_get_ip_ifindex (slave));
nm_device_bring_up (slave, TRUE, &no_firmware);
if (success) {
nm_log_info (LOGD_TEAM, "(%s): enslaved team port %s", iface, slave_iface);
g_object_notify (G_OBJECT (device), "slaves");
}
return success;
}
static gboolean
release_slave (NMDevice *device, NMDevice *slave)
{
gboolean success, no_firmware = FALSE;
success = nm_platform_link_release (nm_device_get_ip_ifindex (device),
nm_device_get_ip_ifindex (slave));
nm_log_info (LOGD_TEAM, "(%s): released team port %s (success %d)",
nm_device_get_ip_iface (device),
nm_device_get_ip_iface (slave),
success);
g_object_notify (G_OBJECT (device), "slaves");
/* Kernel team code "closes" the port when releasing it, (which clears
* IFF_UP), so we must bring it back up here to ensure carrier changes and
* other state is noticed by the now-released port.
*/
if (!nm_device_bring_up (slave, TRUE, &no_firmware)) {
nm_log_warn (LOGD_TEAM, "(%s): released team port could not be brought up.",
nm_device_get_iface (slave));
}
return success;
}
/******************************************************************/
NMDevice *
nm_device_team_new (const char *iface)
{
g_return_val_if_fail (iface != NULL, NULL);
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_TEAM,
NM_DEVICE_IFACE, iface,
NM_DEVICE_DRIVER, "team",
NM_DEVICE_TYPE_DESC, "Team",
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_TEAM,
NM_DEVICE_IS_MASTER, TRUE,
NULL);
}
static void
constructed (GObject *object)
{
G_OBJECT_CLASS (nm_device_team_parent_class)->constructed (object);
nm_log_dbg (LOGD_HW | LOGD_TEAM, "(%s): kernel ifindex %d",
nm_device_get_iface (NM_DEVICE (object)),
nm_device_get_ifindex (NM_DEVICE (object)));
}
static void
nm_device_team_init (NMDeviceTeam * self)
{
}
static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
GPtrArray *slaves;
GSList *list, *iter;
switch (prop_id) {
break;
case PROP_SLAVES:
slaves = g_ptr_array_new ();
list = nm_device_master_get_slaves (NM_DEVICE (object));
for (iter = list; iter; iter = iter->next)
g_ptr_array_add (slaves, g_strdup (nm_device_get_path (NM_DEVICE (iter->data))));
g_slist_free (list);
g_value_take_boxed (value, slaves);
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)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
nm_device_team_class_init (NMDeviceTeamClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass);
g_type_class_add_private (object_class, sizeof (NMDeviceTeamPrivate));
/* virtual methods */
object_class->constructed = constructed;
object_class->get_property = get_property;
object_class->set_property = set_property;
parent_class->get_generic_capabilities = get_generic_capabilities;
parent_class->is_available = is_available;
parent_class->check_connection_compatible = check_connection_compatible;
parent_class->complete_connection = complete_connection;
parent_class->match_l2_config = match_l2_config;
parent_class->act_stage1_prepare = act_stage1_prepare;
parent_class->enslave_slave = enslave_slave;
parent_class->release_slave = release_slave;
/* properties */
g_object_class_install_property
(object_class, PROP_SLAVES,
g_param_spec_boxed (NM_DEVICE_TEAM_SLAVES,
"Slaves",
"Slaves",
DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH,
G_PARAM_READABLE));
nm_dbus_manager_register_exported_type (nm_dbus_manager_get (),
G_TYPE_FROM_CLASS (klass),
&dbus_glib_nm_device_team_object_info);
dbus_g_error_domain_register (NM_TEAM_ERROR, NULL, NM_TYPE_TEAM_ERROR);
}

View file

@ -0,0 +1,61 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* Copyright (C) 2013 Jiri Pirko <jiri@resnulli.us>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef NM_DEVICE_TEAM_H
#define NM_DEVICE_TEAM_H
#include <glib-object.h>
#include "nm-device.h"
G_BEGIN_DECLS
#define NM_TYPE_DEVICE_TEAM (nm_device_team_get_type ())
#define NM_DEVICE_TEAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_TEAM, NMDeviceTeam))
#define NM_DEVICE_TEAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_TEAM, NMDeviceTeamClass))
#define NM_IS_DEVICE_TEAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_TEAM))
#define NM_IS_DEVICE_TEAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_TEAM))
#define NM_DEVICE_TEAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_TEAM, NMDeviceTeamClass))
typedef enum {
NM_TEAM_ERROR_CONNECTION_NOT_TEAM = 0, /*< nick=ConnectionNotTeam >*/
NM_TEAM_ERROR_CONNECTION_INVALID, /*< nick=ConnectionInvalid >*/
NM_TEAM_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/
} NMTeamError;
#define NM_DEVICE_TEAM_SLAVES "slaves"
typedef struct {
NMDevice parent;
} NMDeviceTeam;
typedef struct {
NMDeviceClass parent;
} NMDeviceTeamClass;
GType nm_device_team_get_type (void);
NMDevice *nm_device_team_new (const char *iface);
G_END_DECLS
#endif /* NM_DEVICE_TEAM_H */

View file

@ -280,7 +280,7 @@ typedef struct {
/* allow autoconnect feature */
gboolean autoconnect;
/* master interface for bridge/bond slave */
/* master interface for bridge/bond/team slave */
NMDevice * master;
gboolean enslaved;
@ -806,16 +806,18 @@ nm_device_get_priority (NMDevice *dev)
return 4;
case NM_DEVICE_TYPE_BOND:
return 5;
case NM_DEVICE_TYPE_VLAN:
case NM_DEVICE_TYPE_TEAM:
return 6;
case NM_DEVICE_TYPE_MODEM:
case NM_DEVICE_TYPE_VLAN:
return 7;
case NM_DEVICE_TYPE_BT:
case NM_DEVICE_TYPE_MODEM:
return 8;
case NM_DEVICE_TYPE_WIFI:
case NM_DEVICE_TYPE_BT:
return 9;
case NM_DEVICE_TYPE_OLPC_MESH:
case NM_DEVICE_TYPE_WIFI:
return 10;
case NM_DEVICE_TYPE_OLPC_MESH:
return 11;
default:
return 20;
}
@ -901,8 +903,8 @@ free_slave_info (SlaveInfo *info)
* @slave: the slave device to enslave
* @connection: the slave device's connection
*
* If @dev is capable of enslaving other devices (ie it's a bridge, bond, etc)
* then this function enslaves @slave.
* If @dev is capable of enslaving other devices (ie it's a bridge, bond, team,
* etc) then this function enslaves @slave.
*
* Returns: %TRUE on success, %FALSE on failure or if this device cannot enslave
* other devices.
@ -955,8 +957,8 @@ nm_device_enslave_slave (NMDevice *dev, NMDevice *slave, NMConnection *connectio
* @slave: the slave device to release
* @failed: %TRUE if the release was unexpected, ie the master failed
*
* If @dev is capable of enslaving other devices (ie it's a bridge, bond, etc)
* then this function releases the previously enslaved @slave.
* If @dev is capable of enslaving other devices (ie it's a bridge, bond, team,
* etc) then this function releases the previously enslaved @slave.
*
* Returns: %TRUE on success, %FALSE on failure, if this device cannot enslave
* other devices, or if @slave was never enslaved.
@ -1050,9 +1052,9 @@ carrier_changed (NMDevice *device, gboolean carrier)
}
if (nm_device_is_master (device)) {
/* Bridge/bond carrier does not affect its own activation, but
* when carrier comes on, if there are slaves waiting, it will
* restart them.
/* Bridge/bond/team carrier does not affect its own activation,
* but when carrier comes on, if there are slaves waiting,
* it will restart them.
*/
if (!carrier)
return;
@ -1064,8 +1066,9 @@ carrier_changed (NMDevice *device, gboolean carrier)
return;
} else if (nm_device_get_enslaved (device) && !carrier) {
/* Slaves don't deactivate when they lose carrier; for bonds
* in particular that would be actively counterproductive.
/* Slaves don't deactivate when they lose carrier; for
* bonds/teams in particular that would be actively
* counterproductive.
*/
return;
}
@ -1231,7 +1234,7 @@ slave_state_changed (NMDevice *slave,
if (release) {
nm_device_release_one_slave (self, slave, FALSE);
/* Bridge/bond interfaces are left up until manually deactivated */
/* Bridge/bond/team interfaces are left up until manually deactivated */
if (priv->slaves == NULL && priv->state == NM_DEVICE_STATE_ACTIVATED) {
nm_log_dbg (LOGD_DEVICE, "(%s): last slave removed; remaining activated",
nm_device_get_iface (self));
@ -1244,8 +1247,8 @@ slave_state_changed (NMDevice *slave,
* @dev: the master device
* @slave: the slave device to enslave
*
* If @dev is capable of enslaving other devices (ie it's a bridge, bond, etc)
* then this function adds @slave to the slave list for later enslavement.
* If @dev is capable of enslaving other devices (ie it's a bridge, bond, team,
* etc) then this function adds @slave to the slave list for later enslavement.
*
* Returns: %TRUE on success, %FALSE on failure
*/
@ -1316,7 +1319,7 @@ nm_device_master_get_slave_by_ifindex (NMDevice *dev, int ifindex)
* nm_device_is_master:
* @dev: the device
*
* Returns: whether @dev can enslave other devices (eg, bridge or bond)
* Returns: whether @dev can enslave other devices (eg, bridge or bond or team)
*/
gboolean
nm_device_is_master (NMDevice *dev)
@ -1405,7 +1408,7 @@ nm_device_slave_notify_enslaved (NMDevice *dev,
* @device: the #NMDevice
*
* Returns: %TRUE if the device is enslaved to a master device (eg bridge or
* bond), %FALSE if not
* bond or team), %FALSE if not
*/
gboolean
nm_device_get_enslaved (NMDevice *device)

View file

@ -49,7 +49,7 @@ nm_log_handler (const gchar *log_domain,
LOGD_SUPPLICANT | LOGD_AGENTS | LOGD_SETTINGS | LOGD_SUSPEND | \
LOGD_CORE | LOGD_DEVICE | LOGD_OLPC_MESH | LOGD_WIMAX | \
LOGD_INFINIBAND | LOGD_FIREWALL | LOGD_ADSL | LOGD_BOND | \
LOGD_VLAN | LOGD_BRIDGE | LOGD_DBUS_PROPS)
LOGD_VLAN | LOGD_BRIDGE | LOGD_DBUS_PROPS | LOGD_TEAM)
#define LOGD_DEFAULT (LOGD_ALL & ~(LOGD_WIFI_SCAN | LOGD_DBUS_PROPS))
@ -103,6 +103,7 @@ static const LogDesc domain_descs[] = {
{ LOGD_VLAN, "VLAN" },
{ LOGD_BRIDGE, "BRIDGE" },
{ LOGD_DBUS_PROPS,"DBUS_PROPS" },
{ LOGD_TEAM, "TEAM" },
{ 0, NULL }
};

View file

@ -59,6 +59,7 @@ enum {
LOGD_VLAN = 0x10000000,
LOGD_BRIDGE = 0x20000000,
LOGD_DBUS_PROPS = 0x40000000,
LOGD_TEAM = 0x80000000,
};
#define LOGD_DHCP (LOGD_DHCP4 | LOGD_DHCP6)

View file

@ -360,8 +360,8 @@ device_state_changed (NMDevice *device, GParamSpec *pspec, NMActRequest *self)
* existing connection made before this instance of NM started
* @device: the device/interface to configure according to @connection
* @master: if the activation depends on another device (ie, bond or bridge
* master to which this device will be enslaved) pass the #NMDevice that this
* activation request be enslaved to
* or team master to which this device will be enslaved) pass the #NMDevice
* that this activation request be enslaved to
*
* Begins activation of @device using the given @connection and other details.
*

View file

@ -48,6 +48,7 @@
#include "nm-device-modem.h"
#include "nm-device-infiniband.h"
#include "nm-device-bond.h"
#include "nm-device-team.h"
#include "nm-device-bridge.h"
#include "nm-device-vlan.h"
#include "nm-device-adsl.h"
@ -1102,6 +1103,9 @@ get_virtual_iface_name (NMManager *self,
if (nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME))
return g_strdup (nm_connection_get_virtual_iface_name (connection));
if (nm_connection_is_type (connection, NM_SETTING_TEAM_SETTING_NAME))
return g_strdup (nm_connection_get_virtual_iface_name (connection));
if (nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME))
return g_strdup (nm_connection_get_virtual_iface_name (connection));
@ -1172,6 +1176,7 @@ static gboolean
connection_needs_virtual_device (NMConnection *connection)
{
if ( nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME)
|| nm_connection_is_type (connection, NM_SETTING_TEAM_SETTING_NAME)
|| nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME)
|| nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME))
return TRUE;
@ -1328,6 +1333,14 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
}
device = nm_device_bond_new (iface);
} else if (nm_connection_is_type (connection, NM_SETTING_TEAM_SETTING_NAME)) {
if (!nm_platform_team_add (iface)) {
nm_log_warn (LOGD_DEVICE, "(%s): failed to add team master interface for '%s'",
iface, nm_connection_get_id (connection));
goto out;
}
device = nm_device_team_new (iface);
} else if (nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME)) {
gboolean result;
@ -2305,6 +2318,9 @@ platform_link_added_cb (NMPlatform *platform,
case NM_LINK_TYPE_BOND:
device = nm_device_bond_new (link->name);
break;
case NM_LINK_TYPE_TEAM:
device = nm_device_team_new (link->name);
break;
case NM_LINK_TYPE_BRIDGE:
/* FIXME: always create device when we handle bridges non-destructively */
if (bridge_created_by_nm (self, link->name))
@ -2700,7 +2716,9 @@ ensure_master_active_connection (NMManager *self,
for (iter = connections; iter; iter = g_slist_next (iter)) {
NMConnection *candidate = NM_CONNECTION (iter->data);
/* Ensure eg bond slave and the candidate master is a bond master */
/* Ensure eg bond/team slave and the candidate master is a
* bond/team master
*/
if (!is_compatible_with_slave (candidate, connection))
continue;
@ -2915,10 +2933,11 @@ nm_manager_activate_connection (NMManager *manager,
}
}
} else {
/* Virtual connections (VLAN, bond, etc) may not specify a device
* path because the device may not be created yet, or it be given
* by the connection's properties instead. Find the device the
* connection refers to, or create it if needed.
/* Virtual connections (VLAN, bond, team, etc) may not specify
* a device path because the device may not be created yet,
* or it be given by the connection's properties instead.
* Find the device the connection refers to, or create it
* if needed.
*/
if (!connection_needs_virtual_device (connection)) {
g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
@ -2996,7 +3015,9 @@ nm_manager_activate_connection (NMManager *manager,
nm_device_get_ip_iface (master_device));
}
/* Ensure eg bond slave and the candidate master is a bond master */
/* Ensure eg bond/team slave and the candidate master is
* a bond/team master
*/
if (master_connection && !is_compatible_with_slave (master_connection, connection)) {
g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED,
"The master connection was not compatible");