diff options
author | Fernando Fernandez Mancera <ffmancera@riseup.net> | 2023-05-03 10:52:35 +0200 |
---|---|---|
committer | Fernando Fernandez Mancera <ffmancera@riseup.net> | 2023-05-03 10:52:35 +0200 |
commit | 859faa6509e7bfb9e0257c38c35f4ed5fd768134 (patch) | |
tree | f803c1aac7608fd14c83d72b24024eb6c52082aa | |
parent | d3b54963622f242db1ebeda21dedd9558b484355 (diff) | |
parent | 2f0571f1930ff2c11de4f48b4433ca5fe6c897a0 (diff) | |
download | NetworkManager-859faa6509e7bfb9e0257c38c35f4ed5fd768134.tar.gz |
merge: branch 'ff/bond_port_options'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1564
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" |