diff options
-rw-r--r-- | src/core/devices/nm-device-bond.c | 36 | ||||
-rw-r--r-- | src/libnm-core-aux-intern/nm-libnm-core-utils.c | 3 | ||||
-rw-r--r-- | src/libnm-core-aux-intern/nm-libnm-core-utils.h | 2 | ||||
-rw-r--r-- | src/libnm-core-impl/nm-setting-bond.c | 37 | ||||
-rw-r--r-- | src/libnm-core-intern/nm-core-internal.h | 1 | ||||
-rw-r--r-- | src/libnm-core-public/nm-setting-bond.h | 1 | ||||
-rw-r--r-- | src/libnm-platform/nm-linux-platform.c | 26 | ||||
-rw-r--r-- | src/libnm-platform/nm-platform.c | 16 | ||||
-rw-r--r-- | src/libnm-platform/nm-platform.h | 76 | ||||
-rw-r--r-- | src/libnmc-setting/nm-meta-setting-desc.c | 7 | ||||
-rw-r--r-- | src/nmtui/nmt-page-bond.c | 2 |
11 files changed, 157 insertions, 50 deletions
diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c index 853e1b6c1b..cb32331921 100644 --- a/src/core/devices/nm-device-bond.c +++ b/src/core/devices/nm-device-bond.c @@ -57,7 +57,7 @@ #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 /*****************************************************************************/ @@ -270,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); @@ -367,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; @@ -383,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) { @@ -462,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; 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 5ccb5e400e..e7530c83b6 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); } /*****************************************************************************/ 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 79ddfbbcc7..589291e5a9 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); diff --git a/src/libnm-core-impl/nm-setting-bond.c b/src/libnm-core-impl/nm-setting-bond.c index 5367f5230c..a09129afb0 100644 --- a/src/libnm-core-impl/nm-setting-bond.c +++ b/src/libnm-core-impl/nm-setting-bond.c @@ -94,6 +94,7 @@ static const char *const valid_options_lst[] = { 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, }; @@ -135,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: @@ -213,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}}, @@ -510,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, @@ -524,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; } @@ -580,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; @@ -858,6 +869,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) 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; @@ -1078,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, diff --git a/src/libnm-core-intern/nm-core-internal.h b/src/libnm-core-intern/nm-core-internal.h index 3a56012323..5e1cd3582a 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 1e653abcfa..7cead175c8 100644 --- a/src/libnm-core-public/nm-setting-bond.h +++ b/src/libnm-core-public/nm-setting-bond.h @@ -60,6 +60,7 @@ G_BEGIN_DECLS #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 9c9987bbba..c75fb3bf81 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -182,6 +182,7 @@ 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 @@ -1610,6 +1611,7 @@ _parse_lnk_bond(const char *kind, struct nlattr *info_data) [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)]; @@ -1664,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]) @@ -4709,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) diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index 7f0e444805..eddbaba376 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -6299,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; } @@ -8052,6 +8061,7 @@ nm_platform_lnk_bond_hash_update(const NMPlatformLnkBond *obj, NMHashState *h) obj->fail_over_mac, obj->lacp_rate, obj->lacp_active, + obj->ns_ip6_targets_num, obj->num_grat_arp, obj->mode, obj->primary_reselect, @@ -8069,6 +8079,7 @@ 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 @@ -8076,6 +8087,11 @@ 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, diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index 61173a6cc2..08a7716e39 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -764,43 +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_missed_max; - guint8 arp_ip_targets_num; - guint8 fail_over_mac; - guint8 lacp_active; - guint8 lacp_rate; - 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; + 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 60a2cfd402..1770a2c753 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 edcf681ecf..3396320dab 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 *), |