forked from mirrors/linux
		
	bonding: add new option ns_ip6_target
This patch add a new bonding option ns_ip6_target, which correspond to the arp_ip_target. With this we set IPv6 targets and send IPv6 NS request to determine the health of the link. For other related options like the validation, we still use arp_validate, and will change to ns_validate later. Note: the sysfs configuration support was removed based on https://lore.kernel.org/netdev/8863.1645071997@famine Signed-off-by: Hangbin Liu <liuhangbin@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									4e24be018e
								
							
						
					
					
						commit
						129e3c1bab
					
				
					 7 changed files with 155 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -313,6 +313,17 @@ arp_ip_target
 | 
			
		|||
	maximum number of targets that can be specified is 16.  The
 | 
			
		||||
	default value is no IP addresses.
 | 
			
		||||
 | 
			
		||||
ns_ip6_target
 | 
			
		||||
 | 
			
		||||
	Specifies the IPv6 addresses to use as IPv6 monitoring peers when
 | 
			
		||||
	arp_interval is > 0.  These are the targets of the NS request
 | 
			
		||||
	sent to determine the health of the link to the targets.
 | 
			
		||||
	Specify these values in ffff:ffff::ffff:ffff format.  Multiple IPv6
 | 
			
		||||
	addresses must be separated by a comma.  At least one IPv6
 | 
			
		||||
	address must be given for NS/NA monitoring to function.  The
 | 
			
		||||
	maximum number of targets that can be specified is 16.  The
 | 
			
		||||
	default value is no IPv6 addresses.
 | 
			
		||||
 | 
			
		||||
arp_validate
 | 
			
		||||
 | 
			
		||||
	Specifies whether or not ARP probes and replies should be
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,6 +14,7 @@
 | 
			
		|||
#include <net/netlink.h>
 | 
			
		||||
#include <net/rtnetlink.h>
 | 
			
		||||
#include <net/bonding.h>
 | 
			
		||||
#include <net/ipv6.h>
 | 
			
		||||
 | 
			
		||||
static size_t bond_get_slave_size(const struct net_device *bond_dev,
 | 
			
		||||
				  const struct net_device *slave_dev)
 | 
			
		||||
| 
						 | 
				
			
			@ -111,6 +112,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = {
 | 
			
		|||
	[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_NS_IP6_TARGET]	= { .type = NLA_NESTED },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1] = {
 | 
			
		||||
| 
						 | 
				
			
			@ -272,6 +274,40 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
 | 
			
		|||
		if (err)
 | 
			
		||||
			return err;
 | 
			
		||||
	}
 | 
			
		||||
