diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c index 0b0697e3c..cb3233192 100644 --- a/src/core/devices/nm-device-bond.c +++ b/src/core/devices/nm-device-bond.c @@ -39,7 +39,8 @@ NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE, NM_SETTING_BOND_OPTION_PRIMARY_RESELECT, \ NM_SETTING_BOND_OPTION_RESEND_IGMP, NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB, \ NM_SETTING_BOND_OPTION_USE_CARRIER, NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY, \ - NM_SETTING_BOND_OPTION_NUM_GRAT_ARP, NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY + NM_SETTING_BOND_OPTION_NUM_GRAT_ARP, NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY, \ + NM_SETTING_BOND_OPTION_ARP_MISSED_MAX, NM_SETTING_BOND_OPTION_LACP_ACTIVE #define OPTIONS_REAPPLY_SUBSET \ NM_SETTING_BOND_OPTION_MIIMON, NM_SETTING_BOND_OPTION_UPDELAY, \ @@ -51,11 +52,12 @@ NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE, NM_SETTING_BOND_OPTION_PRIMARY_RESELECT, \ NM_SETTING_BOND_OPTION_RESEND_IGMP, NM_SETTING_BOND_OPTION_USE_CARRIER, \ NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP, \ - NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY + NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY, NM_SETTING_BOND_OPTION_ARP_MISSED_MAX, \ + NM_SETTING_BOND_OPTION_LACP_ACTIVE #define OPTIONS_REAPPLY_FULL \ OPTIONS_REAPPLY_SUBSET, NM_SETTING_BOND_OPTION_ACTIVE_SLAVE, \ - NM_SETTING_BOND_OPTION_ARP_IP_TARGET + NM_SETTING_BOND_OPTION_ARP_IP_TARGET, NM_SETTING_BOND_OPTION_NS_IP6_TARGET /*****************************************************************************/ @@ -268,7 +270,7 @@ set_arp_targets(NMDevice *device, const char *cur_arp_ip_target, const char *new cur_strv = nm_strsplit_set_full(cur_arp_ip_target, NM_ASCII_SPACES, NM_STRSPLIT_SET_FLAGS_STRSTRIP); - new_strv = nm_utils_bond_option_arp_ip_targets_split(new_arp_ip_target); + new_strv = nm_utils_bond_option_ip_split(new_arp_ip_target); cur_len = NM_PTRARRAY_LEN(cur_strv); new_len = NM_PTRARRAY_LEN(new_strv); @@ -365,7 +367,7 @@ _bond_arp_ip_target_to_platform(const char *value, in_addr_t out[static NM_BOND_ int i; int added = 0; - ip = nm_utils_bond_option_arp_ip_targets_split(value); + ip = nm_utils_bond_option_ip_split(value); if (!ip) return added; @@ -381,6 +383,31 @@ _bond_arp_ip_target_to_platform(const char *value, in_addr_t out[static NM_BOND_ return added; } +static guint8 +_bond_ns_ip6_target_to_platform(const char *value, + struct in6_addr out[static NM_BOND_MAX_ARP_TARGETS]) +{ + gs_free const char **ip = NULL; + struct in6_addr in6_a; + int i; + int added = 0; + + ip = nm_utils_bond_option_ip_split(value); + + if (!ip) + return added; + + for (i = 0; ip[i]; i++) { + if (added > NM_BOND_MAX_ARP_TARGETS - 1) + break; + if (!nm_inet_parse_bin(AF_INET6, ip[i], NULL, &in6_a)) + nm_assert_not_reached(); /* verify() already validated the IP addresses */ + + out[added++] = in6_a; + } + return added; +} + static int _setting_bond_primary_opt_as_ifindex(NMSettingBond *s_bond) { @@ -437,6 +464,10 @@ _platform_lnk_bond_init_from_setting(NMSettingBond *s_bond, NMPlatformLnkBond *p NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY), .num_grat_arp = _v_u8(s_bond, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP), .all_ports_active = _v_u8(s_bond, NM_SETTING_BOND_OPTION_ALL_SLAVES_ACTIVE), + .arp_missed_max = _v_u8(s_bond, NM_SETTING_BOND_OPTION_ARP_MISSED_MAX), + .lacp_active = _v_fcn(_nm_setting_bond_lacp_active_from_string, + s_bond, + NM_SETTING_BOND_OPTION_LACP_ACTIVE), .lacp_rate = _v_fcn(_nm_setting_bond_lacp_rate_from_string, s_bond, NM_SETTING_BOND_OPTION_LACP_RATE), @@ -456,6 +487,11 @@ _platform_lnk_bond_init_from_setting(NMSettingBond *s_bond, NMPlatformLnkBond *p props->arp_ip_targets_num = _bond_arp_ip_target_to_platform(opt_value, props->arp_ip_target); + opt_value = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_NS_IP6_TARGET); + if (opt_value != NULL) + props->ns_ip6_targets_num = + _bond_ns_ip6_target_to_platform(opt_value, props->ns_ip6_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; @@ -463,6 +499,7 @@ _platform_lnk_bond_init_from_setting(NMSettingBond *s_bond, NMPlatformLnkBond *p props->resend_igmp_has = props->resend_igmp != 1; props->lp_interval_has = props->lp_interval != 1; props->tlb_dynamic_lb_has = NM_IN_SET(props->mode, NM_BOND_MODE_TLB, NM_BOND_MODE_ALB); + props->lacp_active_has = NM_IN_SET(props->mode, NM_BOND_MODE_8023AD); } static void 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 c4bfd2bd7..e7530c83b 100644 --- a/src/libnm-core-aux-intern/nm-libnm-core-utils.c +++ b/src/libnm-core-aux-intern/nm-libnm-core-utils.c @@ -13,7 +13,7 @@ /*****************************************************************************/ const char ** -nm_utils_bond_option_arp_ip_targets_split(const char *arp_ip_target) +nm_utils_bond_option_ip_split(const char *arp_ip_target) { return nm_strsplit_set_full(arp_ip_target, ",", NM_STRSPLIT_SET_FLAGS_STRSTRIP); } @@ -36,6 +36,7 @@ _nm_setting_bond_remove_options_arp_interval(NMSettingBond *s_bond) nm_setting_bond_remove_option(s_bond, NM_SETTING_BOND_OPTION_ARP_INTERVAL); nm_setting_bond_remove_option(s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET); + nm_setting_bond_remove_option(s_bond, NM_SETTING_BOND_OPTION_NS_IP6_TARGET); } /*****************************************************************************/ @@ -86,6 +87,20 @@ NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( {"follow", NM_BOND_FAIL_OVER_MAC_FOLLOW}, {"none", NM_BOND_FAIL_OVER_MAC_NONE}, ); +NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( + _nm_setting_bond_lacp_active_from_string, + NMBondLacpActive, + { + G_STATIC_ASSERT_EXPR(_NM_BOND_LACP_ACTIVE_NUM <= 2); + + if (name && name[0] < '0' + _NM_BOND_LACP_ACTIVE_NUM && name[0] >= '0' && name[1] == '\0') { + return name[0] - '0'; + } + }, + { return NM_BOND_LACP_ACTIVE_ON; }, + {"off", NM_BOND_LACP_ACTIVE_OFF}, + {"on", NM_BOND_LACP_ACTIVE_ON}, ); + NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( _nm_setting_bond_lacp_rate_from_string, NMBondLacpRate, 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 18af1e1a1..589291e5a 100644 --- a/src/libnm-core-aux-intern/nm-libnm-core-utils.h +++ b/src/libnm-core-aux-intern/nm-libnm-core-utils.h @@ -52,7 +52,7 @@ NM_AUTO_DEFINE_FCN0(NMWireGuardPeer *, _nm_auto_unref_wgpeer, nm_wireguard_peer_ /****************************************************************************/ -const char **nm_utils_bond_option_arp_ip_targets_split(const char *arp_ip_target); +const char **nm_utils_bond_option_ip_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); @@ -95,6 +95,18 @@ typedef enum { NMBondFailOverMac _nm_setting_bond_fail_over_mac_from_string(const char *str); +typedef enum { + NM_BOND_LACP_ACTIVE_UNKNOWN = -1, + + /* The numeric values correspond to kernel's numbering. */ + NM_BOND_LACP_ACTIVE_OFF = 0, + NM_BOND_LACP_ACTIVE_ON = 1, + + _NM_BOND_LACP_ACTIVE_NUM, +} NMBondLacpActive; + +NMBondLacpActive _nm_setting_bond_lacp_active_from_string(const char *str); + typedef enum { NM_BOND_LACP_RATE_UNKNOWN = -1, diff --git a/src/libnm-core-impl/nm-setting-bond.c b/src/libnm-core-impl/nm-setting-bond.c index 54030e0b4..a09129afb 100644 --- a/src/libnm-core-impl/nm-setting-bond.c +++ b/src/libnm-core-impl/nm-setting-bond.c @@ -92,6 +92,9 @@ static const char *const valid_options_lst[] = { NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB, NM_SETTING_BOND_OPTION_LP_INTERVAL, NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY, + NM_SETTING_BOND_OPTION_ARP_MISSED_MAX, + NM_SETTING_BOND_OPTION_LACP_ACTIVE, + NM_SETTING_BOND_OPTION_NS_IP6_TARGET, NULL, }; @@ -133,6 +136,7 @@ _nm_assert_bond_meta(const OptionMeta *option_meta) })); return TRUE; case NM_BOND_OPTION_TYPE_IP: + case NM_BOND_OPTION_TYPE_IP6: nm_assert(option_meta->val); /* fall-through */ case NM_BOND_OPTION_TYPE_IFNAME: @@ -154,8 +158,9 @@ static char const *const _option_default_strv_arp_validate[] = NM_MAKE_STRV("none", "active", "backup", "all", "filter", "filter_active", "filter_backup"); static char const *const _option_default_strv_fail_over_mac[] = NM_MAKE_STRV("none", "active", "follow"); -static char const *const _option_default_strv_lacp_rate[] = NM_MAKE_STRV("slow", "fast"); -static char const *const _option_default_strv_mode[] = NM_MAKE_STRV("balance-rr", +static char const *const _option_default_strv_lacp_rate[] = NM_MAKE_STRV("slow", "fast"); +static char const *const _option_default_strv_lacp_active[] = NM_MAKE_STRV("off", "on"); +static char const *const _option_default_strv_mode[] = NM_MAKE_STRV("balance-rr", "active-backup", "balance-xor", "broadcast", @@ -194,12 +199,15 @@ static NM_UTILS_STRING_TABLE_LOOKUP_STRUCT_DEFINE( {"any", NM_BOND_OPTION_TYPE_BOTH, 0, 1, _option_default_strv_arp_all_targets}}, {NM_SETTING_BOND_OPTION_ARP_INTERVAL, {"0", NM_BOND_OPTION_TYPE_INT, 0, G_MAXINT}}, {NM_SETTING_BOND_OPTION_ARP_IP_TARGET, {"", NM_BOND_OPTION_TYPE_IP}}, + {NM_SETTING_BOND_OPTION_ARP_MISSED_MAX, {"0", NM_BOND_OPTION_TYPE_INT, 0, 255}}, {NM_SETTING_BOND_OPTION_ARP_VALIDATE, {"none", NM_BOND_OPTION_TYPE_BOTH, 0, 6, _option_default_strv_arp_validate}}, {NM_SETTING_BOND_OPTION_BALANCE_SLB, {"0", NM_BOND_OPTION_TYPE_INT, 0, 1}}, {NM_SETTING_BOND_OPTION_DOWNDELAY, {"0", NM_BOND_OPTION_TYPE_INT, 0, G_MAXINT}}, {NM_SETTING_BOND_OPTION_FAIL_OVER_MAC, {"none", NM_BOND_OPTION_TYPE_BOTH, 0, 2, _option_default_strv_fail_over_mac}}, + {NM_SETTING_BOND_OPTION_LACP_ACTIVE, + {"on", NM_BOND_OPTION_TYPE_BOTH, 0, 1, _option_default_strv_lacp_active}}, {NM_SETTING_BOND_OPTION_LACP_RATE, {"slow", NM_BOND_OPTION_TYPE_BOTH, 0, 1, _option_default_strv_lacp_rate}}, {NM_SETTING_BOND_OPTION_LP_INTERVAL, {"1", NM_BOND_OPTION_TYPE_INT, 1, G_MAXINT}}, @@ -207,6 +215,7 @@ static NM_UTILS_STRING_TABLE_LOOKUP_STRUCT_DEFINE( {NM_SETTING_BOND_OPTION_MIN_LINKS, {"0", NM_BOND_OPTION_TYPE_INT, 0, G_MAXINT}}, {NM_SETTING_BOND_OPTION_MODE, {"balance-rr", NM_BOND_OPTION_TYPE_BOTH, 0, 6, _option_default_strv_mode}}, + {NM_SETTING_BOND_OPTION_NS_IP6_TARGET, {"", NM_BOND_OPTION_TYPE_IP6}}, {NM_SETTING_BOND_OPTION_NUM_GRAT_ARP, {"1", NM_BOND_OPTION_TYPE_INT, 0, 255}}, {NM_SETTING_BOND_OPTION_NUM_UNSOL_NA, {"1", NM_BOND_OPTION_TYPE_INT, 0, 255}}, {NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE, {"1", NM_BOND_OPTION_TYPE_INT, 0, 65535}}, @@ -504,12 +513,12 @@ validate_list(const char *name, const char *value, const OptionMeta *option_meta } static gboolean -validate_ip(const char *name, const char *value, GError **error) +validate_ip(int addr_family, const char *name, const char *value, GError **error) { gs_free const char **addrs = NULL; gsize i; - addrs = nm_utils_bond_option_arp_ip_targets_split(value); + addrs = nm_utils_bond_option_ip_split(value); if (!addrs) { g_set_error(error, NM_CONNECTION_ERROR, @@ -518,13 +527,18 @@ validate_ip(const char *name, const char *value, GError **error) name); return FALSE; } + + /* An empty list is invalid. */ + nm_assert(addrs[0]); + for (i = 0; addrs[i]; i++) { - if (!nm_inet_parse_bin(AF_INET, addrs[i], NULL, NULL)) { + if (!nm_inet_parse_bin(addr_family, addrs[i], NULL, NULL)) { g_set_error(error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("'%s' is not a valid IPv4 address for '%s' option"), + _("'%s' is not a valid %s address for '%s' option"), addrs[i], + addr_family == AF_INET ? "IPv4" : "IPv6", name); return FALSE; } @@ -574,7 +588,10 @@ _nm_setting_bond_validate_option(const char *name, const char *value, GError **e goto handle_error; case NM_BOND_OPTION_TYPE_IP: nm_assert(nm_streq0(name, NM_SETTING_BOND_OPTION_ARP_IP_TARGET)); - return validate_ip(name, value, error); + return validate_ip(AF_INET, name, value, error); + case NM_BOND_OPTION_TYPE_IP6: + nm_assert(nm_streq0(name, NM_SETTING_BOND_OPTION_NS_IP6_TARGET)); + return validate_ip(AF_INET6, name, value, error); case NM_BOND_OPTION_TYPE_MAC: success = nm_utils_hwaddr_valid(value, ETH_ALEN); goto handle_error; @@ -846,12 +863,15 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) NMSettingBondPrivate *priv = NM_SETTING_BOND_GET_PRIVATE(setting); int miimon; int arp_interval; + int arp_missed_max; int num_grat_arp; int num_unsol_na; int peer_notif_delay; const char *mode_str; const char *arp_ip_target = NULL; + const char *ns_ip6_target; const char *lacp_rate; + const char *lacp_active; const char *primary; const char *s; NMBondMode bond_mode; @@ -876,6 +896,8 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) miimon = _atoi(_bond_get_option_or_default(self, NM_SETTING_BOND_OPTION_MIIMON)); arp_interval = _atoi(_bond_get_option_or_default(self, NM_SETTING_BOND_OPTION_ARP_INTERVAL)); + arp_missed_max = + _atoi(_bond_get_option_or_default(self, NM_SETTING_BOND_OPTION_ARP_MISSED_MAX)); num_grat_arp = _atoi(_bond_get_option_or_default(self, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP)); num_unsol_na = _atoi(_bond_get_option_or_default(self, NM_SETTING_BOND_OPTION_NUM_UNSOL_NA)); peer_notif_delay = @@ -886,6 +908,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) * arp_interval conflicts [ alb, tlb ] * arp_interval needs arp_ip_target * arp_validate does not work with [ BOND_MODE_8023AD, BOND_MODE_TLB, BOND_MODE_ALB ] + * arp_missed_max does not work with [ BOND_MODE_8023AD, BOND_MODE_TLB, BOND_MODE_ALB ] * downdelay needs miimon * updelay needs miimon * peer_notif_delay needs miimon enabled @@ -929,6 +952,17 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) g_prefix_error(error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS); return FALSE; } + if (arp_missed_max > 0) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s=%s' is incompatible with '%s > 0'"), + NM_SETTING_BOND_OPTION_MODE, + mode_str, + NM_SETTING_BOND_OPTION_ARP_MISSED_MAX); + g_prefix_error(error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS); + return FALSE; + } } primary = _bond_get_option(self, NM_SETTING_BOND_OPTION_PRIMARY); @@ -1056,6 +1090,21 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) } } + /* ns_ip6_target can only be used with arp_interval, and must + * contain a comma-separated list of IPv6 addresses. + */ + ns_ip6_target = _bond_get_option(self, NM_SETTING_BOND_OPTION_NS_IP6_TARGET); + if (ns_ip6_target && arp_interval == 0) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' option requires '%s' option to be set"), + NM_SETTING_BOND_OPTION_NS_IP6_TARGET, + NM_SETTING_BOND_OPTION_ARP_INTERVAL); + g_prefix_error(error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS); + return FALSE; + } + lacp_rate = _bond_get_option(self, NM_SETTING_BOND_OPTION_LACP_RATE); if (lacp_rate && bond_mode != NM_BOND_MODE_8023AD && !NM_IN_STRSET(lacp_rate, "0", "slow")) { g_set_error(error, @@ -1068,6 +1117,18 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } + lacp_active = _bond_get_option(self, NM_SETTING_BOND_OPTION_LACP_ACTIVE); + if (lacp_active && bond_mode != NM_BOND_MODE_8023AD) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' option is only valid with mode '%s'"), + NM_SETTING_BOND_OPTION_LACP_RATE, + "802.3ad"); + g_prefix_error(error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS); + return FALSE; + } + if (_bond_get_option(self, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP) && _bond_get_option(self, NM_SETTING_BOND_OPTION_NUM_UNSOL_NA) && num_grat_arp != num_unsol_na) { diff --git a/src/libnm-core-impl/tests/test-setting.c b/src/libnm-core-impl/tests/test-setting.c index 46e681812..b30758ffa 100644 --- a/src/libnm-core-impl/tests/test-setting.c +++ b/src/libnm-core-impl/tests/test-setting.c @@ -5259,6 +5259,7 @@ test_bond_meta(void) _A(_nm_setting_bond_opt_value_as_u16, set, NM_SETTING_BOND_OPTION_AD_ACTOR_SYS_PRIO, 0, EINVAL); _A(_nm_setting_bond_opt_value_as_u16, set, NM_SETTING_BOND_OPTION_AD_USER_PORT_KEY, 0, EINVAL); _A(_nm_setting_bond_opt_value_as_u8, set, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP, 1, 0); + _A(_nm_setting_bond_opt_value_as_u8, set, NM_SETTING_BOND_OPTION_ARP_MISSED_MAX, 0, 0); _A(_nm_setting_bond_opt_value_as_u8, set, NM_SETTING_BOND_OPTION_ALL_SLAVES_ACTIVE, 0, 0); _A(_nm_setting_bond_opt_value_as_intbool, set, NM_SETTING_BOND_OPTION_USE_CARRIER, 1, 0); _A(_nm_setting_bond_opt_value_as_intbool, diff --git a/src/libnm-core-intern/nm-core-internal.h b/src/libnm-core-intern/nm-core-internal.h index 3a5601232..5e1cd3582 100644 --- a/src/libnm-core-intern/nm-core-internal.h +++ b/src/libnm-core-intern/nm-core-internal.h @@ -471,6 +471,7 @@ typedef enum { NM_BOND_OPTION_TYPE_INT, NM_BOND_OPTION_TYPE_BOTH, NM_BOND_OPTION_TYPE_IP, + NM_BOND_OPTION_TYPE_IP6, NM_BOND_OPTION_TYPE_MAC, NM_BOND_OPTION_TYPE_IFNAME, } NMBondOptionType; diff --git a/src/libnm-core-public/nm-setting-bond.h b/src/libnm-core-public/nm-setting-bond.h index 10d703bca..7cead175c 100644 --- a/src/libnm-core-public/nm-setting-bond.h +++ b/src/libnm-core-public/nm-setting-bond.h @@ -58,6 +58,9 @@ G_BEGIN_DECLS #define NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB "tlb_dynamic_lb" #define NM_SETTING_BOND_OPTION_LP_INTERVAL "lp_interval" #define NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY "peer_notif_delay" +#define NM_SETTING_BOND_OPTION_ARP_MISSED_MAX "arp_missed_max" +#define NM_SETTING_BOND_OPTION_LACP_ACTIVE "lacp_active" +#define NM_SETTING_BOND_OPTION_NS_IP6_TARGET "ns_ip6_target" typedef struct _NMSettingBondClass NMSettingBondClass; diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 94e92a9be..c75fb3bf8 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -180,6 +180,9 @@ G_STATIC_ASSERT(RTA_MAX == (__RTA_MAX - 1)); /*****************************************************************************/ #define IFLA_BOND_PEER_NOTIF_DELAY 28 +#define IFLA_BOND_AD_LACP_ACTIVE 29 +#define IFLA_BOND_MISSED_MAX 30 +#define IFLA_BOND_NS_IP6_TARGET 31 #undef IFLA_BOND_MAX @@ -1606,6 +1609,9 @@ _parse_lnk_bond(const char *kind, struct nlattr *info_data) [IFLA_BOND_AD_ACTOR_SYSTEM] = {.minlen = sizeof(NMEtherAddr)}, [IFLA_BOND_TLB_DYNAMIC_LB] = {.type = NLA_U8}, [IFLA_BOND_PEER_NOTIF_DELAY] = {.type = NLA_U32}, + [IFLA_BOND_MISSED_MAX] = {.type = NLA_U8}, + [IFLA_BOND_AD_LACP_ACTIVE] = {.type = NLA_U8}, + [IFLA_BOND_NS_IP6_TARGET] = {.type = NLA_NESTED}, }; NMPlatformLnkBond *props; struct nlattr *tb[G_N_ELEMENTS(policy)]; @@ -1660,6 +1666,19 @@ _parse_lnk_bond(const char *kind, struct nlattr *info_data) props->arp_ip_target[props->arp_ip_targets_num++] = nla_get_u32(attr); } } + if (tb[IFLA_BOND_NS_IP6_TARGET]) { + struct nlattr *attr; + int rem; + + nla_for_each_nested (attr, tb[IFLA_BOND_NS_IP6_TARGET], rem) { + if (props->ns_ip6_targets_num > NM_BOND_MAX_ARP_TARGETS - 1) + break; + if (nla_len(attr) < sizeof(struct in6_addr)) + break; + + props->ns_ip6_target[props->ns_ip6_targets_num++] = nla_get_in6_addr(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]) @@ -1680,6 +1699,8 @@ _parse_lnk_bond(const char *kind, struct nlattr *info_data) 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_MISSED_MAX]) + props->arp_missed_max = nla_get_u8(tb[IFLA_BOND_MISSED_MAX]); if (tb[IFLA_BOND_MIN_LINKS]) props->min_links = nla_get_u32(tb[IFLA_BOND_MIN_LINKS]); if (tb[IFLA_BOND_LP_INTERVAL]) @@ -1688,6 +1709,10 @@ _parse_lnk_bond(const char *kind, struct nlattr *info_data) 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_LACP_ACTIVE]) { + props->lacp_active = nla_get_u8(tb[IFLA_BOND_AD_LACP_ACTIVE]); + props->lacp_active_has = TRUE; + } 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]) @@ -4699,6 +4724,17 @@ _nl_msg_new_link_set_linkinfo(struct nl_msg *msg, NMLinkType link_type, gconstpo nla_nest_end(msg, targets); } + if (props->ns_ip6_targets_num > 0) { + targets = nla_nest_start(msg, IFLA_BOND_NS_IP6_TARGET); + if (!targets) + goto nla_put_failure; + + for (i = 0; i < props->ns_ip6_targets_num; i++) + NLA_PUT(msg, i, sizeof(struct in6_addr), &props->ns_ip6_target[i]); + + nla_nest_end(msg, targets); + } + if (props->arp_all_targets) NLA_PUT_U32(msg, IFLA_BOND_ARP_ALL_TARGETS, props->arp_all_targets); if (props->arp_interval) @@ -4734,6 +4770,8 @@ _nl_msg_new_link_set_linkinfo(struct nl_msg *msg, NMLinkType link_type, gconstpo &props->ad_actor_system); if (props->ad_select) NLA_PUT_U8(msg, IFLA_BOND_AD_SELECT, props->ad_select); + if (props->arp_missed_max) + NLA_PUT_U8(msg, IFLA_BOND_MISSED_MAX, props->arp_missed_max); NLA_PUT_U8(msg, IFLA_BOND_ALL_SLAVES_ACTIVE, props->all_ports_active); @@ -4741,6 +4779,8 @@ _nl_msg_new_link_set_linkinfo(struct nl_msg *msg, NMLinkType link_type, gconstpo 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->lacp_active_has) + NLA_PUT_U8(msg, IFLA_BOND_AD_LACP_ACTIVE, props->lacp_active); if (props->num_grat_arp) NLA_PUT_U8(msg, IFLA_BOND_NUM_PEER_NOTIF, props->num_grat_arp); diff --git a/src/libnm-platform/nm-netlink.h b/src/libnm-platform/nm-netlink.h index 117525f94..6fed8189b 100644 --- a/src/libnm-platform/nm-netlink.h +++ b/src/libnm-platform/nm-netlink.h @@ -290,6 +290,17 @@ size_t nla_memcpy(void *dst, const struct nlattr *nla, size_t dstsize); } \ G_STMT_END +static inline struct in6_addr +nla_get_in6_addr(const struct nlattr *nla) +{ + struct in6_addr in6; + + nm_assert(nla_len(nla) >= sizeof(struct in6_addr)); + + nla_memcpy(&in6, nla, sizeof(in6)); + return in6; +} + int nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data); static inline int diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index 06c1f4a74..eddbaba37 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -6187,6 +6187,7 @@ nm_platform_lnk_bond_to_string(const NMPlatformLnkBond *lnk, char *buf, gsize le char sbuf_miimon[30]; char sbuf_updelay[30]; char sbuf_downdelay[30]; + char sbuf_lacp_active[30]; char sbuf_peer_notif_delay[60]; char sbuf_resend_igmp[30]; char sbuf_lp_interval[30]; @@ -6221,7 +6222,9 @@ nm_platform_lnk_bond_to_string(const NMPlatformLnkBond *lnk, char *buf, gsize le " xmit_hash_policy %u" " num_gray_arp %u" " all_ports_active %u" + " arp_missed_max %u" " lacp_rate %u" + "%s" /* lacp_active */ " ad_select %u" " use_carrier %d" "%s" /* tlb_dynamic_lb */, @@ -6271,7 +6274,14 @@ nm_platform_lnk_bond_to_string(const NMPlatformLnkBond *lnk, char *buf, gsize le lnk->xmit_hash_policy, lnk->num_grat_arp, lnk->all_ports_active, + lnk->arp_missed_max, lnk->lacp_rate, + lnk->lacp_active_has || lnk->lacp_active != 0 + ? nm_sprintf_buf(sbuf_lacp_active, + " lacp_active%s %u", + !lnk->lacp_active_has ? "?" : "", + lnk->lacp_active) + : "", lnk->ad_select, (int) lnk->use_carrier, lnk->tlb_dynamic_lb_has ? nm_sprintf_buf(sbuf_tlb_dynamic_lb, @@ -6289,6 +6299,15 @@ nm_platform_lnk_bond_to_string(const NMPlatformLnkBond *lnk, char *buf, gsize le nm_strbuf_append_str(&buf, &len, nm_inet4_ntop(lnk->arp_ip_target[i], target)); } } + if (lnk->ns_ip6_targets_num > 0) { + nm_strbuf_append_str(&buf, &len, " ns_ip6_target"); + for (i = 0; i < lnk->ns_ip6_targets_num; i++) { + char target[INET6_ADDRSTRLEN]; + + nm_strbuf_append_c(&buf, &len, ' '); + nm_strbuf_append_str(&buf, &len, nm_inet6_ntop(&lnk->ns_ip6_target[i], target)); + } + } return buf; } @@ -8037,15 +8056,19 @@ nm_platform_lnk_bond_hash_update(const NMPlatformLnkBond *obj, NMHashState *h) obj->ad_actor_system, obj->ad_select, obj->all_ports_active, + obj->arp_missed_max, obj->arp_ip_targets_num, obj->fail_over_mac, obj->lacp_rate, + obj->lacp_active, + obj->ns_ip6_targets_num, obj->num_grat_arp, obj->mode, obj->primary_reselect, obj->xmit_hash_policy, NM_HASH_COMBINE_BOOLS(guint16, obj->downdelay_has, + obj->lacp_active_has, obj->lp_interval_has, obj->miimon_has, obj->peer_notif_delay_has, @@ -8056,12 +8079,19 @@ nm_platform_lnk_bond_hash_update(const NMPlatformLnkBond *obj, NMHashState *h) obj->use_carrier)); nm_hash_update(h, obj->arp_ip_target, obj->arp_ip_targets_num * sizeof(obj->arp_ip_target[0])); + nm_hash_update(h, obj->ns_ip6_target, obj->ns_ip6_targets_num * sizeof(obj->ns_ip6_target[0])); } int nm_platform_lnk_bond_cmp(const NMPlatformLnkBond *a, const NMPlatformLnkBond *b) { NM_CMP_SELF(a, b); + NM_CMP_FIELD(a, b, arp_ip_targets_num); + NM_CMP_FIELD(a, b, ns_ip6_targets_num); + NM_CMP_FIELD_MEMCMP_LEN(a, + b, + ns_ip6_target, + a->ns_ip6_targets_num * sizeof(a->ns_ip6_target[0])); NM_CMP_FIELD_MEMCMP_LEN(a, b, arp_ip_target, @@ -8083,14 +8113,16 @@ nm_platform_lnk_bond_cmp(const NMPlatformLnkBond *a, const NMPlatformLnkBond *b) 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, arp_missed_max); NM_CMP_FIELD(a, b, fail_over_mac); NM_CMP_FIELD(a, b, lacp_rate); + NM_CMP_FIELD(a, b, lacp_active); 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, downdelay_has); + NM_CMP_FIELD_BOOL(a, b, lacp_active_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); diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index d816513cd..08a7716e3 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -764,40 +764,45 @@ extern const NMPlatformLnkBridge nm_platform_lnk_bridge_default; #define NM_BOND_MAX_ARP_TARGETS 16 typedef struct { - int primary; - 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 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 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; + struct in6_addr ns_ip6_target[NM_BOND_MAX_ARP_TARGETS]; + int primary; + 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 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_missed_max; + guint8 arp_ip_targets_num; + guint8 fail_over_mac; + guint8 lacp_active; + guint8 lacp_rate; + guint8 ns_ip6_targets_num; + guint8 num_grat_arp; + guint8 mode; + guint8 primary_reselect; + guint8 xmit_hash_policy; + bool downdelay_has : 1; + bool lacp_active_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; } _nm_alignas(NMPlatformObject) NMPlatformLnkBond; typedef struct { diff --git a/src/libnmc-setting/nm-meta-setting-desc.c b/src/libnmc-setting/nm-meta-setting-desc.c index 60a2cfd40..1770a2c75 100644 --- a/src/libnmc-setting/nm-meta-setting-desc.c +++ b/src/libnmc-setting/nm-meta-setting-desc.c @@ -2474,7 +2474,9 @@ _get_fcn_bond_options(ARGS_GET_FCN) nm_setting_bond_get_option(s_bond, i, &key, &val); - if (nm_streq(key, NM_SETTING_BOND_OPTION_ARP_IP_TARGET)) { + if (NM_IN_STRSET(key, + NM_SETTING_BOND_OPTION_ARP_IP_TARGET, + NM_SETTING_BOND_OPTION_NS_IP6_TARGET)) { val_tmp = g_strdup(val); for (p = val_tmp; p && *p; p++) { if (*p == ',') @@ -2516,7 +2518,8 @@ _nm_meta_setting_bond_add_option(NMSetting *setting, value = nmc_bond_validate_mode(value, error); if (!value) return FALSE; - } else if (nm_streq(name, NM_SETTING_BOND_OPTION_ARP_IP_TARGET)) { + } else if (nm_streq(name, NM_SETTING_BOND_OPTION_ARP_IP_TARGET) + || nm_streq(name, NM_SETTING_BOND_OPTION_NS_IP6_TARGET)) { value = tmp_value = g_strdup(value); for (p = tmp_value; p && *p; p++) if (*p == ' ') diff --git a/src/nmtui/nmt-page-bond.c b/src/nmtui/nmt-page-bond.c index edcf681ec..3396320da 100644 --- a/src/nmtui/nmt-page-bond.c +++ b/src/nmtui/nmt-page-bond.c @@ -141,7 +141,7 @@ bond_options_changed(GObject *object, GParamSpec *pspec, gpointer user_data) nmt_newt_entry_set_text(priv->arp_interval, val ?: "0"); val = nm_setting_bond_get_option_by_name(s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET); - ips = nm_utils_bond_option_arp_ip_targets_split(val); + ips = nm_utils_bond_option_ip_split(val); g_object_set(G_OBJECT(priv->arp_ip_target), "strings", ips ?: NM_PTRARRAY_EMPTY(const char *),