summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFernando Fernandez Mancera <ffmancera@riseup.net>2023-05-03 10:52:35 +0200
committerFernando Fernandez Mancera <ffmancera@riseup.net>2023-05-03 10:52:35 +0200
commit859faa6509e7bfb9e0257c38c35f4ed5fd768134 (patch)
treef803c1aac7608fd14c83d72b24024eb6c52082aa
parentd3b54963622f242db1ebeda21dedd9558b484355 (diff)
parent2f0571f1930ff2c11de4f48b4433ca5fe6c897a0 (diff)
downloadNetworkManager-859faa6509e7bfb9e0257c38c35f4ed5fd768134.tar.gz
merge: branch 'ff/bond_port_options'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1564
-rw-r--r--src/core/devices/nm-device-bond.c90
-rw-r--r--src/core/devices/nm-device.c3
-rw-r--r--src/core/platform/nm-fake-platform.c28
-rw-r--r--src/core/platform/tests/test-link.c36
-rw-r--r--src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c23
-rw-r--r--src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c1
-rw-r--r--src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h2
-rw-r--r--src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c4
-rw-r--r--src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c1
-rw-r--r--src/libnm-base/nm-base.h1
-rw-r--r--src/libnm-client-impl/libnm.ver1
-rw-r--r--src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in4
-rw-r--r--src/libnm-core-impl/nm-setting-bond-port.c50
-rw-r--r--src/libnm-core-public/nm-setting-bond-port.h4
-rw-r--r--src/libnm-glib-aux/nm-shared-utils.h8
-rw-r--r--src/libnm-platform/nm-linux-platform.c91
-rw-r--r--src/libnm-platform/nm-platform.c107
-rw-r--r--src/libnm-platform/nm-platform.h32
-rw-r--r--src/libnmc-setting/nm-meta-setting-desc.c6
-rw-r--r--src/libnmc-setting/settings-docs.h.in1
-rw-r--r--src/nmcli/gen-metadata-nm-settings-nmcli.xml.in3
21 files changed, 440 insertions, 56 deletions
diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c
index 8e0cf33fe6..10fe809204 100644
--- a/src/core/devices/nm-device-bond.c
+++ b/src/core/devices/nm-device-bond.c
@@ -229,24 +229,23 @@ controller_update_port_connection(NMDevice *self,
NMConnection *connection,
GError **error)
{
- NMSettingBondPort *s_port;
- int ifindex_port = nm_device_get_ifindex(port);
- NMConnection *applied_connection = nm_device_get_applied_connection(self);
- uint queue_id = NM_BOND_PORT_QUEUE_ID_DEF;
- gs_free char *queue_id_str = NULL;
+ 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);
- queue_id_str =
- nm_platform_sysctl_slave_get_option(nm_device_get_platform(self), ifindex_port, "queue_id");
- if (queue_id_str) {
- queue_id =
- _nm_utils_ascii_str_to_int64(queue_id_str, 10, 0, 65535, NM_BOND_PORT_QUEUE_ID_DEF);
- g_object_set(s_port, NM_SETTING_BOND_PORT_QUEUE_ID, queue_id, NULL);
- } else
- _LOGW(LOGD_BOND, "failed to read bond port setting '%s'", NM_SETTING_BOND_PORT_QUEUE_ID);
+ 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_MASTER,
@@ -637,23 +636,54 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason)
static void
commit_port_options(NMDevice *bond_device, NMDevice *port, NMSettingBondPort *s_port)
{
- char queue_id_str[IFNAMSIZ + NM_STRLEN(":") + 5 + 100];
-
- /*
- * The queue-id of bond port is read only, we should modify bond interface using:
- * echo "eth1:2" > /sys/class/net/bond0/bonding/queue_id
- * Kernel allows parital editing, so no need to care about other bond ports.
- */
- g_snprintf(queue_id_str,
- sizeof(queue_id_str),
- "%s:%" G_GUINT32_FORMAT,
- nm_device_get_iface(port),
- s_port ? nm_setting_bond_port_get_queue_id(s_port) : NM_BOND_PORT_QUEUE_ID_DEF);
-
- nm_platform_sysctl_master_set_option(nm_device_get_platform(bond_device),
- nm_device_get_ifindex(bond_device),
- "queue_id",
- queue_id_str);
+ 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_SLAVE_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,
+ }),
+ 0);
}
static NMTernary
diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c
index c7d9f9d89b..ed840044c5 100644
--- a/src/core/devices/nm-device.c
+++ b/src/core/devices/nm-device.c
@@ -2861,7 +2861,7 @@ nm_device_link_properties_set(NMDevice *self, gboolean reapply)
_RESET(NM_PLATFORM_LINK_CHANGE_GSO_MAX_SEGMENTS, gso_max_segments);
_RESET(NM_PLATFORM_LINK_CHANGE_GRO_MAX_SIZE, gro_max_size);
- if (nm_platform_link_change(platform, ifindex, &props, flags)) {
+ if (nm_platform_link_change(platform, ifindex, &props, NULL, flags)) {
_LOGD(LOGD_DEVICE, "link properties successfully set");
} else {
_LOGW(LOGD_DEVICE, "failure setting link properties");
@@ -2888,6 +2888,7 @@ link_properties_reset(NMDevice *self)
if (nm_platform_link_change(platform,
ifindex,
&priv->link_props_state.props,
+ NULL,
priv->link_props_state.flags)) {
_LOGD(LOGD_DEVICE, "link properties successfully reset");
} else {
diff --git a/src/core/platform/nm-fake-platform.c b/src/core/platform/nm-fake-platform.c
index 5a16148514..0c1790e797 100644
--- a/src/core/platform/nm-fake-platform.c
+++ b/src/core/platform/nm-fake-platform.c
@@ -701,6 +701,33 @@ link_supports_sriov(NMPlatform *platform, int ifindex)
}
static gboolean
+link_change(NMPlatform *platform,
+ int ifindex,
+ NMPlatformLinkProps *props,
+ NMPortKind port_kind,
+ const NMPlatformLinkPortData *port_data,
+ NMPlatformLinkChangeFlags flags)
+{
+ NMFakePlatformLink *device = link_get(platform, ifindex);
+ nm_auto_nmpobj NMPObject *obj_tmp = NULL;
+
+ switch (port_kind) {
+ case NM_PORT_KIND_BOND:
+ obj_tmp = nmp_object_clone(device->obj, FALSE);
+ obj_tmp->link.port_kind = NM_PORT_KIND_BOND;
+ obj_tmp->link.port_data.bond.queue_id = port_data->bond.queue_id;
+ obj_tmp->link.port_data.bond.prio_has = port_data->bond.prio_has;
+ obj_tmp->link.port_data.bond.prio = port_data->bond.prio;
+ link_set_obj(platform, device, obj_tmp);
+ return TRUE;
+ case NM_PORT_KIND_NONE:
+ return TRUE;
+ }
+
+ return nm_assert_unreachable_val(TRUE);
+}
+
+static gboolean
link_enslave(NMPlatform *platform, int master, int slave)
{
NMFakePlatformLink *device = link_get(platform, slave);
@@ -1394,6 +1421,7 @@ nm_fake_platform_class_init(NMFakePlatformClass *klass)
platform_class->link_set_address = link_set_address;
platform_class->link_set_mtu = link_set_mtu;
+ platform_class->link_change = link_change;
platform_class->link_change_flags = link_change_flags;
platform_class->link_get_driver_info = link_get_driver_info;
diff --git a/src/core/platform/tests/test-link.c b/src/core/platform/tests/test-link.c
index 1b5b800353..5bec6082b7 100644
--- a/src/core/platform/tests/test-link.c
+++ b/src/core/platform/tests/test-link.c
@@ -122,7 +122,7 @@ software_add(NMLinkType link_type, const char *name)
gboolean bond0_exists = !!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "bond0");
int r;
const NMPlatformLnkBond nm_platform_lnk_bond_default = {
- .mode = 3,
+ .mode = nmtst_rand_select(3, 1),
};
r = nm_platform_link_bond_add(NM_PLATFORM_GET, name, &nm_platform_lnk_bond_default, NULL);
@@ -273,6 +273,38 @@ test_slave(int master, int type, SignalData *master_changed)
else
g_assert(!nm_platform_link_is_up(NM_PLATFORM_GET, ifindex));
+ if (NM_IN_SET(link_type, NM_LINK_TYPE_BOND)) {
+ NMPlatformLinkBondPort bond_port;
+ gboolean prio_has;
+ gboolean prio_supported;
+ const NMPlatformLink *link;
+ const NMPlatformLnkBond *lnk;
+
+ link = nmtstp_link_get_typed(NM_PLATFORM_GET, 0, SLAVE_NAME, NM_LINK_TYPE_DUMMY);
+ g_assert(link);
+
+ lnk = nm_platform_link_get_lnk_bond(NM_PLATFORM_GET, master, NULL);
+ g_assert(lnk);
+
+ g_assert(NM_IN_SET(lnk->mode, 3, 1));
+ prio_supported = (lnk->mode == 1);
+ prio_has = nmtst_get_rand_bool() && prio_supported;
+
+ bond_port = (NMPlatformLinkBondPort){
+ .queue_id = 5,
+ .prio_has = prio_has,
+ .prio = prio_has ? 6 : 0,
+ };
+
+ g_assert(nm_platform_link_change(NM_PLATFORM_GET, ifindex, NULL, &bond_port, 0));
+ accept_signals(link_changed, 1, 3);
+
+ link = nmtstp_link_get(NM_PLATFORM_GET, ifindex, SLAVE_NAME);
+ g_assert(link);
+ g_assert_cmpint(link->port_data.bond.queue_id, ==, 5);
+ g_assert(link->port_data.bond.prio_has || link->port_data.bond.prio == 0);
+ }
+
test_link_changed_signal_arg1 = FALSE;
test_link_changed_signal_arg2 = FALSE;
g_signal_connect(NM_PLATFORM_GET,
@@ -2664,7 +2696,7 @@ test_link_set_properties(void)
| NM_PLATFORM_LINK_CHANGE_GSO_MAX_SEGMENTS;
ifindex = nmtstp_link_dummy_add(NM_PLATFORM_GET, FALSE, "dummy1")->ifindex;
- g_assert(nm_platform_link_change(NM_PLATFORM_GET, ifindex, &props, flags));
+ g_assert(nm_platform_link_change(NM_PLATFORM_GET, ifindex, &props, NULL, flags));
link = nmtstp_link_get(NM_PLATFORM_GET, ifindex, "dummy1");
g_assert(link);
diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
index cf2a030f22..4009574472 100644
--- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
+++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
@@ -5590,6 +5590,7 @@ make_bond_port_setting(shvarFile *ifcfg)
gs_free char *value_to_free = NULL;
const char *value;
guint queue_id;
+ gint32 prio;
g_return_val_if_fail(ifcfg != NULL, FALSE);
@@ -5598,11 +5599,23 @@ make_bond_port_setting(shvarFile *ifcfg)
s_port = nm_setting_bond_port_new();
queue_id =
_nm_utils_ascii_str_to_uint64(value, 10, 0, G_MAXUINT16, NM_BOND_PORT_QUEUE_ID_DEF);
- if (errno != 0) {
- PARSE_WARNING("Invalid bond port queue_id value '%s'", value);
- return s_port;
- }
- g_object_set(G_OBJECT(s_port), NM_SETTING_BOND_PORT_QUEUE_ID, queue_id, NULL);
+ if (errno != 0)
+ PARSE_WARNING("Invalid bond port queue_id value BOND_PORT_QUEUE_ID '%s'", value);
+ else
+ g_object_set(G_OBJECT(s_port), NM_SETTING_BOND_PORT_QUEUE_ID, queue_id, NULL);
+ }
+
+ nm_clear_g_free(&value_to_free);
+ value = svGetValue(ifcfg, "BOND_PORT_PRIO", &value_to_free);
+ if (value) {
+ if (!s_port)
+ s_port = nm_setting_bond_port_new();
+ prio =
+ _nm_utils_ascii_str_to_int64(value, 10, G_MININT32, G_MAXINT32, NM_BOND_PORT_PRIO_DEF);
+ if (errno != 0)
+ PARSE_WARNING("Invalid bond port prio value BOND_PORT_PRIO '%s'", value);
+ else
+ g_object_set(G_OBJECT(s_port), NM_SETTING_BOND_PORT_PRIO, prio, NULL);
}
return s_port;
diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c
index f9cce442df..d46d71f99a 100644
--- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c
+++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c
@@ -827,6 +827,7 @@ const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = {
_KEY_TYPE("BAND", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
_KEY_TYPE("BONDING_MASTER", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
_KEY_TYPE("BONDING_OPTS", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
+ _KEY_TYPE("BOND_PORT_PRIO", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
_KEY_TYPE("BOND_PORT_QUEUE_ID", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
_KEY_TYPE("BOOTPROTO", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
_KEY_TYPE("BRIDGE", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h
index ffc3679aee..51b118e3d3 100644
--- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h
+++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h
@@ -33,7 +33,7 @@ typedef struct {
NMSIfcfgKeyTypeFlags key_flags;
} NMSIfcfgKeyTypeInfo;
-extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[262];
+extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[263];
const NMSIfcfgKeyTypeInfo *nms_ifcfg_well_known_key_find_info(const char *key, gssize *out_idx);
diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
index 3cf93e0656..acee4b215e 100644
--- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
+++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
@@ -1911,8 +1911,10 @@ write_bond_port_setting(NMConnection *connection, shvarFile *ifcfg)
NMSettingBondPort *s_port;
s_port = _nm_connection_get_setting(connection, NM_TYPE_SETTING_BOND_PORT);
- if (s_port)
+ if (s_port) {
svSetValueInt64(ifcfg, "BOND_PORT_QUEUE_ID", nm_setting_bond_port_get_queue_id(s_port));
+ svSetValueInt64(ifcfg, "BOND_PORT_PRIO", nm_setting_bond_port_get_prio(s_port));
+ }
}
static gboolean
diff --git a/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
index 40ff7c670e..0172747481 100644
--- a/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
+++ b/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
@@ -8352,6 +8352,7 @@ test_write_bond_port(void)
s_bond_port = _nm_connection_new_setting(connection, NM_TYPE_SETTING_BOND_PORT);
g_object_set(s_bond_port, NM_SETTING_BOND_PORT_QUEUE_ID, 1, NULL);
+ g_object_set(s_bond_port, NM_SETTING_BOND_PORT_PRIO, 10, NULL);
nmtst_assert_connection_verifies(connection);
diff --git a/src/libnm-base/nm-base.h b/src/libnm-base/nm-base.h
index 77d2ef0a16..440fbc90c7 100644
--- a/src/libnm-base/nm-base.h
+++ b/src/libnm-base/nm-base.h
@@ -392,6 +392,7 @@ typedef struct {
/****************************************************************************/
#define NM_BOND_PORT_QUEUE_ID_DEF 0
+#define NM_BOND_PORT_PRIO_DEF 0
/****************************************************************************/
diff --git a/src/libnm-client-impl/libnm.ver b/src/libnm-client-impl/libnm.ver
index d0745e2515..f473da2041 100644
--- a/src/libnm-client-impl/libnm.ver
+++ b/src/libnm-client-impl/libnm.ver
@@ -1928,6 +1928,7 @@ global:
libnm_1_44_0 {
global:
+ nm_setting_bond_port_get_prio;
nm_setting_gsm_get_initial_eps_apn;
nm_setting_gsm_get_initial_eps_config;
nm_setting_ip6_config_get_dhcp_pd_hint;
diff --git a/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in b/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in
index bbb4906af7..4e17a45baa 100644
--- a/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in
+++ b/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in
@@ -584,6 +584,10 @@
<setting name="bond-port"
gtype="NMSettingBondPort"
>
+ <property name="prio"
+ dbus-type="i"
+ gprop-type="gint"
+ />
<property name="queue-id"
dbus-type="u"
gprop-type="guint"
diff --git a/src/libnm-core-impl/nm-setting-bond-port.c b/src/libnm-core-impl/nm-setting-bond-port.c
index 7ea82a763e..e89179023d 100644
--- a/src/libnm-core-impl/nm-setting-bond-port.c
+++ b/src/libnm-core-impl/nm-setting-bond-port.c
@@ -22,9 +22,10 @@
/*****************************************************************************/
-NM_GOBJECT_PROPERTIES_DEFINE(NMSettingBondPort, PROP_QUEUE_ID, );
+NM_GOBJECT_PROPERTIES_DEFINE(NMSettingBondPort, PROP_QUEUE_ID, PROP_PRIO, );
typedef struct {
+ gint32 prio;
guint32 queue_id;
} NMSettingBondPortPrivate;
@@ -65,6 +66,22 @@ nm_setting_bond_port_get_queue_id(NMSettingBondPort *setting)
return NM_SETTING_BOND_PORT_GET_PRIVATE(setting)->queue_id;
}
+/**
+ * nm_setting_bond_port_get_prio:
+ * @setting: the #NMSettingBondPort
+ *
+ * Returns: the #NMSettingBondPort:prio property of the setting
+ *
+ * Since: 1.44
+ **/
+gint32
+nm_setting_bond_port_get_prio(NMSettingBondPort *setting)
+{
+ g_return_val_if_fail(NM_IS_SETTING_BOND_PORT(setting), 0);
+
+ return NM_SETTING_BOND_PORT_GET_PRIVATE(setting)->prio;
+}
+
/*****************************************************************************/
static gboolean
@@ -148,7 +165,7 @@ nm_setting_bond_port_class_init(NMSettingBondPortClass *klass)
**/
/* ---ifcfg-rh---
* property: queue-id
- * variable: BONDING_OPTS: queue-id=
+ * variable: BOND_PORT_QUEUE_ID(+)
* values: 0 - 65535
* default: 0
* description: Queue ID.
@@ -165,6 +182,35 @@ nm_setting_bond_port_class_init(NMSettingBondPortClass *klass)
NMSettingBondPort,
_priv.queue_id);
+ /**
+ * NMSettingBondPort:prio:
+ *
+ * The port priority for bond active port re-selection during failover. A
+ * higher number means a higher priority in selection. The primary port has
+ * the highest priority. This option is only compatible with active-backup,
+ * balance-tlb and balance-alb modes.
+ *
+ * Since: 1.44
+ **/
+ /* ---ifcfg-rh---
+ * property: prio
+ * variable: BOND_PORT_PRIO(+)
+ * values: -2147483648 - 2147483647
+ * default: 0
+ * description: Port priority.
+ * ---end---
+ */
+ _nm_setting_property_define_direct_int32(properties_override,
+ obj_properties,
+ NM_SETTING_BOND_PORT_PRIO,
+ PROP_PRIO,
+ G_MININT32,
+ G_MAXINT32,
+ NM_BOND_PORT_PRIO_DEF,
+ NM_SETTING_PARAM_INFERRABLE,
+ NMSettingBondPort,
+ _priv.prio);
+
g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
_nm_setting_class_commit(setting_class,
diff --git a/src/libnm-core-public/nm-setting-bond-port.h b/src/libnm-core-public/nm-setting-bond-port.h
index 0b20e4a8cb..033c59b492 100644
--- a/src/libnm-core-public/nm-setting-bond-port.h
+++ b/src/libnm-core-public/nm-setting-bond-port.h
@@ -29,6 +29,7 @@ G_BEGIN_DECLS
#define NM_SETTING_BOND_PORT_SETTING_NAME "bond-port"
#define NM_SETTING_BOND_PORT_QUEUE_ID "queue-id"
+#define NM_SETTING_BOND_PORT_PRIO "prio"
typedef struct _NMSettingBondPortClass NMSettingBondPortClass;
@@ -41,6 +42,9 @@ NMSetting *nm_setting_bond_port_new(void);
NM_AVAILABLE_IN_1_34
guint32 nm_setting_bond_port_get_queue_id(NMSettingBondPort *setting);
+NM_AVAILABLE_IN_1_44
+gint32 nm_setting_bond_port_get_prio(NMSettingBondPort *setting);
+
G_END_DECLS
#endif /* __NM_SETTING_BOND_PORT_H__ */
diff --git a/src/libnm-glib-aux/nm-shared-utils.h b/src/libnm-glib-aux/nm-shared-utils.h
index 84ff6b6a1d..7233d77d40 100644
--- a/src/libnm-glib-aux/nm-shared-utils.h
+++ b/src/libnm-glib-aux/nm-shared-utils.h
@@ -93,6 +93,14 @@ G_STATIC_ASSERT(sizeof(int) == sizeof(gint32));
/*****************************************************************************/
+typedef enum _nm_packed {
+ /* No type, empty value */
+ NM_PORT_KIND_NONE,
+ NM_PORT_KIND_BOND,
+} NMPortKind;
+
+/*****************************************************************************/
+
typedef enum {
/* No type, used as error value */
diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c
index 4ca0948540..d0a61832e7 100644
--- a/src/libnm-platform/nm-linux-platform.c
+++ b/src/libnm-platform/nm-linux-platform.c
@@ -179,6 +179,8 @@ G_STATIC_ASSERT(RTA_MAX == (__RTA_MAX - 1));
/*****************************************************************************/
+#define IFLA_BOND_SLAVE_PRIO 9
+
#define IFLA_BOND_PEER_NOTIF_DELAY 28
#define IFLA_BOND_AD_LACP_ACTIVE 29
#define IFLA_BOND_MISSED_MAX 30
@@ -3385,9 +3387,11 @@ _new_from_nl_link(NMPlatform *platform,
if (tb[IFLA_LINKINFO]) {
static const struct nla_policy policy_link_info[] = {
- [IFLA_INFO_KIND] = {.type = NLA_STRING},
- [IFLA_INFO_DATA] = {.type = NLA_NESTED},
- [IFLA_INFO_XSTATS] = {.type = NLA_NESTED},
+ [IFLA_INFO_KIND] = {.type = NLA_STRING},
+ [IFLA_INFO_DATA] = {.type = NLA_NESTED},
+ [IFLA_INFO_XSTATS] = {.type = NLA_NESTED},
+ [IFLA_INFO_SLAVE_KIND] = {.type = NLA_STRING},
+ [IFLA_INFO_SLAVE_DATA] = {.type = NLA_NESTED},
};
struct nlattr *li[G_N_ELEMENTS(policy_link_info)];
@@ -3398,6 +3402,49 @@ _new_from_nl_link(NMPlatform *platform,
nl_info_kind = nla_get_string(li[IFLA_INFO_KIND]);
nl_info_data = li[IFLA_INFO_DATA];
+
+ if (li[IFLA_INFO_SLAVE_KIND]) {
+ const char *s = nla_get_string(li[IFLA_INFO_SLAVE_KIND]);
+
+ if (nm_streq(s, "bond"))
+ obj->link.port_kind = NM_PORT_KIND_BOND;
+ }
+
+ if (li[IFLA_INFO_SLAVE_DATA]) {
+ static const struct nla_policy policy_bond_port[] = {
+ [IFLA_BOND_SLAVE_QUEUE_ID] = {.type = NLA_U16},
+ [IFLA_BOND_SLAVE_PRIO] = {.type = NLA_S32},
+ };
+ struct nlattr *bp[G_N_ELEMENTS(policy_bond_port)];
+
+ switch (obj->link.port_kind) {
+ case NM_PORT_KIND_BOND:
+ if (nla_parse_nested_arr(bp, li[IFLA_INFO_SLAVE_DATA], policy_bond_port) < 0)
+ return NULL;
+
+ if (bp[IFLA_BOND_SLAVE_QUEUE_ID])
+ obj->link.port_data.bond.queue_id = nla_get_u16(bp[IFLA_BOND_SLAVE_QUEUE_ID]);
+
+ if (bp[IFLA_BOND_SLAVE_PRIO]) {
+ obj->link.port_data.bond.prio = nla_get_s32(bp[IFLA_BOND_SLAVE_PRIO]);
+ obj->link.port_data.bond.prio_has = TRUE;
+ if (!_nm_platform_kernel_support_detected(
+ NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_BOND_SLAVE_PRIO)) {
+ /* support for IFLA_BOND_SLAVE_PRIO was added in 0a2ff7cc8ad48a86939a91bd3457f38e59e741a1,
+ * kernel 6.0, 2 October 2022.
+ *
+ * We can only detect support if the attribute is present. A missing attribute
+ * is not conclusive. */
+ _nm_platform_kernel_support_init(
+ NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_BOND_SLAVE_PRIO,
+ 1);
+ }
+ }
+ break;
+ case NM_PORT_KIND_NONE:
+ break;
+ }
+ }
}
if (tb[IFLA_TXQLEN])
@@ -8440,12 +8487,16 @@ link_delete(NMPlatform *platform, int ifindex)
}
static gboolean
-link_change(NMPlatform *platform,
- int ifindex,
- NMPlatformLinkProps *props,
- NMPlatformLinkChangeFlags flags)
+link_change(NMPlatform *platform,
+ int ifindex,
+ NMPlatformLinkProps *props,
+ NMPortKind port_kind,
+ const NMPlatformLinkPortData *port_data,
+ NMPlatformLinkChangeFlags flags)
{
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
+ struct nlattr *nl_info;
+ struct nlattr *nl_port_data;
nlmsg = _nl_msg_new_link(RTM_NEWLINK, 0, ifindex, NULL);
if (!nlmsg)
@@ -8460,6 +8511,32 @@ link_change(NMPlatform *platform,
if (flags & NM_PLATFORM_LINK_CHANGE_GRO_MAX_SIZE)
NLA_PUT_U32(nlmsg, IFLA_GRO_MAX_SIZE, props->gro_max_size);
+ switch (port_kind) {
+ case NM_PORT_KIND_BOND:
+
+ nm_assert(port_data);
+
+ if (!(nl_info = nla_nest_start(nlmsg, IFLA_LINKINFO)))
+ goto nla_put_failure;
+
+ nm_assert(nm_streq0("bond", nm_link_type_to_rtnl_type_string(NM_LINK_TYPE_BOND)));
+ NLA_PUT_STRING(nlmsg, IFLA_INFO_SLAVE_KIND, "bond");
+
+ if (!(nl_port_data = nla_nest_start(nlmsg, IFLA_INFO_SLAVE_DATA)))
+ goto nla_put_failure;
+
+ NLA_PUT_U16(nlmsg, IFLA_BOND_SLAVE_QUEUE_ID, port_data->bond.queue_id);
+
+ if (port_data->bond.prio_has)
+ NLA_PUT_S32(nlmsg, IFLA_BOND_SLAVE_PRIO, port_data->bond.prio);
+
+ nla_nest_end(nlmsg, nl_port_data);
+ nla_nest_end(nlmsg, nl_info);
+ break;
+ case NM_PORT_KIND_NONE:
+ break;
+ }
+
return do_change_link(platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) == 0;
nla_put_failure:
g_return_val_if_reached(FALSE);
diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c
index 779c5fba51..defa08eb27 100644
--- a/src/libnm-platform/nm-platform.c
+++ b/src/libnm-platform/nm-platform.c
@@ -62,6 +62,41 @@ G_STATIC_ASSERT(sizeof(((NMPlatformLink *) NULL)->l_perm_address.data) == _NM_UT
G_STATIC_ASSERT(sizeof(((NMPlatformLink *) NULL)->l_broadcast.data) == _NM_UTILS_HWADDR_LEN_MAX);
static const char *
+_nmp_link_port_data_to_string(NMPortKind port_kind,
+ const NMPlatformLinkPortData *port_data,
+ char *sbuf,
+ gsize sbuf_len)
+{
+ const char *sbuf0 = sbuf;
+ char s0[120];
+
+ nm_assert(port_data);
+
+ switch (port_kind) {
+ case NM_PORT_KIND_NONE:
+ nm_strbuf_append_c(&sbuf, &sbuf_len, '\0');
+ goto out;
+ case NM_PORT_KIND_BOND:
+ nm_strbuf_append(&sbuf,
+ &sbuf_len,
+ "port bond queue-id %u%s",
+ port_data->bond.queue_id,
+ port_data->bond.prio_has || port_data->bond.prio != 0
+ ? nm_sprintf_buf(s0,
+ " prio%s %u",
+ port_data->bond.prio_has ? "" : "?",
+ port_data->bond.prio)
+ : "");
+ goto out;
+ }
+
+ nm_strbuf_append(&sbuf, &sbuf_len, "invalid-port-type %d", (int) port_kind);
+
+out:
+ return sbuf0;
+}
+
+static const char *
_nmp_link_address_to_string(const NMPLinkAddress *addr,
char buf[static(_NM_UTILS_HWADDR_LEN_MAX * 3)])
{
@@ -2137,14 +2172,21 @@ gboolean
nm_platform_link_change(NMPlatform *self,
int ifindex,
NMPlatformLinkProps *props,
+ NMPlatformLinkBondPort *bond_port,
NMPlatformLinkChangeFlags flags)
{
+ char sbuf_prio[100];
+
_CHECK_SELF(self, klass, FALSE);
g_return_val_if_fail(ifindex >= 0, FALSE);
- if (flags == 0)
- return TRUE;
+ nm_assert(!NM_FLAGS_ANY(flags,
+ NM_PLATFORM_LINK_CHANGE_TX_QUEUE_LENGTH
+ | NM_PLATFORM_LINK_CHANGE_GSO_MAX_SIZE
+ | NM_PLATFORM_LINK_CHANGE_GSO_MAX_SEGMENTS
+ | NM_PLATFORM_LINK_CHANGE_GRO_MAX_SIZE)
+ || props);
if (_LOGD_ENABLED()) {
nm_auto_free_gstring GString *str = g_string_new("");
@@ -2157,6 +2199,18 @@ nm_platform_link_change(NMPlatform *self,
g_string_append_printf(str, "gso_max_segments %u ", props->gso_max_segments);
if (flags & NM_PLATFORM_LINK_CHANGE_GRO_MAX_SIZE)
g_string_append_printf(str, "gro_max_size %u ", props->gro_max_size);
+ if (bond_port) {
+ nm_assert(bond_port->prio_has || bond_port->prio == 0);
+ g_string_append_printf(str,
+ "bond-port queue-id %d %s",
+ bond_port->queue_id,
+ bond_port->prio_has || bond_port->prio != 0
+ ? nm_sprintf_buf(sbuf_prio,
+ "prio%s %" G_GINT32_FORMAT,
+ !bond_port->prio_has ? "?" : "",
+ bond_port->prio)
+ : "");
+ }
if (str->len > 0 && str->str[str->len - 1] == ' ')
g_string_truncate(str, str->len - 1);
@@ -2164,7 +2218,12 @@ nm_platform_link_change(NMPlatform *self,
_LOG3D("link: change: %s", str->str);
}
- return klass->link_change(self, ifindex, props, flags);
+ return klass->link_change(self,
+ ifindex,
+ props,
+ bond_port ? NM_PORT_KIND_BOND : NM_PORT_KIND_NONE,
+ (const NMPlatformLinkPortData *) bond_port,
+ flags);
}
/**
@@ -5851,6 +5910,7 @@ nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len)
char *s;
gsize l;
char str_addrmode[30];
+ char str_port_data[200];
char str_address[_NM_UTILS_HWADDR_LEN_MAX * 3];
char str_perm_address[_NM_UTILS_HWADDR_LEN_MAX * 3];
char str_broadcast[_NM_UTILS_HWADDR_LEN_MAX * 3];
@@ -5894,6 +5954,11 @@ nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len)
_nmp_link_address_to_string(&link->l_perm_address, str_perm_address);
_nmp_link_address_to_string(&link->l_broadcast, str_broadcast);
+ _nmp_link_port_data_to_string(link->port_kind,
+ &link->port_data,
+ str_port_data,
+ sizeof(str_port_data));
+
str_link_type = nm_link_type_to_string(link->type);
g_snprintf(
@@ -5915,6 +5980,7 @@ nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len)
"%s%s" /* l_broadcast */
"%s%s" /* inet6_token */
"%s%s" /* driver */
+ "%s%s" /* port_data */
" tx-queue-len %u"
" gso-max-size %u"
" gso-max-segs %u"
@@ -5951,6 +6017,7 @@ nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len)
: "",
link->driver ? " driver " : "",
link->driver ?: "",
+ NM_PRINT_FMT_QUOTED2(str_port_data[0] != '\0', " ", str_port_data, ""),
link->link_props.tx_queue_length,
link->link_props.gso_max_size,
link->link_props.gso_max_segments,
@@ -7806,6 +7873,7 @@ nm_platform_link_hash_update(const NMPlatformLink *obj, NMHashState *h)
obj->link_props.gso_max_size,
obj->link_props.gso_max_segments,
obj->link_props.gro_max_size,
+ obj->port_kind,
obj->rx_packets,
obj->rx_bytes,
obj->tx_packets,
@@ -7824,6 +7892,20 @@ nm_platform_link_hash_update(const NMPlatformLink *obj, NMHashState *h)
nm_hash_update_mem(h,
obj->l_broadcast.data,
NM_MIN(obj->l_broadcast.len, sizeof(obj->l_broadcast.data)));
+
+ switch (obj->port_kind) {
+ case NM_PORT_KIND_NONE:
+ break;
+ case NM_PORT_KIND_BOND:
+ nm_platform_link_bond_port_hash_update(&obj->port_data.bond, h);
+ break;
+ }
+}
+
+void
+nm_platform_link_bond_port_hash_update(const NMPlatformLinkBondPort *obj, NMHashState *h)
+{
+ nm_hash_update_vals(h, obj->prio, obj->queue_id, NM_HASH_COMBINE_BOOLS(guint8, obj->prio_has));
}
int
@@ -7857,6 +7939,14 @@ nm_platform_link_cmp(const NMPlatformLink *a, const NMPlatformLink *b)
NM_CMP_FIELD(a, b, link_props.gso_max_size);
NM_CMP_FIELD(a, b, link_props.gso_max_segments);
NM_CMP_FIELD(a, b, link_props.gro_max_size);
+ NM_CMP_FIELD(a, b, port_kind);
+ switch (a->port_kind) {
+ case NM_PORT_KIND_NONE:
+ break;
+ case NM_PORT_KIND_BOND:
+ NM_CMP_RETURN(nm_platform_link_bond_port_cmp(&a->port_data.bond, &b->port_data.bond));
+ break;
+ }
NM_CMP_FIELD(a, b, rx_packets);
NM_CMP_FIELD(a, b, rx_bytes);
NM_CMP_FIELD(a, b, tx_packets);
@@ -7942,6 +8032,17 @@ nm_platform_lnk_bond_hash_update(const NMPlatformLnkBond *obj, NMHashState *h)
}
int
+nm_platform_link_bond_port_cmp(const NMPlatformLinkBondPort *a, const NMPlatformLinkBondPort *b)
+{
+ NM_CMP_SELF(a, b);
+ NM_CMP_FIELD(a, b, queue_id);
+ NM_CMP_FIELD(a, b, prio);
+ NM_CMP_FIELD_BOOL(a, b, prio_has);
+
+ return 0;
+}
+
+int
nm_platform_lnk_bond_cmp(const NMPlatformLnkBond *a, const NMPlatformLnkBond *b)
{
NM_CMP_SELF(a, b);
diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h
index 1fe0b3cbe7..d987287c74 100644
--- a/src/libnm-platform/nm-platform.h
+++ b/src/libnm-platform/nm-platform.h
@@ -169,6 +169,16 @@ struct _NMPlatformObjWithIfindex {
__NMPlatformObjWithIfindex_COMMON;
} _nm_alignas(NMPlatformObject);
+typedef struct {
+ gint32 prio;
+ guint16 queue_id;
+ bool prio_has : 1;
+} NMPlatformLinkBondPort;
+
+typedef union {
+ NMPlatformLinkBondPort bond;
+} NMPlatformLinkPortData;
+
struct _NMPlatformLink {
__NMPlatformObjWithIfindex_COMMON;
char name[NMP_IFNAMSIZ];
@@ -221,6 +231,12 @@ struct _NMPlatformLink {
NMPlatformLinkProps link_props;
+ /* an interface can only hold IFLA_INFO_SLAVE_DATA for one link type */
+ NMPlatformLinkPortData port_data;
+
+ /* IFLA_INFO_SLAVE_KIND */
+ NMPortKind port_kind;
+
/* @connected is mostly identical to (@n_ifi_flags & IFF_UP). Except for bridge/bond masters,
* where we coerce the link as disconnect if it has no slaves. */
bool connected : 1;
@@ -1012,6 +1028,8 @@ typedef enum {
* were added at the same time. */
NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_IP_PROTO,
+ NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_BOND_SLAVE_PRIO,
+
_NM_PLATFORM_KERNEL_SUPPORT_NUM,
} NMPlatformKernelSupportType;
@@ -1112,10 +1130,12 @@ typedef struct {
NMLinkType type,
int ifindex,
gconstpointer extra_data);
- gboolean (*link_change)(NMPlatform *self,
- int ifindex,
- NMPlatformLinkProps *props,
- NMPlatformLinkChangeFlags flags);
+ gboolean (*link_change)(NMPlatform *self,
+ int ifindex,
+ NMPlatformLinkProps *props,
+ NMPortKind port_kind,
+ const NMPlatformLinkPortData *port_data,
+ NMPlatformLinkChangeFlags flags);
gboolean (*link_delete)(NMPlatform *self, int ifindex);
gboolean (*link_refresh)(NMPlatform *self, int ifindex);
gboolean (*link_set_netns)(NMPlatform *self, int ifindex, int netns_fd);
@@ -1955,6 +1975,7 @@ nm_platform_link_change_flags(NMPlatform *self, int ifindex, unsigned value, gbo
gboolean nm_platform_link_change(NMPlatform *self,
int ifindex,
NMPlatformLinkProps *props,
+ NMPlatformLinkBondPort *bond_port,
NMPlatformLinkChangeFlags flags);
gboolean nm_platform_link_get_udev_property(NMPlatform *self,
@@ -2455,6 +2476,9 @@ int nm_platform_tfilter_cmp(const NMPlatformTfilter *a, const NMPlatformTfilter
int nm_platform_mptcp_addr_cmp(const NMPlatformMptcpAddr *a, const NMPlatformMptcpAddr *b);
void nm_platform_link_hash_update(const NMPlatformLink *obj, NMHashState *h);
+void nm_platform_link_bond_port_hash_update(const NMPlatformLinkBondPort *obj, NMHashState *h);
+int nm_platform_link_bond_port_cmp(const NMPlatformLinkBondPort *a,
+ const NMPlatformLinkBondPort *b);
void nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
NMPlatformIPRouteCmpType cmp_type,
NMHashState *h);
diff --git a/src/libnmc-setting/nm-meta-setting-desc.c b/src/libnmc-setting/nm-meta-setting-desc.c
index fddee2aacd..b03d9ecdc2 100644
--- a/src/libnmc-setting/nm-meta-setting-desc.c
+++ b/src/libnmc-setting/nm-meta-setting-desc.c
@@ -5238,6 +5238,12 @@ static const NMMetaPropertyInfo *const property_infos_BOND_PORT[] = {
.prompt = N_("Queue ID"),
.property_type = &_pt_gobject_int,
),
+ PROPERTY_INFO_WITH_DESC (NM_SETTING_BOND_PORT_PRIO,
+ .is_cli_option = TRUE,
+ .property_alias = "prio",
+ .prompt = N_("Port Priority"),
+ .property_type= &_pt_gobject_int,
+ ),
NULL
};
diff --git a/src/libnmc-setting/settings-docs.h.in b/src/libnmc-setting/settings-docs.h.in
index 8aba737378..9f16a7ffec 100644
--- a/src/libnmc-setting/settings-docs.h.in
+++ b/src/libnmc-setting/settings-docs.h.in
@@ -439,6 +439,7 @@
#define DESCRIBE_DOC_NM_SETTING_WPAN_PAGE N_("IEEE 802.15.4 channel page. A positive integer or -1, meaning \"do not set, use whatever the device is already set to\".")
#define DESCRIBE_DOC_NM_SETTING_WPAN_PAN_ID N_("IEEE 802.15.4 Personal Area Network (PAN) identifier.")
#define DESCRIBE_DOC_NM_SETTING_WPAN_SHORT_ADDRESS N_("Short IEEE 802.15.4 address to be used within a restricted environment.")
+#define DESCRIBE_DOC_NM_SETTING_BOND_PORT_PRIO N_("The port priority for bond active port re-selection during failover. A higher number means a higher priority in selection. The primary port has the highest priority. This option is only compatible with active-backup, balance-tlb and balance-alb modes.")
#define DESCRIBE_DOC_NM_SETTING_BOND_PORT_QUEUE_ID N_("The queue ID of this bond port. The maximum value of queue ID is the number of TX queues currently active in device.")
#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_FROM_DHCP N_("Whether the system hostname can be determined from DHCP on this connection. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1).")
#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_FROM_DNS_LOOKUP N_("Whether the system hostname can be determined from reverse DNS lookup of addresses on this device. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1).")
diff --git a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in
index 1a86b591a7..720b257d20 100644
--- a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in
+++ b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in
@@ -267,6 +267,9 @@
<property name="queue-id"
alias="queue-id"
description="The queue ID of this bond port. The maximum value of queue ID is the number of TX queues currently active in device." />
+ <property name="prio"
+ alias="prio"
+ description="The port priority for bond active port re-selection during failover. A higher number means a higher priority in selection. The primary port has the highest priority. This option is only compatible with active-backup, balance-tlb and balance-alb modes." />
</setting>
<setting name="bridge" >
<property name="mac-address"