#if IS_ENABLED(CONFIG_IPV6)
 | 
			
		||||
	if (data[IFLA_BOND_NS_IP6_TARGET]) {
 | 
			
		||||
		struct nlattr *attr;
 | 
			
		||||
		int i = 0, rem;
 | 
			
		||||
 | 
			
		||||
		bond_option_ns_ip6_targets_clear(bond);
 | 
			
		||||
		nla_for_each_nested(attr, data[IFLA_BOND_NS_IP6_TARGET], rem) {
 | 
			
		||||
			struct in6_addr addr6;
 | 
			
		||||
 | 
			
		||||
			if (nla_len(attr) < sizeof(addr6)) {
 | 
			
		||||
				NL_SET_ERR_MSG(extack, "Invalid IPv6 address");
 | 
			
		||||
				return -EINVAL;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			addr6 = nla_get_in6_addr(attr);
 | 
			
		||||
 | 
			
		||||
			if (ipv6_addr_type(&addr6) & IPV6_ADDR_LINKLOCAL) {
 | 
			
		||||
				NL_SET_ERR_MSG(extack, "Invalid IPv6 addr6");
 | 
			
		||||
				return -EINVAL;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			bond_opt_initextra(&newval, &addr6, sizeof(addr6));
 | 
			
		||||
			err = __bond_opt_set(bond, BOND_OPT_NS_TARGETS,
 | 
			
		||||
					     &newval);
 | 
			
		||||
			if (err)
 | 
			
		||||
				break;
 | 
			
		||||
			i++;
 | 
			
		||||
		}
 | 
			
		||||
		if (i == 0 && bond->params.arp_interval)
 | 
			
		||||
			netdev_warn(bond->dev, "Removing last ns target with arp_interval on\n");
 | 
			
		||||
		if (err)
 | 
			
		||||
			return err;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	if (data[IFLA_BOND_ARP_VALIDATE]) {
 | 
			
		||||
		int arp_validate = nla_get_u32(data[IFLA_BOND_ARP_VALIDATE]);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -526,6 +562,9 @@ static size_t bond_get_size(const struct net_device *bond_dev)
 | 
			
		|||
		nla_total_size(sizeof(u8)) + /* IFLA_BOND_TLB_DYNAMIC_LB */
 | 
			
		||||
		nla_total_size(sizeof(u32)) +	/* IFLA_BOND_PEER_NOTIF_DELAY */
 | 
			
		||||
		nla_total_size(sizeof(u8)) +	/* IFLA_BOND_MISSED_MAX */
 | 
			
		||||
						/* IFLA_BOND_NS_IP6_TARGET */
 | 
			
		||||
		nla_total_size(sizeof(struct nlattr)) +
 | 
			
		||||
		nla_total_size(sizeof(struct in6_addr)) * BOND_MAX_NS_TARGETS +
 | 
			
		||||
		0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -603,6 +642,26 @@ static int bond_fill_info(struct sk_buff *skb,
 | 
			
		|||
			bond->params.arp_all_targets))
 | 
			
		||||
		goto nla_put_failure;
 | 
			
		||||
 | 
			
		||||
#if IS_ENABLED(CONFIG_IPV6)
 | 
			
		||||
	targets = nla_nest_start(skb, IFLA_BOND_NS_IP6_TARGET);
 | 
			
		||||
	if (!targets)
 | 
			
		||||
		goto nla_put_failure;
 | 
			
		||||
 | 
			
		||||
	targets_added = 0;
 | 
			
		||||
	for (i = 0; i < BOND_MAX_NS_TARGETS; i++) {
 | 
			
		||||
		if (!ipv6_addr_any(&bond->params.ns_targets[i])) {
 | 
			
		||||
			if (nla_put_in6_addr(skb, i, &bond->params.ns_targets[i]))
 | 
			
		||||
				goto nla_put_failure;
 | 
			
		||||
			targets_added = 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (targets_added)
 | 
			
		||||
		nla_nest_end(skb, targets);
 | 
			
		||||
	else
 | 
			
		||||
		nla_nest_cancel(skb, targets);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	primary = rtnl_dereference(bond->primary_slave);
 | 
			
		||||
	if (primary &&
 | 
			
		||||
	    nla_put_u32(skb, IFLA_BOND_PRIMARY, primary->dev->ifindex))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,6 +34,10 @@ static int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target);
 | 
			
		|||
static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target);
 | 
			
		||||
static int bond_option_arp_ip_targets_set(struct bonding *bond,
 | 
			
		||||
					  const struct bond_opt_value *newval);
 | 
			
		||||
#if IS_ENABLED(CONFIG_IPV6)
 | 
			
		||||
static int bond_option_ns_ip6_targets_set(struct bonding *bond,
 | 
			
		||||
					  const struct bond_opt_value *newval);
 | 
			
		||||
#endif
 | 
			
		||||
static int bond_option_arp_validate_set(struct bonding *bond,
 | 
			
		||||
					const struct bond_opt_value *newval);
 | 
			
		||||
static int bond_option_arp_all_targets_set(struct bonding *bond,
 | 
			
		||||
| 
						 | 
				
			
			@ -295,6 +299,15 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = {
 | 
			
		|||
		.flags = BOND_OPTFLAG_RAWVAL,
 | 
			
		||||
		.set = bond_option_arp_ip_targets_set
 | 
			
		||||
	},
 | 
			
		||||
#if IS_ENABLED(CONFIG_IPV6)
 | 
			
		||||
	[BOND_OPT_NS_TARGETS] = {
 | 
			
		||||
		.id = BOND_OPT_NS_TARGETS,
 | 
			
		||||
		.name = "ns_ip6_target",
 | 
			
		||||
		.desc = "NS targets in ffff:ffff::ffff:ffff form",
 | 
			
		||||
		.flags = BOND_OPTFLAG_RAWVAL,
 | 
			
		||||
		.set = bond_option_ns_ip6_targets_set
 | 
			
		||||
	},
 | 
			
		||||
#endif
 | 
			
		||||
	[BOND_OPT_DOWNDELAY] = {
 | 
			
		||||
		.id = BOND_OPT_DOWNDELAY,
 | 
			
		||||
		.name = "downdelay",
 | 
			
		||||
| 
						 | 
				
			
			@ -1184,6 +1197,65 @@ static int bond_option_arp_ip_targets_set(struct bonding *bond,
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if IS_ENABLED(CONFIG_IPV6)
 | 
			
		||||
static void _bond_options_ns_ip6_target_set(struct bonding *bond, int slot,
 | 
			
		||||
					    struct in6_addr *target,
 | 
			
		||||
					    unsigned long last_rx)
 | 
			
		||||
{
 | 
			
		||||
	struct in6_addr *targets = bond->params.ns_targets;
 | 
			
		||||
	struct list_head *iter;
 | 
			
		||||
	struct slave *slave;
 | 
			
		||||
 | 
			
		||||
	if (slot >= 0 && slot < BOND_MAX_NS_TARGETS) {
 | 
			
		||||
		bond_for_each_slave(bond, slave, iter)
 | 
			
		||||
			slave->target_last_arp_rx[slot] = last_rx;
 | 
			
		||||
		targets[slot] = *target;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void bond_option_ns_ip6_targets_clear(struct bonding *bond)
 | 
			
		||||
{
 | 
			
		||||
	struct in6_addr addr_any = in6addr_any;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < BOND_MAX_NS_TARGETS; i++)
 | 
			
		||||
		_bond_options_ns_ip6_target_set(bond, i, &addr_any, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int bond_option_ns_ip6_targets_set(struct bonding *bond,
 | 
			
		||||
					  const struct bond_opt_value *newval)
 | 
			
		||||
{
 | 
			
		||||
	struct in6_addr *target = (struct in6_addr *)newval->extra;
 | 
			
		||||
	struct in6_addr *targets = bond->params.ns_targets;
 | 
			
		||||
	struct in6_addr addr_any = in6addr_any;
 | 
			
		||||
	int index;
 | 
			
		||||
 | 
			
		||||
	if (!bond_is_ip6_target_ok(target)) {
 | 
			
		||||
		netdev_err(bond->dev, "invalid NS target %pI6c specified for addition\n",
 | 
			
		||||
			   target);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (bond_get_targets_ip6(targets, target) != -1) { /* dup */
 | 
			
		||||
		netdev_err(bond->dev, "NS target %pI6c is already present\n",
 | 
			
		||||
			   target);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	index = bond_get_targets_ip6(targets, &addr_any); /* first free slot */
 | 
			
		||||
	if (index == -1) {
 | 
			
		||||
		netdev_err(bond->dev, "NS target table is full!\n");
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	netdev_dbg(bond->dev, "Adding NS target %pI6c\n", target);
 | 
			
		||||
 | 
			
		||||
	_bond_options_ns_ip6_target_set(bond, index, target, jiffies);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static int bond_option_arp_validate_set(struct bonding *bond,
 | 
			
		||||
					const struct bond_opt_value *newval)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -66,6 +66,7 @@ enum {
 | 
			
		|||
	BOND_OPT_PEER_NOTIF_DELAY,
 | 
			
		||||
	BOND_OPT_LACP_ACTIVE,
 | 
			
		||||
	BOND_OPT_MISSED_MAX,
 | 
			
		||||
	BOND_OPT_NS_TARGETS,
 | 
			
		||||
	BOND_OPT_LAST
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -140,5 +141,8 @@ static inline void __bond_opt_init(struct bond_opt_value *optval,
 | 
			
		|||
	__bond_opt_init(optval, NULL, ULLONG_MAX, extra, extra_len)
 | 
			
		||||
 | 
			
		||||
void bond_option_arp_ip_targets_clear(struct bonding *bond);
 | 
			
		||||
#if IS_ENABLED(CONFIG_IPV6)
 | 
			
		||||
void bond_option_ns_ip6_targets_clear(struct bonding *bond);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* _NET_BOND_OPTIONS_H */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -503,6 +503,13 @@ static inline int bond_is_ip_target_ok(__be32 addr)
 | 
			
		|||
	return !ipv4_is_lbcast(addr) && !ipv4_is_zeronet(addr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int bond_is_ip6_target_ok(struct in6_addr *addr)
 | 
			
		||||
{
 | 
			
		||||
	return !ipv6_addr_any(addr) &&
 | 
			
		||||
	       !ipv6_addr_loopback(addr) &&
 | 
			
		||||
	       !ipv6_addr_is_multicast(addr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Get the oldest arp which we've received on this slave for bond's
 | 
			
		||||
 * arp_targets.
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -860,6 +860,7 @@ enum {
 | 
			
		|||
	IFLA_BOND_PEER_NOTIF_DELAY,
 | 
			
		||||
	IFLA_BOND_AD_LACP_ACTIVE,
 | 
			
		||||
	IFLA_BOND_MISSED_MAX,
 | 
			
		||||
	IFLA_BOND_NS_IP6_TARGET,
 | 
			
		||||
	__IFLA_BOND_MAX,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -860,6 +860,7 @@ enum {
 | 
			
		|||
	IFLA_BOND_PEER_NOTIF_DELAY,
 | 
			
		||||
	IFLA_BOND_AD_LACP_ACTIVE,
 | 
			
		||||
	IFLA_BOND_MISSED_MAX,
 | 
			
		||||
	IFLA_BOND_NS_IP6_TARGET,
 | 
			
		||||
	__IFLA_BOND_MAX,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue