* [PATCH net-next v5 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags.
@ 2025-07-14 22:54 David Wilder
2025-07-14 22:54 ` [PATCH net-next v5 1/7] bonding: Adding struct bond_arp_target David Wilder
` (6 more replies)
0 siblings, 7 replies; 13+ messages in thread
From: David Wilder @ 2025-07-14 22:54 UTC (permalink / raw)
To: netdev; +Cc: jv, wilder, pradeeps, pradeep, i.maximets, amorenoz, haliu
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 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>
David Wilder (7):
bonding: Adding struct bond_arp_target
bonding: Adding extra_len field to struct bond_opt_value.
bonding: arp_ip_target helpers.
bonding: Processing extended arp_ip_target from user space.
bonding: Update to bond_arp_send_all() to use supplied vlan tags
bonding: Update for extended arp_ip_target format.
bonding: Selftest and documentation for the arp_ip_target parameter.
Documentation/networking/bonding.rst | 11 ++
drivers/net/bonding/bond_main.c | 47 +++--
drivers/net/bonding/bond_netlink.c | 33 +++-
drivers/net/bonding/bond_options.c | 95 +++++++---
drivers/net/bonding/bond_procfs.c | 4 +-
drivers/net/bonding/bond_sysfs.c | 4 +-
include/net/bond_options.h | 29 ++-
include/net/bonding.h | 61 +++++-
.../selftests/drivers/net/bonding/Makefile | 3 +-
.../drivers/net/bonding/bond-arp-ip-target.sh | 179 ++++++++++++++++++
10 files changed, 393 insertions(+), 73 deletions(-)
create mode 100755 tools/testing/selftests/drivers/net/bonding/bond-arp-ip-target.sh
--
2.43.5
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH net-next v5 1/7] bonding: Adding struct bond_arp_target
2025-07-14 22:54 [PATCH net-next v5 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
@ 2025-07-14 22:54 ` David Wilder
2025-07-14 22:54 ` [PATCH net-next v5 2/7] bonding: Adding extra_len field to struct bond_opt_value David Wilder
` (5 subsequent siblings)
6 siblings, 0 replies; 13+ messages in thread
From: David Wilder @ 2025-07-14 22:54 UTC (permalink / raw)
To: netdev; +Cc: jv, wilder, pradeeps, pradeep, i.maximets, amorenoz, haliu
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 17c7542be6a5..7e938077bbde 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 1d639a3be6ba..e04487f8d79a 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.43.5
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH net-next v5 2/7] bonding: Adding extra_len field to struct bond_opt_value.
2025-07-14 22:54 [PATCH net-next v5 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
2025-07-14 22:54 ` [PATCH net-next v5 1/7] bonding: Adding struct bond_arp_target David Wilder
@ 2025-07-14 22:54 ` David Wilder
2025-07-14 22:54 ` [PATCH net-next v5 3/7] bonding: arp_ip_target helpers David Wilder
` (4 subsequent siblings)
6 siblings, 0 replies; 13+ messages in thread
From: David Wilder @ 2025-07-14 22:54 UTC (permalink / raw)
To: netdev; +Cc: jv, wilder, pradeeps, pradeep, i.maximets, amorenoz, haliu
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..b95023bf40c3 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;
+ u16 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.43.5
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH net-next v5 3/7] bonding: arp_ip_target helpers.
2025-07-14 22:54 [PATCH net-next v5 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
2025-07-14 22:54 ` [PATCH net-next v5 1/7] bonding: Adding struct bond_arp_target David Wilder
2025-07-14 22:54 ` [PATCH net-next v5 2/7] bonding: Adding extra_len field to struct bond_opt_value David Wilder
@ 2025-07-14 22:54 ` David Wilder
2025-07-14 22:54 ` [PATCH net-next v5 4/7] bonding: Processing extended arp_ip_target from user space David Wilder
` (3 subsequent siblings)
6 siblings, 0 replies; 13+ messages in thread
From: David Wilder @ 2025-07-14 22:54 UTC (permalink / raw)
To: netdev; +Cc: jv, wilder, pradeeps, pradeep, i.maximets, amorenoz, haliu
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.43.5
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH net-next v5 4/7] bonding: Processing extended arp_ip_target from user space.
2025-07-14 22:54 [PATCH net-next v5 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
` (2 preceding siblings ...)
2025-07-14 22:54 ` [PATCH net-next v5 3/7] bonding: arp_ip_target helpers David Wilder
@ 2025-07-14 22:54 ` David Wilder
2025-07-14 22:54 ` [PATCH net-next v5 5/7] bonding: Update to bond_arp_send_all() to use supplied vlan tags David Wilder
` (2 subsequent siblings)
6 siblings, 0 replies; 13+ messages in thread
From: David Wilder @ 2025-07-14 22:54 UTC (permalink / raw)
To: netdev; +Cc: jv, wilder, pradeeps, pradeep, i.maximets, amorenoz, haliu
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 | 81 +++++++++++++++++++++---------
2 files changed, 60 insertions(+), 26 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 e04487f8d79a..1455e7f15c31 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,45 @@ 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.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);
}
static int bond_option_arp_ip_targets_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
+ size_t len = (size_t)newval->extra_len;
+ char *extra = (char *)newval->extra;
+ struct bond_arp_target target;
int ret = -EPERM;
- __be32 target;
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 +1270,23 @@ 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);
+
+ if (len)
+ target.tags = kmalloc(len, GFP_ATOMIC);
+
+ if (target.tags) {
+ memcpy(target.tags, extra, len);
+ target.flags |= BOND_TARGET_USERTAGS;
+ }
+
ret = bond_option_arp_ip_target_add(bond, target);
}
--
2.43.5
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH net-next v5 5/7] bonding: Update to bond_arp_send_all() to use supplied vlan tags
2025-07-14 22:54 [PATCH net-next v5 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
` (3 preceding siblings ...)
2025-07-14 22:54 ` [PATCH net-next v5 4/7] bonding: Processing extended arp_ip_target from user space David Wilder
@ 2025-07-14 22:54 ` David Wilder
2025-07-14 22:54 ` [PATCH net-next v5 6/7] bonding: Update for extended arp_ip_target format David Wilder
2025-07-14 22:54 ` [PATCH net-next v5 7/7] bonding: Selftest and documentation for the arp_ip_target parameter David Wilder
6 siblings, 0 replies; 13+ messages in thread
From: David Wilder @ 2025-07-14 22:54 UTC (permalink / raw)
To: netdev; +Cc: jv, wilder, pradeeps, pradeep, i.maximets, amorenoz, haliu
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().
bonding_exit() 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 7e938077bbde..2f153c89e401 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);
}
}
@@ -6732,7 +6736,7 @@ static void __exit bonding_exit(void)
bond_netlink_fini();
unregister_pernet_subsys(&bond_net_ops);
-
+ bond_free_vlan_tags(bonding_defaults.arp_targets);
bond_destroy_debugfs();
#ifdef CONFIG_NET_POLL_CONTROLLER
--
2.43.5
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH net-next v5 6/7] bonding: Update for extended arp_ip_target format.
2025-07-14 22:54 [PATCH net-next v5 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
` (4 preceding siblings ...)
2025-07-14 22:54 ` [PATCH net-next v5 5/7] bonding: Update to bond_arp_send_all() to use supplied vlan tags David Wilder
@ 2025-07-14 22:54 ` David Wilder
2025-07-15 13:58 ` Simon Horman
2025-07-16 9:17 ` kernel test robot
2025-07-14 22:54 ` [PATCH net-next v5 7/7] bonding: Selftest and documentation for the arp_ip_target parameter David Wilder
6 siblings, 2 replies; 13+ messages in thread
From: David Wilder @ 2025-07-14 22:54 UTC (permalink / raw)
To: netdev; +Cc: jv, wilder, pradeeps, pradeep, i.maximets, amorenoz, haliu
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 | 28 ++++++++++++++++++++++++++--
include/net/bonding.h | 1 +
2 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
index 5486ef40907e..6e8aebe5629f 100644
--- a/drivers/net/bonding/bond_netlink.c
+++ b/drivers/net/bonding/bond_netlink.c
@@ -701,8 +701,32 @@ 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].target_ip) {
- if (nla_put_be32(skb, i, bond->params.arp_targets[i].target_ip))
+ struct bond_arp_target *target = &bond->params.arp_targets[i];
+ struct Data {
+ __u32 addr;
+ struct bond_vlan_tag vlans[BOND_MAX_VLAN_TAGS + 1];
+ } data;
+ int size = 0;
+
+ if (target->target_ip) {
+ data.addr = target->target_ip;
+ size = sizeof(target->target_ip);
+ }
+
+ for (int level = 0; target->flags & BOND_TARGET_USERTAGS && target->tags; level++) {
+ if (level > BOND_MAX_VLAN_TAGS)
+ goto nla_put_failure;
+
+ memcpy(&data.vlans[level], &target->tags[level],
+ sizeof(struct bond_vlan_tag));
+ size = size + sizeof(struct bond_vlan_tag);
+
+ if (target->tags[level].vlan_proto == BOND_VLAN_PROTO_NONE)
+ break;
+ }
+
+ if (size) {
+ if (nla_put(skb, i, size, &data))
goto nla_put_failure;
targets_added = 1;
}
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.43.5
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH net-next v5 7/7] bonding: Selftest and documentation for the arp_ip_target parameter.
2025-07-14 22:54 [PATCH net-next v5 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
` (5 preceding siblings ...)
2025-07-14 22:54 ` [PATCH net-next v5 6/7] bonding: Update for extended arp_ip_target format David Wilder
@ 2025-07-14 22:54 ` David Wilder
2025-07-15 13:59 ` Simon Horman
6 siblings, 1 reply; 13+ messages in thread
From: David Wilder @ 2025-07-14 22:54 UTC (permalink / raw)
To: netdev; +Cc: jv, wilder, pradeeps, pradeep, i.maximets, amorenoz, haliu
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 | 179 ++++++++++++++++++
3 files changed, 192 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 2b10854e4b1e..c59bb2912a38 100644
--- a/tools/testing/selftests/drivers/net/bonding/Makefile
+++ b/tools/testing/selftests/drivers/net/bonding/Makefile
@@ -10,7 +10,8 @@ TEST_PROGS := \
mode-2-recovery-updelay.sh \
bond_options.sh \
bond-eth-type-change.sh \
- bond_macvlan_ipvlan.sh
+ bond_macvlan_ipvlan.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..e9af27f17d0f
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/bonding/bond-arp-ip-target.sh
@@ -0,0 +1,179 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Test bonding arp_ip_target.
+# Topology for Bond mode 1,5,6 testing
+#
+# +-------------------------+
+# | | Server
+# | bond.10.20.30 | 192.30.2.1/24
+# | | |
+# | 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
+# | | |
+# | eth0.10.20.30 | 192.30.30.2/24
+# +-------------------------+
+
+lib_dir=$(dirname "$0")
+
+# shellcheck source=./bond_topo_2d1c.sh
+source "${lib_dir}"/bond_topo_2d1c.sh
+
+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"
+
+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"
--
2.43.5
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH net-next v5 6/7] bonding: Update for extended arp_ip_target format.
2025-07-14 22:54 ` [PATCH net-next v5 6/7] bonding: Update for extended arp_ip_target format David Wilder
@ 2025-07-15 13:58 ` Simon Horman
2025-07-15 18:22 ` David Wilder
2025-07-16 9:17 ` kernel test robot
1 sibling, 1 reply; 13+ messages in thread
From: Simon Horman @ 2025-07-15 13:58 UTC (permalink / raw)
To: David Wilder; +Cc: netdev, jv, pradeeps, pradeep, i.maximets, amorenoz, haliu
On Mon, Jul 14, 2025 at 03:54:51PM -0700, David Wilder wrote:
> 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 | 28 ++++++++++++++++++++++++++--
> include/net/bonding.h | 1 +
> 2 files changed, 27 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
> index 5486ef40907e..6e8aebe5629f 100644
> --- a/drivers/net/bonding/bond_netlink.c
> +++ b/drivers/net/bonding/bond_netlink.c
> @@ -701,8 +701,32 @@ 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].target_ip) {
> - if (nla_put_be32(skb, i, bond->params.arp_targets[i].target_ip))
> + struct bond_arp_target *target = &bond->params.arp_targets[i];
> + struct Data {
> + __u32 addr;
> + struct bond_vlan_tag vlans[BOND_MAX_VLAN_TAGS + 1];
> + } data;
> + int size = 0;
> +
> + if (target->target_ip) {
> + data.addr = target->target_ip;
Hi David,
There appears to be an endian mismatch here. Sparse says:
.../bond_netlink.c:712:35: warning: incorrect type in assignment (different base types)
.../bond_netlink.c:712:35: expected unsigned int [usertype] addr
.../bond_netlink.c:712:35: got restricted __be32 [usertype] target_ip
> + size = sizeof(target->target_ip);
> + }
It seems that data.addr may be used uninitialised below
if the if condition above is not met.
Flagged by Smatch.
> +
> + for (int level = 0; target->flags & BOND_TARGET_USERTAGS && target->tags; level++) {
> + if (level > BOND_MAX_VLAN_TAGS)
> + goto nla_put_failure;
> +
> + memcpy(&data.vlans[level], &target->tags[level],
> + sizeof(struct bond_vlan_tag));
> + size = size + sizeof(struct bond_vlan_tag);
> +
> + if (target->tags[level].vlan_proto == BOND_VLAN_PROTO_NONE)
> + break;
> + }
> +
> + if (size) {
> + if (nla_put(skb, i, size, &data))
> goto nla_put_failure;
> targets_added = 1;
> }
...
--
pw-bot: changes-requested
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net-next v5 7/7] bonding: Selftest and documentation for the arp_ip_target parameter.
2025-07-14 22:54 ` [PATCH net-next v5 7/7] bonding: Selftest and documentation for the arp_ip_target parameter David Wilder
@ 2025-07-15 13:59 ` Simon Horman
0 siblings, 0 replies; 13+ messages in thread
From: Simon Horman @ 2025-07-15 13:59 UTC (permalink / raw)
To: David Wilder; +Cc: netdev, jv, pradeeps, pradeep, i.maximets, amorenoz, haliu
On Mon, Jul 14, 2025 at 03:54:52PM -0700, David Wilder wrote:
> 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 | 179 ++++++++++++++++++
Hi David,
Perhaps this has already been covered, but if not,
please run shellcheck over bond-arp-ip-target.sh and
see if any of the issues it flags can reasonably be resolved.
Thanks!
^ permalink raw reply [flat|nested] 13+ messages in thread
* RE: [PATCH net-next v5 6/7] bonding: Update for extended arp_ip_target format.
2025-07-15 13:58 ` Simon Horman
@ 2025-07-15 18:22 ` David Wilder
2025-07-16 9:00 ` Simon Horman
0 siblings, 1 reply; 13+ messages in thread
From: David Wilder @ 2025-07-15 18:22 UTC (permalink / raw)
To: Simon Horman
Cc: netdev@vger.kernel.org, jv@jvosburgh.net,
pradeeps@linux.vnet.ibm.com, Pradeep Satyanarayana,
i.maximets@ovn.org, Adrian Moreno Zapata, Hangbin Liu
________________________________________
From: Simon Horman <horms@kernel.org>
Sent: Tuesday, July 15, 2025 6:58 AM
To: David Wilder
Cc: netdev@vger.kernel.org; jv@jvosburgh.net; pradeeps@linux.vnet.ibm.com; Pradeep Satyanarayana; i.maximets@ovn.org; Adrian Moreno Zapata; Hangbin Liu
Subject: [EXTERNAL] Re: [PATCH net-next v5 6/7] bonding: Update for extended arp_ip_target format.
>On Mon, Jul 14, 2025 at 03:54:51PM -0700, David Wilder wrote:
>> 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 | 28 ++++++++++++++++++++++++++--
>> include/net/bonding.h | 1 +
>> 2 files changed, 27 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
>> index 5486ef40907e..6e8aebe5629f 100644
>> --- a/drivers/net/bonding/bond_netlink.c
>> +++ b/drivers/net/bonding/bond_netlink.c
>> @@ -701,8 +701,32 @@ 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].target_ip) {
>> - if (nla_put_be32(skb, i, bond->params.arp_targets[i].target_ip))
>> + struct bond_arp_target *target = &bond->params.arp_targets[i];
>> + struct Data {
>> + __u32 addr;
>> + struct bond_vlan_tag vlans[BOND_MAX_VLAN_TAGS + 1];
>> + } data;
>> + int size = 0;
>> +
>> + if (target->target_ip) {
>> + data.addr = target->target_ip;
>
>Hi David,
>
>There appears to be an endian mismatch here. Sparse says:
>
>.../bond_netlink.c:712:35: warning: incorrect type in assignment (different base types)
>.../bond_netlink.c:712:35: expected unsigned int [usertype] addr
>.../bond_netlink.c:712:35: got restricted __be32 [usertype] target_ip
>
>> + size = sizeof(target->target_ip);
>> + }
>
>It seems that data.addr may be used uninitialised below
>if the if condition above is not met.
>Flagged by Smatch.
Hi Simon
Thanks for catching this, I will make the following change in the next version.
@@ -703,15 +703,14 @@ static int bond_fill_info(struct sk_buff *skb,
for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
struct bond_arp_target *target = &bond->params.arp_targets[i];
struct Data {
- __u32 addr;
+ __be32 addr;
struct bond_vlan_tag vlans[BOND_MAX_VLAN_TAGS + 1];
} data;
int size = 0;
- if (target->target_ip) {
- data.addr = target->target_ip;
- size = sizeof(target->target_ip);
- }
+ BUG_ON(!target->target_ip);
+ data.addr = target->target_ip;
+ size = sizeof(target->target_ip);
for (int level = 0; target->flags & BOND_TARGET_USERTAGS && target->tags; level++) {
if (level > BOND_MAX_VLAN_TAGS)
David Wilder
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net-next v5 6/7] bonding: Update for extended arp_ip_target format.
2025-07-15 18:22 ` David Wilder
@ 2025-07-16 9:00 ` Simon Horman
0 siblings, 0 replies; 13+ messages in thread
From: Simon Horman @ 2025-07-16 9:00 UTC (permalink / raw)
To: David Wilder
Cc: netdev@vger.kernel.org, jv@jvosburgh.net,
pradeeps@linux.vnet.ibm.com, Pradeep Satyanarayana,
i.maximets@ovn.org, Adrian Moreno Zapata, Hangbin Liu
On Tue, Jul 15, 2025 at 06:22:37PM +0000, David Wilder wrote:
>
>
>
> ________________________________________
> From: Simon Horman <horms@kernel.org>
> Sent: Tuesday, July 15, 2025 6:58 AM
> To: David Wilder
> Cc: netdev@vger.kernel.org; jv@jvosburgh.net; pradeeps@linux.vnet.ibm.com; Pradeep Satyanarayana; i.maximets@ovn.org; Adrian Moreno Zapata; Hangbin Liu
> Subject: [EXTERNAL] Re: [PATCH net-next v5 6/7] bonding: Update for extended arp_ip_target format.
>
> >On Mon, Jul 14, 2025 at 03:54:51PM -0700, David Wilder wrote:
> >> 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 | 28 ++++++++++++++++++++++++++--
> >> include/net/bonding.h | 1 +
> >> 2 files changed, 27 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
> >> index 5486ef40907e..6e8aebe5629f 100644
> >> --- a/drivers/net/bonding/bond_netlink.c
> >> +++ b/drivers/net/bonding/bond_netlink.c
> >> @@ -701,8 +701,32 @@ 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].target_ip) {
> >> - if (nla_put_be32(skb, i, bond->params.arp_targets[i].target_ip))
> >> + struct bond_arp_target *target = &bond->params.arp_targets[i];
> >> + struct Data {
> >> + __u32 addr;
> >> + struct bond_vlan_tag vlans[BOND_MAX_VLAN_TAGS + 1];
> >> + } data;
> >> + int size = 0;
> >> +
> >> + if (target->target_ip) {
> >> + data.addr = target->target_ip;
> >
> >Hi David,
> >
> >There appears to be an endian mismatch here. Sparse says:
> >
> >.../bond_netlink.c:712:35: warning: incorrect type in assignment (different base types)
> >.../bond_netlink.c:712:35: expected unsigned int [usertype] addr
> >.../bond_netlink.c:712:35: got restricted __be32 [usertype] target_ip
> >
> >> + size = sizeof(target->target_ip);
> >> + }
> >
> >It seems that data.addr may be used uninitialised below
> >if the if condition above is not met.
>
> >Flagged by Smatch.
>
> Hi Simon
>
> Thanks for catching this, I will make the following change in the next version.
>
> @@ -703,15 +703,14 @@ static int bond_fill_info(struct sk_buff *skb,
> for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
> struct bond_arp_target *target = &bond->params.arp_targets[i];
> struct Data {
> - __u32 addr;
> + __be32 addr;
> struct bond_vlan_tag vlans[BOND_MAX_VLAN_TAGS + 1];
> } data;
> int size = 0;
>
> - if (target->target_ip) {
> - data.addr = target->target_ip;
> - size = sizeof(target->target_ip);
> - }
> + BUG_ON(!target->target_ip);
Hi David,
I think this addresses the issues I raised, thanks!
But please don't use BUG_ON() like this, it will crash the kernel,
which seems disproportionate to the problem at hand.
I'm not particularly familiar with this code. But it seems
that it is filling in netlink attributes. And does not make
any resource allocations. So perhaps this is sufficient?
if (!target->target_ip)
return -EINVAL;
> + data.addr = target->target_ip;
> + size = sizeof(target->target_ip);
>
> for (int level = 0; target->flags & BOND_TARGET_USERTAGS && target->tags; level++) {
> if (level > BOND_MAX_VLAN_TAGS)
>
> David Wilder
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net-next v5 6/7] bonding: Update for extended arp_ip_target format.
2025-07-14 22:54 ` [PATCH net-next v5 6/7] bonding: Update for extended arp_ip_target format David Wilder
2025-07-15 13:58 ` Simon Horman
@ 2025-07-16 9:17 ` kernel test robot
1 sibling, 0 replies; 13+ messages in thread
From: kernel test robot @ 2025-07-16 9:17 UTC (permalink / raw)
To: David Wilder, netdev
Cc: oe-kbuild-all, jv, wilder, pradeeps, pradeep, i.maximets,
amorenoz, haliu
Hi David,
kernel test robot noticed the following build warnings:
[auto build test WARNING on net-next/main]
url: https://github.com/intel-lab-lkp/linux/commits/David-Wilder/bonding-Adding-struct-bond_arp_target/20250715-065747
base: net-next/main
patch link: https://lore.kernel.org/r/20250714225533.1490032-7-wilder%40us.ibm.com
patch subject: [PATCH net-next v5 6/7] bonding: Update for extended arp_ip_target format.
config: i386-randconfig-063-20250716 (https://download.01.org/0day-ci/archive/20250716/202507161722.3vSVtA6S-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250716/202507161722.3vSVtA6S-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202507161722.3vSVtA6S-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
>> drivers/net/bonding/bond_netlink.c:712:35: sparse: sparse: incorrect type in assignment (different base types) @@ expected unsigned int [usertype] addr @@ got restricted __be32 [usertype] target_ip @@
drivers/net/bonding/bond_netlink.c:712:35: sparse: expected unsigned int [usertype] addr
drivers/net/bonding/bond_netlink.c:712:35: sparse: got restricted __be32 [usertype] target_ip
vim +712 drivers/net/bonding/bond_netlink.c
660
661 static int bond_fill_info(struct sk_buff *skb,
662 const struct net_device *bond_dev)
663 {
664 struct bonding *bond = netdev_priv(bond_dev);
665 unsigned int packets_per_slave;
666 int ifindex, i, targets_added;
667 struct nlattr *targets;
668 struct slave *primary;
669
670 if (nla_put_u8(skb, IFLA_BOND_MODE, BOND_MODE(bond)))
671 goto nla_put_failure;
672
673 ifindex = bond_option_active_slave_get_ifindex(bond);
674 if (ifindex && nla_put_u32(skb, IFLA_BOND_ACTIVE_SLAVE, ifindex))
675 goto nla_put_failure;
676
677 if (nla_put_u32(skb, IFLA_BOND_MIIMON, bond->params.miimon))
678 goto nla_put_failure;
679
680 if (nla_put_u32(skb, IFLA_BOND_UPDELAY,
681 bond->params.updelay * bond->params.miimon))
682 goto nla_put_failure;
683
684 if (nla_put_u32(skb, IFLA_BOND_DOWNDELAY,
685 bond->params.downdelay * bond->params.miimon))
686 goto nla_put_failure;
687
688 if (nla_put_u32(skb, IFLA_BOND_PEER_NOTIF_DELAY,
689 bond->params.peer_notif_delay * bond->params.miimon))
690 goto nla_put_failure;
691
692 if (nla_put_u8(skb, IFLA_BOND_USE_CARRIER, bond->params.use_carrier))
693 goto nla_put_failure;
694
695 if (nla_put_u32(skb, IFLA_BOND_ARP_INTERVAL, bond->params.arp_interval))
696 goto nla_put_failure;
697
698 targets = nla_nest_start_noflag(skb, IFLA_BOND_ARP_IP_TARGET);
699 if (!targets)
700 goto nla_put_failure;
701
702 targets_added = 0;
703 for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
704 struct bond_arp_target *target = &bond->params.arp_targets[i];
705 struct Data {
706 __u32 addr;
707 struct bond_vlan_tag vlans[BOND_MAX_VLAN_TAGS + 1];
708 } data;
709 int size = 0;
710
711 if (target->target_ip) {
> 712 data.addr = target->target_ip;
713 size = sizeof(target->target_ip);
714 }
715
716 for (int level = 0; target->flags & BOND_TARGET_USERTAGS && target->tags; level++) {
717 if (level > BOND_MAX_VLAN_TAGS)
718 goto nla_put_failure;
719
720 memcpy(&data.vlans[level], &target->tags[level],
721 sizeof(struct bond_vlan_tag));
722 size = size + sizeof(struct bond_vlan_tag);
723
724 if (target->tags[level].vlan_proto == BOND_VLAN_PROTO_NONE)
725 break;
726 }
727
728 if (size) {
729 if (nla_put(skb, i, size, &data))
730 goto nla_put_failure;
731 targets_added = 1;
732 }
733 }
734
735 if (targets_added)
736 nla_nest_end(skb, targets);
737 else
738 nla_nest_cancel(skb, targets);
739
740 if (nla_put_u32(skb, IFLA_BOND_ARP_VALIDATE, bond->params.arp_validate))
741 goto nla_put_failure;
742
743 if (nla_put_u32(skb, IFLA_BOND_ARP_ALL_TARGETS,
744 bond->params.arp_all_targets))
745 goto nla_put_failure;
746
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2025-07-16 9:17 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-14 22:54 [PATCH net-next v5 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
2025-07-14 22:54 ` [PATCH net-next v5 1/7] bonding: Adding struct bond_arp_target David Wilder
2025-07-14 22:54 ` [PATCH net-next v5 2/7] bonding: Adding extra_len field to struct bond_opt_value David Wilder
2025-07-14 22:54 ` [PATCH net-next v5 3/7] bonding: arp_ip_target helpers David Wilder
2025-07-14 22:54 ` [PATCH net-next v5 4/7] bonding: Processing extended arp_ip_target from user space David Wilder
2025-07-14 22:54 ` [PATCH net-next v5 5/7] bonding: Update to bond_arp_send_all() to use supplied vlan tags David Wilder
2025-07-14 22:54 ` [PATCH net-next v5 6/7] bonding: Update for extended arp_ip_target format David Wilder
2025-07-15 13:58 ` Simon Horman
2025-07-15 18:22 ` David Wilder
2025-07-16 9:00 ` Simon Horman
2025-07-16 9:17 ` kernel test robot
2025-07-14 22:54 ` [PATCH net-next v5 7/7] bonding: Selftest and documentation for the arp_ip_target parameter David Wilder
2025-07-15 13:59 ` Simon Horman
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).