Commit 129e3c1b authored by Hangbin Liu's avatar Hangbin Liu Committed by David S. Miller
Browse files

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: default avatarHangbin Liu <liuhangbin@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4e24be01
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -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
+59 −0
Original line number Diff line number Diff line
@@ -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))
+72 −0
Original line number Diff line number Diff line
@@ -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)
{
+4 −0
Original line number Diff line number Diff line
@@ -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 */
+7 −0
Original line number Diff line number Diff line
@@ -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.
 */
Loading