From 9800bd172354f8b6db394814b9ddf7f98ad666d2 Mon Sep 17 00:00:00 2001 From: Fernando Fernandez Mancera Date: Thu, 9 Mar 2023 12:18:14 +0100 Subject: bonding: add support to prio property in bond ports Add per port priority support for bond active port re-selection during failover. A higher number means a higher priority in selection. The primary port still has the highest priority. This option is only compatible with active-backup, balance-tlb and balance-alb modes. --- src/core/devices/nm-device-bond.c | 62 +++++++++++++++++++--- .../plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 14 +++++ .../settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c | 1 + .../settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h | 2 +- .../plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 4 +- .../plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 1 + src/libnm-base/nm-base.h | 1 + src/libnm-client-impl/libnm.ver | 1 + .../gen-metadata-nm-settings-libnm-core.xml.in | 4 ++ src/libnm-core-impl/nm-setting-bond-port.c | 48 ++++++++++++++++- src/libnm-core-public/nm-setting-bond-port.h | 4 ++ src/libnmc-setting/nm-meta-setting-desc.c | 6 +++ src/libnmc-setting/settings-docs.h.in | 1 + src/nmcli/gen-metadata-nm-settings-nmcli.xml.in | 3 ++ 14 files changed, 141 insertions(+), 11 deletions(-) diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c index 4b48db3344..10fe809204 100644 --- a/src/core/devices/nm-device-bond.c +++ b/src/core/devices/nm-device-bond.c @@ -240,7 +240,12 @@ controller_update_port_connection(NMDevice *self, 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, NULL); + 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, @@ -631,13 +636,54 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) static void commit_port_options(NMDevice *bond_device, NMDevice *port, NMSettingBondPort *s_port) { - 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}), - 0); + 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/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index cf2a030f22..1646fa7aef 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); @@ -5605,6 +5606,19 @@ make_bond_port_setting(shvarFile *ifcfg) g_object_set(G_OBJECT(s_port), NM_SETTING_BOND_PORT_QUEUE_ID, queue_id, NULL); } + 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_MAXUINT32, NM_BOND_PORT_PRIO_DEF); + if (errno != 0) { + PARSE_WARNING("Invalid bond port prio value '%s'", value); + return s_port; + } + 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 @@ + 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 @@ -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/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 @@ +