diff options
Diffstat (limited to 'src/libnm-platform')
| -rw-r--r-- | src/libnm-platform/nm-linux-platform.c | 106 | ||||
| -rw-r--r-- | src/libnm-platform/nm-platform.c | 121 | ||||
| -rw-r--r-- | src/libnm-platform/nm-platform.h | 44 |
3 files changed, 256 insertions, 15 deletions
diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 049095b2..484087b9 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 @@ -3347,9 +3349,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)]; @@ -3360,6 +3364,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_STATS64]) { @@ -8277,7 +8324,7 @@ out: } static int -link_change(NMPlatform *platform, NMLinkType type, int ifindex, gconstpointer extra_data) +link_change_extra(NMPlatform *platform, NMLinkType type, int ifindex, gconstpointer extra_data) { nm_auto_nlmsg struct nl_msg *nlmsg = NULL; @@ -8355,6 +8402,51 @@ link_delete(NMPlatform *platform, int ifindex) } static gboolean +link_change(NMPlatform *platform, + int ifindex, + NMPortKind port_kind, + const NMPlatformLinkPortData *port_data) +{ + 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) + return FALSE; + + 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); +} + +static gboolean link_refresh(NMPlatform *platform, int ifindex) { do_request_link(platform, ifindex, NULL); @@ -11121,9 +11213,11 @@ nm_linux_platform_class_init(NMLinuxPlatformClass *klass) platform_class->sysctl_set_async = sysctl_set_async; platform_class->sysctl_get = sysctl_get; - platform_class->link_add = link_add; + platform_class->link_add = link_add; + platform_class->link_change_extra = link_change_extra; + platform_class->link_delete = link_delete; + platform_class->link_change = link_change; - platform_class->link_delete = link_delete; platform_class->link_refresh = link_refresh; diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index dc643ed2..1c495d60 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)]) { @@ -1406,7 +1441,10 @@ nm_platform_link_add(NMPlatform *self, } int -nm_platform_link_change(NMPlatform *self, NMLinkType type, int ifindex, gconstpointer extra_data) +nm_platform_link_change_extra(NMPlatform *self, + NMLinkType type, + int ifindex, + gconstpointer extra_data) { char buf[512]; const char *name = nm_platform_link_get_name(self, ifindex); @@ -1447,7 +1485,7 @@ nm_platform_link_change(NMPlatform *self, NMLinkType type, int ifindex, gconstpo buf; })); - return klass->link_change(self, type, ifindex, extra_data); + return klass->link_change_extra(self, type, ifindex, extra_data); } /** @@ -2107,6 +2145,43 @@ nm_platform_link_set_name(NMPlatform *self, int ifindex, const char *name) return klass->link_set_name(self, ifindex, 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); + + if (_LOGD_ENABLED()) { + nm_auto_free_gstring GString *str = g_string_new(""); + + 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); + + _LOG3D("link: change: %s", str->str); + } + + return klass->link_change(self, + ifindex, + bond_port ? NM_PORT_KIND_BOND : NM_PORT_KIND_NONE, + (const NMPlatformLinkPortData *) bond_port); +} + /** * nm_platform_link_get_physical_port_id: * @self: platform instance @@ -5893,6 +5968,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]; @@ -5936,6 +6012,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( @@ -5957,6 +6038,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 */ " rx:%" G_GUINT64_FORMAT ",%" G_GUINT64_FORMAT " tx:%" G_GUINT64_FORMAT ",%" G_GUINT64_FORMAT, link->ifindex, @@ -5989,6 +6071,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->rx_packets, link->rx_bytes, link->tx_packets, @@ -7821,6 +7904,7 @@ nm_platform_link_hash_update(const NMPlatformLink *obj, NMHashState *h) obj->arptype, obj->inet6_addr_gen_mode_inv, obj->inet6_token, + obj->port_kind, obj->rx_packets, obj->rx_bytes, obj->tx_packets, @@ -7839,6 +7923,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 @@ -7868,6 +7966,14 @@ nm_platform_link_cmp(const NMPlatformLink *a, const NMPlatformLink *b) if (a->l_broadcast.len) NM_CMP_FIELD_MEMCMP_LEN(a, b, l_broadcast.data, a->l_broadcast.len); NM_CMP_FIELD_MEMCMP(a, b, inet6_token); + 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); @@ -7948,6 +8054,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 ca6cdff8..d442ad9b 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -154,6 +154,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]; @@ -204,6 +214,12 @@ struct _NMPlatformLink { guint64 tx_packets; guint64 tx_bytes; + /* 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; @@ -990,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; @@ -1086,9 +1104,14 @@ typedef struct { guint32 mtu, gconstpointer extra_data, const NMPlatformLink **out_link); - - int (*link_change)(NMPlatform *self, NMLinkType type, int ifindex, gconstpointer extra_data); - + int (*link_change_extra)(NMPlatform *self, + NMLinkType type, + int ifindex, + gconstpointer extra_data); + gboolean (*link_change)(NMPlatform *self, + int ifindex, + NMPortKind port_kind, + const NMPlatformLinkPortData *port_data); 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); @@ -1590,8 +1613,10 @@ int nm_platform_link_add(NMPlatform *self, gconstpointer extra_data, const NMPlatformLink **out_link); -int -nm_platform_link_change(NMPlatform *self, NMLinkType type, int ifindex, gconstpointer extra_data); +int nm_platform_link_change_extra(NMPlatform *self, + NMLinkType type, + int ifindex, + gconstpointer extra_data); static inline int nm_platform_link_veth_add(NMPlatform *self, @@ -1631,13 +1656,13 @@ nm_platform_link_bridge_add(NMPlatform *self, static inline int nm_platform_link_bridge_change(NMPlatform *self, int ifindex, const NMPlatformLnkBridge *props) { - return nm_platform_link_change(self, NM_LINK_TYPE_BRIDGE, ifindex, props); + return nm_platform_link_change_extra(self, NM_LINK_TYPE_BRIDGE, ifindex, props); } static inline int nm_platform_link_bond_change(NMPlatform *self, int ifindex, const NMPlatformLnkBond *props) { - return nm_platform_link_change(self, NM_LINK_TYPE_BOND, ifindex, props); + return nm_platform_link_change_extra(self, NM_LINK_TYPE_BOND, ifindex, props); } static inline int @@ -1914,6 +1939,8 @@ nm_platform_link_change_flags(NMPlatform *self, int ifindex, unsigned value, gbo return nm_platform_link_change_flags_full(self, ifindex, value, set ? value : 0u); } +gboolean nm_platform_link_change(NMPlatform *self, int ifindex, NMPlatformLinkBondPort *bond_port); + gboolean nm_platform_link_get_udev_property(NMPlatform *self, int ifindex, const char *name, @@ -2391,6 +2418,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); |