summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFernando Fernandez Mancera <ffmancera@riseup.net>2022-05-06 10:11:16 +0200
committerFernando Fernandez Mancera <ffmancera@riseup.net>2022-07-13 16:22:17 +0200
commit89fb27c53ce8bc417e7260fb22c975dd023826d9 (patch)
treef65f1ab76c435f4df441f3ee2861ce71a61dcd47
parent34c1497ee40cc196cc5e67d3428facc7f9a5c7fd (diff)
platform: use netlink to set bond optionsff/bond_netlink
sysfs is deprecated and kernel people will not add new bond options to sysfs. Netlink is a stable API and therefore is the right method to communicate with kernel in order to set the link options.
-rw-r--r--src/core/devices/nm-device-bond.c217
-rw-r--r--src/core/nm-manager.c16
-rw-r--r--src/core/nm-manager.h1
-rw-r--r--src/core/platform/nm-fake-platform.c9
-rw-r--r--src/core/platform/tests/test-link.c8
-rw-r--r--src/libnm-platform/nm-linux-platform.c217
-rw-r--r--src/libnm-platform/nm-netlink.h8
-rw-r--r--src/libnm-platform/nm-platform.c147
-rw-r--r--src/libnm-platform/nm-platform.h55
-rw-r--r--src/libnm-platform/nmp-base.h1
-rw-r--r--src/libnm-platform/nmp-object.c12
-rw-r--r--src/libnm-platform/nmp-object.h8
12 files changed, 663 insertions, 36 deletions
diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c
index 21fe9b07eb..de6e67764c 100644
--- a/src/core/devices/nm-device-bond.c
+++ b/src/core/devices/nm-device-bond.c
@@ -9,6 +9,8 @@
#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"
@@ -16,6 +18,7 @@
#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"
#define _NMLOG_DEVICE_TYPE NMDeviceBond
@@ -349,51 +352,194 @@ set_bond_arp_ip_targets(NMDevice *device, NMSettingBond *s_bond)
nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET));
}
-static gboolean
-apply_bonding_config(NMDeviceBond *self)
+static void
+_bond_to_nm_ether_addr_ad_actor_system(const char *ad_actor, NMEtherAddr *out_addr)
{
- NMDevice *device = NM_DEVICE(self);
- NMSettingBond *s_bond;
- NMBondMode mode;
- const char *mode_str;
- gs_free char *device_bond_mode = NULL;
+ if (ad_actor == NULL) {
+ *out_addr = NM_ETHER_ADDR_INIT(0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+ return;
+ }
+ if (!nm_utils_hwaddr_aton(ad_actor, out_addr, ETH_ALEN))
+ nm_assert_not_reached();
+}
+
+static guint64
+_bond_opt_value_to_platform(const char *value, guint8 type)
+{
+ if (value != NULL) {
+ if (type == 8)
+ return _nm_utils_ascii_str_to_uint64(value, 10, 0, G_MAXUINT8, 0);
+ else if (type == 16)
+ return _nm_utils_ascii_str_to_uint64(value, 10, 0, G_MAXUINT16, 0);
+ else
+ return _nm_utils_ascii_str_to_uint64(value, 10, 0, G_MAXUINT32, 0);
+ }
+ return 0;
+}
- s_bond = nm_device_get_applied_setting(device, NM_TYPE_SETTING_BOND);
- g_return_val_if_fail(s_bond, FALSE);
+static void
+_bond_arp_ip_target_to_platform(const char *value,
+ struct in_addr out[NM_BOND_MAX_ARP_TARGETS],
+ guint8 *ip_count)
+{
+ gs_free const char **ip = NULL;
+ struct in_addr in_a;
+ int i, added = 0;
- mode_str = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_MODE);
- mode = _nm_setting_bond_mode_from_string(mode_str);
- g_return_val_if_fail(mode != NM_BOND_MODE_UNKNOWN, FALSE);
+ ip = nm_strsplit_set(value, " ");
- /* Set mode first, as some other options (e.g. arp_interval) are valid
- * only for certain modes.
- */
- device_bond_mode = nm_platform_sysctl_master_get_option(nm_device_get_platform(device),
- nm_device_get_ifindex(device),
- NM_SETTING_BOND_OPTION_MODE);
- /* Need to release all slaves before we can change bond mode */
- if (!nm_streq0(device_bond_mode, mode_str))
- nm_device_master_release_slaves_all(device);
+ if (!ip)
+ return;
- set_bond_attr_or_default(device, s_bond, NM_SETTING_BOND_OPTION_MODE);
+ for (i = 0; ip[i]; i++) {
+ if (!inet_aton(ip[i], &in_a))
+ continue;
+ added++;
- set_bond_arp_ip_targets(device, s_bond);
+ out[i] = in_a;
+ }
+ *ip_count = added;
+}
- set_bond_attrs_or_default(device, s_bond, NM_MAKE_STRV(OPTIONS_APPLY_SUBSET));
- return TRUE;
+static int
+_bond_primary_ifname_to_ifindex(const char *value)
+{
+ int ifindex = -1;
+ NMDevice *device = NULL;
+
+ if (value != NULL) {
+ device = nm_manager_get_device_by_iface(NM_MANAGER_GET, value);
+ if (!device)
+ return ifindex;
+
+ ifindex = nm_device_get_ifindex(device);
+ }
+ return ifindex;
+}
+
+static void
+_platform_lnk_bond_init_from_setting(NMSettingBond *s_bond, NMPlatformLnkBond *props)
+{
+ *props = (NMPlatformLnkBond){
+ .mode = _bond_opt_value_to_platform(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_MODE),
+ 8),
+ .primary = _bond_primary_ifname_to_ifindex(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_PRIMARY)),
+ .miimon = (guint32) _bond_opt_value_to_platform(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_MIIMON),
+ 32),
+ .updelay = (guint32) _bond_opt_value_to_platform(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_UPDELAY),
+ 32),
+ .downdelay = (guint32) _bond_opt_value_to_platform(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_DOWNDELAY),
+ 32),
+ .arp_interval = (guint32) _bond_opt_value_to_platform(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_ARP_INTERVAL),
+ 32),
+ .resend_igmp = (guint32) _bond_opt_value_to_platform(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_RESEND_IGMP),
+ 32),
+ .min_links = (guint32) _bond_opt_value_to_platform(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_MIN_LINKS),
+ 32),
+ .lp_interval = (guint32) _bond_opt_value_to_platform(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_LP_INTERVAL),
+ 32),
+ .packets_per_port = (guint32) _bond_opt_value_to_platform(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE),
+ 32),
+ .peer_notif_delay = (guint32) _bond_opt_value_to_platform(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY),
+ 32),
+ .arp_all_targets = (guint32) _bond_opt_value_to_platform(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_ARP_ALL_TARGETS),
+ 32),
+ .arp_validate = (guint32) _bond_opt_value_to_platform(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_ARP_VALIDATE),
+ 32),
+ .ad_actor_sys_prio = (guint16) _bond_opt_value_to_platform(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_AD_ACTOR_SYS_PRIO),
+ 16),
+ .ad_user_port_key = (guint16) _bond_opt_value_to_platform(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_AD_USER_PORT_KEY),
+ 16),
+ .primary_reselect = (guint8) _bond_opt_value_to_platform(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_PRIMARY_RESELECT),
+ 8),
+ .fail_over_mac = (guint8) _bond_opt_value_to_platform(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_FAIL_OVER_MAC),
+ 8),
+ .xmit_hash_policy = (guint8) _bond_opt_value_to_platform(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY),
+ 8),
+ .num_unsol_na = (guint8) _bond_opt_value_to_platform(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_NUM_UNSOL_NA),
+ 8),
+ .num_grat_arp = (guint8) _bond_opt_value_to_platform(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP),
+ 8),
+ .all_ports_active = (guint8) _bond_opt_value_to_platform(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_ALL_SLAVES_ACTIVE),
+ 8),
+ .lacp_rate = (guint8) _bond_opt_value_to_platform(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_LACP_RATE),
+ 8),
+ .ad_select = (guint8) _bond_opt_value_to_platform(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_AD_SELECT),
+ 8),
+ };
+
+ _bond_to_nm_ether_addr_ad_actor_system(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_AD_ACTOR_SYSTEM),
+ &props->ad_actor_system);
+
+ if (nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_USE_CARRIER) != NULL) {
+ props->use_carrier = _nm_utils_ascii_str_to_bool(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_USE_CARRIER),
+ FALSE);
+ }
+ if (nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB)
+ != NULL) {
+ props->tlb_dynamic_lb = _nm_utils_ascii_str_to_bool(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB),
+ FALSE);
+ }
+ if (nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET)
+ != NULL) {
+ _bond_arp_ip_target_to_platform(
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET),
+ props->arp_ip_target,
+ &props->arp_ip_targets_num);
+ }
}
static NMActStageReturn
act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason)
{
- NMDeviceBond *self = NM_DEVICE_BOND(device);
- NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
+ 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);
+
+ _platform_lnk_bond_init_from_setting(s_bond, &props);
/* Interface must be down to set bond options */
nm_device_take_down(device, TRUE);
- if (!apply_bonding_config(self))
+ r = nm_platform_link_bond_change(nm_device_get_platform(device), ifindex, &props);
+ if (r < 0) {
ret = NM_ACT_STAGE_RETURN_FAILURE;
- else {
+ 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;
}
@@ -535,12 +681,19 @@ create_and_realize(NMDevice *device,
const NMPlatformLink **out_plink,
GError **error)
{
- const char *iface = nm_device_get_iface(device);
- int r;
+ const char *iface = nm_device_get_iface(device);
+ NMSettingBond *s_bond;
+ NMPlatformLnkBond props;
+ int r;
g_assert(iface);
- r = nm_platform_link_bond_add(nm_device_get_platform(device), iface, out_plink);
+ 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,
diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c
index ee661e499e..3fb4a7e104 100644
--- a/src/core/nm-manager.c
+++ b/src/core/nm-manager.c
@@ -1334,6 +1334,22 @@ nm_manager_get_device_by_ifindex(NMManager *self, int ifindex)
return NULL;
}
+NMDevice *
+nm_manager_get_device_by_iface(NMManager *self, const char *iface)
+{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
+ NMDevice *device;
+
+ if (iface) {
+ c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
+ if (nm_streq0(nm_device_get_iface(device), iface))
+ return device;
+ }
+ }
+
+ return NULL;
+}
+
static NMDevice *
find_device_by_permanent_hw_addr(NMManager *self, const char *hwaddr)
{
diff --git a/src/core/nm-manager.h b/src/core/nm-manager.h
index fcb0022720..c4cd977aee 100644
--- a/src/core/nm-manager.h
+++ b/src/core/nm-manager.h
@@ -150,6 +150,7 @@ const CList *nm_manager_get_devices(NMManager *manager);
});)
NMDevice *nm_manager_get_device_by_ifindex(NMManager *manager, int ifindex);
+NMDevice *nm_manager_get_device_by_iface(NMManager *manager, const char *iface);
NMDevice *nm_manager_get_device_by_path(NMManager *manager, const char *path);
guint32
diff --git a/src/core/platform/nm-fake-platform.c b/src/core/platform/nm-fake-platform.c
index 7d8986d764..a1ca5434cb 100644
--- a/src/core/platform/nm-fake-platform.c
+++ b/src/core/platform/nm-fake-platform.c
@@ -323,6 +323,15 @@ link_add(NMPlatform *platform,
dev_lnk = nmp_object_new(NMP_OBJECT_TYPE_LNK_BRIDGE, props);
break;
}
+ case NM_LINK_TYPE_BOND:
+ {
+ const NMPlatformLnkBond *props = extra_data;
+
+ nm_assert(props);
+
+ dev_lnk = nmp_object_new(NMP_OBJECT_TYPE_LNK_BOND, props);
+ break;
+ }
case NM_LINK_TYPE_VETH:
veth_peer = extra_data;
g_assert(veth_peer);
diff --git a/src/core/platform/tests/test-link.c b/src/core/platform/tests/test-link.c
index 87280e097d..79c8077453 100644
--- a/src/core/platform/tests/test-link.c
+++ b/src/core/platform/tests/test-link.c
@@ -93,6 +93,10 @@ test_loopback(void)
g_assert(!nm_platform_link_supports_vlans(NM_PLATFORM_GET, LO_INDEX));
}
+const NMPlatformLnkBond nm_platform_lnk_bond_default = {
+ .mode = 3,
+};
+
static gboolean
software_add(NMLinkType link_type, const char *name)
{
@@ -112,12 +116,12 @@ software_add(NMLinkType link_type, const char *name)
gboolean bond0_exists = !!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "bond0");
int r;
- r = nm_platform_link_bond_add(NM_PLATFORM_GET, name, NULL);
+ r = nm_platform_link_bond_add(NM_PLATFORM_GET, name, &nm_platform_lnk_bond_default, NULL);
/* Check that bond0 is *not* automatically created. */
if (!bond0_exists)
g_assert(!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "bond0"));
- return r >= 0;
+ return NMTST_NM_ERR_SUCCESS(r);
}
case NM_LINK_TYPE_TEAM:
return NMTST_NM_ERR_SUCCESS(nm_platform_link_team_add(NM_PLATFORM_GET, name, NULL));
diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c
index 6b39375136..488d638641 100644
--- a/src/libnm-platform/nm-linux-platform.c
+++ b/src/libnm-platform/nm-linux-platform.c
@@ -1433,6 +1433,131 @@ _parse_lnk_bridge(const char *kind, struct nlattr *info_data)
/***********************************************************************************/
static NMPObject *
+_parse_lnk_bond(const char *kind, struct nlattr *info_data)
+{
+ static const struct nla_policy policy[] = {
+ [IFLA_BOND_MODE] = {.type = NLA_U8},
+ [IFLA_BOND_ACTIVE_SLAVE] = {.type = NLA_U32},
+ [IFLA_BOND_MIIMON] = {.type = NLA_U32},
+ [IFLA_BOND_UPDELAY] = {.type = NLA_U32},
+ [IFLA_BOND_DOWNDELAY] = {.type = NLA_U32},
+ [IFLA_BOND_USE_CARRIER] = {.type = NLA_U8},
+ [IFLA_BOND_ARP_INTERVAL] = {.type = NLA_U32},
+ [IFLA_BOND_ARP_IP_TARGET] = {.type = NLA_NESTED},
+ [IFLA_BOND_ARP_VALIDATE] = {.type = NLA_U32},
+ [IFLA_BOND_ARP_ALL_TARGETS] = {.type = NLA_U32},
+ [IFLA_BOND_PRIMARY] = {.type = NLA_U32},
+ [IFLA_BOND_PRIMARY_RESELECT] = {.type = NLA_U8},
+ [IFLA_BOND_FAIL_OVER_MAC] = {.type = NLA_U8},
+ [IFLA_BOND_XMIT_HASH_POLICY] = {.type = NLA_U8},
+ [IFLA_BOND_RESEND_IGMP] = {.type = NLA_U32},
+ [IFLA_BOND_NUM_PEER_NOTIF] = {.type = NLA_U8},
+ [IFLA_BOND_ALL_SLAVES_ACTIVE] = {.type = NLA_U8},
+ [IFLA_BOND_MIN_LINKS] = {.type = NLA_U32},
+ [IFLA_BOND_LP_INTERVAL] = {.type = NLA_U32},
+ [IFLA_BOND_PACKETS_PER_SLAVE] = {.type = NLA_U32},
+ [IFLA_BOND_AD_LACP_RATE] = {.type = NLA_U8},
+ [IFLA_BOND_AD_SELECT] = {.type = NLA_U8},
+ [IFLA_BOND_AD_ACTOR_SYS_PRIO] = {.type = NLA_U16},
+ [IFLA_BOND_AD_USER_PORT_KEY] = {.type = NLA_U16},
+ [IFLA_BOND_AD_ACTOR_SYSTEM] = {.minlen = sizeof(NMEtherAddr)},
+ [IFLA_BOND_TLB_DYNAMIC_LB] = {.type = NLA_U8},
+ [IFLA_BOND_PEER_NOTIF_DELAY] = {.type = NLA_U32},
+ };
+ NMPlatformLnkBond *props;
+ struct nlattr *tb[G_N_ELEMENTS(policy)];
+ NMPObject *obj = NULL;
+
+ if (!info_data || !nm_streq0(kind, "bond"))
+ return NULL;
+
+ if (nla_parse_nested_arr(tb, info_data, policy) < 0)
+ return NULL;
+
+ obj = nmp_object_new(NMP_OBJECT_TYPE_LNK_BOND, NULL);
+
+ props = &obj->lnk_bond;
+
+ if (tb[IFLA_BOND_MODE])
+ props->mode = nla_get_u8(tb[IFLA_BOND_MODE]);
+ if (tb[IFLA_BOND_PRIMARY]) {
+ props->primary = nla_get_u32(tb[IFLA_BOND_PRIMARY]);
+ } else if (tb[IFLA_BOND_ACTIVE_SLAVE]) {
+ props->primary = nla_get_u32(tb[IFLA_BOND_ACTIVE_SLAVE]);
+ }
+ if (tb[IFLA_BOND_MIIMON])
+ props->miimon = nla_get_u32(tb[IFLA_BOND_MIIMON]);
+ if (tb[IFLA_BOND_UPDELAY])
+ props->updelay = nla_get_u32(tb[IFLA_BOND_UPDELAY]);
+ if (tb[IFLA_BOND_DOWNDELAY])
+ props->downdelay = nla_get_u32(tb[IFLA_BOND_DOWNDELAY]);
+ if (tb[IFLA_BOND_USE_CARRIER])
+ props->use_carrier = nla_get_u8(tb[IFLA_BOND_USE_CARRIER]);
+ if (tb[IFLA_BOND_ARP_INTERVAL])
+ props->arp_interval = nla_get_u32(tb[IFLA_BOND_ARP_INTERVAL]);
+ if (tb[IFLA_BOND_ARP_IP_TARGET]) {
+ struct nlattr *attr;
+ int i = 0, rem;
+
+ nla_for_each_nested (attr, tb[IFLA_BOND_ARP_IP_TARGET], rem) {
+ uint32_t ip;
+
+ if (i > 15)
+ break;
+ if (nla_len(attr) < sizeof(ip))
+ break;
+
+ ip = nla_get_be32(attr);
+ props->arp_ip_target[i] = *(struct in_addr *) &ip;
+ props->arp_ip_targets_num++;
+ i++;
+ }
+ }
+ if (tb[IFLA_BOND_ARP_VALIDATE])
+ props->arp_validate = nla_get_u32(tb[IFLA_BOND_ARP_VALIDATE]);
+ if (tb[IFLA_BOND_ARP_ALL_TARGETS])
+ props->arp_all_targets = nla_get_u32(tb[IFLA_BOND_ARP_ALL_TARGETS]);
+ if (tb[IFLA_BOND_PRIMARY_RESELECT])
+ props->primary_reselect = nla_get_u8(tb[IFLA_BOND_PRIMARY_RESELECT]);
+ if (tb[IFLA_BOND_FAIL_OVER_MAC])
+ props->fail_over_mac = nla_get_u8(tb[IFLA_BOND_FAIL_OVER_MAC]);
+ if (tb[IFLA_BOND_XMIT_HASH_POLICY])
+ props->xmit_hash_policy = nla_get_u8(tb[IFLA_BOND_XMIT_HASH_POLICY]);
+ if (tb[IFLA_BOND_RESEND_IGMP])
+ props->resend_igmp = nla_get_u32(tb[IFLA_BOND_RESEND_IGMP]);
+ if (tb[IFLA_BOND_NUM_PEER_NOTIF]) {
+ props->num_grat_arp = nla_get_u8(tb[IFLA_BOND_NUM_PEER_NOTIF]);
+ props->num_unsol_na = nla_get_u8(tb[IFLA_BOND_NUM_PEER_NOTIF]);
+ }
+ if (tb[IFLA_BOND_ALL_SLAVES_ACTIVE])
+ props->all_ports_active = nla_get_u8(tb[IFLA_BOND_ALL_SLAVES_ACTIVE]);
+ if (tb[IFLA_BOND_MIN_LINKS])
+ props->min_links = nla_get_u32(tb[IFLA_BOND_MIN_LINKS]);
+ if (tb[IFLA_BOND_LP_INTERVAL])
+ props->lp_interval = nla_get_u32(tb[IFLA_BOND_LP_INTERVAL]);
+ if (tb[IFLA_BOND_PACKETS_PER_SLAVE])
+ props->packets_per_port = nla_get_u32(tb[IFLA_BOND_PACKETS_PER_SLAVE]);
+ if (tb[IFLA_BOND_AD_LACP_RATE])
+ props->lacp_rate = nla_get_u8(tb[IFLA_BOND_AD_LACP_RATE]);
+ if (tb[IFLA_BOND_AD_SELECT])
+ props->ad_select = nla_get_u8(tb[IFLA_BOND_AD_SELECT]);
+ if (tb[IFLA_BOND_AD_ACTOR_SYS_PRIO])
+ props->ad_actor_sys_prio = nla_get_u16(tb[IFLA_BOND_AD_ACTOR_SYS_PRIO]);
+ if (tb[IFLA_BOND_AD_USER_PORT_KEY])
+ props->ad_user_port_key = nla_get_u16(tb[IFLA_BOND_AD_USER_PORT_KEY]);
+ if (tb[IFLA_BOND_AD_ACTOR_SYSTEM])
+ props->ad_actor_system = *nla_data_as(NMEtherAddr, tb[IFLA_BOND_AD_ACTOR_SYSTEM]);
+ if (tb[IFLA_BOND_TLB_DYNAMIC_LB])
+ props->tlb_dynamic_lb = nla_get_u8(tb[IFLA_BOND_TLB_DYNAMIC_LB]);
+ if (tb[IFLA_BOND_PEER_NOTIF_DELAY])
+ props->peer_notif_delay = nla_get_u32(tb[IFLA_BOND_PEER_NOTIF_DELAY]);
+
+ return obj;
+}
+
+/***********************************************************************************/
+
+static NMPObject *
_parse_lnk_gre(const char *kind, struct nlattr *info_data)
{
static const struct nla_policy policy[] = {
@@ -3116,6 +3241,9 @@ _new_from_nl_link(NMPlatform *platform,
case NM_LINK_TYPE_BRIDGE:
lnk_data = _parse_lnk_bridge(nl_info_kind, nl_info_data);
break;
+ case NM_LINK_TYPE_BOND:
+ lnk_data = _parse_lnk_bond(nl_info_kind, nl_info_data);
+ break;
case NM_LINK_TYPE_GRE:
case NM_LINK_TYPE_GRETAP:
lnk_data = _parse_lnk_gre(nl_info_kind, nl_info_data);
@@ -4277,6 +4405,95 @@ _nl_msg_new_link_set_linkinfo(struct nl_msg *msg, NMLinkType link_type, gconstpo
NLA_PUT_U64(msg, IFLA_BR_MCAST_STARTUP_QUERY_INTVL, props->mcast_startup_query_interval);
break;
}
+ case NM_LINK_TYPE_BOND:
+ {
+ const NMPlatformLnkBond *props = extra_data;
+ struct nlattr *targets;
+ int targets_added = 0, i = 0;
+
+ nm_assert(extra_data);
+
+ if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
+ goto nla_put_failure;
+
+ NLA_PUT_U8(msg, IFLA_BOND_MODE, props->mode);
+
+ targets = nla_nest_start(msg, IFLA_BOND_ARP_IP_TARGET);
+ if (!targets)
+ goto nla_put_failure;
+
+ for (i = 0; i < props->arp_ip_targets_num; i++) {
+ if (props->arp_ip_target[i].s_addr) {
+ NLA_PUT_U32(msg, i, props->arp_ip_target[i].s_addr);
+ targets_added++;
+ }
+ }
+
+ if (targets_added)
+ nla_nest_end(msg, targets);
+ else
+ nla_nest_cancel(msg, targets);
+
+ NLA_PUT_U8(msg, IFLA_BOND_ALL_SLAVES_ACTIVE, props->all_ports_active);
+ NLA_PUT_U8(msg, IFLA_BOND_USE_CARRIER, !!props->use_carrier);
+ NLA_PUT_U32(msg, IFLA_BOND_ARP_INTERVAL, props->arp_interval);
+ NLA_PUT_U32(msg, IFLA_BOND_ARP_VALIDATE, props->arp_validate);
+ NLA_PUT_U32(msg, IFLA_BOND_MIIMON, props->miimon);
+ if (props->miimon) {
+ NLA_PUT_U32(msg, IFLA_BOND_UPDELAY, props->updelay);
+ NLA_PUT_U32(msg, IFLA_BOND_DOWNDELAY, props->downdelay);
+ }
+ if (props->miimon || props->arp_interval)
+ NLA_PUT_U32(msg, IFLA_BOND_PEER_NOTIF_DELAY, props->peer_notif_delay);
+
+ if (NM_IN_SET(props->mode, 0)) {
+ NLA_PUT_U32(msg, IFLA_BOND_PACKETS_PER_SLAVE, props->packets_per_port);
+ NLA_PUT_U32(msg, IFLA_BOND_RESEND_IGMP, props->resend_igmp);
+ }
+
+ if (NM_IN_SET(props->mode, 1)) {
+ NLA_PUT_U8(msg, IFLA_BOND_FAIL_OVER_MAC, props->fail_over_mac);
+ /* num_unsol_na and num_grat_arp cannot be different. */
+ NLA_PUT_U8(msg, IFLA_BOND_NUM_PEER_NOTIF, props->num_unsol_na);
+ NLA_PUT_U8(msg, IFLA_BOND_PRIMARY_RESELECT, props->primary_reselect);
+ NLA_PUT_U32(msg, IFLA_BOND_ARP_ALL_TARGETS, props->arp_all_targets);
+ NLA_PUT_U32(msg, IFLA_BOND_PRIMARY, props->primary);
+ NLA_PUT_U32(msg, IFLA_BOND_RESEND_IGMP, props->resend_igmp);
+ }
+
+ if (NM_IN_SET(props->mode, 2))
+ NLA_PUT_U8(msg, IFLA_BOND_XMIT_HASH_POLICY, props->xmit_hash_policy);
+
+ if (NM_IN_SET(props->mode, 4)) {
+ NLA_PUT_U8(msg, IFLA_BOND_AD_SELECT, props->ad_select);
+ NLA_PUT_U8(msg, IFLA_BOND_AD_LACP_RATE, props->lacp_rate);
+ NLA_PUT_U8(msg, IFLA_BOND_XMIT_HASH_POLICY, props->xmit_hash_policy);
+ NLA_PUT_U16(msg, IFLA_BOND_AD_ACTOR_SYS_PRIO, props->ad_actor_sys_prio);
+ NLA_PUT_U16(msg, IFLA_BOND_AD_USER_PORT_KEY, props->ad_user_port_key);
+ NLA_PUT_U32(msg, IFLA_BOND_MIN_LINKS, props->min_links);
+ NLA_PUT(msg,
+ IFLA_BOND_AD_ACTOR_SYSTEM,
+ sizeof(props->ad_actor_system),
+ &props->ad_actor_system);
+ }
+
+ if (NM_IN_SET(props->mode, 5)) {
+ NLA_PUT_U8(msg, IFLA_BOND_TLB_DYNAMIC_LB, !!props->tlb_dynamic_lb);
+ NLA_PUT_U8(msg, IFLA_BOND_XMIT_HASH_POLICY, props->xmit_hash_policy);
+ NLA_PUT_U8(msg, IFLA_BOND_PRIMARY_RESELECT, props->primary_reselect);
+ NLA_PUT_U32(msg, IFLA_BOND_PRIMARY, props->primary);
+ NLA_PUT_U32(msg, IFLA_BOND_RESEND_IGMP, props->resend_igmp);
+ NLA_PUT_U32(msg, IFLA_BOND_LP_INTERVAL, props->lp_interval);
+ }
+
+ if (NM_IN_SET(props->mode, 6)) {
+ NLA_PUT_U8(msg, IFLA_BOND_PRIMARY_RESELECT, props->primary_reselect);
+ NLA_PUT_U32(msg, IFLA_BOND_PRIMARY, props->primary);
+ NLA_PUT_U32(msg, IFLA_BOND_RESEND_IGMP, props->resend_igmp);
+ NLA_PUT_U32(msg, IFLA_BOND_LP_INTERVAL, props->lp_interval);
+ }
+ break;
+ }
case NM_LINK_TYPE_VLAN:
{
const NMPlatformLnkVlan *props = extra_data;
diff --git a/src/libnm-platform/nm-netlink.h b/src/libnm-platform/nm-netlink.h
index efc9585313..36d8a869b8 100644
--- a/src/libnm-platform/nm-netlink.h
+++ b/src/libnm-platform/nm-netlink.h
@@ -234,6 +234,14 @@ nla_get_be64(const struct nlattr *nla)
return unaligned_read_be64(nla_data(nla));
}
+static inline uint32_t
+nla_get_be32(const struct nlattr *nla)
+{
+ nm_assert(nla_len(nla) >= sizeof(uint32_t));
+
+ return unaligned_read_be32(nla_data(nla));
+}
+
static inline char *
nla_get_string(const struct nlattr *nla)
{
diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c
index 50204abc5f..12183bb3e5 100644
--- a/src/libnm-platform/nm-platform.c
+++ b/src/libnm-platform/nm-platform.c
@@ -1292,6 +1292,12 @@ nm_platform_link_add(NMPlatform *self,
buf_p,
buf_len);
break;
+ case NM_LINK_TYPE_BOND:
+ nm_strbuf_append_str(&buf_p, &buf_len, ", ");
+ nm_platform_lnk_bond_to_string((const NMPlatformLnkBond *) extra_data,
+ buf_p,
+ buf_len);
+ break;
default:
nm_assert(!extra_data);
break;
@@ -1332,6 +1338,12 @@ nm_platform_link_change(NMPlatform *self, NMLinkType type, int ifindex, gconstpo
buf_p,
buf_len);
break;
+ case NM_LINK_TYPE_BOND:
+ nm_strbuf_append_str(&buf_p, &buf_len, ", ");
+ nm_platform_lnk_bond_to_string((const NMPlatformLnkBond *) extra_data,
+ buf_p,
+ buf_len);
+ break;
default:
nm_assert(!extra_data);
break;
@@ -2232,6 +2244,12 @@ _link_get_lnk(NMPlatform *self, int ifindex, NMLinkType link_type, const NMPlatf
return lnk ? &lnk->object : NULL;
}
+const NMPlatformLnkBond *
+nm_platform_link_get_lnk_bond(NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
+{
+ return _link_get_lnk(self, ifindex, NM_LINK_TYPE_BOND, out_link);
+}
+
const NMPlatformLnkBridge *
nm_platform_link_get_lnk_bridge(NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
@@ -5976,6 +5994,69 @@ nm_platform_lnk_bridge_to_string(const NMPlatformLnkBridge *lnk, char *buf, gsiz
}
const char *
+nm_platform_lnk_bond_to_string(const NMPlatformLnkBond *lnk, char *buf, gsize len)
+{
+ if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len))
+ return buf;
+
+ g_snprintf(buf,
+ len,
+ "bond"
+ " mode %u"
+ " primary %u"
+ " miimon %u"
+ " updelay %u"
+ " downdelay %u"
+ " arp_interval %u"
+ " resend_igmp %u"
+ " min_links %u"
+ " lp_interval %u"
+ " packets_per_port %u"
+ " peer_notif_delay %u"
+ " arp_all_targets %u"
+ " arp_validate %u"
+ " ad_actor_sys_prio %u"
+ " ad_user_port_key %u"
+ " ad_actor_system " NM_ETHER_ADDR_FORMAT_STR " primary_reselect %u"
+ " fail_over_mac %u"
+ " xmit_hash_policy %u"
+ " num_unsol_na %u"
+ " num_gray_arp %u"
+ " all_ports_active %u"
+ " lacp_rate %u"
+ " ad_select %u"
+ " use_carrier %d"
+ " tlb_dynamic_lb %d",
+ lnk->mode,
+ lnk->primary,
+ lnk->miimon,
+ lnk->updelay,
+ lnk->downdelay,
+ lnk->arp_interval,
+ lnk->resend_igmp,
+ lnk->min_links,
+ lnk->lp_interval,
+ lnk->packets_per_port,
+ lnk->peer_notif_delay,
+ lnk->arp_all_targets,
+ lnk->arp_validate,
+ lnk->ad_actor_sys_prio,
+ lnk->ad_user_port_key,
+ NM_ETHER_ADDR_FORMAT_VAL(&lnk->ad_actor_system),
+ lnk->primary_reselect,
+ lnk->fail_over_mac,
+ lnk->xmit_hash_policy,
+ lnk->num_unsol_na,
+ lnk->num_grat_arp,
+ lnk->all_ports_active,
+ lnk->lacp_rate,
+ lnk->ad_select,
+ (int) lnk->use_carrier,
+ (int) lnk->tlb_dynamic_lb);
+ return buf;
+}
+
+const char *
nm_platform_lnk_gre_to_string(const NMPlatformLnkGre *lnk, char *buf, gsize len)
{
char str_local[30];
@@ -7692,6 +7773,72 @@ nm_platform_lnk_bridge_hash_update(const NMPlatformLnkBridge *obj, NMHashState *
obj->vlan_stats_enabled));
}
+void
+nm_platform_lnk_bond_hash_update(const NMPlatformLnkBond *obj, NMHashState *h)
+{
+ nm_hash_update_vals(h,
+ obj->mode,
+ obj->primary,
+ obj->miimon,
+ obj->updelay,
+ obj->downdelay,
+ obj->arp_interval,
+ obj->resend_igmp,
+ obj->min_links,
+ obj->lp_interval,
+ obj->packets_per_port,
+ obj->peer_notif_delay,
+ obj->arp_all_targets,
+ obj->arp_validate,
+ obj->ad_actor_sys_prio,
+ obj->ad_user_port_key,
+ obj->ad_actor_system,
+ obj->primary_reselect,
+ obj->fail_over_mac,
+ obj->xmit_hash_policy,
+ obj->num_unsol_na,
+ obj->num_grat_arp,
+ obj->all_ports_active,
+ obj->lacp_rate,
+ obj->ad_select,
+ NM_HASH_COMBINE_BOOLS(guint8, obj->use_carrier, obj->tlb_dynamic_lb));
+}
+
+int
+nm_platform_lnk_bond_cmp(const NMPlatformLnkBond *a, const NMPlatformLnkBond *b)
+{
+ NM_CMP_SELF(a, b);
+ NM_CMP_FIELD(a, b, mode);
+ NM_CMP_FIELD(a, b, primary);
+ NM_CMP_FIELD_MEMCMP(a, b, arp_ip_target);
+ NM_CMP_FIELD(a, b, miimon);
+ NM_CMP_FIELD(a, b, updelay);
+ NM_CMP_FIELD(a, b, downdelay);
+ NM_CMP_FIELD(a, b, arp_interval);
+ NM_CMP_FIELD(a, b, resend_igmp);
+ NM_CMP_FIELD(a, b, min_links);
+ NM_CMP_FIELD(a, b, lp_interval);
+ NM_CMP_FIELD(a, b, packets_per_port);
+ NM_CMP_FIELD(a, b, peer_notif_delay);
+ NM_CMP_FIELD(a, b, arp_all_targets);
+ NM_CMP_FIELD(a, b, arp_validate);
+ NM_CMP_FIELD(a, b, ad_actor_sys_prio);
+ NM_CMP_FIELD(a, b, ad_user_port_key);
+ NM_CMP_FIELD_MEMCMP(a, b, ad_actor_system);
+ NM_CMP_FIELD(a, b, primary_reselect);
+ NM_CMP_FIELD(a, b, fail_over_mac);
+ NM_CMP_FIELD(a, b, xmit_hash_policy);
+ NM_CMP_FIELD(a, b, num_unsol_na);
+ NM_CMP_FIELD(a, b, num_grat_arp);
+ NM_CMP_FIELD(a, b, all_ports_active);
+ NM_CMP_FIELD(a, b, lacp_rate);
+ NM_CMP_FIELD(a, b, ad_select);
+ NM_CMP_FIELD_BOOL(a, b, use_carrier);
+ NM_CMP_FIELD_BOOL(a, b, tlb_dynamic_lb);
+
+ return 0;
+}
+
int
nm_platform_lnk_bridge_cmp(const NMPlatformLnkBridge *a, const NMPlatformLnkBridge *b)
{
diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h
index b921a2f562..df0cc3ee19 100644
--- a/src/libnm-platform/nm-platform.h
+++ b/src/libnm-platform/nm-platform.h
@@ -881,6 +881,42 @@ typedef struct {
extern const NMPlatformLnkBridge nm_platform_lnk_bridge_default;
+/* Defined in net/bonding.h. */
+#define NM_BOND_MAX_ARP_TARGETS 16
+
+G_STATIC_ASSERT(NM_BOND_MAX_ARP_TARGETS == 16);
+
+typedef struct {
+ struct in_addr arp_ip_target[NM_BOND_MAX_ARP_TARGETS];
+ guint32 primary;
+ guint32 miimon;
+ guint32 updelay;
+ guint32 downdelay;
+ guint32 arp_interval;
+ guint32 resend_igmp;
+ guint32 min_links;
+ guint32 lp_interval;
+ guint32 packets_per_port;
+ guint32 peer_notif_delay;
+ guint32 arp_all_targets;
+ guint32 arp_validate;
+ guint16 ad_actor_sys_prio;
+ guint16 ad_user_port_key;
+ NMEtherAddr ad_actor_system;
+ guint8 mode;
+ guint8 primary_reselect;
+ guint8 fail_over_mac;
+ guint8 xmit_hash_policy;
+ guint8 num_unsol_na;
+ guint8 num_grat_arp;
+ guint8 all_ports_active;
+ guint8 lacp_rate;
+ guint8 ad_select;
+ guint8 arp_ip_targets_num;
+ bool use_carrier : 1;
+ bool tlb_dynamic_lb : 1;
+} NMPlatformLnkBond;
+
typedef struct {
int parent_ifindex;
in_addr_t local;
@@ -1212,6 +1248,7 @@ typedef struct {
gboolean egress_reset_all,
const NMVlanQosMapping *egress_map,
gsize n_egress_map);
+
gboolean (*link_tun_add)(NMPlatform *self,
const char *name,
const NMPlatformLnkTun *props,
@@ -1664,9 +1701,18 @@ nm_platform_link_bridge_change(NMPlatform *self, int ifindex, const NMPlatformLn
}
static inline int
-nm_platform_link_bond_add(NMPlatform *self, const char *name, const NMPlatformLink **out_link)
+nm_platform_link_bond_change(NMPlatform *self, int ifindex, const NMPlatformLnkBond *props)
+{
+ return nm_platform_link_change(self, NM_LINK_TYPE_BOND, ifindex, props);
+}
+
+static inline int
+nm_platform_link_bond_add(NMPlatform *self,
+ const char *name,
+ const NMPlatformLnkBond *props,
+ const NMPlatformLink **out_link)
{
- return nm_platform_link_add(self, NM_LINK_TYPE_BOND, name, 0, NULL, 0, 0, NULL, out_link);
+ return nm_platform_link_add(self, NM_LINK_TYPE_BOND, name, 0, NULL, 0, 0, props, out_link);
}
static inline int
@@ -2000,6 +2046,8 @@ const NMPObject *nm_platform_link_get_lnk(NMPlatform *self,
int ifindex,
NMLinkType link_type,
const NMPlatformLink **out_link);
+const NMPlatformLnkBond *
+nm_platform_link_get_lnk_bond(NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkBridge *
nm_platform_link_get_lnk_bridge(NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkGre *
@@ -2294,6 +2342,7 @@ gboolean nm_platform_tc_sync(NMPlatform *self,
GPtrArray *known_tfilters);
const char *nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len);
+const char *nm_platform_lnk_bond_to_string(const NMPlatformLnkBond *lnk, char *buf, gsize len);
const char *nm_platform_lnk_bridge_to_string(const NMPlatformLnkBridge *lnk, char *buf, gsize len);
const char *nm_platform_lnk_gre_to_string(const NMPlatformLnkGre *lnk, char *buf, gsize len);
const char *
@@ -2334,6 +2383,7 @@ const char *
nm_platform_wireguard_peer_to_string(const struct _NMPWireGuardPeer *peer, char *buf, gsize len);
int nm_platform_link_cmp(const NMPlatformLink *a, const NMPlatformLink *b);
+int nm_platform_lnk_bond_cmp(const NMPlatformLnkBond *a, const NMPlatformLnkBond *b);
int nm_platform_lnk_bridge_cmp(const NMPlatformLnkBridge *a, const NMPlatformLnkBridge *b);
int nm_platform_lnk_gre_cmp(const NMPlatformLnkGre *a, const NMPlatformLnkGre *b);
int nm_platform_lnk_infiniband_cmp(const NMPlatformLnkInfiniband *a,
@@ -2423,6 +2473,7 @@ void nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj,
void nm_platform_routing_rule_hash_update(const NMPlatformRoutingRule *obj,
NMPlatformRoutingRuleCmpType cmp_type,
NMHashState *h);
+void nm_platform_lnk_bond_hash_update(const NMPlatformLnkBond *obj, NMHashState *h);
void nm_platform_lnk_bridge_hash_update(const NMPlatformLnkBridge *obj, NMHashState *h);
void nm_platform_lnk_gre_hash_update(const NMPlatformLnkGre *obj, NMHashState *h);
void nm_platform_lnk_infiniband_hash_update(const NMPlatformLnkInfiniband *obj, NMHashState *h);
diff --git a/src/libnm-platform/nmp-base.h b/src/libnm-platform/nmp-base.h
index 4863168855..c288ab49b3 100644
--- a/src/libnm-platform/nmp-base.h
+++ b/src/libnm-platform/nmp-base.h
@@ -147,6 +147,7 @@ typedef enum _nm_packed {
NMP_OBJECT_TYPE_LNK_VRF,
NMP_OBJECT_TYPE_LNK_VXLAN,
NMP_OBJECT_TYPE_LNK_WIREGUARD,
+ NMP_OBJECT_TYPE_LNK_BOND,
__NMP_OBJECT_TYPE_LAST,
NMP_OBJECT_TYPE_MAX = __NMP_OBJECT_TYPE_LAST - 1,
diff --git a/src/libnm-platform/nmp-object.c b/src/libnm-platform/nmp-object.c
index 99e2287691..b36940b91f 100644
--- a/src/libnm-platform/nmp-object.c
+++ b/src/libnm-platform/nmp-object.c
@@ -3472,4 +3472,16 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_wireguard_hash_update,
.cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_wireguard_cmp,
},
+ [NMP_OBJECT_TYPE_LNK_BOND - 1] =
+ {
+ .parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
+ .obj_type = NMP_OBJECT_TYPE_LNK_BOND,
+ .sizeof_data = sizeof(NMPObjectLnkBond),
+ .sizeof_public = sizeof(NMPlatformLnkBond),
+ .obj_type_name = "bond",
+ .lnk_link_type = NM_LINK_TYPE_BOND,
+ .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_lnk_bond_to_string,
+ .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_bond_hash_update,
+ .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_bond_cmp,
+ },
};
diff --git a/src/libnm-platform/nmp-object.h b/src/libnm-platform/nmp-object.h
index d0c0463f13..345f597d3a 100644
--- a/src/libnm-platform/nmp-object.h
+++ b/src/libnm-platform/nmp-object.h
@@ -250,6 +250,10 @@ typedef struct {
} NMPObjectLnkBridge;
typedef struct {
+ NMPlatformLnkBond _public;
+} NMPObjectLnkBond;
+
+typedef struct {
NMPlatformLnkGre _public;
} NMPObjectLnkGre;
@@ -352,6 +356,9 @@ struct _NMPObject {
NMPlatformLnkBridge lnk_bridge;
NMPObjectLnkBridge _lnk_bridge;
+ NMPlatformLnkBond lnk_bond;
+ NMPObjectLnkBond _lnk_bond;
+
NMPlatformLnkGre lnk_gre;
NMPObjectLnkGre _lnk_gre;
@@ -493,6 +500,7 @@ _NMP_OBJECT_TYPE_IS_OBJ_WITH_IFINDEX(NMPObjectType obj_type)
case NMP_OBJECT_TYPE_TFILTER:
case NMP_OBJECT_TYPE_LNK_BRIDGE:
+ case NMP_OBJECT_TYPE_LNK_BOND:
case NMP_OBJECT_TYPE_LNK_GRE:
case NMP_OBJECT_TYPE_LNK_GRETAP:
case NMP_OBJECT_TYPE_LNK_INFINIBAND: