* [PATCH net-next v11 1/7] bonding: Adding struct bond_arp_target
2025-09-30 1:27 [PATCH net-next v11 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
@ 2025-09-30 1:27 ` David Wilder
2025-09-30 1:27 ` [PATCH net-next v11 2/7] bonding: Adding extra_len field to struct bond_opt_value David Wilder
` (6 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: David Wilder @ 2025-09-30 1:27 UTC (permalink / raw)
To: netdev
Cc: jv, wilder, pradeeps, pradeep, i.maximets, amorenoz, haliu,
stephen, horms, kuba, pabeni, andrew+netdev, edumazet
Replacing the definition of bond_params.arp_targets (__be32 arp_targets[])
with:
struct bond_arp_target {
__be32 target_ip;
u32 flags;
struct bond_vlan_tag *tags;
};
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 1ea41f1a9190..57cf4585816d 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3066,26 +3066,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;
}
@@ -3103,15 +3106,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);
}
}
@@ -6066,7 +6069,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;
@@ -6260,7 +6263,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 ba71d95a82d2..cc00fbad9dd3 100644
--- a/drivers/net/bonding/bond_netlink.c
+++ b/drivers/net/bonding/bond_netlink.c
@@ -714,8 +714,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 495a87f2ea7c..91d57ba968d6 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -1125,7 +1125,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) {
@@ -1153,20 +1153,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)) {
@@ -1201,7 +1201,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;
@@ -1220,20 +1220,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 9a75ad3181ab..7114bd4d7735 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 e6eedf23aea1..dea58a07e4cc 100644
--- a/include/net/bond_options.h
+++ b/include/net/bond_options.h
@@ -121,6 +121,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;
+ u32 flags;
+ struct bond_vlan_tag *tags;
+};
+
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 37335f62f579..a0eae209315f 100644
--- a/include/net/bonding.h
+++ b/include/net/bonding.h
@@ -136,7 +136,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;
@@ -276,11 +276,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
*
@@ -524,7 +519,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];
@@ -762,14 +757,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] 11+ messages in thread* [PATCH net-next v11 2/7] bonding: Adding extra_len field to struct bond_opt_value.
2025-09-30 1:27 [PATCH net-next v11 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
2025-09-30 1:27 ` [PATCH net-next v11 1/7] bonding: Adding struct bond_arp_target David Wilder
@ 2025-09-30 1:27 ` David Wilder
2025-09-30 1:27 ` [PATCH net-next v11 3/7] bonding: arp_ip_target helpers David Wilder
` (5 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: David Wilder @ 2025-09-30 1:27 UTC (permalink / raw)
To: netdev
Cc: jv, wilder, pradeeps, pradeep, i.maximets, amorenoz, haliu,
stephen, horms, kuba, pabeni, andrew+netdev, edumazet
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 dea58a07e4cc..e3eb5fe6d1e8 100644
--- a/include/net/bond_options.h
+++ b/include/net/bond_options.h
@@ -87,14 +87,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;
@@ -169,8 +170,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] 11+ messages in thread* [PATCH net-next v11 3/7] bonding: arp_ip_target helpers.
2025-09-30 1:27 [PATCH net-next v11 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
2025-09-30 1:27 ` [PATCH net-next v11 1/7] bonding: Adding struct bond_arp_target David Wilder
2025-09-30 1:27 ` [PATCH net-next v11 2/7] bonding: Adding extra_len field to struct bond_opt_value David Wilder
@ 2025-09-30 1:27 ` David Wilder
2025-09-30 1:27 ` [PATCH net-next v11 4/7] bonding: Processing extended arp_ip_target from user space David Wilder
` (4 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: David Wilder @ 2025-09-30 1:27 UTC (permalink / raw)
To: netdev
Cc: jv, wilder, pradeeps, pradeep, i.maximets, amorenoz, haliu,
stephen, horms, kuba, pabeni, andrew+netdev, edumazet
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 | 46 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/include/net/bonding.h b/include/net/bonding.h
index a0eae209315f..75f6b1e32b3d 100644
--- a/include/net/bonding.h
+++ b/include/net/bonding.h
@@ -808,4 +808,50 @@ 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_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,
+ 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] 11+ messages in thread* [PATCH net-next v11 4/7] bonding: Processing extended arp_ip_target from user space.
2025-09-30 1:27 [PATCH net-next v11 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
` (2 preceding siblings ...)
2025-09-30 1:27 ` [PATCH net-next v11 3/7] bonding: arp_ip_target helpers David Wilder
@ 2025-09-30 1:27 ` David Wilder
2025-09-30 1:27 ` [PATCH net-next v11 5/7] bonding: Update to bond_arp_send_all() to use supplied vlan tags David Wilder
` (3 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: David Wilder @ 2025-09-30 1:27 UTC (permalink / raw)
To: netdev
Cc: jv, wilder, pradeeps, pradeep, i.maximets, amorenoz, haliu,
stephen, horms, kuba, pabeni, andrew+netdev, edumazet
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 | 126 +++++++++++++++++++++++------
2 files changed, 104 insertions(+), 27 deletions(-)
diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
index cc00fbad9dd3..97fdbd962513 100644
--- a/drivers/net/bonding/bond_netlink.c
+++ b/drivers/net/bonding/bond_netlink.c
@@ -307,9 +307,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 91d57ba968d6..ba97479080ba 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -13,6 +13,7 @@
#include <linux/ctype.h>
#include <linux/inet.h>
#include <linux/sched/signal.h>
+#include <linux/if_vlan.h>
#include <net/bonding.h>
#include <net/ndisc.h>
@@ -31,8 +32,10 @@ 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,
@@ -1150,7 +1153,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;
@@ -1160,24 +1163,26 @@ 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;
}
@@ -1187,43 +1192,46 @@ 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;
@@ -1231,30 +1239,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;
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;
+
+ if (len % sizeof(struct bond_vlan_tag) != 0)
+ return -1;
+
+ 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 || tags->vlan_id >= VLAN_VID_MASK)
+ 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;
}
@@ -1265,8 +1320,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 */
+ 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;
+ } else if (size == -1) {
+ netdev_err(bond->dev, "Invalid list of vlans provided with %pI4\n",
+ &target.target_ip);
+ return -EINVAL;
+ }
+
ret = bond_option_arp_ip_target_add(bond, target);
+
+ if (ret)
+ kfree(target.tags);
}
return ret;
--
2.50.1
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH net-next v11 5/7] bonding: Update to bond_arp_send_all() to use supplied vlan tags
2025-09-30 1:27 [PATCH net-next v11 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
` (3 preceding siblings ...)
2025-09-30 1:27 ` [PATCH net-next v11 4/7] bonding: Processing extended arp_ip_target from user space David Wilder
@ 2025-09-30 1:27 ` David Wilder
2025-09-30 1:27 ` [PATCH net-next v11 6/7] bonding: Update for extended arp_ip_target format David Wilder
` (2 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: David Wilder @ 2025-09-30 1:27 UTC (permalink / raw)
To: netdev
Cc: jv, wilder, pradeeps, pradeep, i.maximets, amorenoz, haliu,
stephen, horms, kuba, pabeni, andrew+netdev, edumazet
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().
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 | 23 +++++++++++++++--------
1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 57cf4585816d..333f7fef9c8b 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3064,18 +3064,21 @@ 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;
+ u32 flags;
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;
+ flags = targets[i].flags;
- 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,
@@ -3097,9 +3100,11 @@ 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);
+ rcu_read_unlock();
+ }
if (!IS_ERR_OR_NULL(tags))
goto found;
@@ -3115,7 +3120,8 @@ 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);
+ if (!(flags & BOND_TARGET_USERTAGS))
+ kfree(tags);
}
}
@@ -6047,6 +6053,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);
--
2.50.1
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH net-next v11 6/7] bonding: Update for extended arp_ip_target format.
2025-09-30 1:27 [PATCH net-next v11 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
` (4 preceding siblings ...)
2025-09-30 1:27 ` [PATCH net-next v11 5/7] bonding: Update to bond_arp_send_all() to use supplied vlan tags David Wilder
@ 2025-09-30 1:27 ` David Wilder
2025-09-30 1:27 ` [PATCH net-next v11 7/7] bonding: Selftest and documentation for the arp_ip_target parameter David Wilder
2025-09-30 7:21 ` [PATCH net-next v11 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags Paolo Abeni
7 siblings, 0 replies; 11+ messages in thread
From: David Wilder @ 2025-09-30 1:27 UTC (permalink / raw)
To: netdev
Cc: jv, wilder, pradeeps, pradeep, i.maximets, amorenoz, haliu,
stephen, horms, kuba, pabeni, andrew+netdev, edumazet
Updated bond_fill_info() to support extended arp_ip_target format.
Forward and backward compatibility between the kernel and iproute2 is
preserved.
Signed-off-by: David Wilder <wilder@us.ibm.com>
---
drivers/net/bonding/bond_netlink.c | 30 +++++++++++++++++++++++++-----
1 file changed, 25 insertions(+), 5 deletions(-)
diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
index 97fdbd962513..349b5525d007 100644
--- a/drivers/net/bonding/bond_netlink.c
+++ b/drivers/net/bonding/bond_netlink.c
@@ -676,6 +676,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;
@@ -714,12 +715,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 + 1];
+ } __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 + 1 ; 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)
--
2.50.1
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH net-next v11 7/7] bonding: Selftest and documentation for the arp_ip_target parameter.
2025-09-30 1:27 [PATCH net-next v11 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
` (5 preceding siblings ...)
2025-09-30 1:27 ` [PATCH net-next v11 6/7] bonding: Update for extended arp_ip_target format David Wilder
@ 2025-09-30 1:27 ` David Wilder
2025-09-30 7:21 ` [PATCH net-next v11 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags Paolo Abeni
7 siblings, 0 replies; 11+ messages in thread
From: David Wilder @ 2025-09-30 1:27 UTC (permalink / raw)
To: netdev
Cc: jv, wilder, pradeeps, pradeep, i.maximets, amorenoz, haliu,
stephen, horms, kuba, pabeni, andrew+netdev, edumazet
Selftest provided as a functional test for the arp_ip_target parameter
both with and without user supplied vlan tags. Bonding documentation
has been updated for the arp_ip_target option.
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 | 205 ++++++++++++++++++
3 files changed, 218 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 e700bf1d095c..08a3191a0322 100644
--- a/Documentation/networking/bonding.rst
+++ b/Documentation/networking/bonding.rst
@@ -330,6 +330,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 3462783ed3ac..44965026fe45 100644
--- a/tools/testing/selftests/drivers/net/bonding/Makefile
+++ b/tools/testing/selftests/drivers/net/bonding/Makefile
@@ -12,7 +12,8 @@ TEST_PROGS := \
bond-eth-type-change.sh \
bond_macvlan_ipvlan.sh \
bond_passive_lacp.sh \
- bond_lacp_prio.sh
+ bond_lacp_prio.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..40cbd56c00f9
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/bonding/bond-arp-ip-target.sh
@@ -0,0 +1,205 @@
+#!/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 1
+ 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
+}
+
+wait_for_arp_request()
+{
+ local target=$1
+ local ip
+ local interface
+
+ ip=$(echo "${target}" | awk -F "[" '{print $1}')
+ interface="$(ip -n "${c_ns}" -br addr show | grep "${ip}" | awk -F @ '{print $1}')"
+
+ tc -n "${c_ns}" qdisc add dev "${interface}" clsact
+ tc -n "${c_ns}" filter add dev "${interface}" ingress protocol arp \
+ handle 101 flower skip_hw arp_op request arp_tip "${ip}" action pass
+
+ slowwait_for_counter 5 5 tc_rule_handle_stats_get \
+ "dev ${interface} ingress" 101 ".packets" "-n ${c_ns}" &> /dev/null || RET=1
+
+ tc -n "${c_ns}" filter del dev "${interface}" ingress
+ tc -n "${c_ns}" qdisc del dev "${interface}" clsact
+
+ if [ "$RET" -ne 0 ]; then
+ msg="Arp probe not received by ${interface}"
+ return 1
+ fi
+}
+
+# Check for link flapping.
+# First verify the arp requests are being received
+# by the target. Then verify that the Link Failure
+# Counts are not increasing over time.
+# Arp probes are sent every 100ms, two probes must
+# be missed to trigger a slave failure. A one second
+# wait should be sufficient.
+check_failure_count()
+{
+ local bond=$1
+ local target=$2
+ local proc_file=/proc/net/bonding/${bond}
+
+ wait_for_arp_request "${target}" || return 1
+
+ LinkFailureCount1=$(ip netns exec "${s_ns}" grep -F "Link Failure Count" "${proc_file}" \
+ | awk -F: '{ sum += $2 } END { print sum }')
+ sleep 1
+ LinkFailureCount2=$(ip netns exec "${s_ns}" grep -F "Link Failure Count" "${proc_file}" \
+ | awk -F: '{ sum += $2 } END { print sum }')
+
+ [ "$LinkFailureCount1" != "$LinkFailureCount2" ] && RET=1
+}
+
+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 bond0 "${target}"
+ 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 bond0 "${target}"
+ log_test "arp_ip_target=${target} ${msg}"
+ done
+}
+
+trap cleanup EXIT
+
+mode=active-backup
+
+setup_bond_topo
+tests_run
+
+exit "$EXIT_STATUS"
--
2.50.1
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH net-next v11 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags.
2025-09-30 1:27 [PATCH net-next v11 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
` (6 preceding siblings ...)
2025-09-30 1:27 ` [PATCH net-next v11 7/7] bonding: Selftest and documentation for the arp_ip_target parameter David Wilder
@ 2025-09-30 7:21 ` Paolo Abeni
2025-09-30 7:58 ` Hangbin Liu
7 siblings, 1 reply; 11+ messages in thread
From: Paolo Abeni @ 2025-09-30 7:21 UTC (permalink / raw)
To: David Wilder, netdev
Cc: jv, pradeeps, pradeep, i.maximets, amorenoz, haliu, stephen,
horms, kuba, andrew+netdev, edumazet
On 9/30/25 3:27 AM, David Wilder wrote:
> The current implementation of the arp monitor builds a list of vlan-tags by
> following the chain of net_devices above the bond. See bond_verify_device_path().
> Unfortunately, with some configurations, this is not possible. One example is
> when an ovs switch is configured above the bond.
>
> This change extends the "arp_ip_target" parameter format to allow for a list of
> vlan tags to be included for each arp target. This new list of tags is optional
> and may be omitted to preserve the current format and process of discovering
> vlans.
>
> The new format for arp_ip_target is:
> arp_ip_target ipv4-address[vlan-tag\...],...
>
> For example:
> arp_ip_target 10.0.0.1[10/20]
> arp_ip_target 10.0.0.1[] (used to disable vlan discovery)
>
> Changes since V10
> Thanks Paolo:
> - 1/7 Changed the layout of struct bond_arp_target to reduce size of the struct.
> - 3/7 Fixed format 'size-num' -> 'size - num'
> - 7/7 Updated selftest (bond-arp-ip-target.sh). Removed sleep 10 in check_failure_count().
> Added call to tc to verify arp probes are reaching the target interface. Then I verify that
> the Link Failure counts are not increasing over "time". Arp probes are sent every 100ms,
> two missed probes will trigger a Link failure. A one second wait between checking counts
> should be be more than sufficient. This speeds up the execution of the test.
>
> Thanks Nikolay:
> - 4/7 In bond_option_arp_ip_targets_clear() I changed the definition of empty_target to empty_target = {}.
> - bond_validate_tags() now verifies input is a multiple of sizeof(struct bond_vlan_tag).
> Updated VID validity check to use: !tags->vlan_id || tags->vlan_id >= VLAN_VID_MASK) as suggested.
> - In bond_option_arp_ip_targets_set() removed the redundant length check of target.target_ip.
> - Added kfree(target.tags) when bond_option_arp_ip_target_add() results in an error.
> - Removed the caching of struct bond_vlan_tag returned by bond_verify_device_path(), Nikolay
> pointed out that caching tags prevented the detection of VLAN configuration changes.
> Added a kfree(tags) for tags allocated in bond_verify_device_path().
>
> Jay, Nikolay and I had a discussion regarding locking when adding, deleting or changing vlan tags.
> Jay pointed out that user supplied tags that are stashed in the bond configuration and can only be
> changed via user space this can be done safely in an RCU manner as netlink always operates with RTNL
> held. If user space provided tags and then replumbs things, it'll be on user space to update the tags
> in a safe manor.
>
> I was concerned about changing options on a configured bond, I found that attempting to change
> a bonds configuration (using "ip set") will abort the attempt to make a change if the bond's state is
> "UP" or has slaves configured. Therefor the configuration and operational side of a bond is separated.
> I agree with Jay that the existing locking scheme is sufficient.
>
> Change since V9
> Fix kdoc build error.
>
> Changes since V8:
> Moved the #define BOND_MAX_VLAN_TAGS from patch 6 to patch 3.
> Thanks Simon for catching the bisection break.
>
> Changes since V7:
> These changes should eliminate the CI failures I have been seeing.
> 1) patch 2, changed type of bond_opt_value.extra_len to size_t.
> 2) Patch 4, added bond_validate_tags() to validate the array of bond_vlan_tag provided by
> the user.
>
> Changes since V6:
> 1) I made a number of changes to fix the failure seen in the
> kernel CI. I am still unable to reproduce the this failure, hopefully I
> have fixed it. These change are in patch #4 to functions:
> bond_option_arp_ip_targets_clear() and
> bond_option_arp_ip_targets_set()
>
> Changes since V5: Only the last 2 patches have changed since V5.
> 1) Fixed sparse warning in bond_fill_info().
> 2) Also in bond_fill_info() I resolved data.addr uninitialized when if condition is not met.
> Thank you Simon for catching this. Note: The change is different that what I shared earlier.
> 3) Fixed shellcheck warnings in test script: Blocked source warning, Ignored specific unassigned
> references and exported ALL_TESTS to resolve a reference warning.
>
> Changes since V4:
> 1)Dropped changes to proc and sysfs APIs to bonding. These APIs
> do not need to be updated to support new functionality. Netlink
> and iproute2 have been updated to do the right thing, but the
> other APIs are more or less frozen in the past.
>
> 2)Jakub reported a warning triggered in bond_info_seq_show() during
> testing. I was unable to reproduce this warning or identify
> it with code inspection. However, all my changes to bond_info_seq_show()
> have been dropped as unnecessary (see above).
> Hopefully this will resolve the issue.
>
> 3)Selftest script has been updated based on the results of shellcheck.
> Two unresolved references that are not possible to resolve are all
> that remain.
>
> 4)A patch was added updating bond_info_fill()
> to support "ip -d show <bond-device>" command.
>
> The inclusion of a list of vlan tags is optional. The new logic
> preserves both forward and backward compatibility with the kernel
> and iproute2 versions.
>
> Changes since V3:
> 1) Moved the parsing of the extended arp_ip_target out of the kernel and into
> userspace (ip command). A separate patch to iproute2 to follow shortly.
> 2) Split up the patch set to make review easier.
>
> Please see iproute changes in a separate posting.
>
> Thank you for your time and reviews.
>
> Signed-off-by: David Wilder <wilder@us.ibm.com>
Not a formal reviews, but this is apparently causing self tests failures:
[ 274.739699][ T2985] Oops: general protection fault, probably for
non-canonical address 0xe2b11fc1bf7efa00: 0000 [#1] SMP KASAN
[ 274.740206][ T2985] KASAN: maybe wild-memory-access in range
[0x15891e0dfbf7d000-0x15891e0dfbf7d007]
[ 274.740513][ T2985] CPU: 0 UID: 0 PID: 2985 Comm: ip Not tainted
6.17.0-rc7-virtme #1 PREEMPT(full)
[ 274.740820][ T2985] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011
[ 274.741034][ T2985] RIP: 0010:bond_fill_info+0x4e9/0x17c0
[ 274.741271][ T2985] Code: 5d 08 41 b9 08 00 00 00 48 8d ac 24 ee 00
00 00 45 31 f6 41 29 d9 4d 63 c6 49 83 f8 05 0f 87 98 0f 00 00 48 89 d8
48 c1 e8 03 <42> 0f b6 14 20 48 89 d8 83 e0 07 83 c0 01 38 d0 7c 08 84
d2 0f 85
[ 274.741933][ T2985] RSP: 0018:ffffc900056f6db8 EFLAGS: 00010206
[ 274.742160][ T2985] RAX: 02b123c1bf7efa00 RBX: 15891e0dfbf7d000 RCX:
0000000000000000
[ 274.742475][ T2985] RDX: 0000000000000004 RSI: 0000000000000000 RDI:
ffff88800aaa2ef0
[ 274.742752][ T2985] RBP: ffffc900056f6ea6 R08: 0000000000000000 R09:
0000000004083008
[ 274.743027][ T2985] R10: 0000000000000000 R11: ffffffffb6d6ff00 R12:
dffffc0000000000
[ 274.743302][ T2985] R13: ffff88800aaa2ee8 R14: 0000000000000000 R15:
0000000000000000
[ 274.743572][ T2985] FS: 00007fdb2f61a800(0000)
GS:ffff8880783ac000(0000) knlGS:0000000000000000
[ 274.743871][ T2985] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 274.744092][ T2985] CR2: 00000000004e5a38 CR3: 0000000008c5c006 CR4:
0000000000772ef0
[ 274.744381][ T2985] PKRU: 55555554
[ 274.744515][ T2985] Call Trace:
[ 274.744645][ T2985] <TASK>
[ 274.745942][ T2985] rtnl_link_fill+0x22e/0x890[ 274.739699][ T2985]
full oops:
https://netdev-3.bots.linux.dev/vmksft-bonding-dbg/results/320021/1-bond-options-sh/stderr
more:
https://netdev-3.bots.linux.dev/vmksft-bonding-dbg/results/320021/8-bond-arp-interval-causes-panic-sh/stderr
https://netdev-3.bots.linux.dev/vmksft-bonding-dbg/results/320021/15-bond-arp-ip-target-sh/stderr
Also:
## Form letter - net-next-closed
The merge window for v6.18 has begun and therefore net-next is closed
for new drivers, features, code refactoring and optimizations. We are
currently accepting bug fixes only.
Please repost when net-next reopens after June 8th.
RFC patches sent for review only are obviously welcome at any time.
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH net-next v11 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags.
2025-09-30 7:21 ` [PATCH net-next v11 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags Paolo Abeni
@ 2025-09-30 7:58 ` Hangbin Liu
2025-09-30 9:27 ` Paolo Abeni
0 siblings, 1 reply; 11+ messages in thread
From: Hangbin Liu @ 2025-09-30 7:58 UTC (permalink / raw)
To: Paolo Abeni
Cc: David Wilder, netdev, jv, pradeeps, pradeep, i.maximets, amorenoz,
stephen, horms, kuba, andrew+netdev, edumazet
On Tue, Sep 30, 2025 at 09:21:30AM +0200, Paolo Abeni wrote:
> ## Form letter - net-next-closed
>
> The merge window for v6.18 has begun and therefore net-next is closed
> for new drivers, features, code refactoring and optimizations. We are
> currently accepting bug fixes only.
>
> Please repost when net-next reopens after June 8th.
>
> RFC patches sent for review only are obviously welcome at any time.
>
I guess you mean after October 13th[1].
[1] https://patchwork.hopto.org/net-next.html
Thanks
Hangbin
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH net-next v11 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags.
2025-09-30 7:58 ` Hangbin Liu
@ 2025-09-30 9:27 ` Paolo Abeni
0 siblings, 0 replies; 11+ messages in thread
From: Paolo Abeni @ 2025-09-30 9:27 UTC (permalink / raw)
To: Hangbin Liu
Cc: David Wilder, netdev, jv, pradeeps, pradeep, i.maximets, amorenoz,
stephen, horms, kuba, andrew+netdev, edumazet
On 9/30/25 9:58 AM, Hangbin Liu wrote:
> On Tue, Sep 30, 2025 at 09:21:30AM +0200, Paolo Abeni wrote:
>> ## Form letter - net-next-closed
>>
>> The merge window for v6.18 has begun and therefore net-next is closed
>> for new drivers, features, code refactoring and optimizations. We are
>> currently accepting bug fixes only.
>>
>> Please repost when net-next reopens after June 8th.
>>
>> RFC patches sent for review only are obviously welcome at any time.
>>
>
> I guess you mean after October 13th[1].
Whoops, bad C&P here while writing the form letter. Thanks for catching
it! To be more accurate: after Oct 12th.
/P
^ permalink raw reply [flat|nested] 11+ messages in thread