mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-20 02:20:06 +01:00
Detected by lintian: Example: I: network-manager: typo-in-manual-page "allows to" "allows one to" [usr/share/man/man5/NetworkManager.conf.5.gz:1266]
1100 lines
43 KiB
C
1100 lines
43 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
/*
|
|
* Copyright (C) 2011 - 2018 Red Hat, Inc.
|
|
*/
|
|
|
|
#include "src/core/nm-default-daemon.h"
|
|
|
|
#include "nm-device-bond.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <net/if.h>
|
|
#include <linux/if_ether.h>
|
|
#include <linux/if_link.h>
|
|
|
|
#include "NetworkManagerUtils.h"
|
|
#include "nm-device-private.h"
|
|
#include "libnm-platform/nm-platform.h"
|
|
#include "nm-device-factory.h"
|
|
#include "libnm-core-aux-intern/nm-libnm-core-utils.h"
|
|
#include "libnm-core-intern/nm-core-internal.h"
|
|
#include "nm-manager.h"
|
|
#include "nm-setting-bond-port.h"
|
|
#include "nm-bond-manager.h"
|
|
|
|
#define _NMLOG_DEVICE_TYPE NMDeviceBond
|
|
#include "nm-device-logging.h"
|
|
|
|
/*****************************************************************************/
|
|
|
|
#define OPTIONS_APPLY_SUBSET \
|
|
NM_SETTING_BOND_OPTION_MIIMON, NM_SETTING_BOND_OPTION_UPDELAY, \
|
|
NM_SETTING_BOND_OPTION_DOWNDELAY, NM_SETTING_BOND_OPTION_ARP_INTERVAL, \
|
|
NM_SETTING_BOND_OPTION_ARP_VALIDATE, NM_SETTING_BOND_OPTION_PRIMARY, \
|
|
NM_SETTING_BOND_OPTION_AD_ACTOR_SYSTEM, NM_SETTING_BOND_OPTION_AD_ACTOR_SYS_PRIO, \
|
|
NM_SETTING_BOND_OPTION_AD_SELECT, NM_SETTING_BOND_OPTION_AD_USER_PORT_KEY, \
|
|
NM_SETTING_BOND_OPTION_ALL_SLAVES_ACTIVE, NM_SETTING_BOND_OPTION_ARP_ALL_TARGETS, \
|
|
NM_SETTING_BOND_OPTION_FAIL_OVER_MAC, NM_SETTING_BOND_OPTION_LACP_RATE, \
|
|
NM_SETTING_BOND_OPTION_LP_INTERVAL, NM_SETTING_BOND_OPTION_MIN_LINKS, \
|
|
NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE, NM_SETTING_BOND_OPTION_PRIMARY_RESELECT, \
|
|
NM_SETTING_BOND_OPTION_RESEND_IGMP, NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB, \
|
|
NM_SETTING_BOND_OPTION_USE_CARRIER, NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY, \
|
|
NM_SETTING_BOND_OPTION_NUM_GRAT_ARP, NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY, \
|
|
NM_SETTING_BOND_OPTION_ARP_MISSED_MAX, NM_SETTING_BOND_OPTION_LACP_ACTIVE
|
|
|
|
#define OPTIONS_REAPPLY_SUBSET \
|
|
NM_SETTING_BOND_OPTION_MIIMON, NM_SETTING_BOND_OPTION_UPDELAY, \
|
|
NM_SETTING_BOND_OPTION_DOWNDELAY, NM_SETTING_BOND_OPTION_ARP_INTERVAL, \
|
|
NM_SETTING_BOND_OPTION_ARP_VALIDATE, NM_SETTING_BOND_OPTION_PRIMARY, \
|
|
NM_SETTING_BOND_OPTION_AD_ACTOR_SYSTEM, NM_SETTING_BOND_OPTION_AD_ACTOR_SYS_PRIO, \
|
|
NM_SETTING_BOND_OPTION_ALL_SLAVES_ACTIVE, NM_SETTING_BOND_OPTION_ARP_ALL_TARGETS, \
|
|
NM_SETTING_BOND_OPTION_LP_INTERVAL, NM_SETTING_BOND_OPTION_MIN_LINKS, \
|
|
NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE, NM_SETTING_BOND_OPTION_PRIMARY_RESELECT, \
|
|
NM_SETTING_BOND_OPTION_RESEND_IGMP, NM_SETTING_BOND_OPTION_USE_CARRIER, \
|
|
NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP, \
|
|
NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY, NM_SETTING_BOND_OPTION_ARP_MISSED_MAX, \
|
|
NM_SETTING_BOND_OPTION_LACP_ACTIVE
|
|
|
|
#define OPTIONS_REAPPLY_FULL \
|
|
OPTIONS_REAPPLY_SUBSET, NM_SETTING_BOND_OPTION_ACTIVE_SLAVE, \
|
|
NM_SETTING_BOND_OPTION_ARP_IP_TARGET, NM_SETTING_BOND_OPTION_NS_IP6_TARGET
|
|
|
|
/*****************************************************************************/
|
|
|
|
struct _NMDeviceBond {
|
|
NMDevice parent;
|
|
NMBondManager *bond_manager;
|
|
};
|
|
|
|
struct _NMDeviceBondClass {
|
|
NMDeviceClass parent;
|
|
};
|
|
|
|
G_DEFINE_TYPE(NMDeviceBond, nm_device_bond, NM_TYPE_DEVICE)
|
|
|
|
/*****************************************************************************/
|
|
|
|
static NMDeviceCapabilities
|
|
get_generic_capabilities(NMDevice *dev)
|
|
{
|
|
return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE;
|
|
}
|
|
|
|
static gboolean
|
|
complete_connection(NMDevice *device,
|
|
NMConnection *connection,
|
|
const char *specific_object,
|
|
NMConnection *const *existing_connections,
|
|
GError **error)
|
|
{
|
|
nm_utils_complete_generic(nm_device_get_platform(device),
|
|
connection,
|
|
NM_SETTING_BOND_SETTING_NAME,
|
|
existing_connections,
|
|
NULL,
|
|
_("Bond connection"),
|
|
"bond",
|
|
NULL);
|
|
|
|
_nm_connection_ensure_setting(connection, NM_TYPE_SETTING_BOND);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static gboolean
|
|
_set_bond_attr(NMDevice *device, const char *attr, const char *value)
|
|
{
|
|
NMDeviceBond *self = NM_DEVICE_BOND(device);
|
|
int ifindex = nm_device_get_ifindex(device);
|
|
gboolean ret;
|
|
|
|
nm_assert(attr && attr[0]);
|
|
nm_assert(value);
|
|
|
|
if (nm_streq(value, NM_BOND_AD_ACTOR_SYSTEM_DEFAULT)
|
|
&& nm_streq(attr, NM_SETTING_BOND_OPTION_AD_ACTOR_SYSTEM)) {
|
|
gs_free char *cur_val = NULL;
|
|
|
|
/* kernel does not allow setting ad_actor_system to "00:00:00:00:00:00". We would thus
|
|
* log an EINVAL error. Avoid that... at least, if the value is already "00:00:00:00:00:00". */
|
|
cur_val =
|
|
nm_platform_sysctl_controller_get_option(nm_device_get_platform(device), ifindex, attr);
|
|
if (nm_streq0(cur_val, NM_BOND_AD_ACTOR_SYSTEM_DEFAULT))
|
|
return TRUE;
|
|
|
|
/* OK, the current value is different, and we will proceed setting "00:00:00:00:00:00".
|
|
* That will fail, and we will log a warning. There is nothing else to do. */
|
|
}
|
|
|
|
ret = nm_platform_sysctl_controller_set_option(nm_device_get_platform(device),
|
|
ifindex,
|
|
attr,
|
|
value);
|
|
if (!ret)
|
|
_LOGW(LOGD_PLATFORM, "failed to set bonding attribute '%s' to '%s'", attr, value);
|
|
return ret;
|
|
}
|
|
|
|
#define _set_bond_attr_take(device, attr, value) \
|
|
G_STMT_START \
|
|
{ \
|
|
gs_free char *_tmp = (value); \
|
|
\
|
|
_set_bond_attr(device, NM_SETTING_BOND_OPTION_ARP_IP_TARGET, _tmp); \
|
|
} \
|
|
G_STMT_END
|
|
|
|
#define _set_bond_attr_printf(device, attr, fmt, ...) \
|
|
_set_bond_attr_take((device), (attr), g_strdup_printf(fmt, __VA_ARGS__))
|
|
|
|
static gboolean
|
|
ignore_option(NMSettingBond *s_bond, const char *option, const char *value)
|
|
{
|
|
const char *defvalue;
|
|
|
|
if (nm_streq0(option, NM_SETTING_BOND_OPTION_MIIMON)) {
|
|
/* The default value for miimon, when missing in the setting, is
|
|
* 0 if arp_interval is != 0, and 100 otherwise. So, let's ignore
|
|
* miimon=0 (which means that miimon is disabled) and accept any
|
|
* other value. Adding miimon=100 does not cause any harm.
|
|
*/
|
|
defvalue = "0";
|
|
} else
|
|
defvalue = nm_setting_bond_get_option_default(s_bond, option);
|
|
|
|
return nm_streq0(value, defvalue);
|
|
}
|
|
|
|
static void
|
|
update_connection(NMDevice *device, NMConnection *connection)
|
|
{
|
|
NMDeviceBond *self = NM_DEVICE_BOND(device);
|
|
NMSettingBond *s_bond = _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_BOND);
|
|
int ifindex = nm_device_get_ifindex(device);
|
|
NMBondMode mode = NM_BOND_MODE_UNKNOWN;
|
|
const char **options;
|
|
|
|
/* Read bond options from sysfs and update the Bond setting to match */
|
|
options = nm_setting_bond_get_valid_options(NULL);
|
|
for (; options[0]; options++) {
|
|
const char *option = options[0];
|
|
gs_free char *value = NULL;
|
|
char *p;
|
|
|
|
if (NM_IN_STRSET(option,
|
|
NM_SETTING_BOND_OPTION_ACTIVE_SLAVE,
|
|
NM_SETTING_BOND_OPTION_BALANCE_SLB))
|
|
continue;
|
|
|
|
value = nm_platform_sysctl_controller_get_option(nm_device_get_platform(device),
|
|
ifindex,
|
|
option);
|
|
|
|
if (value && _nm_setting_bond_get_option_type(s_bond, option) == NM_BOND_OPTION_TYPE_BOTH) {
|
|
p = strchr(value, ' ');
|
|
if (p)
|
|
*p = '\0';
|
|
}
|
|
|
|
if (mode == NM_BOND_MODE_UNKNOWN) {
|
|
if (value && nm_streq(option, NM_SETTING_BOND_OPTION_MODE))
|
|
mode = _nm_setting_bond_mode_from_string(value);
|
|
if (mode == NM_BOND_MODE_UNKNOWN)
|
|
continue;
|
|
}
|
|
|
|
if (!_nm_setting_bond_option_supported(option, mode))
|
|
continue;
|
|
|
|
if (value && value[0] && !ignore_option(s_bond, option, value)) {
|
|
/* Replace " " with "," for arp_ip_targets from the kernel */
|
|
if (nm_streq(option, NM_SETTING_BOND_OPTION_ARP_IP_TARGET)) {
|
|
for (p = value; *p; p++) {
|
|
if (*p == ' ')
|
|
*p = ',';
|
|
}
|
|
}
|
|
|
|
if (!_nm_setting_bond_validate_option(option, value, NULL))
|
|
_LOGT(LOGD_BOND, "cannot set invalid bond option '%s' = '%s'", option, value);
|
|
else
|
|
nm_setting_bond_add_option(s_bond, option, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
controller_update_port_connection(NMDevice *self,
|
|
NMDevice *port,
|
|
NMConnection *connection,
|
|
GError **error)
|
|
{
|
|
NMSettingBondPort *s_port;
|
|
int ifindex_port = nm_device_get_ifindex(port);
|
|
NMConnection *applied_connection = nm_device_get_applied_connection(self);
|
|
const NMPlatformLink *pllink;
|
|
|
|
g_return_val_if_fail(ifindex_port > 0, FALSE);
|
|
|
|
s_port = _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_BOND_PORT);
|
|
pllink = nm_platform_link_get(nm_device_get_platform(port), ifindex_port);
|
|
|
|
if (pllink && pllink->port_kind == NM_PORT_KIND_BOND)
|
|
g_object_set(s_port,
|
|
NM_SETTING_BOND_PORT_QUEUE_ID,
|
|
pllink->port_data.bond.queue_id,
|
|
NM_SETTING_BOND_PORT_PRIO,
|
|
pllink->port_data.bond.prio,
|
|
NULL);
|
|
|
|
g_object_set(nm_connection_get_setting_connection(connection),
|
|
NM_SETTING_CONNECTION_CONTROLLER,
|
|
nm_connection_get_uuid(applied_connection),
|
|
NM_SETTING_CONNECTION_PORT_TYPE,
|
|
NM_SETTING_BOND_SETTING_NAME,
|
|
NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
set_arp_targets(NMDevice *device, const char *cur_arp_ip_target, const char *new_arp_ip_target)
|
|
{
|
|
gs_unref_ptrarray GPtrArray *free_list = NULL;
|
|
gs_free const char **cur_strv = NULL;
|
|
gs_free const char **new_strv = NULL;
|
|
gsize cur_len;
|
|
gsize new_len;
|
|
gsize i;
|
|
gsize j;
|
|
|
|
cur_strv =
|
|
nm_strsplit_set_full(cur_arp_ip_target, NM_ASCII_SPACES, NM_STRSPLIT_SET_FLAGS_STRSTRIP);
|
|
new_strv = nm_utils_bond_option_ip_split(new_arp_ip_target);
|
|
|
|
cur_len = NM_PTRARRAY_LEN(cur_strv);
|
|
new_len = NM_PTRARRAY_LEN(new_strv);
|
|
|
|
if (new_len > 0) {
|
|
for (j = 0, i = 0; i < new_len; i++) {
|
|
const char *s;
|
|
in_addr_t a4;
|
|
|
|
s = new_strv[i];
|
|
if (nm_inet_parse_bin(AF_INET, s, NULL, &a4)) {
|
|
char sbuf[INET_ADDRSTRLEN];
|
|
|
|
nm_inet4_ntop(a4, sbuf);
|
|
if (!nm_streq(s, sbuf)) {
|
|
if (!free_list)
|
|
free_list = g_ptr_array_new_with_free_func(g_free);
|
|
s = g_strdup(sbuf);
|
|
g_ptr_array_add(free_list, (gpointer) s);
|
|
}
|
|
}
|
|
|
|
if (!nm_strv_contains(new_strv, i, s))
|
|
new_strv[j++] = s;
|
|
}
|
|
new_strv[j] = NULL;
|
|
new_len = j;
|
|
}
|
|
|
|
if (cur_len == 0 && new_len == 0)
|
|
return;
|
|
|
|
if (nm_strv_equal(cur_strv, new_strv))
|
|
return;
|
|
|
|
for (i = 0; i < cur_len; i++)
|
|
_set_bond_attr_printf(device, NM_SETTING_BOND_OPTION_ARP_IP_TARGET, "-%s", cur_strv[i]);
|
|
for (i = 0; i < new_len; i++)
|
|
_set_bond_attr_printf(device, NM_SETTING_BOND_OPTION_ARP_IP_TARGET, "+%s", new_strv[i]);
|
|
}
|
|
|
|
/*
|
|
* Sets bond attribute stored in the option hashtable or
|
|
* the default value if no value was set.
|
|
*/
|
|
static void
|
|
set_bond_attr_or_default(NMDevice *device, NMSettingBond *s_bond, const char *opt)
|
|
{
|
|
NMDeviceBond *self = NM_DEVICE_BOND(device);
|
|
const char *value;
|
|
|
|
value = nm_setting_bond_get_option_normalized(s_bond, opt);
|
|
if (!value) {
|
|
if (_LOGT_ENABLED(LOGD_BOND) && nm_setting_bond_get_option_by_name(s_bond, opt))
|
|
_LOGT(LOGD_BOND, "bond option '%s' not set as it conflicts with other options", opt);
|
|
return;
|
|
}
|
|
|
|
_set_bond_attr(device, opt, value);
|
|
}
|
|
|
|
static void
|
|
set_bond_attrs_or_default(NMDevice *device, NMSettingBond *s_bond, const char *const *attr_v)
|
|
{
|
|
nm_assert(NM_IS_DEVICE(device));
|
|
nm_assert(s_bond);
|
|
nm_assert(attr_v);
|
|
|
|
for (; *attr_v; ++attr_v)
|
|
set_bond_attr_or_default(device, s_bond, *attr_v);
|
|
}
|
|
|
|
static void
|
|
set_bond_arp_ip_targets(NMDevice *device, NMSettingBond *s_bond)
|
|
{
|
|
int ifindex = nm_device_get_ifindex(device);
|
|
gs_free char *cur_arp_ip_target = NULL;
|
|
|
|
/* ARP targets: clear and initialize the list */
|
|
cur_arp_ip_target =
|
|
nm_platform_sysctl_controller_get_option(nm_device_get_platform(device),
|
|
ifindex,
|
|
NM_SETTING_BOND_OPTION_ARP_IP_TARGET);
|
|
set_arp_targets(
|
|
device,
|
|
cur_arp_ip_target,
|
|
nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET));
|
|
}
|
|
|
|
static guint8
|
|
_bond_arp_ip_target_to_platform(const char *value, in_addr_t out[static NM_BOND_MAX_ARP_TARGETS])
|
|
{
|
|
gs_free const char **ip = NULL;
|
|
in_addr_t in_a;
|
|
int i;
|
|
int added = 0;
|
|
|
|
ip = nm_utils_bond_option_ip_split(value);
|
|
|
|
if (!ip)
|
|
return added;
|
|
|
|
for (i = 0; ip[i]; i++) {
|
|
if (added > NM_BOND_MAX_ARP_TARGETS - 1)
|
|
break;
|
|
if (!nm_inet_parse_bin(AF_INET, ip[i], NULL, &in_a))
|
|
nm_assert_not_reached(); /* verify() already validated the IP addresses */
|
|
|
|
out[added++] = in_a;
|
|
}
|
|
return added;
|
|
}
|
|
|
|
static guint8
|
|
_bond_ns_ip6_target_to_platform(const char *value,
|
|
struct in6_addr out[static NM_BOND_MAX_ARP_TARGETS])
|
|
{
|
|
gs_free const char **ip = NULL;
|
|
struct in6_addr in6_a;
|
|
int i;
|
|
int added = 0;
|
|
|
|
ip = nm_utils_bond_option_ip_split(value);
|
|
|
|
if (!ip)
|
|
return added;
|
|
|
|
for (i = 0; ip[i]; i++) {
|
|
if (added > NM_BOND_MAX_ARP_TARGETS - 1)
|
|
break;
|
|
if (!nm_inet_parse_bin(AF_INET6, ip[i], NULL, &in6_a))
|
|
nm_assert_not_reached(); /* verify() already validated the IP addresses */
|
|
|
|
out[added++] = in6_a;
|
|
}
|
|
return added;
|
|
}
|
|
|
|
static int
|
|
_setting_bond_primary_opt_as_ifindex(NMSettingBond *s_bond)
|
|
{
|
|
const char *primary_str;
|
|
int ifindex = 0;
|
|
|
|
primary_str = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_PRIMARY);
|
|
|
|
if (primary_str != NULL)
|
|
ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, primary_str);
|
|
|
|
return ifindex;
|
|
}
|
|
|
|
static void
|
|
_platform_lnk_bond_init_from_setting(NMSettingBond *s_bond, NMPlatformLnkBond *props)
|
|
{
|
|
const char *opt_value;
|
|
|
|
#define _v_fcn(fcn, s_bond, opt) (fcn(nm_setting_bond_get_option_normalized((s_bond), (opt))))
|
|
#define _v_u8(s_bond, opt) _nm_setting_bond_opt_value_as_u8((s_bond), (opt))
|
|
#define _v_u16(s_bond, opt) _nm_setting_bond_opt_value_as_u16((s_bond), (opt))
|
|
#define _v_u32(s_bond, opt) _nm_setting_bond_opt_value_as_u32((s_bond), (opt))
|
|
#define _v_intbool(s_bond, opt) _nm_setting_bond_opt_value_as_intbool((s_bond), (opt))
|
|
|
|
*props = (NMPlatformLnkBond) {
|
|
.mode = _v_fcn(_nm_setting_bond_mode_from_string, s_bond, NM_SETTING_BOND_OPTION_MODE),
|
|
.primary = _setting_bond_primary_opt_as_ifindex(s_bond),
|
|
.miimon = _v_u32(s_bond, NM_SETTING_BOND_OPTION_MIIMON),
|
|
.updelay = _v_u32(s_bond, NM_SETTING_BOND_OPTION_UPDELAY),
|
|
.downdelay = _v_u32(s_bond, NM_SETTING_BOND_OPTION_DOWNDELAY),
|
|
.arp_interval = _v_u32(s_bond, NM_SETTING_BOND_OPTION_ARP_INTERVAL),
|
|
.resend_igmp = _v_u32(s_bond, NM_SETTING_BOND_OPTION_RESEND_IGMP),
|
|
.min_links = _v_u32(s_bond, NM_SETTING_BOND_OPTION_MIN_LINKS),
|
|
.lp_interval = _v_u32(s_bond, NM_SETTING_BOND_OPTION_LP_INTERVAL),
|
|
.packets_per_port = _v_u32(s_bond, NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE),
|
|
.peer_notif_delay = _v_u32(s_bond, NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY),
|
|
.arp_all_targets = _v_fcn(_nm_setting_bond_arp_all_targets_from_string,
|
|
s_bond,
|
|
NM_SETTING_BOND_OPTION_ARP_ALL_TARGETS),
|
|
.arp_validate = _v_fcn(_nm_setting_bond_arp_validate_from_string,
|
|
s_bond,
|
|
NM_SETTING_BOND_OPTION_ARP_VALIDATE),
|
|
.ad_actor_sys_prio = _v_u16(s_bond, NM_SETTING_BOND_OPTION_AD_ACTOR_SYS_PRIO),
|
|
.ad_user_port_key = _v_u16(s_bond, NM_SETTING_BOND_OPTION_AD_USER_PORT_KEY),
|
|
.primary_reselect = _v_fcn(_nm_setting_bond_primary_reselect_from_string,
|
|
s_bond,
|
|
NM_SETTING_BOND_OPTION_PRIMARY_RESELECT),
|
|
.fail_over_mac = _v_fcn(_nm_setting_bond_fail_over_mac_from_string,
|
|
s_bond,
|
|
NM_SETTING_BOND_OPTION_FAIL_OVER_MAC),
|
|
.xmit_hash_policy = _v_fcn(_nm_setting_bond_xmit_hash_policy_from_string,
|
|
s_bond,
|
|
NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY),
|
|
.num_grat_arp = _v_u8(s_bond, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP),
|
|
.all_ports_active = _v_u8(s_bond, NM_SETTING_BOND_OPTION_ALL_SLAVES_ACTIVE),
|
|
.arp_missed_max = _v_u8(s_bond, NM_SETTING_BOND_OPTION_ARP_MISSED_MAX),
|
|
.lacp_active = _v_fcn(_nm_setting_bond_lacp_active_from_string,
|
|
s_bond,
|
|
NM_SETTING_BOND_OPTION_LACP_ACTIVE),
|
|
.lacp_rate = _v_fcn(_nm_setting_bond_lacp_rate_from_string,
|
|
s_bond,
|
|
NM_SETTING_BOND_OPTION_LACP_RATE),
|
|
.ad_select = _v_fcn(_nm_setting_bond_ad_select_from_string,
|
|
s_bond,
|
|
NM_SETTING_BOND_OPTION_AD_SELECT),
|
|
.use_carrier = _v_intbool(s_bond, NM_SETTING_BOND_OPTION_USE_CARRIER),
|
|
.tlb_dynamic_lb = _v_intbool(s_bond, NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB),
|
|
};
|
|
|
|
nm_ether_addr_from_string(
|
|
&props->ad_actor_system,
|
|
nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_AD_ACTOR_SYSTEM));
|
|
|
|
opt_value = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET);
|
|
if (opt_value != NULL)
|
|
props->arp_ip_targets_num =
|
|
_bond_arp_ip_target_to_platform(opt_value, props->arp_ip_target);
|
|
|
|
opt_value = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_NS_IP6_TARGET);
|
|
if (opt_value != NULL)
|
|
props->ns_ip6_targets_num =
|
|
_bond_ns_ip6_target_to_platform(opt_value, props->ns_ip6_target);
|
|
|
|
props->miimon_has = !props->arp_interval && !props->arp_validate;
|
|
props->updelay_has = props->miimon_has && props->miimon;
|
|
props->downdelay_has = props->miimon_has && props->miimon;
|
|
props->peer_notif_delay_has = (props->miimon || props->arp_interval) && props->peer_notif_delay;
|
|
props->resend_igmp_has = props->resend_igmp != 1;
|
|
props->lp_interval_has = props->lp_interval != 1;
|
|
props->tlb_dynamic_lb_has = NM_IN_SET(props->mode, NM_BOND_MODE_TLB, NM_BOND_MODE_ALB);
|
|
props->lacp_active_has = NM_IN_SET(props->mode, NM_BOND_MODE_8023AD);
|
|
}
|
|
|
|
static void
|
|
_balance_slb_cb(NMBondManager *bond_manager, NMBondManagerEventType event_type, gpointer user_data)
|
|
{
|
|
NMDevice *device = user_data;
|
|
NMDeviceBond *self = NM_DEVICE_BOND(device);
|
|
|
|
nm_assert(NM_IS_DEVICE_BOND(self));
|
|
nm_assert(self->bond_manager == bond_manager);
|
|
|
|
switch (event_type) {
|
|
case NM_BOND_MANAGER_EVENT_TYPE_STATE:
|
|
switch (nm_bond_manager_get_state(bond_manager)) {
|
|
case NM_OPTION_BOOL_FALSE:
|
|
if (nm_device_get_state(device) <= NM_DEVICE_STATE_ACTIVATED) {
|
|
_LOGD(LOGD_BOND, "balance-slb: failed");
|
|
nm_device_state_changed(device,
|
|
NM_DEVICE_STATE_FAILED,
|
|
NM_DEVICE_STATE_REASON_CONFIG_FAILED);
|
|
}
|
|
return;
|
|
case NM_OPTION_BOOL_TRUE:
|
|
if (nm_device_get_state(device) <= NM_DEVICE_STATE_ACTIVATED
|
|
&& nm_device_devip_get_state(device, AF_UNSPEC) <= NM_DEVICE_IP_STATE_PENDING) {
|
|
nm_device_devip_set_state(device, AF_UNSPEC, NM_DEVICE_IP_STATE_READY, NULL);
|
|
}
|
|
return;
|
|
case NM_OPTION_BOOL_DEFAULT:
|
|
if (nm_device_get_state(device) <= NM_DEVICE_STATE_ACTIVATED
|
|
&& nm_device_devip_get_state(device, AF_UNSPEC) == NM_DEVICE_IP_STATE_READY) {
|
|
/* We are again busy. We can also go back to "pending" from "ready".
|
|
* If ip-config state is not yet complete, this will further delay it.
|
|
* Otherwise, it should have no effect. */
|
|
nm_device_devip_set_state(device, AF_UNSPEC, NM_DEVICE_IP_STATE_PENDING, NULL);
|
|
}
|
|
return;
|
|
}
|
|
nm_assert_not_reached();
|
|
return;
|
|
}
|
|
|
|
nm_assert_not_reached();
|
|
}
|
|
|
|
static void
|
|
_balance_slb_setup(NMDeviceBond *self, NMConnection *connection)
|
|
{
|
|
int ifindex = nm_device_get_ifindex(NM_DEVICE(self));
|
|
gboolean balance_slb = FALSE;
|
|
const char *uuid;
|
|
NMSettingBond *s_bond;
|
|
|
|
if (ifindex > 0 && connection && (s_bond = nm_connection_get_setting_bond(connection)))
|
|
balance_slb = _v_intbool(s_bond, NM_SETTING_BOND_OPTION_BALANCE_SLB);
|
|
|
|
if (!balance_slb) {
|
|
if (nm_clear_pointer(&self->bond_manager, nm_bond_manager_destroy)) {
|
|
_LOGD(LOGD_BOND, "balance-slb: stopped");
|
|
nm_device_devip_set_state(NM_DEVICE(self), AF_UNSPEC, NM_DEVICE_IP_STATE_NONE, NULL);
|
|
}
|
|
return;
|
|
}
|
|
|
|
uuid = nm_connection_get_uuid(connection);
|
|
|
|
if (self->bond_manager) {
|
|
if (nm_bond_manager_get_ifindex(self->bond_manager) == ifindex
|
|
&& nm_streq0(nm_bond_manager_get_connection_uuid(self->bond_manager), uuid)) {
|
|
_LOGD(LOGD_BOND, "balance-slb: reapply");
|
|
nm_bond_manager_reapply(self->bond_manager);
|
|
return;
|
|
}
|
|
nm_clear_pointer(&self->bond_manager, nm_bond_manager_destroy);
|
|
_LOGD(LOGD_BOND, "balance-slb: restart");
|
|
}
|
|
|
|
_LOGD(LOGD_BOND, "balance-slb: start");
|
|
if (nm_device_devip_get_state(NM_DEVICE(self), AF_UNSPEC) < NM_DEVICE_IP_STATE_PENDING)
|
|
nm_device_devip_set_state(NM_DEVICE(self), AF_UNSPEC, NM_DEVICE_IP_STATE_PENDING, NULL);
|
|
self->bond_manager = nm_bond_manager_new(nm_device_get_platform(NM_DEVICE(self)),
|
|
ifindex,
|
|
uuid,
|
|
_balance_slb_cb,
|
|
self);
|
|
nm_assert(nm_bond_manager_get_state(self->bond_manager) == NM_OPTION_BOOL_DEFAULT);
|
|
}
|
|
|
|
static NMActStageReturn
|
|
act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason)
|
|
{
|
|
NMDeviceBond *self = NM_DEVICE_BOND(device);
|
|
NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
|
|
NMConnection *connection;
|
|
NMSettingBond *s_bond;
|
|
NMPlatformLnkBond props;
|
|
int r;
|
|
int ifindex = nm_device_get_ifindex(device);
|
|
|
|
connection = nm_device_get_applied_connection(device);
|
|
g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE);
|
|
|
|
s_bond = nm_connection_get_setting_bond(connection);
|
|
g_return_val_if_fail(s_bond, NM_ACT_STAGE_RETURN_FAILURE);
|
|
|
|
if (nm_device_managed_type_is_external(device))
|
|
return NM_ACT_STAGE_RETURN_SUCCESS;
|
|
|
|
_balance_slb_setup(self, connection);
|
|
|
|
if (nm_device_managed_type_is_external_or_assume(device))
|
|
return NM_ACT_STAGE_RETURN_SUCCESS;
|
|
|
|
_platform_lnk_bond_init_from_setting(s_bond, &props);
|
|
|
|
/* Interface must be down to set bond options */
|
|
nm_device_take_down(device, TRUE);
|
|
r = nm_platform_link_bond_change(nm_device_get_platform(device), ifindex, &props);
|
|
if (r < 0) {
|
|
ret = NM_ACT_STAGE_RETURN_FAILURE;
|
|
NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED);
|
|
} else {
|
|
if (!nm_device_hw_addr_set_cloned(device, nm_device_get_applied_connection(device), FALSE))
|
|
ret = NM_ACT_STAGE_RETURN_FAILURE;
|
|
}
|
|
|
|
/* This is a workaround because netlink do not support ifname as primary */
|
|
set_bond_attr_or_default(device, s_bond, NM_SETTING_BOND_OPTION_PRIMARY);
|
|
|
|
nm_device_bring_up(device);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
commit_port_options(NMDevice *bond_device, NMDevice *port, NMSettingBondPort *s_port)
|
|
{
|
|
NMBondMode mode = NM_BOND_MODE_UNKNOWN;
|
|
const char *value;
|
|
NMSettingBond *s_bond;
|
|
gint32 prio;
|
|
gboolean prio_has;
|
|
|
|
s_bond = nm_device_get_applied_setting(bond_device, NM_TYPE_SETTING_BOND);
|
|
if (s_bond) {
|
|
value = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_MODE);
|
|
mode = _nm_setting_bond_mode_from_string(value);
|
|
}
|
|
|
|
prio = s_port ? nm_setting_bond_port_get_prio(s_port) : NM_BOND_PORT_PRIO_DEF;
|
|
|
|
if (prio != 0) {
|
|
/* The profile explicitly sets the priority. No matter what, we try to set it
|
|
* in netlink. */
|
|
prio_has = TRUE;
|
|
} else if (!NM_IN_SET(mode, NM_BOND_MODE_ACTIVEBACKUP, NM_BOND_MODE_TLB, NM_BOND_MODE_ALB)) {
|
|
/* The priority only is configurable with certain modes. If we don't have
|
|
* one of those modes, don't try to set the priority explicitly to zero. */
|
|
prio_has = FALSE;
|
|
} else if (nm_platform_kernel_support_get_full(
|
|
NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_BOND_PORT_PRIO,
|
|
FALSE)
|
|
== NM_OPTION_BOOL_TRUE) {
|
|
/* We can only detect support if we have it. We cannot detect lack of support if
|
|
* we don't have it.
|
|
*
|
|
* But we did explicitly detect support, so explicitly set the prio to zero. */
|
|
prio_has = TRUE;
|
|
} else {
|
|
/* We either have an unsuitable mode or didn't detect kernel support for the
|
|
* priority. Don't explicitly set priority to zero. It is already the default,
|
|
* so it shouldn't be necessary. */
|
|
prio_has = FALSE;
|
|
}
|
|
|
|
nm_platform_link_change(nm_device_get_platform(port),
|
|
nm_device_get_ifindex(port),
|
|
NULL,
|
|
&((NMPlatformLinkBondPort) {
|
|
.queue_id = s_port ? nm_setting_bond_port_get_queue_id(s_port)
|
|
: NM_BOND_PORT_QUEUE_ID_DEF,
|
|
.prio = prio_has ? prio : 0,
|
|
.prio_has = prio_has,
|
|
}),
|
|
NULL,
|
|
0);
|
|
}
|
|
|
|
static NMTernary
|
|
attach_port(NMDevice *device,
|
|
NMDevice *port,
|
|
NMConnection *connection,
|
|
gboolean configure,
|
|
GCancellable *cancellable,
|
|
NMDeviceAttachPortCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
NMDeviceBond *self = NM_DEVICE_BOND(device);
|
|
NMSettingBondPort *s_port;
|
|
|
|
nm_device_controller_check_port_physical_port(device, port, LOGD_BOND);
|
|
|
|
if (configure) {
|
|
gboolean success;
|
|
|
|
nm_device_take_down(port, TRUE);
|
|
success = nm_platform_link_attach_port(nm_device_get_platform(device),
|
|
nm_device_get_ip_ifindex(device),
|
|
nm_device_get_ip_ifindex(port));
|
|
nm_device_bring_up(port);
|
|
|
|
if (!success) {
|
|
_LOGI(LOGD_BOND, "attaching bond port %s: failed", nm_device_get_ip_iface(port));
|
|
return FALSE;
|
|
}
|
|
|
|
s_port = _nm_connection_get_setting(connection, NM_TYPE_SETTING_BOND_PORT);
|
|
|
|
commit_port_options(device, port, s_port);
|
|
|
|
_LOGI(LOGD_BOND, "attached bond port %s", nm_device_get_ip_iface(port));
|
|
} else
|
|
_LOGI(LOGD_BOND, "bond port %s was attached", nm_device_get_ip_iface(port));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static NMTernary
|
|
detach_port(NMDevice *device,
|
|
NMDevice *port,
|
|
gboolean configure,
|
|
GCancellable *cancellable,
|
|
NMDeviceAttachPortCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
NMDeviceBond *self = NM_DEVICE_BOND(device);
|
|
gboolean success;
|
|
gs_free char *address = NULL;
|
|
int ifindex_port;
|
|
int ifindex;
|
|
|
|
if (configure) {
|
|
ifindex = nm_device_get_ifindex(device);
|
|
if (ifindex <= 0 || !nm_platform_link_get(nm_device_get_platform(device), ifindex))
|
|
configure = FALSE;
|
|
}
|
|
|
|
ifindex_port = nm_device_get_ip_ifindex(port);
|
|
|
|
if (ifindex_port <= 0)
|
|
_LOGD(LOGD_BOND, "bond port %s is already detached", nm_device_get_ip_iface(port));
|
|
|
|
if (configure) {
|
|
NMConnection *applied;
|
|
NMSettingWired *s_wired;
|
|
const char *cloned_mac;
|
|
|
|
address = g_strdup(nm_device_get_hw_address(device));
|
|
|
|
if (ifindex_port > 0) {
|
|
success = nm_platform_link_release_port(nm_device_get_platform(device),
|
|
nm_device_get_ip_ifindex(device),
|
|
ifindex_port);
|
|
|
|
if (success) {
|
|
_LOGI(LOGD_BOND, "detached bond port %s", nm_device_get_ip_iface(port));
|
|
} else {
|
|
_LOGW(LOGD_BOND, "failed to detach bond port %s", nm_device_get_ip_iface(port));
|
|
}
|
|
}
|
|
|
|
if ((applied = nm_device_get_applied_connection(device))
|
|
&& ((s_wired = nm_connection_get_setting_wired(applied)))
|
|
&& ((cloned_mac = nm_setting_wired_get_cloned_mac_address(s_wired)))) {
|
|
/* When the last port is released the bond MAC will be set to a random
|
|
* value by kernel; if we have set a cloned-mac-address, we need to
|
|
* restore it to the previous value. */
|
|
nm_platform_process_events(nm_device_get_platform(device));
|
|
if (nm_device_update_hw_address(device))
|
|
nm_device_hw_addr_set(device, address, "restore", FALSE);
|
|
}
|
|
|
|
/* Kernel bonding 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 (ifindex_port > 0) {
|
|
if (!nm_device_bring_up(port))
|
|
_LOGW(LOGD_BOND, "detached bond port could not be brought up.");
|
|
}
|
|
} else {
|
|
if (ifindex_port > 0) {
|
|
_LOGI(LOGD_BOND, "bond port %s was detached", nm_device_get_ip_iface(port));
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
create_and_realize(NMDevice *device,
|
|
NMConnection *connection,
|
|
NMDevice *parent,
|
|
const NMPlatformLink **out_plink,
|
|
GError **error)
|
|
{
|
|
const char *iface = nm_device_get_iface(device);
|
|
NMSettingBond *s_bond;
|
|
NMPlatformLnkBond props;
|
|
int r;
|
|
|
|
g_assert(iface);
|
|
|
|
s_bond = nm_connection_get_setting_bond(connection);
|
|
nm_assert(s_bond);
|
|
|
|
_platform_lnk_bond_init_from_setting(s_bond, &props);
|
|
|
|
r = nm_platform_link_bond_add(nm_device_get_platform(device), iface, &props, out_plink);
|
|
if (r < 0) {
|
|
g_set_error(error,
|
|
NM_DEVICE_ERROR,
|
|
NM_DEVICE_ERROR_CREATION_FAILED,
|
|
"Failed to create bond interface '%s' for '%s': %s",
|
|
iface,
|
|
nm_connection_get_id(connection),
|
|
nm_strerror(r));
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
can_reapply_change(NMDevice *device,
|
|
const char *setting_name,
|
|
NMSetting *s_old,
|
|
NMSetting *s_new,
|
|
GHashTable *diffs,
|
|
GError **error)
|
|
{
|
|
NMDeviceClass *device_class;
|
|
|
|
/* Only handle bond setting here, delegate other settings to parent class */
|
|
if (nm_streq(setting_name, NM_SETTING_BOND_SETTING_NAME)) {
|
|
NMSettingBond *s_a = NM_SETTING_BOND(s_old);
|
|
NMSettingBond *s_b = NM_SETTING_BOND(s_new);
|
|
const char **option_list;
|
|
|
|
if (!nm_device_hash_check_invalid_keys(diffs,
|
|
NM_SETTING_BOND_SETTING_NAME,
|
|
error,
|
|
NM_SETTING_BOND_OPTIONS))
|
|
return FALSE;
|
|
|
|
option_list = nm_setting_bond_get_valid_options(NULL);
|
|
|
|
for (; *option_list; ++option_list) {
|
|
const char *name = *option_list;
|
|
|
|
/* We support changes to these */
|
|
if (NM_IN_STRSET(name, OPTIONS_REAPPLY_FULL, NM_SETTING_BOND_OPTION_BALANCE_SLB))
|
|
continue;
|
|
|
|
/* Reject any other changes */
|
|
if (!nm_streq0(nm_setting_bond_get_option_normalized(s_a, name),
|
|
nm_setting_bond_get_option_normalized(s_b, name))) {
|
|
g_set_error(error,
|
|
NM_DEVICE_ERROR,
|
|
NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
|
|
"Can't reapply '%s' bond option",
|
|
name);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
device_class = NM_DEVICE_CLASS(nm_device_bond_parent_class);
|
|
return device_class->can_reapply_change(device, setting_name, s_old, s_new, diffs, error);
|
|
}
|
|
|
|
static void
|
|
reapply_connection(NMDevice *device, NMConnection *con_old, NMConnection *con_new)
|
|
{
|
|
NMDeviceBond *self = NM_DEVICE_BOND(device);
|
|
NMSettingBond *s_bond;
|
|
const char *value;
|
|
NMBondMode mode;
|
|
|
|
NM_DEVICE_CLASS(nm_device_bond_parent_class)->reapply_connection(device, con_old, con_new);
|
|
|
|
_LOGD(LOGD_BOND, "reapplying bond settings");
|
|
s_bond = nm_connection_get_setting_bond(con_new);
|
|
g_return_if_fail(s_bond);
|
|
|
|
value = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_MODE);
|
|
mode = _nm_setting_bond_mode_from_string(value);
|
|
g_return_if_fail(mode != NM_BOND_MODE_UNKNOWN);
|
|
|
|
/* Below we set only the bond options that kernel allows one to modify
|
|
* while keeping the bond interface up */
|
|
|
|
set_bond_arp_ip_targets(device, s_bond);
|
|
|
|
set_bond_attrs_or_default(device, s_bond, NM_MAKE_STRV(OPTIONS_REAPPLY_SUBSET));
|
|
|
|
_balance_slb_setup(self, con_new);
|
|
}
|
|
|
|
static void
|
|
deactivate(NMDevice *device)
|
|
{
|
|
NMDeviceBond *self = NM_DEVICE_BOND(device);
|
|
|
|
_balance_slb_setup(self, NULL);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
gboolean
|
|
nm_device_bond_is_slb(NMDevice *device)
|
|
{
|
|
NMConnection *connection;
|
|
NMSettingBond *s_bond;
|
|
|
|
connection = nm_device_get_applied_connection(device);
|
|
if (!connection)
|
|
return FALSE;
|
|
|
|
s_bond = nm_connection_get_setting_bond(connection);
|
|
if (!s_bond)
|
|
return FALSE;
|
|
|
|
if (!_nm_setting_bond_opt_value_as_intbool(s_bond, NM_SETTING_BOND_OPTION_BALANCE_SLB))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
nm_device_bond_announce_ports_on_slb(NMDevice *controller, NMDevice *port)
|
|
{
|
|
NMDeviceBond *self = NM_DEVICE_BOND(controller);
|
|
int port_ifindex = nm_device_get_ifindex(port);
|
|
int controller_ifindex = nm_device_get_ifindex(controller);
|
|
NML3Cfg *l3cfg = nm_device_get_l3cfg(controller);
|
|
NMDevice *bond_controller = nm_device_get_controller(controller);
|
|
NML3Cfg *bridge_l3cfg;
|
|
gs_free in_addr_t *addrs_array = NULL;
|
|
gsize addrs_len;
|
|
|
|
addrs_array = nm_l3cfg_get_configured_ip4_addresses(l3cfg, &addrs_len);
|
|
|
|
if (addrs_len > 0) {
|
|
/* the bond has IPs configured, it is not attached to a
|
|
* bridge then. */
|
|
if (!nm_bond_manager_send_arp(controller_ifindex,
|
|
-1,
|
|
nm_device_get_platform(port),
|
|
addrs_array,
|
|
addrs_len)) {
|
|
_LOGT(LOGD_BOND,
|
|
"failed to send gARP on port %s (ifindex %d)",
|
|
nm_device_get_iface(port),
|
|
port_ifindex);
|
|
return FALSE;
|
|
}
|
|
} else if (bond_controller
|
|
&& nm_device_get_device_type(bond_controller) == NM_DEVICE_TYPE_BRIDGE) {
|
|
/* the bond is attached to a bridge, firts let's check if the bridge has IP
|
|
* configuration. */
|
|
bridge_l3cfg = nm_device_get_l3cfg(bond_controller);
|
|
addrs_array = nm_l3cfg_get_configured_ip4_addresses(bridge_l3cfg, &addrs_len);
|
|
if (addrs_len > 0) {
|
|
/* the bridge has IPs configured, announcing them on the bond */
|
|
if (!nm_bond_manager_send_arp(controller_ifindex,
|
|
-1,
|
|
nm_device_get_platform(port),
|
|
addrs_array,
|
|
addrs_len)) {
|
|
_LOGT(LOGD_BOND,
|
|
"failed to send gARP on port %s (ifindex %d) on behalf of bridge",
|
|
nm_device_get_iface(port),
|
|
port_ifindex);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/* we are going to ARP probe the content of the FDB table */
|
|
if (!nm_bond_manager_send_arp(controller_ifindex,
|
|
nm_device_get_ifindex(bond_controller),
|
|
nm_device_get_platform(port),
|
|
NULL,
|
|
0)) {
|
|
_LOGT(LOGD_BOND, "failed to send ARP probing with content of FDB table");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
nm_device_bond_init(NMDeviceBond *self)
|
|
{
|
|
nm_assert(nm_device_is_controller(NM_DEVICE(self)));
|
|
}
|
|
|
|
static const NMDBusInterfaceInfoExtended interface_info_device_bond = {
|
|
.parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT(
|
|
NM_DBUS_INTERFACE_DEVICE_BOND,
|
|
.properties = NM_DEFINE_GDBUS_PROPERTY_INFOS(
|
|
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE(
|
|
"HwAddress",
|
|
"s",
|
|
NM_DEVICE_HW_ADDRESS,
|
|
.annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ),
|
|
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE(
|
|
"Carrier",
|
|
"b",
|
|
NM_DEVICE_CARRIER,
|
|
.annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ),
|
|
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE(
|
|
"Slaves",
|
|
"ao",
|
|
NM_DEVICE_SLAVES,
|
|
.annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), ), ),
|
|
};
|
|
|
|
static void
|
|
nm_device_bond_class_init(NMDeviceBondClass *klass)
|
|
{
|
|
NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass);
|
|
NMDeviceClass *device_class = NM_DEVICE_CLASS(klass);
|
|
|
|
dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_bond);
|
|
|
|
device_class->connection_type_supported = NM_SETTING_BOND_SETTING_NAME;
|
|
device_class->connection_type_check_compatible = NM_SETTING_BOND_SETTING_NAME;
|
|
device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_BOND);
|
|
|
|
device_class->is_controller = TRUE;
|
|
device_class->get_generic_capabilities = get_generic_capabilities;
|
|
device_class->complete_connection = complete_connection;
|
|
|
|
device_class->update_connection = update_connection;
|
|
device_class->controller_update_port_connection = controller_update_port_connection;
|
|
|
|
device_class->create_and_realize = create_and_realize;
|
|
device_class->act_stage1_prepare = act_stage1_prepare;
|
|
device_class->act_stage1_prepare_also_for_external_or_assume = TRUE;
|
|
device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired;
|
|
device_class->attach_port = attach_port;
|
|
device_class->detach_port = detach_port;
|
|
device_class->can_reapply_change = can_reapply_change;
|
|
device_class->reapply_connection = reapply_connection;
|
|
device_class->deactivate = deactivate;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
#define NM_TYPE_BOND_DEVICE_FACTORY (nm_bond_device_factory_get_type())
|
|
#define NM_BOND_DEVICE_FACTORY(obj) \
|
|
(_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_BOND_DEVICE_FACTORY, NMBondDeviceFactory))
|
|
|
|
static NMDevice *
|
|
create_device(NMDeviceFactory *factory,
|
|
const char *iface,
|
|
const NMPlatformLink *plink,
|
|
NMConnection *connection,
|
|
gboolean *out_ignore)
|
|
{
|
|
return 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,
|
|
NM_DEVICE_LINK_TYPE,
|
|
NM_LINK_TYPE_BOND,
|
|
NULL);
|
|
}
|
|
|
|
NM_DEVICE_FACTORY_DEFINE_INTERNAL(
|
|
BOND,
|
|
Bond,
|
|
bond,
|
|
NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_BOND)
|
|
NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_BOND_SETTING_NAME),
|
|
factory_class->create_device = create_device;);
|