* [PATCH net-next v8 1/7] bonding: Adding struct bond_arp_target
2025-08-28 22:18 [PATCH net-next v8 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
@ 2025-08-28 22:18 ` David Wilder
2025-08-28 22:18 ` [PATCH net-next v8 2/7] bonding: Adding extra_len field to struct bond_opt_value David Wilder
` (5 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: David Wilder @ 2025-08-28 22:18 UTC (permalink / raw)
To: netdev
Cc: jv, wilder, pradeeps, pradeep, i.maximets, amorenoz, haliu,
stephen, horms
Replacing the definition of bond_params.arp_targets (__be32 arp_targets[])
with:
struct bond_arp_target {
__be32 target_ip;
struct bond_vlan_tag *tags;
u32 flags;
};
To provide storage for a list of vlan tags for each target.
All references to arp_target are change to use the new structure.
Signed-off-by: David Wilder <wilder@us.ibm.com>
---
drivers/net/bonding/bond_main.c | 29 ++++++++++++++++-------------
drivers/net/bonding/bond_netlink.c | 4 ++--
drivers/net/bonding/bond_options.c | 18 +++++++++---------
drivers/net/bonding/bond_procfs.c | 4 ++--
drivers/net/bonding/bond_sysfs.c | 4 ++--
include/net/bond_options.h | 20 ++++++++++++++++++++
include/net/bonding.h | 15 +++++----------
7 files changed, 56 insertions(+), 38 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 257333c88710..a095ca4e14a7 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3163,26 +3163,29 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
{
struct rtable *rt;
struct bond_vlan_tag *tags;
- __be32 *targets = bond->params.arp_targets, addr;
+ struct bond_arp_target *targets = bond->params.arp_targets;
+ __be32 target_ip, addr;
int i;
- for (i = 0; i < BOND_MAX_ARP_TARGETS && targets[i]; i++) {
+ for (i = 0; i < BOND_MAX_ARP_TARGETS && targets[i].target_ip; i++) {
+ target_ip = targets[i].target_ip;
+ tags = targets[i].tags;
+
slave_dbg(bond->dev, slave->dev, "%s: target %pI4\n",
- __func__, &targets[i]);
- tags = NULL;
+ __func__, &target_ip);
/* Find out through which dev should the packet go */
- rt = ip_route_output(dev_net(bond->dev), targets[i], 0, 0, 0,
+ rt = ip_route_output(dev_net(bond->dev), target_ip, 0, 0, 0,
RT_SCOPE_LINK);
if (IS_ERR(rt)) {
- /* there's no route to target - try to send arp
+ /* there's no route to target_ip - try to send arp
* probe to generate any traffic (arp_validate=0)
*/
if (bond->params.arp_validate)
pr_warn_once("%s: no route to arp_ip_target %pI4 and arp_validate is set\n",
bond->dev->name,
- &targets[i]);
- bond_arp_send(slave, ARPOP_REQUEST, targets[i],
+ &target_ip);
+ bond_arp_send(slave, ARPOP_REQUEST, target_ip,
0, tags);
continue;
}
@@ -3200,15 +3203,15 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
/* Not our device - skip */
slave_dbg(bond->dev, slave->dev, "no path to arp_ip_target %pI4 via rt.dev %s\n",
- &targets[i], rt->dst.dev ? rt->dst.dev->name : "NULL");
+ &target_ip, rt->dst.dev ? rt->dst.dev->name : "NULL");
ip_rt_put(rt);
continue;
found:
- addr = bond_confirm_addr(rt->dst.dev, targets[i], 0);
+ addr = bond_confirm_addr(rt->dst.dev, target_ip, 0);
ip_rt_put(rt);
- bond_arp_send(slave, ARPOP_REQUEST, targets[i], addr, tags);
+ bond_arp_send(slave, ARPOP_REQUEST, target_ip, addr, tags);
kfree(tags);
}
}
@@ -6164,7 +6167,7 @@ static int __init bond_check_params(struct bond_params *params)
int arp_all_targets_value = 0;
u16 ad_actor_sys_prio = 0;
u16 ad_user_port_key = 0;
- __be32 arp_target[BOND_MAX_ARP_TARGETS] = { 0 };
+ struct bond_arp_target arp_target[BOND_MAX_ARP_TARGETS] = { 0 };
int arp_ip_count;
int bond_mode = BOND_MODE_ROUNDROBIN;
int xmit_hashtype = BOND_XMIT_POLICY_LAYER2;
@@ -6358,7 +6361,7 @@ static int __init bond_check_params(struct bond_params *params)
arp_interval = 0;
} else {
if (bond_get_targets_ip(arp_target, ip) == -1)
- arp_target[arp_ip_count++] = ip;
+ arp_target[arp_ip_count++].target_ip = ip;
else
pr_warn("Warning: duplicate address %pI4 in arp_ip_target, skipping\n",
&ip);
diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
index 57fff2421f1b..9939e28dedd9 100644
--- a/drivers/net/bonding/bond_netlink.c
+++ b/drivers/net/bonding/bond_netlink.c
@@ -700,8 +700,8 @@ static int bond_fill_info(struct sk_buff *skb,
targets_added = 0;
for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
- if (bond->params.arp_targets[i]) {
- if (nla_put_be32(skb, i, bond->params.arp_targets[i]))
+ if (bond->params.arp_targets[i].target_ip) {
+ if (nla_put_be32(skb, i, bond->params.arp_targets[i].target_ip))
goto nla_put_failure;
targets_added = 1;
}
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index 3b6f815c55ff..2c5e8d95999d 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -1113,7 +1113,7 @@ static int bond_option_arp_interval_set(struct bonding *bond,
netdev_dbg(bond->dev, "ARP monitoring cannot be used with MII monitoring. Disabling MII monitoring\n");
bond->params.miimon = 0;
}
- if (!bond->params.arp_targets[0])
+ if (!bond->params.arp_targets[0].target_ip)
netdev_dbg(bond->dev, "ARP monitoring has been set up, but no ARP targets have been specified\n");
}
if (bond->dev->flags & IFF_UP) {
@@ -1141,20 +1141,20 @@ static void _bond_options_arp_ip_target_set(struct bonding *bond, int slot,
__be32 target,
unsigned long last_rx)
{
- __be32 *targets = bond->params.arp_targets;
+ struct bond_arp_target *targets = bond->params.arp_targets;
struct list_head *iter;
struct slave *slave;
if (slot >= 0 && slot < BOND_MAX_ARP_TARGETS) {
bond_for_each_slave(bond, slave, iter)
slave->target_last_arp_rx[slot] = last_rx;
- targets[slot] = target;
+ targets[slot].target_ip = target;
}
}
static int _bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
{
- __be32 *targets = bond->params.arp_targets;
+ struct bond_arp_target *targets = bond->params.arp_targets;
int ind;
if (!bond_is_ip_target_ok(target)) {
@@ -1189,7 +1189,7 @@ 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)
{
- __be32 *targets = bond->params.arp_targets;
+ struct bond_arp_target *targets = bond->params.arp_targets;
struct list_head *iter;
struct slave *slave;
unsigned long *targets_rx;
@@ -1208,20 +1208,20 @@ static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target)
return -EINVAL;
}
- if (ind == 0 && !targets[1] && bond->params.arp_interval)
+ if (ind == 0 && !targets[1].target_ip && bond->params.arp_interval)
netdev_warn(bond->dev, "Removing last arp target with arp_interval on\n");
netdev_dbg(bond->dev, "Removing ARP target %pI4\n", &target);
bond_for_each_slave(bond, slave, iter) {
targets_rx = slave->target_last_arp_rx;
- for (i = ind; (i < BOND_MAX_ARP_TARGETS-1) && targets[i+1]; i++)
+ for (i = ind; (i < BOND_MAX_ARP_TARGETS - 1) && targets[i + 1].target_ip; i++)
targets_rx[i] = targets_rx[i+1];
targets_rx[i] = 0;
}
- for (i = ind; (i < BOND_MAX_ARP_TARGETS-1) && targets[i+1]; i++)
+ for (i = ind; (i < BOND_MAX_ARP_TARGETS - 1) && targets[i + 1].target_ip; i++)
targets[i] = targets[i+1];
- targets[i] = 0;
+ targets[i].target_ip = 0;
return 0;
}
diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c
index 7edf72ec816a..94e6fd7041ee 100644
--- a/drivers/net/bonding/bond_procfs.c
+++ b/drivers/net/bonding/bond_procfs.c
@@ -121,11 +121,11 @@ static void bond_info_show_master(struct seq_file *seq)
seq_printf(seq, "ARP IP target/s (n.n.n.n form):");
for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) {
- if (!bond->params.arp_targets[i])
+ if (!bond->params.arp_targets[i].target_ip)
break;
if (printed)
seq_printf(seq, ",");
- seq_printf(seq, " %pI4", &bond->params.arp_targets[i]);
+ seq_printf(seq, " %pI4", &bond->params.arp_targets[i].target_ip);
printed = 1;
}
seq_printf(seq, "\n");
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 1e13bb170515..d7c09e0a14dd 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -290,9 +290,9 @@ static ssize_t bonding_show_arp_targets(struct device *d,
int i, res = 0;
for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
- if (bond->params.arp_targets[i])
+ if (bond->params.arp_targets[i].target_ip)
res += sysfs_emit_at(buf, res, "%pI4 ",
- &bond->params.arp_targets[i]);
+ &bond->params.arp_targets[i].target_ip);
}
if (res)
buf[res-1] = '\n'; /* eat the leftover space */
diff --git a/include/net/bond_options.h b/include/net/bond_options.h
index 022b122a9fb6..b7f275bc33a1 100644
--- a/include/net/bond_options.h
+++ b/include/net/bond_options.h
@@ -120,6 +120,26 @@ struct bond_option {
int (*set)(struct bonding *bond, const struct bond_opt_value *val);
};
+struct bond_vlan_tag {
+ __be16 vlan_proto;
+ unsigned short vlan_id;
+};
+
+/* Value type flags:
+ * BOND_TARGET_DONTFREE - never free the tags
+ * BOND_TARGET_USERTAGS - tags have been supplied by the user
+ */
+enum {
+ BOND_TARGET_DONTFREE = BIT(0),
+ BOND_TARGET_USERTAGS = BIT(1),
+};
+
+struct bond_arp_target {
+ __be32 target_ip;
+ struct bond_vlan_tag *tags;
+ u32 flags;
+};
+
int __bond_opt_set(struct bonding *bond, unsigned int option,
struct bond_opt_value *val,
struct nlattr *bad_attr, struct netlink_ext_ack *extack);
diff --git a/include/net/bonding.h b/include/net/bonding.h
index e06f0d63b2c1..27fbce667a4c 100644
--- a/include/net/bonding.h
+++ b/include/net/bonding.h
@@ -137,7 +137,7 @@ struct bond_params {
int ad_select;
char primary[IFNAMSIZ];
int primary_reselect;
- __be32 arp_targets[BOND_MAX_ARP_TARGETS];
+ struct bond_arp_target arp_targets[BOND_MAX_ARP_TARGETS];
int tx_queues;
int all_slaves_active;
int resend_igmp;
@@ -277,11 +277,6 @@ struct bonding {
void bond_queue_slave_event(struct slave *slave);
void bond_lower_state_changed(struct slave *slave);
-struct bond_vlan_tag {
- __be16 vlan_proto;
- unsigned short vlan_id;
-};
-
/*
* Returns NULL if the net_device does not belong to any of the bond's slaves
*
@@ -525,7 +520,7 @@ static inline unsigned long slave_oldest_target_arp_rx(struct bonding *bond,
int i = 1;
unsigned long ret = slave->target_last_arp_rx[0];
- for (; (i < BOND_MAX_ARP_TARGETS) && bond->params.arp_targets[i]; i++)
+ for (; (i < BOND_MAX_ARP_TARGETS) && bond->params.arp_targets[i].target_ip; i++)
if (time_before(slave->target_last_arp_rx[i], ret))
ret = slave->target_last_arp_rx[i];
@@ -763,14 +758,14 @@ static inline bool bond_slave_has_mac_rcu(struct bonding *bond, const u8 *mac)
/* Check if the ip is present in arp ip list, or first free slot if ip == 0
* Returns -1 if not found, index if found
*/
-static inline int bond_get_targets_ip(__be32 *targets, __be32 ip)
+static inline int bond_get_targets_ip(struct bond_arp_target *targets, __be32 ip)
{
int i;
for (i = 0; i < BOND_MAX_ARP_TARGETS; i++)
- if (targets[i] == ip)
+ if (targets[i].target_ip == ip)
return i;
- else if (targets[i] == 0)
+ else if (targets[i].target_ip == 0)
break;
return -1;
--
2.50.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH net-next v8 2/7] bonding: Adding extra_len field to struct bond_opt_value.
2025-08-28 22:18 [PATCH net-next v8 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
2025-08-28 22:18 ` [PATCH net-next v8 1/7] bonding: Adding struct bond_arp_target David Wilder
@ 2025-08-28 22:18 ` David Wilder
2025-08-28 22:18 ` [PATCH net-next v8 3/7] bonding: arp_ip_target helpers David Wilder
` (4 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: David Wilder @ 2025-08-28 22:18 UTC (permalink / raw)
To: netdev
Cc: jv, wilder, pradeeps, pradeep, i.maximets, amorenoz, haliu,
stephen, horms
Used to record the size of the extra array.
__bond_opt_init() is updated to set extra_len.
BOND_OPT_EXTRA_MAXLEN is increased from 16 to 64.
This is needed for the extended arp_ip_target option.
The ip command will now pass a variable length value when
setting arp_ip_target.
Signed-off-by: David Wilder <wilder@us.ibm.com>
---
include/net/bond_options.h | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/include/net/bond_options.h b/include/net/bond_options.h
index b7f275bc33a1..7d22bbe67121 100644
--- a/include/net/bond_options.h
+++ b/include/net/bond_options.h
@@ -86,14 +86,15 @@ enum {
* - if value != ULLONG_MAX -> parse value
* - if string != NULL -> parse string
* - if the opt is RAW data and length less than maxlen,
- * copy the data to extra storage
+ * copy the data to extra storage, extra_len is set to the size of data copied.
*/
-#define BOND_OPT_EXTRA_MAXLEN 16
+#define BOND_OPT_EXTRA_MAXLEN 64
struct bond_opt_value {
char *string;
u64 value;
u32 flags;
+ size_t extra_len;
union {
char extra[BOND_OPT_EXTRA_MAXLEN];
struct net_device *slave_dev;
@@ -168,8 +169,10 @@ static inline void __bond_opt_init(struct bond_opt_value *optval,
else if (string)
optval->string = string;
- if (extra && extra_len <= BOND_OPT_EXTRA_MAXLEN)
+ if (extra && extra_len <= BOND_OPT_EXTRA_MAXLEN) {
memcpy(optval->extra, extra, extra_len);
+ optval->extra_len = extra_len;
+ }
}
#define bond_opt_initval(optval, value) __bond_opt_init(optval, NULL, value, NULL, 0)
#define bond_opt_initstr(optval, str) __bond_opt_init(optval, str, ULLONG_MAX, NULL, 0)
--
2.50.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH net-next v8 3/7] bonding: arp_ip_target helpers.
2025-08-28 22:18 [PATCH net-next v8 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
2025-08-28 22:18 ` [PATCH net-next v8 1/7] bonding: Adding struct bond_arp_target David Wilder
2025-08-28 22:18 ` [PATCH net-next v8 2/7] bonding: Adding extra_len field to struct bond_opt_value David Wilder
@ 2025-08-28 22:18 ` David Wilder
2025-08-28 22:18 ` [PATCH net-next v8 4/7] bonding: Processing extended arp_ip_target from user space David Wilder
` (3 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: David Wilder @ 2025-08-28 22:18 UTC (permalink / raw)
To: netdev
Cc: jv, wilder, pradeeps, pradeep, i.maximets, amorenoz, haliu,
stephen, horms
Adding helpers and defines needed for extending the
arp_ip_target parameters.
Signed-off-by: David Wilder <wilder@us.ibm.com>
---
include/net/bonding.h | 45 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/include/net/bonding.h b/include/net/bonding.h
index 27fbce667a4c..1989b71ffa16 100644
--- a/include/net/bonding.h
+++ b/include/net/bonding.h
@@ -809,4 +809,49 @@ static inline netdev_tx_t bond_tx_drop(struct net_device *dev, struct sk_buff *s
return NET_XMIT_DROP;
}
+/* Helpers for handling arp_ip_target */
+#define BOND_OPTION_STRING_MAX_SIZE 64
+#define BOND_VLAN_PROTO_NONE cpu_to_be16(0xffff)
+
+static inline char *bond_arp_target_to_string(struct bond_arp_target *target,
+ char *buf, int size)
+{
+ struct bond_vlan_tag *tags = target->tags;
+ int i, num = 0;
+
+ if (!(target->flags & BOND_TARGET_USERTAGS)) {
+ num = snprintf(&buf[0], size, "%pI4", &target->target_ip);
+ return buf;
+ }
+
+ num = snprintf(&buf[0], size, "%pI4[", &target->target_ip);
+ if (tags) {
+ for (i = 0; (tags[i].vlan_proto != BOND_VLAN_PROTO_NONE); i++) {
+ if (!tags[i].vlan_id)
+ continue;
+ if (i != 0)
+ num = num + snprintf(&buf[num], size-num, "/");
+ num = num + snprintf(&buf[num], size-num, "%u",
+ tags[i].vlan_id);
+ }
+ }
+ snprintf(&buf[num], size-num, "]");
+ return buf;
+}
+
+static inline void bond_free_vlan_tag(struct bond_arp_target *target)
+{
+ kfree(target->tags);
+}
+
+static inline void __bond_free_vlan_tags(struct bond_arp_target *targets)
+{
+ int i;
+
+ for (i = 0; i < BOND_MAX_ARP_TARGETS && targets[i].tags; i++)
+ bond_free_vlan_tag(&targets[i]);
+}
+
+#define bond_free_vlan_tags(targets) __bond_free_vlan_tags(targets)
+
#endif /* _NET_BONDING_H */
--
2.50.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH net-next v8 4/7] bonding: Processing extended arp_ip_target from user space.
2025-08-28 22:18 [PATCH net-next v8 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
` (2 preceding siblings ...)
2025-08-28 22:18 ` [PATCH net-next v8 3/7] bonding: arp_ip_target helpers David Wilder
@ 2025-08-28 22:18 ` David Wilder
2025-08-29 13:18 ` Simon Horman
2025-08-28 22:18 ` [PATCH net-next v8 5/7] bonding: Update to bond_arp_send_all() to use supplied vlan tags David Wilder
` (2 subsequent siblings)
6 siblings, 1 reply; 9+ messages in thread
From: David Wilder @ 2025-08-28 22:18 UTC (permalink / raw)
To: netdev
Cc: jv, wilder, pradeeps, pradeep, i.maximets, amorenoz, haliu,
stephen, horms
Changes to bond_netlink and bond_options to process extended
format arp_ip_target option sent from user space via the ip
command.
The extended format adds a list of vlan tags to the ip target address.
Signed-off-by: David Wilder <wilder@us.ibm.com>
---
drivers/net/bonding/bond_netlink.c | 5 +-
drivers/net/bonding/bond_options.c | 121 +++++++++++++++++++++++------
2 files changed, 99 insertions(+), 27 deletions(-)
diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
index 9939e28dedd9..5486ef40907e 100644
--- a/drivers/net/bonding/bond_netlink.c
+++ b/drivers/net/bonding/bond_netlink.c
@@ -293,9 +293,10 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
if (nla_len(attr) < sizeof(target))
return -EINVAL;
- target = nla_get_be32(attr);
+ bond_opt_initextra(&newval,
+ (__force void *)nla_data(attr),
+ nla_len(attr));
- bond_opt_initval(&newval, (__force u64)target);
err = __bond_opt_set(bond, BOND_OPT_ARP_TARGETS,
&newval,
data[IFLA_BOND_ARP_IP_TARGET],
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index 2c5e8d95999d..9f6b6ea11568 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -31,8 +31,8 @@ static int bond_option_use_carrier_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_arp_interval_set(struct bonding *bond,
const struct bond_opt_value *newval);
-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_target_add(struct bonding *bond, struct bond_arp_target target);
+static int bond_option_arp_ip_target_rem(struct bonding *bond, struct bond_arp_target target);
static int bond_option_arp_ip_targets_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_ns_ip6_targets_set(struct bonding *bond,
@@ -1138,7 +1138,7 @@ static int bond_option_arp_interval_set(struct bonding *bond,
}
static void _bond_options_arp_ip_target_set(struct bonding *bond, int slot,
- __be32 target,
+ struct bond_arp_target target,
unsigned long last_rx)
{
struct bond_arp_target *targets = bond->params.arp_targets;
@@ -1148,24 +1148,25 @@ static void _bond_options_arp_ip_target_set(struct bonding *bond, int slot,
if (slot >= 0 && slot < BOND_MAX_ARP_TARGETS) {
bond_for_each_slave(bond, slave, iter)
slave->target_last_arp_rx[slot] = last_rx;
- targets[slot].target_ip = target;
+ memcpy(&targets[slot], &target, sizeof(target));
}
}
-static int _bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
+static int _bond_option_arp_ip_target_add(struct bonding *bond, struct bond_arp_target target)
{
struct bond_arp_target *targets = bond->params.arp_targets;
+ char pbuf[BOND_OPTION_STRING_MAX_SIZE];
int ind;
- if (!bond_is_ip_target_ok(target)) {
+ if (!bond_is_ip_target_ok(target.target_ip)) {
netdev_err(bond->dev, "invalid ARP target %pI4 specified for addition\n",
- &target);
+ &target.target_ip);
return -EINVAL;
}
- if (bond_get_targets_ip(targets, target) != -1) { /* dup */
+ if (bond_get_targets_ip(targets, target.target_ip) != -1) { /* dup */
netdev_err(bond->dev, "ARP target %pI4 is already present\n",
- &target);
+ &target.target_ip);
return -EINVAL;
}
@@ -1175,43 +1176,44 @@ static int _bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
return -EINVAL;
}
- netdev_dbg(bond->dev, "Adding ARP target %pI4\n", &target);
+ netdev_dbg(bond->dev, "Adding ARP target %s\n",
+ bond_arp_target_to_string(&target, pbuf, sizeof(pbuf)));
_bond_options_arp_ip_target_set(bond, ind, target, jiffies);
return 0;
}
-static int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
+static int bond_option_arp_ip_target_add(struct bonding *bond, struct bond_arp_target target)
{
return _bond_option_arp_ip_target_add(bond, target);
}
-static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target)
+static int bond_option_arp_ip_target_rem(struct bonding *bond, struct bond_arp_target target)
{
struct bond_arp_target *targets = bond->params.arp_targets;
+ unsigned long *targets_rx;
struct list_head *iter;
struct slave *slave;
- unsigned long *targets_rx;
int ind, i;
- if (!bond_is_ip_target_ok(target)) {
+ if (!bond_is_ip_target_ok(target.target_ip)) {
netdev_err(bond->dev, "invalid ARP target %pI4 specified for removal\n",
- &target);
+ &target.target_ip);
return -EINVAL;
}
- ind = bond_get_targets_ip(targets, target);
+ ind = bond_get_targets_ip(targets, target.target_ip);
if (ind == -1) {
netdev_err(bond->dev, "unable to remove nonexistent ARP target %pI4\n",
- &target);
+ &target.target_ip);
return -EINVAL;
}
if (ind == 0 && !targets[1].target_ip && bond->params.arp_interval)
netdev_warn(bond->dev, "Removing last arp target with arp_interval on\n");
- netdev_dbg(bond->dev, "Removing ARP target %pI4\n", &target);
+ netdev_dbg(bond->dev, "Removing ARP target %pI4\n", &target.target_ip);
bond_for_each_slave(bond, slave, iter) {
targets_rx = slave->target_last_arp_rx;
@@ -1219,30 +1221,77 @@ static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target)
targets_rx[i] = targets_rx[i+1];
targets_rx[i] = 0;
}
- for (i = ind; (i < BOND_MAX_ARP_TARGETS - 1) && targets[i + 1].target_ip; i++)
- targets[i] = targets[i+1];
+
+ bond_free_vlan_tag(&targets[ind]);
+
+ for (i = ind; (i < BOND_MAX_ARP_TARGETS - 1) && targets[i + 1].target_ip; i++) {
+ targets[i].target_ip = targets[i + 1].target_ip;
+ targets[i].tags = targets[i + 1].tags;
+ targets[i].flags = targets[i + 1].flags;
+ }
targets[i].target_ip = 0;
+ targets[i].flags = 0;
+ targets[i].tags = NULL;
return 0;
}
void bond_option_arp_ip_targets_clear(struct bonding *bond)
{
+ struct bond_arp_target empty_target;
int i;
+ empty_target.target_ip = 0;
+ empty_target.flags = 0;
+ empty_target.tags = NULL;
+
for (i = 0; i < BOND_MAX_ARP_TARGETS; i++)
- _bond_options_arp_ip_target_set(bond, i, 0, 0);
+ _bond_options_arp_ip_target_set(bond, i, empty_target, 0);
+}
+
+/**
+ * bond_validate_tags - validate an array of bond_vlan_tag.
+ * @tags: the array to validate
+ * @len: the length in bytes of @tags
+ *
+ * Validate that @tags points to a valid array of struct bond_vlan_tag.
+ * Returns the length of the validated bytes in the array or -1 if no
+ * valid list is found.
+ */
+static int bond_validate_tags(struct bond_vlan_tag *tags, size_t len)
+{
+ size_t i, ntags = 0;
+
+ if (len == 0 || !tags)
+ return 0;
+
+ for (i = 0; i <= len; i = i + sizeof(struct bond_vlan_tag)) {
+ if (ntags > BOND_MAX_VLAN_TAGS)
+ break;
+
+ if (tags->vlan_proto == BOND_VLAN_PROTO_NONE)
+ return i + sizeof(struct bond_vlan_tag);
+
+ if (tags->vlan_id > 4094)
+ break;
+ tags++;
+ ntags++;
+ }
+ return -1;
}
static int bond_option_arp_ip_targets_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
- int ret = -EPERM;
- __be32 target;
+ size_t len = (size_t)newval->extra_len;
+ char *extra = (char *)newval->extra;
+ struct bond_arp_target target;
+ int size, ret = -EPERM;
if (newval->string) {
+ /* Adding or removing arp_ip_target from sysfs */
if (strlen(newval->string) < 1 ||
- !in4_pton(newval->string + 1, -1, (u8 *)&target, -1, NULL)) {
+ !in4_pton(newval->string + 1, -1, (u8 *)&target.target_ip, -1, NULL)) {
netdev_err(bond->dev, "invalid ARP target specified\n");
return ret;
}
@@ -1253,7 +1302,29 @@ static int bond_option_arp_ip_targets_set(struct bonding *bond,
else
netdev_err(bond->dev, "no command found in arp_ip_targets file - use +<addr> or -<addr>\n");
} else {
- target = newval->value;
+ /* Adding arp_ip_target from netlink. aka: ip command */
+ if (len < sizeof(target.target_ip)) {
+ netdev_err(bond->dev, "invalid ARP target specified\n");
+ return ret;
+ }
+ memcpy(&target.target_ip, newval->extra, sizeof(__be32));
+ len = len - sizeof(target.target_ip);
+ extra = extra + sizeof(target.target_ip);
+
+ size = bond_validate_tags((struct bond_vlan_tag *)extra, len);
+
+ if (size > 0) {
+ target.tags = kmalloc((size_t)size, GFP_ATOMIC);
+ if (!target.tags)
+ return -ENOMEM;
+ memcpy(target.tags, extra, size);
+ target.flags |= BOND_TARGET_USERTAGS;
+ }
+
+ if (size == -1)
+ netdev_warn(bond->dev, "Invalid list of vlans provided with %pI4\n",
+ &target.target_ip);
+
ret = bond_option_arp_ip_target_add(bond, target);
}
--
2.50.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH net-next v8 4/7] bonding: Processing extended arp_ip_target from user space.
2025-08-28 22:18 ` [PATCH net-next v8 4/7] bonding: Processing extended arp_ip_target from user space David Wilder
@ 2025-08-29 13:18 ` Simon Horman
0 siblings, 0 replies; 9+ messages in thread
From: Simon Horman @ 2025-08-29 13:18 UTC (permalink / raw)
To: David Wilder
Cc: netdev, jv, pradeeps, pradeep, i.maximets, amorenoz, haliu,
stephen
On Thu, Aug 28, 2025 at 03:18:06PM -0700, David Wilder wrote:
> Changes to bond_netlink and bond_options to process extended
> format arp_ip_target option sent from user space via the ip
> command.
>
> The extended format adds a list of vlan tags to the ip target address.
>
> Signed-off-by: David Wilder <wilder@us.ibm.com>
...
> diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
...
> +/**
> + * bond_validate_tags - validate an array of bond_vlan_tag.
> + * @tags: the array to validate
> + * @len: the length in bytes of @tags
> + *
> + * Validate that @tags points to a valid array of struct bond_vlan_tag.
> + * Returns the length of the validated bytes in the array or -1 if no
> + * valid list is found.
> + */
> +static int bond_validate_tags(struct bond_vlan_tag *tags, size_t len)
> +{
> + size_t i, ntags = 0;
> +
> + if (len == 0 || !tags)
> + return 0;
> +
> + for (i = 0; i <= len; i = i + sizeof(struct bond_vlan_tag)) {
> + if (ntags > BOND_MAX_VLAN_TAGS)
> + break;
Hi David,
BOND_MAX_VLAN_TAGS is used here but it isn't defined until a subsequent
patch in this series. Which breaks bisection.
I didn't check, but probably this can be addressed by moving
the definition of BOND_MAX_VLAN_TAGS to this patch.
> +
> + if (tags->vlan_proto == BOND_VLAN_PROTO_NONE)
> + return i + sizeof(struct bond_vlan_tag);
> +
> + if (tags->vlan_id > 4094)
> + break;
> + tags++;
> + ntags++;
> + }
> + return -1;
> }
...
--
pw-bot: changes-requested
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH net-next v8 5/7] bonding: Update to bond_arp_send_all() to use supplied vlan tags
2025-08-28 22:18 [PATCH net-next v8 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
` (3 preceding siblings ...)
2025-08-28 22:18 ` [PATCH net-next v8 4/7] bonding: Processing extended arp_ip_target from user space David Wilder
@ 2025-08-28 22:18 ` David Wilder
2025-08-28 22:18 ` [PATCH net-next v8 6/7] bonding: Update for extended arp_ip_target format David Wilder
2025-08-28 22:18 ` [PATCH net-next v8 7/7] bonding: Selftest and documentation for the arp_ip_target parameter David Wilder
6 siblings, 0 replies; 9+ messages in thread
From: David Wilder @ 2025-08-28 22:18 UTC (permalink / raw)
To: netdev
Cc: jv, wilder, pradeeps, pradeep, i.maximets, amorenoz, haliu,
stephen, horms
bond_arp_send_all() will pass the vlan tags supplied by
the user to bond_arp_send(). If vlan tags have not been
supplied the vlans in the path to the target will be
discovered by bond_verify_device_path(). The discovered
vlan tags are then saved to be used on future calls to
bond_arp_send().
bond_uninit() is also updated to free vlan tags when a
bond is destroyed.
Signed-off-by: David Wilder <wilder@us.ibm.com>
---
drivers/net/bonding/bond_main.c | 22 +++++++++++++---------
1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index a095ca4e14a7..0096535b521b 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3161,18 +3161,19 @@ struct bond_vlan_tag *bond_verify_device_path(struct net_device *start_dev,
static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
{
- struct rtable *rt;
- struct bond_vlan_tag *tags;
struct bond_arp_target *targets = bond->params.arp_targets;
+ char pbuf[BOND_OPTION_STRING_MAX_SIZE];
+ struct bond_vlan_tag *tags;
__be32 target_ip, addr;
+ struct rtable *rt;
int i;
for (i = 0; i < BOND_MAX_ARP_TARGETS && targets[i].target_ip; i++) {
target_ip = targets[i].target_ip;
tags = targets[i].tags;
- slave_dbg(bond->dev, slave->dev, "%s: target %pI4\n",
- __func__, &target_ip);
+ slave_dbg(bond->dev, slave->dev, "%s: target %s\n", __func__,
+ bond_arp_target_to_string(&targets[i], pbuf, sizeof(pbuf)));
/* Find out through which dev should the packet go */
rt = ip_route_output(dev_net(bond->dev), target_ip, 0, 0, 0,
@@ -3194,9 +3195,13 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
if (rt->dst.dev == bond->dev)
goto found;
- rcu_read_lock();
- tags = bond_verify_device_path(bond->dev, rt->dst.dev, 0);
- rcu_read_unlock();
+ if (!tags) {
+ rcu_read_lock();
+ tags = bond_verify_device_path(bond->dev, rt->dst.dev, 0);
+ /* cache the tags */
+ targets[i].tags = tags;
+ rcu_read_unlock();
+ }
if (!IS_ERR_OR_NULL(tags))
goto found;
@@ -3212,7 +3217,6 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
addr = bond_confirm_addr(rt->dst.dev, target_ip, 0);
ip_rt_put(rt);
bond_arp_send(slave, ARPOP_REQUEST, target_ip, addr, tags);
- kfree(tags);
}
}
@@ -6145,6 +6149,7 @@ static void bond_uninit(struct net_device *bond_dev)
bond_for_each_slave(bond, slave, iter)
__bond_release_one(bond_dev, slave->dev, true, true);
netdev_info(bond_dev, "Released all slaves\n");
+ bond_free_vlan_tags(bond->params.arp_targets);
#ifdef CONFIG_XFRM_OFFLOAD
mutex_destroy(&bond->ipsec_lock);
@@ -6732,7 +6737,6 @@ static void __exit bonding_exit(void)
bond_netlink_fini();
unregister_pernet_subsys(&bond_net_ops);
-
bond_destroy_debugfs();
#ifdef CONFIG_NET_POLL_CONTROLLER
--
2.50.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH net-next v8 6/7] bonding: Update for extended arp_ip_target format.
2025-08-28 22:18 [PATCH net-next v8 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
` (4 preceding siblings ...)
2025-08-28 22:18 ` [PATCH net-next v8 5/7] bonding: Update to bond_arp_send_all() to use supplied vlan tags David Wilder
@ 2025-08-28 22:18 ` David Wilder
2025-08-28 22:18 ` [PATCH net-next v8 7/7] bonding: Selftest and documentation for the arp_ip_target parameter David Wilder
6 siblings, 0 replies; 9+ messages in thread
From: David Wilder @ 2025-08-28 22:18 UTC (permalink / raw)
To: netdev
Cc: jv, wilder, pradeeps, pradeep, i.maximets, amorenoz, haliu,
stephen, horms
Updated bond_fill_info() to support extended arp_ip_target format.
Forward and backward compatibility between the kernel and iprout2 is
preserved.
Signed-off-by: David Wilder <wilder@us.ibm.com>
---
drivers/net/bonding/bond_netlink.c | 30 +++++++++++++++++++++++++-----
include/net/bonding.h | 1 +
2 files changed, 26 insertions(+), 5 deletions(-)
diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
index 5486ef40907e..0857c93a57d0 100644
--- a/drivers/net/bonding/bond_netlink.c
+++ b/drivers/net/bonding/bond_netlink.c
@@ -662,6 +662,7 @@ static int bond_fill_info(struct sk_buff *skb,
const struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
+ struct bond_arp_target *arptargets;
unsigned int packets_per_slave;
int ifindex, i, targets_added;
struct nlattr *targets;
@@ -700,12 +701,31 @@ static int bond_fill_info(struct sk_buff *skb,
goto nla_put_failure;
targets_added = 0;
- for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
- if (bond->params.arp_targets[i].target_ip) {
- if (nla_put_be32(skb, i, bond->params.arp_targets[i].target_ip))
- goto nla_put_failure;
- targets_added = 1;
+
+ arptargets = bond->params.arp_targets;
+ for (i = 0; i < BOND_MAX_ARP_TARGETS && arptargets[i].target_ip ; i++) {
+ struct Data {
+ __be32 addr;
+ struct bond_vlan_tag vlans[BOND_MAX_VLAN_TAGS];
+ } __packed data;
+ int level, size;
+
+ data.addr = arptargets[i].target_ip;
+ size = sizeof(__be32);
+ targets_added = 1;
+
+ if (arptargets[i].flags & BOND_TARGET_USERTAGS) {
+ for (level = 0; level < BOND_MAX_VLAN_TAGS ; level++) {
+ data.vlans[level].vlan_proto = arptargets[i].tags[level].vlan_proto;
+ data.vlans[level].vlan_id = arptargets[i].tags[level].vlan_id;
+ size = size + sizeof(struct bond_vlan_tag);
+ if (arptargets[i].tags[level].vlan_proto == BOND_VLAN_PROTO_NONE)
+ break;
+ }
}
+
+ if (nla_put(skb, i, size, &data))
+ goto nla_put_failure;
}
if (targets_added)
diff --git a/include/net/bonding.h b/include/net/bonding.h
index 1989b71ffa16..2502cf8428b3 100644
--- a/include/net/bonding.h
+++ b/include/net/bonding.h
@@ -811,6 +811,7 @@ static inline netdev_tx_t bond_tx_drop(struct net_device *dev, struct sk_buff *s
/* Helpers for handling arp_ip_target */
#define BOND_OPTION_STRING_MAX_SIZE 64
+#define BOND_MAX_VLAN_TAGS 5
#define BOND_VLAN_PROTO_NONE cpu_to_be16(0xffff)
static inline char *bond_arp_target_to_string(struct bond_arp_target *target,
--
2.50.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH net-next v8 7/7] bonding: Selftest and documentation for the arp_ip_target parameter.
2025-08-28 22:18 [PATCH net-next v8 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
` (5 preceding siblings ...)
2025-08-28 22:18 ` [PATCH net-next v8 6/7] bonding: Update for extended arp_ip_target format David Wilder
@ 2025-08-28 22:18 ` David Wilder
6 siblings, 0 replies; 9+ messages in thread
From: David Wilder @ 2025-08-28 22:18 UTC (permalink / raw)
To: netdev
Cc: jv, wilder, pradeeps, pradeep, i.maximets, amorenoz, haliu,
stephen, horms
This selftest provided a functional test for the arp_ip_target parameter
both with and without user supplied vlan tags.
and
Updates to the bonding documentation.
Signed-off-by: David Wilder <wilder@us.ibm.com>
---
Documentation/networking/bonding.rst | 11 ++
.../selftests/drivers/net/bonding/Makefile | 3 +-
.../drivers/net/bonding/bond-arp-ip-target.sh | 180 ++++++++++++++++++
.../selftests/drivers/net/bonding/config | 1 +
4 files changed, 194 insertions(+), 1 deletion(-)
create mode 100755 tools/testing/selftests/drivers/net/bonding/bond-arp-ip-target.sh
diff --git a/Documentation/networking/bonding.rst b/Documentation/networking/bonding.rst
index f8f5766703d4..4a80da56b784 100644
--- a/Documentation/networking/bonding.rst
+++ b/Documentation/networking/bonding.rst
@@ -313,6 +313,17 @@ arp_ip_target
maximum number of targets that can be specified is 16. The
default value is no IP addresses.
+ When an arp_ip_target is configured the bonding driver will
+ attempt to automatically determine what vlans the arp probe will
+ pass through. This process of gathering vlan tags is required
+ for the arp probe to be sent. However, in some configurations
+ this process may fail. In these cases you may manually
+ supply a list of vlan tags. To specify a list of vlan tags
+ append the ipv4 address with [tag1/tag2...]. For example:
+ arp_ip_target=10.0.0.1[10]. If you simply need to disable the
+ vlan discovery process you may provide an empty list, for example:
+ arp_ip_target=10.0.0.1[].
+
ns_ip6_target
Specifies the IPv6 addresses to use as IPv6 monitoring peers when
diff --git a/tools/testing/selftests/drivers/net/bonding/Makefile b/tools/testing/selftests/drivers/net/bonding/Makefile
index 44b98f17f8ff..b7d5e11fc9d3 100644
--- a/tools/testing/selftests/drivers/net/bonding/Makefile
+++ b/tools/testing/selftests/drivers/net/bonding/Makefile
@@ -11,7 +11,8 @@ TEST_PROGS := \
bond_options.sh \
bond-eth-type-change.sh \
bond_macvlan_ipvlan.sh \
- bond_passive_lacp.sh
+ bond_passive_lacp.sh \
+ bond-arp-ip-target.sh
TEST_FILES := \
lag_lib.sh \
diff --git a/tools/testing/selftests/drivers/net/bonding/bond-arp-ip-target.sh b/tools/testing/selftests/drivers/net/bonding/bond-arp-ip-target.sh
new file mode 100755
index 000000000000..124bfb6a2f02
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/bonding/bond-arp-ip-target.sh
@@ -0,0 +1,180 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Test bonding arp_ip_target.
+# Topology for Bond mode 1,5,6 testing
+#
+# +-------------------------+
+# | | Server
+# | bond0.10.20 | 192.20.2.1/24
+# | | |
+# | bond0.10 | 192.10.2.1/24
+# | | |
+# | bond0 | 192.0.2.1/24
+# | | |
+# | + |
+# | eth0 | eth1 |
+# | +---+---+ |
+# | | | |
+# +-------------------------+
+# | |
+# +-------------------------+
+# | | | |
+# | +---+-------+---+ | Gateway
+# | | br0 | |
+# | +-------+-------+ |
+# | | |
+# +-------------------------+
+# |
+# +-------------------------+
+# | | | Client
+# | eth0 | 192.0.0.2/24
+# | | |
+# | eth0.10 | 192.10.10.2/24
+# | | |
+# | eth0.10.20 | 192.20.20.2/24
+# +-------------------------+
+
+# shellcheck disable=SC2317
+
+lib_dir=$(dirname "$0")
+
+# shellcheck source=/dev/null # Ignore source warning.
+source "${lib_dir}"/bond_topo_2d1c.sh
+
+# shellcheck disable=SC2154 # Ignore unassigned referenced warning.
+echo "${c_ns}" "${s_ns}" > /dev/null
+
+DEBUG=${DEBUG:-0}
+test "${DEBUG}" -ne 0 && set -x
+
+# vlan subnets
+c_ip4="192.0.2.10"
+c_ip4v10="192.10.2.10"
+c_ip4v20="192.20.2.10"
+
+export ALL_TESTS="
+ no_vlan_hints
+ with_vlan_hints
+"
+
+# Build stacked vlans on top of an interface.
+stack_vlans()
+{
+ RET=0
+ local interface="$1"
+ local ns=$2
+ local last="$interface"
+ local tags="10 20"
+
+ if ! ip -n "${ns}" link show "${interface}" > /dev/null; then
+ RET=1
+ msg="Failed to create ${interface}"
+ return
+ fi
+
+ if [ "$ns" == "${s_ns}" ]; then host=1; else host=10;fi
+
+ for tag in $tags; do
+ ip -n "${ns}" link add link "$last" name "$last"."$tag" type vlan id "$tag"
+ ip -n "${ns}" address add 192."$tag".2."$host"/24 dev "$last"."$tag"
+ ip -n "${ns}" link set up dev "$last"."$tag"
+ last=$last.$tag
+ done
+}
+
+# Check for link flapping
+check_failure_count()
+{
+ RET=0
+ local ns=$1
+ local proc_file=/proc/net/bonding/$2
+ local counts
+
+ # Give the bond time to settle.
+ sleep 10
+
+ counts=$(ip netns exec "${ns}" grep -F "Link Failure Count" "${proc_file}" \
+ | awk -F: '{print $2}')
+
+ local i
+ for i in $counts; do
+ [ "$i" != 0 ] && RET=1
+ done
+}
+
+setup_bond_topo()
+{
+ setup_prepare
+ setup_wait
+ stack_vlans bond0 "${s_ns}"
+ stack_vlans eth0 "${c_ns}"
+}
+
+skip_with_vlan_hints()
+{
+ # check if iproute supports arp_ip_target with vlans option.
+ if ! ip -n "${s_ns}" link add bond2 type bond arp_ip_target 10.0.0.1[10]; then
+ ip -n "${s_ns}" link del bond2 2> /dev/null
+ return 0
+ fi
+ return 1
+}
+
+no_vlan_hints()
+{
+ RET=0
+ local targets="${c_ip4} ${c_ip4v10} ${c_ip4v20}"
+ local target
+ msg=""
+
+ for target in $targets; do
+ bond_reset "mode $mode arp_interval 100 arp_ip_target ${target}"
+
+ stack_vlans bond0 "${s_ns}"
+ if [ "$RET" -ne 0 ]; then
+ log_test "no_vlan_hints" "${msg}"
+ return
+ fi
+
+ check_failure_count "${s_ns}" bond0
+ log_test "arp_ip_target=${target} ${msg}"
+ done
+}
+
+with_vlan_hints()
+{
+ RET=0
+ local targets="${c_ip4}[] ${c_ip4v10}[10] ${c_ip4v20}[10/20]"
+ local target
+ msg=""
+
+ if skip_with_vlan_hints; then
+ log_test_skip "skip_with_vlan_hints" \
+ "Installed iproute doesn't support extended arp_ip_target options."
+ return 0
+ fi
+
+ for target in $targets; do
+ bond_reset "mode $mode arp_interval 100 arp_ip_target ${target}"
+
+ stack_vlans bond0 "${s_ns}"
+ if [ "$RET" -ne 0 ]; then
+ log_test "no_vlan_hints" "${msg}"
+ return
+ fi
+
+ check_failure_count "${s_ns}" bond0
+ log_test "arp_ip_target=${target} ${msg}"
+ done
+}
+
+
+trap cleanup EXIT
+
+mode=active-backup
+
+setup_bond_topo
+tests_run
+
+exit "$EXIT_STATUS"
diff --git a/tools/testing/selftests/drivers/net/bonding/config b/tools/testing/selftests/drivers/net/bonding/config
index 4d16a69ffc65..90e9d7b19d98 100644
--- a/tools/testing/selftests/drivers/net/bonding/config
+++ b/tools/testing/selftests/drivers/net/bonding/config
@@ -10,3 +10,4 @@ CONFIG_NET_CLS_MATCHALL=m
CONFIG_NET_SCH_INGRESS=y
CONFIG_NLMON=y
CONFIG_VETH=y
+CONFIG_VLAN_8021Q=y
--
2.50.1
^ permalink raw reply related [flat|nested] 9+ messages in thread