From cd31559deddd3f70f8cbfa5f1ea50e3f6d395b82 Mon Sep 17 00:00:00 2001 From: Fernando Fernandez Mancera Date: Thu, 21 Jul 2022 10:38:04 +0200 Subject: [PATCH 1/4] utils: introduce nm_ether_addr_from_string() helper --- src/libnm-glib-aux/nm-shared-utils.c | 12 ++++++++++++ src/libnm-glib-aux/nm-shared-utils.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/src/libnm-glib-aux/nm-shared-utils.c b/src/libnm-glib-aux/nm-shared-utils.c index 9c0d16164a..20a704b500 100644 --- a/src/libnm-glib-aux/nm-shared-utils.c +++ b/src/libnm-glib-aux/nm-shared-utils.c @@ -146,6 +146,18 @@ G_STATIC_ASSERT(ETH_ALEN == sizeof(NMEtherAddr)); G_STATIC_ASSERT(_nm_alignof(struct ether_addr) <= _nm_alignof(NMEtherAddr)); +NMEtherAddr * +nm_ether_addr_from_string(NMEtherAddr *addr, const char *str) +{ + nm_assert(addr); + + if (!str || !_nm_utils_hwaddr_aton_exact(str, addr, ETH_ALEN)) { + *addr = NM_ETHER_ADDR_INIT(0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + return NULL; + } + + return addr; +} /*****************************************************************************/ /** diff --git a/src/libnm-glib-aux/nm-shared-utils.h b/src/libnm-glib-aux/nm-shared-utils.h index 1584042ac5..d8ec065732 100644 --- a/src/libnm-glib-aux/nm-shared-utils.h +++ b/src/libnm-glib-aux/nm-shared-utils.h @@ -2859,6 +2859,8 @@ nm_ether_addr_to_string(const NMEtherAddr *ether_addr, char sbuf[static(sizeof(N #define nm_ether_addr_to_string_a(ether_addr) \ nm_ether_addr_to_string((ether_addr), g_alloca(sizeof(NMEtherAddr) * 3)) +NMEtherAddr *nm_ether_addr_from_string(NMEtherAddr *addr, const char *str); + guint8 *nm_utils_hexstr2bin_full(const char *hexstr, gboolean allow_0x_prefix, gboolean delimiter_required, -- GitLab From f900f7bc2c52bf4851ac372e92cbeecd13fd4e0e Mon Sep 17 00:00:00 2001 From: Fernando Fernandez Mancera Date: Mon, 25 Jul 2022 16:01:35 +0200 Subject: [PATCH 2/4] platform: add netlink support for bond link sysfs is deprecated and kernel people will not add new bond options to sysfs. Netlink is a stable API and therefore is the right method to communicate with kernel in order to set the link options. --- src/core/devices/nm-device-bond.c | 2 +- src/core/platform/nm-fake-platform.c | 9 + src/core/platform/tests/test-link.c | 7 +- src/libnm-platform/nm-linux-platform.c | 229 +++++++++++++++++++++++++ src/libnm-platform/nm-platform.c | 224 ++++++++++++++++++++++++ src/libnm-platform/nm-platform.h | 60 ++++++- src/libnm-platform/nmp-base.h | 1 + src/libnm-platform/nmp-object.c | 12 ++ src/libnm-platform/nmp-object.h | 8 + 9 files changed, 547 insertions(+), 5 deletions(-) diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c index 21fe9b07eb..2a0116b1cb 100644 --- a/src/core/devices/nm-device-bond.c +++ b/src/core/devices/nm-device-bond.c @@ -540,7 +540,7 @@ create_and_realize(NMDevice *device, g_assert(iface); - r = nm_platform_link_bond_add(nm_device_get_platform(device), iface, out_plink); + r = nm_platform_link_bond_add(nm_device_get_platform(device), iface, NULL, out_plink); if (r < 0) { g_set_error(error, NM_DEVICE_ERROR, diff --git a/src/core/platform/nm-fake-platform.c b/src/core/platform/nm-fake-platform.c index 7d8986d764..a1ca5434cb 100644 --- a/src/core/platform/nm-fake-platform.c +++ b/src/core/platform/nm-fake-platform.c @@ -323,6 +323,15 @@ link_add(NMPlatform *platform, dev_lnk = nmp_object_new(NMP_OBJECT_TYPE_LNK_BRIDGE, props); break; } + case NM_LINK_TYPE_BOND: + { + const NMPlatformLnkBond *props = extra_data; + + nm_assert(props); + + dev_lnk = nmp_object_new(NMP_OBJECT_TYPE_LNK_BOND, props); + break; + } case NM_LINK_TYPE_VETH: veth_peer = extra_data; g_assert(veth_peer); diff --git a/src/core/platform/tests/test-link.c b/src/core/platform/tests/test-link.c index 87280e097d..b72bcb65b2 100644 --- a/src/core/platform/tests/test-link.c +++ b/src/core/platform/tests/test-link.c @@ -111,13 +111,16 @@ 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, + }; - r = nm_platform_link_bond_add(NM_PLATFORM_GET, name, NULL); + r = nm_platform_link_bond_add(NM_PLATFORM_GET, name, &nm_platform_lnk_bond_default, NULL); /* Check that bond0 is *not* automatically created. */ if (!bond0_exists) g_assert(!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "bond0")); - return r >= 0; + return NMTST_NM_ERR_SUCCESS(r); } case NM_LINK_TYPE_TEAM: return NMTST_NM_ERR_SUCCESS(nm_platform_link_team_add(NM_PLATFORM_GET, name, NULL)); diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index ee5cb10434..d8e537b158 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -1535,6 +1535,152 @@ _parse_lnk_bridge(const char *kind, struct nlattr *info_data) /***********************************************************************************/ +static NMPObject * +_parse_lnk_bond(const char *kind, struct nlattr *info_data) +{ + static const struct nla_policy policy[] = { + [IFLA_BOND_MODE] = {.type = NLA_U8}, + [IFLA_BOND_ACTIVE_SLAVE] = {.type = NLA_U32}, + [IFLA_BOND_MIIMON] = {.type = NLA_U32}, + [IFLA_BOND_UPDELAY] = {.type = NLA_U32}, + [IFLA_BOND_DOWNDELAY] = {.type = NLA_U32}, + [IFLA_BOND_USE_CARRIER] = {.type = NLA_U8}, + [IFLA_BOND_ARP_INTERVAL] = {.type = NLA_U32}, + [IFLA_BOND_ARP_IP_TARGET] = {.type = NLA_NESTED}, + [IFLA_BOND_ARP_VALIDATE] = {.type = NLA_U32}, + [IFLA_BOND_ARP_ALL_TARGETS] = {.type = NLA_U32}, + [IFLA_BOND_PRIMARY] = {.type = NLA_U32}, + [IFLA_BOND_PRIMARY_RESELECT] = {.type = NLA_U8}, + [IFLA_BOND_FAIL_OVER_MAC] = {.type = NLA_U8}, + [IFLA_BOND_XMIT_HASH_POLICY] = {.type = NLA_U8}, + [IFLA_BOND_RESEND_IGMP] = {.type = NLA_U32}, + [IFLA_BOND_NUM_PEER_NOTIF] = {.type = NLA_U8}, + [IFLA_BOND_ALL_SLAVES_ACTIVE] = {.type = NLA_U8}, + [IFLA_BOND_MIN_LINKS] = {.type = NLA_U32}, + [IFLA_BOND_LP_INTERVAL] = {.type = NLA_U32}, + [IFLA_BOND_PACKETS_PER_SLAVE] = {.type = NLA_U32}, + [IFLA_BOND_AD_LACP_RATE] = {.type = NLA_U8}, + [IFLA_BOND_AD_SELECT] = {.type = NLA_U8}, + [IFLA_BOND_AD_ACTOR_SYS_PRIO] = {.type = NLA_U16}, + [IFLA_BOND_AD_USER_PORT_KEY] = {.type = NLA_U16}, + [IFLA_BOND_AD_ACTOR_SYSTEM] = {.minlen = sizeof(NMEtherAddr)}, + [IFLA_BOND_TLB_DYNAMIC_LB] = {.type = NLA_U8}, + [IFLA_BOND_PEER_NOTIF_DELAY] = {.type = NLA_U32}, + }; + NMPlatformLnkBond *props; + struct nlattr *tb[G_N_ELEMENTS(policy)]; + NMPObject *obj = NULL; + + if (!info_data || !nm_streq0(kind, "bond")) + return NULL; + + if (nla_parse_nested_arr(tb, info_data, policy) < 0) + return NULL; + + obj = nmp_object_new(NMP_OBJECT_TYPE_LNK_BOND, NULL); + + props = &obj->lnk_bond; + + if (tb[IFLA_BOND_MODE]) + props->mode = nla_get_u8(tb[IFLA_BOND_MODE]); + if (tb[IFLA_BOND_PRIMARY]) { + props->primary = nla_get_u32(tb[IFLA_BOND_PRIMARY]); + } else if (tb[IFLA_BOND_ACTIVE_SLAVE]) { + props->primary = nla_get_u32(tb[IFLA_BOND_ACTIVE_SLAVE]); + } + if (tb[IFLA_BOND_MIIMON]) { + props->miimon = nla_get_u32(tb[IFLA_BOND_MIIMON]); + props->miimon_has = TRUE; + } else { + props->miimon_has = FALSE; + } + if (tb[IFLA_BOND_UPDELAY]) { + props->updelay = nla_get_u32(tb[IFLA_BOND_UPDELAY]); + props->updelay_has = TRUE; + } else { + props->updelay_has = FALSE; + } + if (tb[IFLA_BOND_DOWNDELAY]) { + props->downdelay = nla_get_u32(tb[IFLA_BOND_DOWNDELAY]); + props->downdelay_has = TRUE; + } else { + props->downdelay_has = FALSE; + } + if (tb[IFLA_BOND_USE_CARRIER]) + props->use_carrier = nla_get_u8(tb[IFLA_BOND_USE_CARRIER]); + if (tb[IFLA_BOND_ARP_INTERVAL]) + props->arp_interval = nla_get_u32(tb[IFLA_BOND_ARP_INTERVAL]); + if (tb[IFLA_BOND_ARP_IP_TARGET]) { + struct nlattr *attr; + int rem; + + nla_for_each_nested (attr, tb[IFLA_BOND_ARP_IP_TARGET], rem) { + if (props->arp_ip_targets_num > NM_BOND_MAX_ARP_TARGETS - 1) + break; + if (nla_len(attr) < sizeof(in_addr_t)) + break; + + props->arp_ip_target[props->arp_ip_targets_num++] = nla_get_u32(attr); + } + } + if (tb[IFLA_BOND_ARP_VALIDATE]) + props->arp_validate = nla_get_u32(tb[IFLA_BOND_ARP_VALIDATE]); + if (tb[IFLA_BOND_ARP_ALL_TARGETS]) { + props->arp_all_targets = nla_get_u32(tb[IFLA_BOND_ARP_ALL_TARGETS]); + props->arp_all_targets_has = TRUE; + } else { + props->arp_all_targets_has = FALSE; + } + if (tb[IFLA_BOND_PRIMARY_RESELECT]) + props->primary_reselect = nla_get_u8(tb[IFLA_BOND_PRIMARY_RESELECT]); + if (tb[IFLA_BOND_FAIL_OVER_MAC]) + props->fail_over_mac = nla_get_u8(tb[IFLA_BOND_FAIL_OVER_MAC]); + if (tb[IFLA_BOND_XMIT_HASH_POLICY]) + props->xmit_hash_policy = nla_get_u8(tb[IFLA_BOND_XMIT_HASH_POLICY]); + if (tb[IFLA_BOND_RESEND_IGMP]) { + props->resend_igmp = nla_get_u32(tb[IFLA_BOND_RESEND_IGMP]); + props->resend_igmp_has = TRUE; + } else { + props->resend_igmp_has = FALSE; + } + if (tb[IFLA_BOND_NUM_PEER_NOTIF]) + props->num_grat_arp = nla_get_u8(tb[IFLA_BOND_NUM_PEER_NOTIF]); + if (tb[IFLA_BOND_ALL_SLAVES_ACTIVE]) + props->all_ports_active = nla_get_u8(tb[IFLA_BOND_ALL_SLAVES_ACTIVE]); + if (tb[IFLA_BOND_MIN_LINKS]) + props->min_links = nla_get_u32(tb[IFLA_BOND_MIN_LINKS]); + if (tb[IFLA_BOND_LP_INTERVAL]) + props->lp_interval = nla_get_u32(tb[IFLA_BOND_LP_INTERVAL]); + if (tb[IFLA_BOND_PACKETS_PER_SLAVE]) + props->packets_per_port = nla_get_u32(tb[IFLA_BOND_PACKETS_PER_SLAVE]); + if (tb[IFLA_BOND_AD_LACP_RATE]) + props->lacp_rate = nla_get_u8(tb[IFLA_BOND_AD_LACP_RATE]); + if (tb[IFLA_BOND_AD_SELECT]) + props->ad_select = nla_get_u8(tb[IFLA_BOND_AD_SELECT]); + if (tb[IFLA_BOND_AD_ACTOR_SYS_PRIO]) + props->ad_actor_sys_prio = nla_get_u16(tb[IFLA_BOND_AD_ACTOR_SYS_PRIO]); + if (tb[IFLA_BOND_AD_USER_PORT_KEY]) + props->ad_user_port_key = nla_get_u16(tb[IFLA_BOND_AD_USER_PORT_KEY]); + if (tb[IFLA_BOND_AD_ACTOR_SYSTEM]) + props->ad_actor_system = *nla_data_as(NMEtherAddr, tb[IFLA_BOND_AD_ACTOR_SYSTEM]); + if (tb[IFLA_BOND_TLB_DYNAMIC_LB]) { + props->tlb_dynamic_lb = nla_get_u8(tb[IFLA_BOND_TLB_DYNAMIC_LB]); + props->tlb_dynamic_lb_has = TRUE; + } else { + props->tlb_dynamic_lb_has = FALSE; + } + if (tb[IFLA_BOND_PEER_NOTIF_DELAY]) { + props->peer_notif_delay = nla_get_u32(tb[IFLA_BOND_PEER_NOTIF_DELAY]); + props->peer_notif_delay_has = TRUE; + } else { + props->peer_notif_delay_has = FALSE; + } + + return obj; +} + +/***********************************************************************************/ + static NMPObject * _parse_lnk_gre(const char *kind, struct nlattr *info_data) { @@ -3202,6 +3348,9 @@ _new_from_nl_link(NMPlatform *platform, case NM_LINK_TYPE_BRIDGE: lnk_data = _parse_lnk_bridge(nl_info_kind, nl_info_data); break; + case NM_LINK_TYPE_BOND: + lnk_data = _parse_lnk_bond(nl_info_kind, nl_info_data); + break; case NM_LINK_TYPE_GRE: case NM_LINK_TYPE_GRETAP: lnk_data = _parse_lnk_gre(nl_info_kind, nl_info_data); @@ -4354,6 +4503,86 @@ _nl_msg_new_link_set_linkinfo(struct nl_msg *msg, NMLinkType link_type, gconstpo NLA_PUT_U64(msg, IFLA_BR_MCAST_STARTUP_QUERY_INTVL, props->mcast_startup_query_interval); break; } + case NM_LINK_TYPE_BOND: + { + const NMPlatformLnkBond *props = extra_data; + struct nlattr *targets; + int i = 0; + + nm_assert(extra_data); + + if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) + goto nla_put_failure; + + if (props->arp_ip_targets_num > 0) { + targets = nla_nest_start(msg, IFLA_BOND_ARP_IP_TARGET); + if (!targets) + goto nla_put_failure; + + for (i = 0; i < props->arp_ip_targets_num; i++) + NLA_PUT_U32(msg, i, props->arp_ip_target[i]); + + nla_nest_end(msg, targets); + } + + if (props->arp_all_targets_has) + NLA_PUT_U32(msg, IFLA_BOND_ARP_ALL_TARGETS, props->arp_all_targets); + if (props->arp_interval) + NLA_PUT_U32(msg, IFLA_BOND_ARP_INTERVAL, props->arp_interval); + if (props->arp_validate) + NLA_PUT_U32(msg, IFLA_BOND_ARP_VALIDATE, props->arp_validate); + if (props->downdelay_has) + NLA_PUT_U32(msg, IFLA_BOND_DOWNDELAY, props->downdelay); + if (props->lp_interval_has) + NLA_PUT_U32(msg, IFLA_BOND_LP_INTERVAL, props->lp_interval); + if (props->miimon_has) + NLA_PUT_U32(msg, IFLA_BOND_MIIMON, props->miimon); + if (props->min_links) + NLA_PUT_U32(msg, IFLA_BOND_MIN_LINKS, props->min_links); + if (props->packets_per_port) + NLA_PUT_U32(msg, IFLA_BOND_PACKETS_PER_SLAVE, props->packets_per_port); + if (props->peer_notif_delay_has) + NLA_PUT_U32(msg, IFLA_BOND_PEER_NOTIF_DELAY, props->peer_notif_delay); + if (props->primary) + NLA_PUT_U32(msg, IFLA_BOND_PRIMARY, props->primary); + if (props->resend_igmp_has) + NLA_PUT_U32(msg, IFLA_BOND_RESEND_IGMP, props->resend_igmp); + if (props->updelay_has) + NLA_PUT_U32(msg, IFLA_BOND_UPDELAY, props->updelay); + if (props->ad_actor_sys_prio) + NLA_PUT_U16(msg, IFLA_BOND_AD_ACTOR_SYS_PRIO, props->ad_actor_sys_prio); + if (props->ad_user_port_key) + NLA_PUT_U16(msg, IFLA_BOND_AD_USER_PORT_KEY, props->ad_user_port_key); + if (!nm_ether_addr_equal(&props->ad_actor_system, &nm_ether_addr_zero)) + NLA_PUT(msg, + IFLA_BOND_AD_ACTOR_SYSTEM, + sizeof(props->ad_actor_system), + &props->ad_actor_system); + if (props->ad_select) + NLA_PUT_U8(msg, IFLA_BOND_AD_SELECT, props->ad_select); + + NLA_PUT_U8(msg, IFLA_BOND_ALL_SLAVES_ACTIVE, props->all_ports_active); + + if (props->fail_over_mac) + NLA_PUT_U8(msg, IFLA_BOND_FAIL_OVER_MAC, props->fail_over_mac); + if (props->lacp_rate) + NLA_PUT_U8(msg, IFLA_BOND_AD_LACP_RATE, props->lacp_rate); + if (props->num_grat_arp) + NLA_PUT_U8(msg, IFLA_BOND_NUM_PEER_NOTIF, props->num_grat_arp); + + NLA_PUT_U8(msg, IFLA_BOND_MODE, props->mode); + + if (props->primary_reselect) + NLA_PUT_U8(msg, IFLA_BOND_PRIMARY_RESELECT, props->primary_reselect); + if (props->xmit_hash_policy) + NLA_PUT_U8(msg, IFLA_BOND_XMIT_HASH_POLICY, props->xmit_hash_policy); + if (props->tlb_dynamic_lb_has) + NLA_PUT_U8(msg, IFLA_BOND_TLB_DYNAMIC_LB, !!props->tlb_dynamic_lb); + + NLA_PUT_U8(msg, IFLA_BOND_USE_CARRIER, !!props->use_carrier); + + break; + } case NM_LINK_TYPE_VLAN: { const NMPlatformLnkVlan *props = extra_data; diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index 213a8abad4..e2bc22e4c0 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -1362,6 +1362,12 @@ nm_platform_link_add(NMPlatform *self, buf_p, buf_len); break; + case NM_LINK_TYPE_BOND: + nm_strbuf_append_str(&buf_p, &buf_len, ", "); + nm_platform_lnk_bond_to_string((const NMPlatformLnkBond *) extra_data, + buf_p, + buf_len); + break; default: nm_assert(!extra_data); break; @@ -1402,6 +1408,12 @@ nm_platform_link_change(NMPlatform *self, NMLinkType type, int ifindex, gconstpo buf_p, buf_len); break; + case NM_LINK_TYPE_BOND: + nm_strbuf_append_str(&buf_p, &buf_len, ", "); + nm_platform_lnk_bond_to_string((const NMPlatformLnkBond *) extra_data, + buf_p, + buf_len); + break; default: nm_assert(!extra_data); break; @@ -2302,6 +2314,12 @@ _link_get_lnk(NMPlatform *self, int ifindex, NMLinkType link_type, const NMPlatf return lnk ? &lnk->object : NULL; } +const NMPlatformLnkBond * +nm_platform_link_get_lnk_bond(NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk(self, ifindex, NM_LINK_TYPE_BOND, out_link); +} + const NMPlatformLnkBridge * nm_platform_link_get_lnk_bridge(NMPlatform *self, int ifindex, const NMPlatformLink **out_link) { @@ -6047,6 +6065,123 @@ nm_platform_lnk_bridge_to_string(const NMPlatformLnkBridge *lnk, char *buf, gsiz return buf; } +const char * +nm_platform_lnk_bond_to_string(const NMPlatformLnkBond *lnk, char *buf, gsize len) +{ + char sbuf_miimon[30]; + char sbuf_updelay[30]; + char sbuf_downdelay[30]; + char sbuf_peer_notif_delay[60]; + char sbuf_arp_all_targets[30]; + char sbuf_resend_igmp[30]; + char sbuf_lp_interval[30]; + char sbuf_tlb_dynamic_lb[30]; + int i; + + if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len)) + return buf; + + nm_strbuf_append( + &buf, + &len, + "bond" + " mode %u" + " primary %u" + "%s" /* miimon */ + "%s" /* updelay */ + "%s" /* downdelay */ + " arp_interval %u" + "%s" /* resend_igmp */ + " min_links %u" + "%s" /* lp_interval */ + " packets_per_port %u" + "%s" /* peer_notif_delay */ + "%s" /* arp_all_targets */ + " arp_validate %u" + " ad_actor_sys_prio %u" + " ad_user_port_key %u" + " ad_actor_system " NM_ETHER_ADDR_FORMAT_STR "" + " primary_reselect %u" + " fail_over_mac %u" + " xmit_hash_policy %u" + " num_gray_arp %u" + " all_ports_active %u" + " lacp_rate %u" + " ad_select %u" + " use_carrier %d" + "%s" /* tlb_dynamic_lb */, + lnk->mode, + lnk->primary, + lnk->miimon_has || lnk->miimon != 0 + ? nm_sprintf_buf(sbuf_miimon, " miimon%s %u", !lnk->miimon_has ? "?" : "", lnk->miimon) + : "", + lnk->updelay_has || lnk->updelay != 0 ? nm_sprintf_buf(sbuf_updelay, + " updelay%s %u", + !lnk->updelay_has ? "?" : "", + lnk->updelay) + : "", + lnk->downdelay_has || lnk->downdelay != 0 ? nm_sprintf_buf(sbuf_downdelay, + " downdelay%s %u", + !lnk->downdelay_has ? "?" : "", + lnk->downdelay) + : "", + lnk->arp_interval, + lnk->resend_igmp_has || lnk->resend_igmp != 0 + ? nm_sprintf_buf(sbuf_resend_igmp, + " resend_igmp%s %u", + !lnk->resend_igmp_has ? "?" : "", + lnk->resend_igmp) + : "", + lnk->min_links, + lnk->lp_interval_has || lnk->lp_interval != 1 + ? nm_sprintf_buf(sbuf_lp_interval, + " lp_interval%s %u", + !lnk->lp_interval_has ? "?" : "", + lnk->lp_interval) + : "", + lnk->packets_per_port, + lnk->peer_notif_delay_has || lnk->peer_notif_delay != 0 + ? nm_sprintf_buf(sbuf_peer_notif_delay, + " peer_notif_delay%s %u", + !lnk->peer_notif_delay_has ? "?" : "", + lnk->peer_notif_delay) + : "", + lnk->arp_all_targets_has || lnk->arp_all_targets != 0 + ? nm_sprintf_buf(sbuf_arp_all_targets, + " arp_all_targets%s %u", + !lnk->arp_all_targets_has ? "?" : "", + lnk->arp_all_targets) + : "", + lnk->arp_validate, + lnk->ad_actor_sys_prio, + lnk->ad_user_port_key, + NM_ETHER_ADDR_FORMAT_VAL(&lnk->ad_actor_system), + lnk->primary_reselect, + lnk->fail_over_mac, + lnk->xmit_hash_policy, + lnk->num_grat_arp, + lnk->all_ports_active, + lnk->lacp_rate, + lnk->ad_select, + (int) lnk->use_carrier, + lnk->tlb_dynamic_lb_has ? nm_sprintf_buf(sbuf_tlb_dynamic_lb, + " tlb_dynamic_lb%s %u", + !lnk->tlb_dynamic_lb_has ? "?" : "", + (int) lnk->tlb_dynamic_lb) + : ""); + + if (lnk->arp_ip_targets_num > 0) { + nm_strbuf_append_str(&buf, &len, " arp_ip_target"); + for (i = 0; i < lnk->arp_ip_targets_num; i++) { + char target[INET_ADDRSTRLEN]; + + nm_strbuf_append_c(&buf, &len, ' '); + nm_strbuf_append_str(&buf, &len, _nm_utils_inet4_ntop(lnk->arp_ip_target[i], target)); + } + } + return buf; +} + const char * nm_platform_lnk_gre_to_string(const NMPlatformLnkGre *lnk, char *buf, gsize len) { @@ -7855,6 +7990,95 @@ nm_platform_lnk_bridge_hash_update(const NMPlatformLnkBridge *obj, NMHashState * obj->vlan_stats_enabled)); } +void +nm_platform_lnk_bond_hash_update(const NMPlatformLnkBond *obj, NMHashState *h) +{ + nm_hash_update_vals(h, + obj->arp_all_targets, + obj->arp_interval, + obj->arp_validate, + obj->downdelay, + obj->lp_interval, + obj->miimon, + obj->min_links, + obj->packets_per_port, + obj->peer_notif_delay, + obj->primary, + obj->resend_igmp, + obj->updelay, + obj->ad_actor_sys_prio, + obj->ad_user_port_key, + obj->ad_actor_system, + obj->ad_select, + obj->all_ports_active, + obj->arp_ip_targets_num, + obj->fail_over_mac, + obj->lacp_rate, + obj->num_grat_arp, + obj->mode, + obj->primary_reselect, + obj->xmit_hash_policy, + NM_HASH_COMBINE_BOOLS(guint16, + obj->arp_all_targets_has, + obj->downdelay_has, + obj->lp_interval_has, + obj->miimon_has, + obj->peer_notif_delay_has, + obj->resend_igmp_has, + obj->tlb_dynamic_lb, + obj->tlb_dynamic_lb_has, + obj->updelay_has, + obj->use_carrier)); + + nm_hash_update(h, obj->arp_ip_target, obj->arp_ip_targets_num * sizeof(obj->arp_ip_target[0])); +} + +int +nm_platform_lnk_bond_cmp(const NMPlatformLnkBond *a, const NMPlatformLnkBond *b) +{ + NM_CMP_SELF(a, b); + NM_CMP_FIELD_MEMCMP_LEN(a, + b, + arp_ip_target, + a->arp_ip_targets_num * sizeof(a->arp_ip_target[0])); + NM_CMP_FIELD(a, b, arp_all_targets); + NM_CMP_FIELD(a, b, arp_interval); + NM_CMP_FIELD(a, b, arp_validate); + NM_CMP_FIELD(a, b, downdelay); + NM_CMP_FIELD(a, b, lp_interval); + NM_CMP_FIELD(a, b, miimon); + NM_CMP_FIELD(a, b, min_links); + NM_CMP_FIELD(a, b, packets_per_port); + NM_CMP_FIELD(a, b, peer_notif_delay); + NM_CMP_FIELD(a, b, primary); + NM_CMP_FIELD(a, b, resend_igmp); + NM_CMP_FIELD(a, b, updelay); + NM_CMP_FIELD(a, b, ad_actor_sys_prio); + NM_CMP_FIELD(a, b, ad_user_port_key); + NM_CMP_FIELD_MEMCMP(a, b, ad_actor_system); + NM_CMP_FIELD(a, b, ad_select); + NM_CMP_FIELD(a, b, all_ports_active); + NM_CMP_FIELD(a, b, arp_ip_targets_num); + NM_CMP_FIELD(a, b, fail_over_mac); + NM_CMP_FIELD(a, b, lacp_rate); + NM_CMP_FIELD(a, b, num_grat_arp); + NM_CMP_FIELD(a, b, mode); + NM_CMP_FIELD(a, b, primary_reselect); + NM_CMP_FIELD(a, b, xmit_hash_policy); + NM_CMP_FIELD_BOOL(a, b, arp_all_targets_has); + NM_CMP_FIELD_BOOL(a, b, downdelay_has); + NM_CMP_FIELD_BOOL(a, b, lp_interval_has); + NM_CMP_FIELD_BOOL(a, b, miimon_has); + NM_CMP_FIELD_BOOL(a, b, peer_notif_delay_has); + NM_CMP_FIELD_BOOL(a, b, resend_igmp_has); + NM_CMP_FIELD_BOOL(a, b, tlb_dynamic_lb); + NM_CMP_FIELD_BOOL(a, b, tlb_dynamic_lb_has); + NM_CMP_FIELD_BOOL(a, b, updelay_has); + NM_CMP_FIELD_BOOL(a, b, use_carrier); + + return 0; +} + int nm_platform_lnk_bridge_cmp(const NMPlatformLnkBridge *a, const NMPlatformLnkBridge *b) { diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index 26fffe23ac..d93843a854 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -891,6 +891,47 @@ typedef struct { extern const NMPlatformLnkBridge nm_platform_lnk_bridge_default; +/* Defined in net/bonding.h. */ +#define NM_BOND_MAX_ARP_TARGETS 16 + +typedef struct { + in_addr_t arp_ip_target[NM_BOND_MAX_ARP_TARGETS]; + guint32 arp_all_targets; + guint32 arp_interval; + guint32 arp_validate; + guint32 downdelay; + guint32 lp_interval; + guint32 miimon; + guint32 min_links; + guint32 packets_per_port; + guint32 peer_notif_delay; + guint32 primary; + guint32 resend_igmp; + guint32 updelay; + guint16 ad_actor_sys_prio; + guint16 ad_user_port_key; + NMEtherAddr ad_actor_system; + guint8 ad_select; + guint8 all_ports_active; + guint8 arp_ip_targets_num; + guint8 fail_over_mac; + guint8 lacp_rate; + guint8 num_grat_arp; + guint8 mode; + guint8 primary_reselect; + guint8 xmit_hash_policy; + bool arp_all_targets_has : 1; + bool downdelay_has : 1; + bool lp_interval_has : 1; + bool miimon_has : 1; + bool peer_notif_delay_has : 1; + bool resend_igmp_has : 1; + bool tlb_dynamic_lb : 1; + bool tlb_dynamic_lb_has : 1; + bool updelay_has : 1; + bool use_carrier : 1; +} NMPlatformLnkBond; + typedef struct { int parent_ifindex; in_addr_t local; @@ -1262,6 +1303,7 @@ typedef struct { gboolean egress_reset_all, const NMVlanQosMapping *egress_map, gsize n_egress_map); + gboolean (*link_tun_add)(NMPlatform *self, const char *name, const NMPlatformLnkTun *props, @@ -1748,9 +1790,18 @@ nm_platform_link_bridge_change(NMPlatform *self, int ifindex, const NMPlatformLn } static inline int -nm_platform_link_bond_add(NMPlatform *self, const char *name, const NMPlatformLink **out_link) +nm_platform_link_bond_change(NMPlatform *self, int ifindex, const NMPlatformLnkBond *props) +{ + return nm_platform_link_change(self, NM_LINK_TYPE_BOND, ifindex, props); +} + +static inline int +nm_platform_link_bond_add(NMPlatform *self, + const char *name, + const NMPlatformLnkBond *props, + const NMPlatformLink **out_link) { - return nm_platform_link_add(self, NM_LINK_TYPE_BOND, name, 0, NULL, 0, 0, NULL, out_link); + return nm_platform_link_add(self, NM_LINK_TYPE_BOND, name, 0, NULL, 0, 0, props, out_link); } static inline int @@ -2084,6 +2135,8 @@ const NMPObject *nm_platform_link_get_lnk(NMPlatform *self, int ifindex, NMLinkType link_type, const NMPlatformLink **out_link); +const NMPlatformLnkBond * +nm_platform_link_get_lnk_bond(NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkBridge * nm_platform_link_get_lnk_bridge(NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkGre * @@ -2378,6 +2431,7 @@ gboolean nm_platform_tc_sync(NMPlatform *self, GPtrArray *known_tfilters); const char *nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len); +const char *nm_platform_lnk_bond_to_string(const NMPlatformLnkBond *lnk, char *buf, gsize len); const char *nm_platform_lnk_bridge_to_string(const NMPlatformLnkBridge *lnk, char *buf, gsize len); const char *nm_platform_lnk_gre_to_string(const NMPlatformLnkGre *lnk, char *buf, gsize len); const char * @@ -2421,6 +2475,7 @@ const char * nm_platform_mptcp_addr_to_string(const NMPlatformMptcpAddr *mptcp_addr, char *buf, gsize len); int nm_platform_link_cmp(const NMPlatformLink *a, const NMPlatformLink *b); +int nm_platform_lnk_bond_cmp(const NMPlatformLnkBond *a, const NMPlatformLnkBond *b); int nm_platform_lnk_bridge_cmp(const NMPlatformLnkBridge *a, const NMPlatformLnkBridge *b); int nm_platform_lnk_gre_cmp(const NMPlatformLnkGre *a, const NMPlatformLnkGre *b); int nm_platform_lnk_infiniband_cmp(const NMPlatformLnkInfiniband *a, @@ -2512,6 +2567,7 @@ void nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj, void nm_platform_routing_rule_hash_update(const NMPlatformRoutingRule *obj, NMPlatformRoutingRuleCmpType cmp_type, NMHashState *h); +void nm_platform_lnk_bond_hash_update(const NMPlatformLnkBond *obj, NMHashState *h); void nm_platform_lnk_bridge_hash_update(const NMPlatformLnkBridge *obj, NMHashState *h); void nm_platform_lnk_gre_hash_update(const NMPlatformLnkGre *obj, NMHashState *h); void nm_platform_lnk_infiniband_hash_update(const NMPlatformLnkInfiniband *obj, NMHashState *h); diff --git a/src/libnm-platform/nmp-base.h b/src/libnm-platform/nmp-base.h index 02420ebf4b..a6ee3df1d1 100644 --- a/src/libnm-platform/nmp-base.h +++ b/src/libnm-platform/nmp-base.h @@ -147,6 +147,7 @@ typedef enum _nm_packed { NMP_OBJECT_TYPE_LNK_VRF, NMP_OBJECT_TYPE_LNK_VXLAN, NMP_OBJECT_TYPE_LNK_WIREGUARD, + NMP_OBJECT_TYPE_LNK_BOND, NMP_OBJECT_TYPE_MPTCP_ADDR, diff --git a/src/libnm-platform/nmp-object.c b/src/libnm-platform/nmp-object.c index edccef3373..f5a2a10cf0 100644 --- a/src/libnm-platform/nmp-object.c +++ b/src/libnm-platform/nmp-object.c @@ -3499,6 +3499,18 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_wireguard_hash_update, .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_wireguard_cmp, }, + [NMP_OBJECT_TYPE_LNK_BOND - 1] = + { + .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), + .obj_type = NMP_OBJECT_TYPE_LNK_BOND, + .sizeof_data = sizeof(NMPObjectLnkBond), + .sizeof_public = sizeof(NMPlatformLnkBond), + .obj_type_name = "bond", + .lnk_link_type = NM_LINK_TYPE_BOND, + .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_lnk_bond_to_string, + .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_bond_hash_update, + .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_bond_cmp, + }, [NMP_OBJECT_TYPE_MPTCP_ADDR - 1] = { .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), diff --git a/src/libnm-platform/nmp-object.h b/src/libnm-platform/nmp-object.h index 5b789404a4..4958404a47 100644 --- a/src/libnm-platform/nmp-object.h +++ b/src/libnm-platform/nmp-object.h @@ -244,6 +244,10 @@ typedef struct { NMPlatformLnkBridge _public; } NMPObjectLnkBridge; +typedef struct { + NMPlatformLnkBond _public; +} NMPObjectLnkBond; + typedef struct { NMPlatformLnkGre _public; } NMPObjectLnkGre; @@ -351,6 +355,9 @@ struct _NMPObject { NMPlatformLnkBridge lnk_bridge; NMPObjectLnkBridge _lnk_bridge; + NMPlatformLnkBond lnk_bond; + NMPObjectLnkBond _lnk_bond; + NMPlatformLnkGre lnk_gre; NMPObjectLnkGre _lnk_gre; @@ -495,6 +502,7 @@ _NMP_OBJECT_TYPE_IS_OBJ_WITH_IFINDEX(NMPObjectType obj_type) case NMP_OBJECT_TYPE_TFILTER: case NMP_OBJECT_TYPE_LNK_BRIDGE: + case NMP_OBJECT_TYPE_LNK_BOND: case NMP_OBJECT_TYPE_LNK_GRE: case NMP_OBJECT_TYPE_LNK_GRETAP: case NMP_OBJECT_TYPE_LNK_INFINIBAND: -- GitLab From 32870d82337997ffce79e779718c96db55723bf3 Mon Sep 17 00:00:00 2001 From: Fernando Fernandez Mancera Date: Tue, 26 Jul 2022 12:11:56 +0200 Subject: [PATCH 3/4] libnm-utils: convert string bond opts to int NMPlatform code for bond netlink support will use the numeric values, therefore we need functions to convert all the string values to int. --- .../nm-libnm-core-utils.c | 115 ++++++++++++++++++ .../nm-libnm-core-utils.h | 96 +++++++++++++++ src/libnm-core-impl/nm-setting-bond.c | 33 +++++ src/libnm-core-intern/nm-core-internal.h | 4 + 4 files changed, 248 insertions(+) diff --git a/src/libnm-core-aux-intern/nm-libnm-core-utils.c b/src/libnm-core-aux-intern/nm-libnm-core-utils.c index 3751881570..1f2d687590 100644 --- a/src/libnm-core-aux-intern/nm-libnm-core-utils.c +++ b/src/libnm-core-aux-intern/nm-libnm-core-utils.c @@ -40,6 +40,121 @@ _nm_setting_bond_remove_options_arp_interval(NMSettingBond *s_bond) /*****************************************************************************/ +NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( + _nm_setting_bond_ad_select_from_string, + NMBondAdSelect, + { + G_STATIC_ASSERT_EXPR(_NM_BOND_AD_SELECT_NUM <= 3); + + if (name && name[0] < '0' + _NM_BOND_AD_SELECT_NUM && name[0] >= '0' && name[1] == '\0') { + return name[0] - '0'; + } + }, + { return NM_BOND_AD_SELECT_STABLE; }, + {"bandwith", NM_BOND_AD_SELECT_BANDWIDTH}, + {"count", NM_BOND_AD_SELECT_COUNT}, + {"stable", NM_BOND_AD_SELECT_STABLE}, ); + +NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( + _nm_setting_bond_arp_all_targets_from_string, + NMBondArpAllTargets, + { + G_STATIC_ASSERT_EXPR(_NM_BOND_ARP_ALL_TARGETS_NUM <= 2); + + if (name && name[0] < '0' + _NM_BOND_ARP_ALL_TARGETS_NUM && name[0] >= '0' + && name[1] == '\0') { + return name[0] - '0'; + } + }, + { return NM_BOND_ARP_ALL_TARGETS_ANY; }, + {"all", NM_BOND_ARP_ALL_TARGETS_ALL}, + {"any", NM_BOND_ARP_ALL_TARGETS_ANY}, ); + +NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( + _nm_setting_bond_fail_over_mac_from_string, + NMBondFailOverMac, + { + G_STATIC_ASSERT_EXPR(_NM_BOND_FAIL_OVER_MAC_NUM <= 3); + + if (name && name[0] < '0' + _NM_BOND_FAIL_OVER_MAC_NUM && name[0] >= '0' + && name[1] == '\0') { + return name[0] - '0'; + } + }, + { return NM_BOND_FAIL_OVER_MAC_NONE; }, + {"active", NM_BOND_FAIL_OVER_MAC_ACTIVE}, + {"follow", NM_BOND_FAIL_OVER_MAC_FOLLOW}, + {"none", NM_BOND_FAIL_OVER_MAC_NONE}, ); + +NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( + _nm_setting_bond_lacp_rate_from_string, + NMBondLacpRate, + { + G_STATIC_ASSERT_EXPR(_NM_BOND_LACP_RATE_NUM <= 2); + + if (name && name[0] < '0' + _NM_BOND_LACP_RATE_NUM && name[0] >= '0' && name[1] == '\0') { + return name[0] - '0'; + } + }, + { return NM_BOND_LACP_RATE_SLOW; }, + {"fast", NM_BOND_LACP_RATE_FAST}, + {"slow", NM_BOND_LACP_RATE_SLOW}, ); + +NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( + _nm_setting_bond_arp_validate_from_string, + NMBondArpValidate, + { + G_STATIC_ASSERT_EXPR(_NM_BOND_ARP_VALIDATE_NUM <= 7); + + if (name && name[0] < '0' + _NM_BOND_ARP_VALIDATE_NUM && name[0] >= '0' + && name[1] == '\0') { + return name[0] - '0'; + } + }, + { return NM_BOND_ARP_VALIDATE_NONE; }, + {"active", NM_BOND_ARP_VALIDATE_ACTIVE}, + {"all", NM_BOND_ARP_VALIDATE_ALL}, + {"backup", NM_BOND_ARP_VALIDATE_BACKUP}, + {"filter", NM_BOND_ARP_VALIDATE_FILTER}, + {"filter_active", NM_BOND_ARP_VALIDATE_FILTER_ACTIVE}, + {"filter_backup", NM_BOND_ARP_VALIDATE_FILTER_BACKUP}, + {"none", NM_BOND_ARP_VALIDATE_NONE}, ); + +NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( + _nm_setting_bond_primary_reselect_from_string, + NMBondPrimaryReselect, + { + G_STATIC_ASSERT_EXPR(_NM_BOND_PRIMARY_RESELECT_NUM <= 3); + + if (name && name[0] < '0' + _NM_BOND_PRIMARY_RESELECT_NUM && name[0] >= '0' + && name[1] == '\0') { + return name[0] - '0'; + } + }, + { return NM_BOND_PRIMARY_RESELECT_ALWAYS; }, + {"always", NM_BOND_PRIMARY_RESELECT_ALWAYS}, + {"better", NM_BOND_PRIMARY_RESELECT_BETTER}, + {"failure", NM_BOND_PRIMARY_RESELECT_FAILURE}, ); + +NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( + _nm_setting_bond_xmit_hash_policy_from_string, + NMBondXmitHashPolicy, + { + G_STATIC_ASSERT_EXPR(_NM_BOND_XMIT_HASH_POLICY_NUM <= 6); + + if (name && name[0] < '0' + _NM_BOND_XMIT_HASH_POLICY_NUM && name[0] >= '0' + && name[1] == '\0') { + return name[0] - '0'; + } + }, + { return NM_BOND_XMIT_HASH_POLICY_LAYER2; }, + {"encap2+3", NM_BOND_XMIT_HASH_POLICY_ENCAP2_3}, + {"encap3+4", NM_BOND_XMIT_HASH_POLICY_ENCAP3_4}, + {"layer2", NM_BOND_XMIT_HASH_POLICY_LAYER2}, + {"layer2+3", NM_BOND_XMIT_HASH_POLICY_LAYER2_3}, + {"layer3+4", NM_BOND_XMIT_HASH_POLICY_LAYER3_4}, + {"vlan+srcmac", NM_BOND_XMIT_HASH_POLICY_VLAN_SRCMAC}, ); + NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( _nm_setting_bond_mode_from_string, NMBondMode, diff --git a/src/libnm-core-aux-intern/nm-libnm-core-utils.h b/src/libnm-core-aux-intern/nm-libnm-core-utils.h index eb30c931fa..2c3ee78d2a 100644 --- a/src/libnm-core-aux-intern/nm-libnm-core-utils.h +++ b/src/libnm-core-aux-intern/nm-libnm-core-utils.h @@ -57,6 +57,102 @@ const char **nm_utils_bond_option_arp_ip_targets_split(const char *arp_ip_target void _nm_setting_bond_remove_options_miimon(NMSettingBond *s_bond); void _nm_setting_bond_remove_options_arp_interval(NMSettingBond *s_bond); +typedef enum { + NM_BOND_AD_SELECT_UNKNOWN = -1, + + /* The numeric values correspond to kernel's numbering. */ + NM_BOND_AD_SELECT_STABLE = 0, + NM_BOND_AD_SELECT_BANDWIDTH = 1, + NM_BOND_AD_SELECT_COUNT = 2, + + _NM_BOND_AD_SELECT_NUM, +} NMBondAdSelect; + +NMBondAdSelect _nm_setting_bond_ad_select_from_string(const char *str); + +typedef enum { + NM_BOND_ARP_ALL_TARGETS_UNKNOWN = -1, + + /* The numeric values correspond to kernel's numbering. */ + NM_BOND_ARP_ALL_TARGETS_ANY = 0, + NM_BOND_ARP_ALL_TARGETS_ALL = 1, + + _NM_BOND_ARP_ALL_TARGETS_NUM, +} NMBondArpAllTargets; + +NMBondArpAllTargets _nm_setting_bond_arp_all_targets_from_string(const char *str); + +typedef enum { + NM_BOND_FAIL_OVER_MAC_UNKNOWN = -1, + + /* The numeric values correspond to kernel's numbering. */ + NM_BOND_FAIL_OVER_MAC_NONE = 0, + NM_BOND_FAIL_OVER_MAC_ACTIVE = 1, + NM_BOND_FAIL_OVER_MAC_FOLLOW = 2, + + _NM_BOND_FAIL_OVER_MAC_NUM, +} NMBondFailOverMac; + +NMBondFailOverMac _nm_setting_bond_fail_over_mac_from_string(const char *str); + +typedef enum { + NM_BOND_LACP_RATE_UNKNOWN = -1, + + /* The numeric values correspond to kernel's numbering. */ + NM_BOND_LACP_RATE_SLOW = 0, + NM_BOND_LACP_RATE_FAST = 1, + + _NM_BOND_LACP_RATE_NUM, +} NMBondLacpRate; + +NMBondLacpRate _nm_setting_bond_lacp_rate_from_string(const char *str); + +typedef enum { + NM_BOND_ARP_VALIDATE_UNKNOWN = -1, + + /* The numeric values correspond to kernel's numbering. */ + NM_BOND_ARP_VALIDATE_NONE = 0, + NM_BOND_ARP_VALIDATE_ACTIVE = 1, + NM_BOND_ARP_VALIDATE_BACKUP = 2, + NM_BOND_ARP_VALIDATE_ALL = 3, + NM_BOND_ARP_VALIDATE_FILTER = 4, + NM_BOND_ARP_VALIDATE_FILTER_ACTIVE = 5, + NM_BOND_ARP_VALIDATE_FILTER_BACKUP = 6, + + _NM_BOND_ARP_VALIDATE_NUM, +} NMBondArpValidate; + +NMBondArpValidate _nm_setting_bond_arp_validate_from_string(const char *str); + +typedef enum { + NM_BOND_PRIMARY_RESELECT_UNKNOWN = -1, + + /* The numeric values correspond to kernel's numbering. */ + NM_BOND_PRIMARY_RESELECT_ALWAYS = 0, + NM_BOND_PRIMARY_RESELECT_BETTER = 1, + NM_BOND_PRIMARY_RESELECT_FAILURE = 2, + + _NM_BOND_PRIMARY_RESELECT_NUM, +} NMBondPrimaryReselect; + +NMBondPrimaryReselect _nm_setting_bond_primary_reselect_from_string(const char *str); + +typedef enum { + NM_BOND_XMIT_HASH_POLICY_UNKNOWN = -1, + + /* The numeric values correspond to kernel's numbering. */ + NM_BOND_XMIT_HASH_POLICY_LAYER2 = 0, + NM_BOND_XMIT_HASH_POLICY_LAYER3_4 = 1, + NM_BOND_XMIT_HASH_POLICY_LAYER2_3 = 2, + NM_BOND_XMIT_HASH_POLICY_ENCAP2_3 = 3, + NM_BOND_XMIT_HASH_POLICY_ENCAP3_4 = 4, + NM_BOND_XMIT_HASH_POLICY_VLAN_SRCMAC = 5, + + _NM_BOND_XMIT_HASH_POLICY_NUM, +} NMBondXmitHashPolicy; + +NMBondXmitHashPolicy _nm_setting_bond_xmit_hash_policy_from_string(const char *str); + typedef enum { NM_BOND_MODE_UNKNOWN = -1, diff --git a/src/libnm-core-impl/nm-setting-bond.c b/src/libnm-core-impl/nm-setting-bond.c index 2984e6fc22..cdfc764187 100644 --- a/src/libnm-core-impl/nm-setting-bond.c +++ b/src/libnm-core-impl/nm-setting-bond.c @@ -764,6 +764,39 @@ _nm_setting_bond_get_option_type(NMSettingBond *setting, const char *name) return option_meta->opt_type; } +guint32 +_nm_setting_bond_opt_value_as_u32(NMSettingBond *s_bond, const char *opt) +{ + nm_assert(_get_option_meta(opt)->opt_type == NM_BOND_OPTION_TYPE_INT); + return _nm_utils_ascii_str_to_uint64(nm_setting_bond_get_option_normalized(s_bond, opt), + 10, + 0, + G_MAXUINT32, + 0); +} + +guint16 +_nm_setting_bond_opt_value_as_u16(NMSettingBond *s_bond, const char *opt) +{ + nm_assert(_get_option_meta(opt)->opt_type == NM_BOND_OPTION_TYPE_INT); + return _nm_utils_ascii_str_to_uint64(nm_setting_bond_get_option_normalized(s_bond, opt), + 10, + 0, + G_MAXUINT16, + 0); +} + +guint8 +_nm_setting_bond_opt_value_as_u8(NMSettingBond *s_bond, const char *opt) +{ + nm_assert(_get_option_meta(opt)->opt_type == NM_BOND_OPTION_TYPE_INT); + return _nm_utils_ascii_str_to_uint64(nm_setting_bond_get_option_normalized(s_bond, opt), + 10, + 0, + G_MAXUINT8, + 0); +} + /*****************************************************************************/ static gboolean diff --git a/src/libnm-core-intern/nm-core-internal.h b/src/libnm-core-intern/nm-core-internal.h index f669bf8d80..ee4cc25b42 100644 --- a/src/libnm-core-intern/nm-core-internal.h +++ b/src/libnm-core-intern/nm-core-internal.h @@ -517,6 +517,10 @@ NMConnectionMultiConnect _nm_connection_get_multi_connect(NMConnection *connecti gboolean _nm_setting_bond_option_supported(const char *option, NMBondMode mode); +guint32 _nm_setting_bond_opt_value_as_u32(NMSettingBond *s_bond, const char *opt); +guint16 _nm_setting_bond_opt_value_as_u16(NMSettingBond *s_bond, const char *opt); +guint8 _nm_setting_bond_opt_value_as_u8(NMSettingBond *s_bond, const char *opt); + /*****************************************************************************/ GPtrArray *_nm_setting_bridge_get_vlans(NMSettingBridge *setting); -- GitLab From e064eb9d1361f5f17a092097807c452add8040bc Mon Sep 17 00:00:00 2001 From: Fernando Fernandez Mancera Date: Mon, 25 Jul 2022 16:02:37 +0200 Subject: [PATCH 4/4] bond: use netlink to set bond options Use the netlink platform implementation for setting the bond link options. --- src/core/devices/nm-device-bond.c | 167 ++++++++++++++++++++++++------ 1 file changed, 135 insertions(+), 32 deletions(-) diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c index 2a0116b1cb..ef1baef788 100644 --- a/src/core/devices/nm-device-bond.c +++ b/src/core/devices/nm-device-bond.c @@ -9,6 +9,8 @@ #include #include +#include +#include #include "NetworkManagerUtils.h" #include "nm-device-private.h" @@ -16,6 +18,7 @@ #include "nm-device-factory.h" #include "libnm-core-aux-intern/nm-libnm-core-utils.h" #include "libnm-core-intern/nm-core-internal.h" +#include "nm-manager.h" #include "nm-setting-bond-port.h" #define _NMLOG_DEVICE_TYPE NMDeviceBond @@ -349,51 +352,144 @@ set_bond_arp_ip_targets(NMDevice *device, NMSettingBond *s_bond) nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET)); } -static gboolean -apply_bonding_config(NMDeviceBond *self) +static guint8 +_bond_arp_ip_target_to_platform(const char *value, in_addr_t out[static NM_BOND_MAX_ARP_TARGETS]) { - NMDevice *device = NM_DEVICE(self); - NMSettingBond *s_bond; - NMBondMode mode; - const char *mode_str; - gs_free char *device_bond_mode = NULL; + gs_free const char **ip = NULL; + in_addr_t in_a; + int i; + int added = 0; - s_bond = nm_device_get_applied_setting(device, NM_TYPE_SETTING_BOND); - g_return_val_if_fail(s_bond, FALSE); + ip = nm_strsplit_set(value, " "); - mode_str = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_MODE); - mode = _nm_setting_bond_mode_from_string(mode_str); - g_return_val_if_fail(mode != NM_BOND_MODE_UNKNOWN, FALSE); + if (!ip) + return added; - /* Set mode first, as some other options (e.g. arp_interval) are valid - * only for certain modes. - */ - device_bond_mode = nm_platform_sysctl_master_get_option(nm_device_get_platform(device), - nm_device_get_ifindex(device), - NM_SETTING_BOND_OPTION_MODE); - /* Need to release all slaves before we can change bond mode */ - if (!nm_streq0(device_bond_mode, mode_str)) - nm_device_master_release_slaves_all(device); + for (i = 0; ip[i]; i++) { + if (added > NM_BOND_MAX_ARP_TARGETS - 1) + break; + if (!nm_utils_parse_inaddr_bin(AF_INET, ip[i], NULL, &in_a)) + continue; + + out[added++] = in_a; + } + return added; +} + +static int +_setting_bond_primary_opt_as_ifindex(NMSettingBond *s_bond) +{ + const char *primary_str; + int ifindex = 0; - set_bond_attr_or_default(device, s_bond, NM_SETTING_BOND_OPTION_MODE); + primary_str = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_PRIMARY); - set_bond_arp_ip_targets(device, s_bond); + if (primary_str != NULL) + ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, primary_str); - set_bond_attrs_or_default(device, s_bond, NM_MAKE_STRV(OPTIONS_APPLY_SUBSET)); - return TRUE; + return ifindex; +} + +static void +_platform_lnk_bond_init_from_setting(NMSettingBond *s_bond, NMPlatformLnkBond *props) +{ + const char *opt_value; + + *props = (NMPlatformLnkBond){ + .mode = _nm_setting_bond_mode_from_string( + nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_MODE)), + .primary = _setting_bond_primary_opt_as_ifindex(s_bond), + .miimon = _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_MIIMON), + .updelay = _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_UPDELAY), + .downdelay = _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_DOWNDELAY), + .arp_interval = + _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_ARP_INTERVAL), + .resend_igmp = + _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_RESEND_IGMP), + .min_links = _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_MIN_LINKS), + .lp_interval = + _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_LP_INTERVAL), + .packets_per_port = + _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE), + .peer_notif_delay = + _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY), + .arp_all_targets = _nm_setting_bond_arp_all_targets_from_string( + nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_ARP_ALL_TARGETS)), + .arp_validate = _nm_setting_bond_arp_validate_from_string( + nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_ARP_VALIDATE)), + .ad_actor_sys_prio = + _nm_setting_bond_opt_value_as_u16(s_bond, NM_SETTING_BOND_OPTION_AD_ACTOR_SYS_PRIO), + .ad_user_port_key = + _nm_setting_bond_opt_value_as_u16(s_bond, NM_SETTING_BOND_OPTION_AD_USER_PORT_KEY), + .primary_reselect = _nm_setting_bond_primary_reselect_from_string( + nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_PRIMARY_RESELECT)), + .fail_over_mac = _nm_setting_bond_fail_over_mac_from_string( + nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_FAIL_OVER_MAC)), + .xmit_hash_policy = _nm_setting_bond_xmit_hash_policy_from_string( + nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY)), + .num_grat_arp = + _nm_setting_bond_opt_value_as_u8(s_bond, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP), + .all_ports_active = + _nm_setting_bond_opt_value_as_u8(s_bond, NM_SETTING_BOND_OPTION_ALL_SLAVES_ACTIVE), + .lacp_rate = _nm_setting_bond_lacp_rate_from_string( + nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_LACP_RATE)), + .ad_select = _nm_setting_bond_ad_select_from_string( + nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_AD_SELECT)), + }; + + nm_ether_addr_from_string( + &props->ad_actor_system, + nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_AD_ACTOR_SYSTEM)); + + opt_value = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_USE_CARRIER); + if (opt_value != NULL) + props->use_carrier = _nm_utils_ascii_str_to_bool(opt_value, FALSE); + + opt_value = + nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB); + if (opt_value != NULL) + props->tlb_dynamic_lb = _nm_utils_ascii_str_to_bool(opt_value, FALSE); + + opt_value = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET); + if (opt_value != NULL) + props->arp_ip_targets_num = + _bond_arp_ip_target_to_platform(opt_value, props->arp_ip_target); + + props->miimon_has = !props->arp_interval && !props->arp_validate; + props->updelay_has = props->miimon_has && props->miimon; + props->downdelay_has = props->miimon_has && props->miimon; + props->peer_notif_delay_has = (props->miimon || props->arp_interval) && props->peer_notif_delay; + props->arp_all_targets_has = props->arp_interval && props->arp_all_targets; + props->resend_igmp_has = props->resend_igmp != 1; + props->lp_interval = props->lp_interval != 1; + props->tlb_dynamic_lb_has = NM_IN_SET(props->mode, NM_BOND_MODE_TLB, NM_BOND_MODE_ALB); } static NMActStageReturn act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) { - NMDeviceBond *self = NM_DEVICE_BOND(device); - NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; + NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; + NMConnection *connection; + NMSettingBond *s_bond; + NMPlatformLnkBond props; + int r; + int ifindex = nm_device_get_ifindex(device); + + connection = nm_device_get_applied_connection(device); + g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE); + + s_bond = nm_connection_get_setting_bond(connection); + g_return_val_if_fail(s_bond, NM_ACT_STAGE_RETURN_FAILURE); + + _platform_lnk_bond_init_from_setting(s_bond, &props); /* Interface must be down to set bond options */ nm_device_take_down(device, TRUE); - if (!apply_bonding_config(self)) + r = nm_platform_link_bond_change(nm_device_get_platform(device), ifindex, &props); + if (r < 0) { ret = NM_ACT_STAGE_RETURN_FAILURE; - else { + NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED); + } else { if (!nm_device_hw_addr_set_cloned(device, nm_device_get_applied_connection(device), FALSE)) ret = NM_ACT_STAGE_RETURN_FAILURE; } @@ -535,12 +631,19 @@ create_and_realize(NMDevice *device, const NMPlatformLink **out_plink, GError **error) { - const char *iface = nm_device_get_iface(device); - int r; + const char *iface = nm_device_get_iface(device); + NMSettingBond *s_bond; + NMPlatformLnkBond props; + int r; g_assert(iface); - r = nm_platform_link_bond_add(nm_device_get_platform(device), iface, NULL, out_plink); + s_bond = nm_connection_get_setting_bond(connection); + nm_assert(s_bond); + + _platform_lnk_bond_init_from_setting(s_bond, &props); + + r = nm_platform_link_bond_add(nm_device_get_platform(device), iface, &props, out_plink); if (r < 0) { g_set_error(error, NM_DEVICE_ERROR, -- GitLab