diff --git a/src/core/platform/nm-fake-platform.c b/src/core/platform/nm-fake-platform.c index 4cc9733567..b8d24a99ac 100644 --- a/src/core/platform/nm-fake-platform.c +++ b/src/core/platform/nm-fake-platform.c @@ -680,6 +680,8 @@ link_change(NMPlatform *platform, 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: diff --git a/src/core/platform/tests/test-link.c b/src/core/platform/tests/test-link.c index a947ec0874..587f69936a 100644 --- a/src/core/platform/tests/test-link.c +++ b/src/core/platform/tests/test-link.c @@ -112,7 +112,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); @@ -264,18 +264,35 @@ test_slave(int master, int type, SignalData *master_changed) g_assert(!nm_platform_link_is_up(NM_PLATFORM_GET, ifindex)); if (NM_IN_SET(link_type, NM_LINK_TYPE_BOND)) { - const NMPlatformLink *link; - NMPlatformLinkBondPort bond_port; + 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, &bond_port)); 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; diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 9958d8385f..484087b9b1 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -177,6 +177,8 @@ G_STATIC_ASSERT(RTA_MAX == (__RTA_MAX - 1)); /*****************************************************************************/ +#define IFLA_BOND_SLAVE_PRIO 9 + #define IFLA_BOND_PEER_NOTIF_DELAY 28 #undef IFLA_BOND_MAX @@ -3373,6 +3375,7 @@ _new_from_nl_link(NMPlatform *platform, 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)]; @@ -3384,6 +3387,21 @@ _new_from_nl_link(NMPlatform *platform, 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; @@ -8413,6 +8431,9 @@ link_change(NMPlatform *platform, 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; diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index 4ece500639..1c495d60d2 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -68,6 +68,7 @@ _nmp_link_port_data_to_string(NMPortKind port_kind, gsize sbuf_len) { const char *sbuf0 = sbuf; + char s0[120]; nm_assert(port_data); @@ -76,7 +77,16 @@ _nmp_link_port_data_to_string(NMPortKind port_kind, 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", port_data->bond.queue_id); + 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; } @@ -2138,6 +2148,8 @@ nm_platform_link_set_name(NMPlatform *self, int ifindex, const char *name) gboolean nm_platform_link_change(NMPlatform *self, int ifindex, NMPlatformLinkBondPort *bond_port) { + char sbuf_prio[100]; + _CHECK_SELF(self, klass, FALSE); g_return_val_if_fail(ifindex >= 0, FALSE); @@ -2145,8 +2157,18 @@ nm_platform_link_change(NMPlatform *self, int ifindex, NMPlatformLinkBondPort *b if (_LOGD_ENABLED()) { nm_auto_free_gstring GString *str = g_string_new(""); - if (bond_port) - g_string_append_printf(str, "bond-port queue-id %d", bond_port->queue_id); + 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); @@ -7914,7 +7936,7 @@ nm_platform_link_hash_update(const NMPlatformLink *obj, NMHashState *h) void nm_platform_link_bond_port_hash_update(const NMPlatformLinkBondPort *obj, NMHashState *h) { - nm_hash_update_vals(h, obj->queue_id); + nm_hash_update_vals(h, obj->prio, obj->queue_id, NM_HASH_COMBINE_BOOLS(guint8, obj->prio_has)); } int @@ -8036,6 +8058,8 @@ nm_platform_link_bond_port_cmp(const NMPlatformLinkBondPort *a, const NMPlatform { 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; } diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index 36a32bc58d..d442ad9bae 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -155,7 +155,9 @@ struct _NMPlatformObjWithIfindex { } _nm_alignas(NMPlatformObject); typedef struct { + gint32 prio; guint16 queue_id; + bool prio_has : 1; } NMPlatformLinkBondPort; typedef union { @@ -212,12 +214,12 @@ struct _NMPlatformLink { guint64 tx_packets; guint64 tx_bytes; - /* IFLA_INFO_SLAVE_KIND */ - NMPortKind port_kind; - /* 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; @@ -1004,6 +1006,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;