2012-02-15 17:31:37 -06:00
|
|
|
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
|
|
|
|
/* NetworkManager -- Network link manager
|
|
|
|
|
*
|
|
|
|
|
* 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.
|
|
|
|
|
*
|
|
|
|
|
* Copyright 2011 - 2012 Red Hat, Inc.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
|
|
#include <glib.h>
|
|
|
|
|
#include <glib/gi18n.h>
|
|
|
|
|
|
2013-10-01 18:27:25 +02:00
|
|
|
#include <errno.h>
|
|
|
|
|
#include <stdlib.h>
|
2012-02-15 17:31:37 -06:00
|
|
|
|
2013-08-28 10:38:46 +02:00
|
|
|
#include "gsystem-local-alloc.h"
|
2012-02-15 17:31:37 -06:00
|
|
|
#include "nm-device-bond.h"
|
|
|
|
|
#include "nm-logging.h"
|
|
|
|
|
#include "nm-utils.h"
|
|
|
|
|
#include "NetworkManagerUtils.h"
|
|
|
|
|
#include "nm-device-private.h"
|
2013-01-21 15:12:24 +01:00
|
|
|
#include "nm-platform.h"
|
2012-10-17 16:10:03 -04:00
|
|
|
#include "nm-dbus-glib-types.h"
|
2013-05-07 12:18:41 -04:00
|
|
|
#include "nm-dbus-manager.h"
|
2012-02-15 17:31:37 -06:00
|
|
|
#include "nm-enum-types.h"
|
|
|
|
|
|
|
|
|
|
#include "nm-device-bond-glue.h"
|
|
|
|
|
|
2014-08-02 15:14:26 +02:00
|
|
|
#include "nm-device-logging.h"
|
|
|
|
|
_LOG_DECLARE_SELF(NMDeviceBond);
|
2012-02-15 17:31:37 -06:00
|
|
|
|
2013-05-07 16:18:19 -04:00
|
|
|
G_DEFINE_TYPE (NMDeviceBond, nm_device_bond, NM_TYPE_DEVICE)
|
2012-02-15 17:31:37 -06:00
|
|
|
|
|
|
|
|
#define NM_DEVICE_BOND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_BOND, NMDeviceBondPrivate))
|
|
|
|
|
|
|
|
|
|
#define NM_BOND_ERROR (nm_bond_error_quark ())
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
2013-05-01 09:28:16 -04:00
|
|
|
int dummy;
|
2012-02-15 17:31:37 -06:00
|
|
|
} NMDeviceBondPrivate;
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
PROP_0,
|
2012-10-17 16:10:03 -04:00
|
|
|
PROP_SLAVES,
|
2012-02-15 17:31:37 -06:00
|
|
|
|
|
|
|
|
LAST_PROP
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
|
|
|
|
|
|
|
|
static GQuark
|
|
|
|
|
nm_bond_error_quark (void)
|
|
|
|
|
{
|
|
|
|
|
static GQuark quark = 0;
|
|
|
|
|
if (!quark)
|
|
|
|
|
quark = g_quark_from_static_string ("nm-bond-error");
|
|
|
|
|
return quark;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
|
|
|
|
|
|
|
|
static guint32
|
2012-09-27 12:12:15 -04:00
|
|
|
get_generic_capabilities (NMDevice *dev)
|
2012-02-15 17:31:37 -06:00
|
|
|
{
|
2013-05-17 10:58:38 -05:00
|
|
|
return NM_DEVICE_CAP_CARRIER_DETECT;
|
2012-02-15 17:31:37 -06:00
|
|
|
}
|
|
|
|
|
|
2013-01-21 18:16:32 -06:00
|
|
|
static gboolean
|
2013-03-19 09:17:41 -04:00
|
|
|
is_available (NMDevice *dev)
|
2013-01-21 18:16:32 -06:00
|
|
|
{
|
2013-06-13 15:13:58 -05:00
|
|
|
if (NM_DEVICE_GET_CLASS (dev)->is_up)
|
|
|
|
|
return NM_DEVICE_GET_CLASS (dev)->is_up (dev);
|
2013-01-21 18:16:32 -06:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-06 17:44:18 -06:00
|
|
|
static gboolean
|
|
|
|
|
check_connection_available (NMDevice *device,
|
|
|
|
|
NMConnection *connection,
|
|
|
|
|
const char *specific_object)
|
|
|
|
|
{
|
|
|
|
|
/* Connections are always available because the carrier state is determined
|
|
|
|
|
* by the slave carrier states, not the bonds's state.
|
|
|
|
|
*/
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-15 17:31:37 -06:00
|
|
|
static gboolean
|
2014-05-30 13:44:53 -05:00
|
|
|
check_connection_compatible (NMDevice *device, NMConnection *connection)
|
2012-02-15 17:31:37 -06:00
|
|
|
{
|
|
|
|
|
const char *iface;
|
|
|
|
|
NMSettingBond *s_bond;
|
|
|
|
|
|
2014-05-30 13:44:53 -05:00
|
|
|
if (!NM_DEVICE_CLASS (nm_device_bond_parent_class)->check_connection_compatible (device, connection))
|
2013-03-07 07:44:36 -05:00
|
|
|
return FALSE;
|
|
|
|
|
|
2012-02-15 17:31:37 -06:00
|
|
|
s_bond = nm_connection_get_setting_bond (connection);
|
2014-05-30 13:44:53 -05:00
|
|
|
if (!s_bond || !nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME))
|
2012-02-15 17:31:37 -06:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Bond connections must specify the virtual interface name */
|
|
|
|
|
iface = nm_connection_get_virtual_iface_name (connection);
|
2014-05-30 13:44:53 -05:00
|
|
|
if (!iface || strcmp (nm_device_get_iface (device), iface))
|
2012-02-15 17:31:37 -06:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* FIXME: match bond properties like mode, etc? */
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
2012-09-27 12:12:15 -04:00
|
|
|
complete_connection (NMDevice *device,
|
|
|
|
|
NMConnection *connection,
|
|
|
|
|
const char *specific_object,
|
|
|
|
|
const GSList *existing_connections,
|
|
|
|
|
GError **error)
|
2012-02-15 17:31:37 -06:00
|
|
|
{
|
|
|
|
|
NMSettingBond *s_bond, *tmp;
|
|
|
|
|
guint32 i = 0;
|
|
|
|
|
char *name;
|
|
|
|
|
const GSList *iter;
|
|
|
|
|
gboolean found;
|
|
|
|
|
|
|
|
|
|
nm_utils_complete_generic (connection,
|
|
|
|
|
NM_SETTING_BOND_SETTING_NAME,
|
|
|
|
|
existing_connections,
|
|
|
|
|
_("Bond connection %d"),
|
|
|
|
|
NULL,
|
|
|
|
|
TRUE);
|
|
|
|
|
|
|
|
|
|
s_bond = nm_connection_get_setting_bond (connection);
|
|
|
|
|
if (!s_bond) {
|
|
|
|
|
s_bond = (NMSettingBond *) nm_setting_bond_new ();
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_bond));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Grab the first name that doesn't exist in either our connections
|
|
|
|
|
* or a device on the system.
|
|
|
|
|
*/
|
|
|
|
|
while (i < 500 && !nm_setting_bond_get_interface_name (s_bond)) {
|
|
|
|
|
name = g_strdup_printf ("bond%u", i);
|
|
|
|
|
/* check interface names */
|
2013-01-21 15:12:24 +01:00
|
|
|
if (!nm_platform_link_exists (name)) {
|
2012-02-15 17:31:37 -06:00
|
|
|
/* check existing bond connections */
|
|
|
|
|
for (iter = existing_connections, found = FALSE; iter; iter = g_slist_next (iter)) {
|
|
|
|
|
NMConnection *candidate = iter->data;
|
|
|
|
|
|
|
|
|
|
tmp = nm_connection_get_setting_bond (candidate);
|
|
|
|
|
if (tmp && nm_connection_is_type (candidate, NM_SETTING_BOND_SETTING_NAME)) {
|
|
|
|
|
if (g_strcmp0 (nm_setting_bond_get_interface_name (tmp), name) == 0) {
|
|
|
|
|
found = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
|
g_object_set (G_OBJECT (s_bond), NM_SETTING_BOND_INTERFACE_NAME, name, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_free (name);
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
|
|
|
|
2013-08-28 10:38:46 +02:00
|
|
|
static gboolean
|
2013-10-01 20:15:03 +02:00
|
|
|
set_bond_attr (NMDevice *device, const char *attr, const char *value)
|
2013-08-28 10:38:46 +02:00
|
|
|
{
|
2014-08-02 15:14:26 +02:00
|
|
|
NMDeviceBond *self = NM_DEVICE_BOND (device);
|
2013-10-01 18:27:25 +02:00
|
|
|
gboolean ret;
|
2013-10-01 20:15:03 +02:00
|
|
|
int ifindex = nm_device_get_ifindex (device);
|
2013-10-01 18:27:25 +02:00
|
|
|
|
2013-10-01 20:15:03 +02:00
|
|
|
ret = nm_platform_master_set_option (ifindex, attr, value);
|
2014-08-02 15:14:26 +02:00
|
|
|
if (!ret)
|
|
|
|
|
_LOGW (LOGD_HW, "failed to set bonding attribute '%s' to '%s'", attr, value);
|
2013-10-01 18:27:25 +02:00
|
|
|
return ret;
|
2013-08-28 10:38:46 +02:00
|
|
|
}
|
|
|
|
|
|
2013-08-28 11:47:44 +02:00
|
|
|
/* Ignore certain bond options if they are zero (off/disabled) */
|
|
|
|
|
static gboolean
|
|
|
|
|
ignore_if_zero (const char *option, const char *value)
|
|
|
|
|
{
|
|
|
|
|
if (strcmp (option, "arp_interval") &&
|
|
|
|
|
strcmp (option, "miimon") &&
|
|
|
|
|
strcmp (option, "downdelay") &&
|
|
|
|
|
strcmp (option, "updelay"))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
return g_strcmp0 (value, "0") == 0 ? TRUE : FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
update_connection (NMDevice *device, NMConnection *connection)
|
|
|
|
|
{
|
|
|
|
|
NMSettingBond *s_bond = nm_connection_get_setting_bond (connection);
|
|
|
|
|
const char *ifname = nm_device_get_iface (device);
|
|
|
|
|
int ifindex = nm_device_get_ifindex (device);
|
|
|
|
|
const char **options;
|
|
|
|
|
|
|
|
|
|
if (!s_bond) {
|
|
|
|
|
s_bond = (NMSettingBond *) nm_setting_bond_new ();
|
|
|
|
|
nm_connection_add_setting (connection, (NMSetting *) s_bond);
|
|
|
|
|
g_object_set (s_bond, NM_SETTING_BOND_INTERFACE_NAME, ifname, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read bond options from sysfs and update the Bond setting to match */
|
|
|
|
|
options = nm_setting_bond_get_valid_options (s_bond);
|
|
|
|
|
while (options && *options) {
|
|
|
|
|
gs_free char *value = nm_platform_master_get_option (ifindex, *options);
|
|
|
|
|
const char *defvalue = nm_setting_bond_get_option_default (s_bond, *options);
|
|
|
|
|
|
|
|
|
|
if (value && !ignore_if_zero (*options, value) && (g_strcmp0 (value, defvalue) != 0)) {
|
|
|
|
|
/* Replace " " with "," for arp_ip_targets from the kernel */
|
|
|
|
|
if (strcmp (*options, "arp_ip_target") == 0) {
|
|
|
|
|
char *p = value;
|
|
|
|
|
|
|
|
|
|
while (p && *p) {
|
|
|
|
|
if (*p == ' ')
|
|
|
|
|
*p = ',';
|
|
|
|
|
p++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nm_setting_bond_add_option (s_bond, *options, value);
|
|
|
|
|
}
|
|
|
|
|
options++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-18 20:17:57 +02:00
|
|
|
static gboolean
|
|
|
|
|
master_update_slave_connection (NMDevice *self,
|
|
|
|
|
NMDevice *slave,
|
|
|
|
|
NMConnection *connection,
|
|
|
|
|
GError **error)
|
|
|
|
|
{
|
|
|
|
|
g_object_set (nm_connection_get_setting_connection (connection),
|
|
|
|
|
NM_SETTING_CONNECTION_MASTER, nm_device_get_iface (self),
|
|
|
|
|
NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BOND_SETTING_NAME,
|
|
|
|
|
NULL);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-05 16:41:51 +02:00
|
|
|
static void
|
2013-10-01 20:15:03 +02:00
|
|
|
set_arp_targets (NMDevice *device,
|
2013-10-01 18:27:25 +02:00
|
|
|
const char *value,
|
|
|
|
|
const char *delim,
|
|
|
|
|
const char *prefix)
|
2013-07-05 16:41:51 +02:00
|
|
|
{
|
2013-10-01 18:27:25 +02:00
|
|
|
char **items, **iter, *tmp;
|
|
|
|
|
|
2013-10-01 20:15:03 +02:00
|
|
|
if (!value || !*value)
|
|
|
|
|
return;
|
|
|
|
|
|
2013-10-01 18:27:25 +02:00
|
|
|
items = g_strsplit_set (value, delim, 0);
|
|
|
|
|
for (iter = items; iter && *iter; iter++) {
|
|
|
|
|
if (*iter[0]) {
|
|
|
|
|
tmp = g_strdup_printf ("%s%s", prefix, *iter);
|
2013-10-01 20:15:03 +02:00
|
|
|
set_bond_attr (device, "arp_ip_target", tmp);
|
2013-10-01 18:27:25 +02:00
|
|
|
g_free (tmp);
|
|
|
|
|
}
|
2013-07-05 16:41:51 +02:00
|
|
|
}
|
2013-10-01 18:27:25 +02:00
|
|
|
g_strfreev (items);
|
2013-07-05 16:41:51 +02:00
|
|
|
}
|
|
|
|
|
|
2013-10-01 18:27:25 +02:00
|
|
|
static void
|
2013-10-01 20:15:03 +02:00
|
|
|
set_simple_option (NMDevice *device,
|
2013-10-01 18:27:25 +02:00
|
|
|
const char *attr,
|
|
|
|
|
NMSettingBond *s_bond,
|
|
|
|
|
const char *opt)
|
2013-07-05 16:41:51 +02:00
|
|
|
{
|
2013-10-01 20:15:03 +02:00
|
|
|
const char *value;
|
2013-10-01 18:27:25 +02:00
|
|
|
|
|
|
|
|
value = nm_setting_bond_get_option_by_name (s_bond, opt);
|
2013-10-01 20:15:03 +02:00
|
|
|
if (!value)
|
|
|
|
|
value = nm_setting_bond_get_option_default (s_bond, opt);
|
|
|
|
|
set_bond_attr (device, attr, value);
|
2013-10-01 18:27:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NMActStageReturn
|
|
|
|
|
apply_bonding_config (NMDevice *device)
|
|
|
|
|
{
|
|
|
|
|
NMConnection *connection;
|
|
|
|
|
NMSettingBond *s_bond;
|
2013-10-01 20:15:03 +02:00
|
|
|
int ifindex = nm_device_get_ifindex (device);
|
2013-10-01 18:27:25 +02:00
|
|
|
const char *mode, *value;
|
2013-10-01 20:15:03 +02:00
|
|
|
char *contents;
|
2013-10-01 18:27:25 +02:00
|
|
|
gboolean set_arp_interval = TRUE;
|
|
|
|
|
|
|
|
|
|
/* Option restrictions:
|
|
|
|
|
*
|
|
|
|
|
* arp_interval conflicts miimon > 0
|
|
|
|
|
* arp_interval conflicts [ alb, tlb ]
|
|
|
|
|
* arp_validate needs [ active-backup ]
|
|
|
|
|
* downdelay needs miimon
|
|
|
|
|
* updelay needs miimon
|
|
|
|
|
* primary needs [ active-backup, tlb, alb ]
|
|
|
|
|
*
|
|
|
|
|
* clearing miimon requires that arp_interval be 0, but clearing
|
|
|
|
|
* arp_interval doesn't require miimon to be 0
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
connection = nm_device_get_connection (device);
|
|
|
|
|
g_assert (connection);
|
|
|
|
|
s_bond = nm_connection_get_setting_bond (connection);
|
|
|
|
|
g_assert (s_bond);
|
|
|
|
|
|
|
|
|
|
mode = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_MODE);
|
|
|
|
|
if (mode == NULL)
|
|
|
|
|
mode = "balance-rr";
|
|
|
|
|
|
|
|
|
|
value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_MIIMON);
|
|
|
|
|
if (value && atoi (value)) {
|
|
|
|
|
/* clear arp interval */
|
2013-10-01 20:15:03 +02:00
|
|
|
set_bond_attr (device, "arp_interval", "0");
|
2013-10-01 18:27:25 +02:00
|
|
|
set_arp_interval = FALSE;
|
|
|
|
|
|
2013-10-01 20:15:03 +02:00
|
|
|
set_bond_attr (device, "miimon", value);
|
|
|
|
|
set_simple_option (device, "updelay", s_bond, NM_SETTING_BOND_OPTION_UPDELAY);
|
|
|
|
|
set_simple_option (device, "downdelay", s_bond, NM_SETTING_BOND_OPTION_DOWNDELAY);
|
2013-10-01 18:27:25 +02:00
|
|
|
} else if (!value) {
|
|
|
|
|
/* If not given, and arp_interval is not given, default to 100 */
|
|
|
|
|
long int val_int;
|
|
|
|
|
char *end;
|
|
|
|
|
|
|
|
|
|
value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_ARP_INTERVAL);
|
|
|
|
|
errno = 0;
|
|
|
|
|
val_int = strtol (value ? value : "0", &end, 10);
|
|
|
|
|
if (!value || (val_int == 0 && errno == 0 && *end == '\0'))
|
2013-10-01 20:15:03 +02:00
|
|
|
set_bond_attr (device, "miimon", "100");
|
2013-07-05 16:41:51 +02:00
|
|
|
}
|
|
|
|
|
|
2013-10-01 18:27:25 +02:00
|
|
|
/* The stuff after 'mode' requires the given mode or doesn't care */
|
2013-10-01 20:15:03 +02:00
|
|
|
set_bond_attr (device, "mode", mode);
|
2013-07-05 16:41:51 +02:00
|
|
|
|
2013-10-01 18:27:25 +02:00
|
|
|
/* arp_interval not compatible with ALB, TLB */
|
|
|
|
|
if (g_strcmp0 (mode, "balance-alb") == 0 || g_strcmp0 (mode, "balance-tlb") == 0)
|
|
|
|
|
set_arp_interval = FALSE;
|
2013-08-28 10:38:46 +02:00
|
|
|
|
2013-10-01 18:27:25 +02:00
|
|
|
if (set_arp_interval) {
|
2013-10-01 20:15:03 +02:00
|
|
|
set_simple_option (device, "arp_interval", s_bond, NM_SETTING_BOND_OPTION_ARP_INTERVAL);
|
2013-10-01 18:27:25 +02:00
|
|
|
|
|
|
|
|
/* Just let miimon get cleared automatically; even setting miimon to
|
|
|
|
|
* 0 (disabled) clears arp_interval.
|
|
|
|
|
*/
|
2013-07-05 16:41:51 +02:00
|
|
|
}
|
|
|
|
|
|
2013-10-01 18:27:25 +02:00
|
|
|
value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_ARP_VALIDATE);
|
|
|
|
|
/* arp_validate > 0 only valid in active-backup mode */
|
|
|
|
|
if ( value
|
|
|
|
|
&& g_strcmp0 (value, "0") != 0
|
|
|
|
|
&& g_strcmp0 (value, "none") != 0
|
|
|
|
|
&& g_strcmp0 (mode, "active-backup") == 0)
|
2013-10-01 20:15:03 +02:00
|
|
|
set_bond_attr (device, "arp_validate", value);
|
2013-10-01 18:27:25 +02:00
|
|
|
else
|
2013-10-01 20:15:03 +02:00
|
|
|
set_bond_attr (device, "arp_validate", "0");
|
2013-10-01 18:27:25 +02:00
|
|
|
|
|
|
|
|
if ( g_strcmp0 (mode, "active-backup") == 0
|
|
|
|
|
|| g_strcmp0 (mode, "balance-alb") == 0
|
|
|
|
|
|| g_strcmp0 (mode, "balance-tlb") == 0) {
|
|
|
|
|
value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_PRIMARY);
|
2013-10-01 20:15:03 +02:00
|
|
|
set_bond_attr (device, "primary", value ? value : "");
|
2013-10-01 18:27:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Clear ARP targets */
|
2013-10-01 20:15:03 +02:00
|
|
|
contents = nm_platform_master_get_option (ifindex, "arp_ip_target");
|
|
|
|
|
set_arp_targets (device, contents, " \n", "-");
|
|
|
|
|
g_free (contents);
|
2013-10-01 18:27:25 +02:00
|
|
|
|
|
|
|
|
/* Add new ARP targets */
|
|
|
|
|
value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET);
|
2013-10-01 20:15:03 +02:00
|
|
|
set_arp_targets (device, value, ",", "+");
|
|
|
|
|
|
|
|
|
|
set_simple_option (device, "primary_reselect", s_bond, NM_SETTING_BOND_OPTION_PRIMARY_RESELECT);
|
|
|
|
|
set_simple_option (device, "fail_over_mac", s_bond, NM_SETTING_BOND_OPTION_FAIL_OVER_MAC);
|
|
|
|
|
set_simple_option (device, "use_carrier", s_bond, NM_SETTING_BOND_OPTION_USE_CARRIER);
|
|
|
|
|
set_simple_option (device, "ad_select", s_bond, NM_SETTING_BOND_OPTION_AD_SELECT);
|
|
|
|
|
set_simple_option (device, "xmit_hash_policy", s_bond, NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY);
|
|
|
|
|
set_simple_option (device, "resend_igmp", s_bond, NM_SETTING_BOND_OPTION_RESEND_IGMP);
|
2013-10-01 18:27:25 +02:00
|
|
|
|
|
|
|
|
return NM_ACT_STAGE_RETURN_SUCCESS;
|
2013-07-05 16:41:51 +02:00
|
|
|
}
|
|
|
|
|
|
2013-10-01 18:27:25 +02:00
|
|
|
|
2012-02-29 12:39:57 -06:00
|
|
|
static NMActStageReturn
|
2012-09-27 12:12:15 -04:00
|
|
|
act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
|
2012-02-29 12:39:57 -06:00
|
|
|
{
|
|
|
|
|
NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
|
|
|
|
|
gboolean no_firmware = FALSE;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
|
|
|
|
|
|
|
|
|
|
ret = NM_DEVICE_CLASS (nm_device_bond_parent_class)->act_stage1_prepare (dev, reason);
|
2013-10-01 18:27:25 +02:00
|
|
|
if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
|
|
|
|
|
return ret;
|
2012-02-29 12:39:57 -06:00
|
|
|
|
2013-10-01 18:27:25 +02:00
|
|
|
/* Interface must be down to set bond options */
|
|
|
|
|
nm_device_take_down (dev, TRUE);
|
|
|
|
|
ret = apply_bonding_config (dev);
|
|
|
|
|
nm_device_bring_up (dev, TRUE, &no_firmware);
|
2012-02-29 12:39:57 -06:00
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-28 18:35:30 -06:00
|
|
|
static gboolean
|
2013-11-07 01:08:02 -06:00
|
|
|
enslave_slave (NMDevice *device,
|
|
|
|
|
NMDevice *slave,
|
|
|
|
|
NMConnection *connection,
|
|
|
|
|
gboolean configure)
|
2012-02-28 18:35:30 -06:00
|
|
|
{
|
2014-08-02 15:14:26 +02:00
|
|
|
NMDeviceBond *self = NM_DEVICE_BOND (device);
|
2013-11-07 01:08:02 -06:00
|
|
|
gboolean success = TRUE, no_firmware = FALSE;
|
2012-11-14 14:05:30 -06:00
|
|
|
const char *slave_iface = nm_device_get_ip_iface (slave);
|
2012-02-28 18:35:30 -06:00
|
|
|
|
2013-10-11 14:59:26 -04:00
|
|
|
nm_device_master_check_slave_physical_port (device, slave, LOGD_BOND);
|
|
|
|
|
|
2013-11-07 01:08:02 -06:00
|
|
|
if (configure) {
|
|
|
|
|
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);
|
2012-11-14 14:05:30 -06:00
|
|
|
|
2014-02-25 16:44:01 -05:00
|
|
|
if (!success)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2014-08-02 15:14:26 +02:00
|
|
|
_LOGI (LOGD_BOND, "enslaved bond slave %s", slave_iface);
|
2014-02-25 16:44:01 -05:00
|
|
|
} else
|
2014-08-02 15:14:26 +02:00
|
|
|
_LOGI (LOGD_BOND, "bond slave %s was enslaved", slave_iface);
|
2012-02-28 18:35:30 -06:00
|
|
|
|
2014-02-25 16:44:01 -05:00
|
|
|
g_object_notify (G_OBJECT (device), NM_DEVICE_BOND_SLAVES);
|
|
|
|
|
return TRUE;
|
2012-02-28 18:35:30 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
2014-02-25 16:44:01 -05:00
|
|
|
release_slave (NMDevice *device,
|
|
|
|
|
NMDevice *slave,
|
|
|
|
|
gboolean configure)
|
2012-02-28 18:35:30 -06:00
|
|
|
{
|
2014-08-02 15:14:26 +02:00
|
|
|
NMDeviceBond *self = NM_DEVICE_BOND (device);
|
2014-02-25 16:44:01 -05:00
|
|
|
gboolean success = TRUE, no_firmware = FALSE;
|
2012-02-28 18:35:30 -06:00
|
|
|
|
2014-02-25 16:44:01 -05:00
|
|
|
if (configure) {
|
|
|
|
|
success = nm_platform_link_release (nm_device_get_ip_ifindex (device),
|
|
|
|
|
nm_device_get_ip_ifindex (slave));
|
2013-01-21 15:12:24 +01:00
|
|
|
|
2014-02-25 16:44:01 -05:00
|
|
|
if (success) {
|
2014-08-02 15:14:26 +02:00
|
|
|
_LOGI (LOGD_BOND, "released bond slave %s",
|
|
|
|
|
nm_device_get_ip_iface (slave));
|
2014-02-25 16:44:01 -05:00
|
|
|
} else {
|
2014-08-02 15:14:26 +02:00
|
|
|
_LOGW (LOGD_BOND, "failed to release bond slave %s",
|
|
|
|
|
nm_device_get_ip_iface (slave));
|
2014-02-25 16:44:01 -05:00
|
|
|
}
|
2014-02-25 16:41:33 -05:00
|
|
|
} else {
|
2014-08-02 15:14:26 +02:00
|
|
|
_LOGI (LOGD_BOND, "bond slave %s was released",
|
2014-02-25 16:41:33 -05:00
|
|
|
nm_device_get_ip_iface (slave));
|
|
|
|
|
}
|
2013-01-21 14:33:40 -06:00
|
|
|
|
2014-02-25 16:44:01 -05:00
|
|
|
if (success)
|
|
|
|
|
g_object_notify (G_OBJECT (device), NM_DEVICE_BOND_SLAVES);
|
|
|
|
|
|
|
|
|
|
if (configure) {
|
|
|
|
|
/* Kernel bonding code "closes" the slave 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 slave.
|
|
|
|
|
*/
|
2014-08-02 15:14:26 +02:00
|
|
|
if (!nm_device_bring_up (slave, TRUE, &no_firmware))
|
|
|
|
|
_LOGW (LOGD_BOND, "released bond slave could not be brought up.");
|
2013-01-21 14:33:40 -06:00
|
|
|
}
|
|
|
|
|
|
2012-02-28 18:35:30 -06:00
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
|
|
|
|
2012-02-15 17:31:37 -06:00
|
|
|
NMDevice *
|
2013-09-03 14:23:16 -04:00
|
|
|
nm_device_bond_new (NMPlatformLink *platform_device)
|
2012-02-15 17:31:37 -06:00
|
|
|
{
|
2013-09-03 14:23:16 -04:00
|
|
|
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);
|
2012-02-15 17:31:37 -06:00
|
|
|
g_return_val_if_fail (iface != NULL, NULL);
|
|
|
|
|
|
2013-09-03 14:23:16 -04:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-15 17:31:37 -06:00
|
|
|
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BOND,
|
|
|
|
|
NM_DEVICE_IFACE, iface,
|
|
|
|
|
NM_DEVICE_DRIVER, "bonding",
|
|
|
|
|
NM_DEVICE_TYPE_DESC, "Bond",
|
|
|
|
|
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BOND,
|
2013-01-24 17:47:59 -06:00
|
|
|
NM_DEVICE_IS_MASTER, TRUE,
|
2012-02-15 17:31:37 -06:00
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
nm_device_bond_init (NMDeviceBond * self)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
get_property (GObject *object, guint prop_id,
|
|
|
|
|
GValue *value, GParamSpec *pspec)
|
|
|
|
|
{
|
2012-10-17 16:10:03 -04:00
|
|
|
GPtrArray *slaves;
|
2012-11-14 14:05:30 -06:00
|
|
|
GSList *list, *iter;
|
2012-02-15 17:31:37 -06:00
|
|
|
|
|
|
|
|
switch (prop_id) {
|
|
|
|
|
break;
|
2012-10-17 16:10:03 -04:00
|
|
|
case PROP_SLAVES:
|
|
|
|
|
slaves = g_ptr_array_new ();
|
2012-11-14 14:05:30 -06:00
|
|
|
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);
|
2012-10-17 16:10:03 -04:00
|
|
|
g_value_take_boxed (value, slaves);
|
|
|
|
|
break;
|
2012-02-15 17:31:37 -06:00
|
|
|
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_bond_class_init (NMDeviceBondClass *klass)
|
|
|
|
|
{
|
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass);
|
|
|
|
|
|
|
|
|
|
g_type_class_add_private (object_class, sizeof (NMDeviceBondPrivate));
|
|
|
|
|
|
2013-08-28 11:47:44 +02:00
|
|
|
parent_class->connection_type = NM_SETTING_BOND_SETTING_NAME;
|
|
|
|
|
|
2012-02-15 17:31:37 -06:00
|
|
|
/* virtual methods */
|
|
|
|
|
object_class->get_property = get_property;
|
|
|
|
|
object_class->set_property = set_property;
|
|
|
|
|
|
2012-09-27 12:12:15 -04:00
|
|
|
parent_class->get_generic_capabilities = get_generic_capabilities;
|
2013-01-21 18:16:32 -06:00
|
|
|
parent_class->is_available = is_available;
|
2012-09-27 12:12:15 -04:00
|
|
|
parent_class->check_connection_compatible = check_connection_compatible;
|
2013-11-06 17:44:18 -06:00
|
|
|
parent_class->check_connection_available = check_connection_available;
|
2012-09-27 12:12:15 -04:00
|
|
|
parent_class->complete_connection = complete_connection;
|
2012-02-15 17:31:37 -06:00
|
|
|
|
2013-08-28 11:47:44 +02:00
|
|
|
parent_class->update_connection = update_connection;
|
2014-06-18 20:17:57 +02:00
|
|
|
parent_class->master_update_slave_connection = master_update_slave_connection;
|
2012-02-15 17:31:37 -06:00
|
|
|
|
2012-09-27 12:12:15 -04:00
|
|
|
parent_class->act_stage1_prepare = act_stage1_prepare;
|
2012-02-28 18:35:30 -06:00
|
|
|
parent_class->enslave_slave = enslave_slave;
|
|
|
|
|
parent_class->release_slave = release_slave;
|
|
|
|
|
|
2012-02-15 17:31:37 -06:00
|
|
|
/* properties */
|
2012-10-17 16:10:03 -04:00
|
|
|
g_object_class_install_property
|
|
|
|
|
(object_class, PROP_SLAVES,
|
2014-06-09 16:17:37 -04:00
|
|
|
g_param_spec_boxed (NM_DEVICE_BOND_SLAVES, "", "",
|
2012-10-17 16:10:03 -04:00
|
|
|
DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH,
|
2014-06-09 16:17:37 -04:00
|
|
|
G_PARAM_READABLE |
|
|
|
|
|
G_PARAM_STATIC_STRINGS));
|
2012-10-17 16:10:03 -04:00
|
|
|
|
2013-05-07 12:18:41 -04:00
|
|
|
nm_dbus_manager_register_exported_type (nm_dbus_manager_get (),
|
|
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
|
&dbus_glib_nm_device_bond_object_info);
|
2012-02-15 17:31:37 -06:00
|
|
|
|
|
|
|
|
dbus_g_error_domain_register (NM_BOND_ERROR, NULL, NM_TYPE_BOND_ERROR);
|
|
|
|
|
}
|