* [PATCH net-next v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags.
@ 2025-06-27 20:17 David Wilder
2025-06-27 20:17 ` [PATCH net-next v4 1/7] bonding: Adding struct bond_arp_target David Wilder
` (8 more replies)
0 siblings, 9 replies; 18+ messages in thread
From: David Wilder @ 2025-06-27 20:17 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)
The extended format of arp_ip_target is only supported by using the ip command when
creating the bond. Module parameters and the sysfs file do not allow the use of the
extended format.
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.
--
I have run into issues with the ns_ip6_target feature. I am unable to get
the existing code to function with vlans. Therefor I am unable to support
A this change for ns_ip6_target.
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 to bond's sysfs and procfs 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 | 9 +-
drivers/net/bonding/bond_options.c | 95 ++++++---
drivers/net/bonding/bond_procfs.c | 7 +-
drivers/net/bonding/bond_sysfs.c | 9 +-
include/net/bond_options.h | 29 ++-
include/net/bonding.h | 60 +++++-
.../selftests/drivers/net/bonding/Makefile | 3 +-
.../drivers/net/bonding/bond-arp-ip-target.sh | 194 ++++++++++++++++++
10 files changed, 390 insertions(+), 74 deletions(-)
create mode 100755 tools/testing/selftests/drivers/net/bonding/bond-arp-ip-target.sh
--
2.43.5
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH net-next v4 1/7] bonding: Adding struct bond_arp_target
2025-06-27 20:17 [PATCH net-next v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
@ 2025-06-27 20:17 ` David Wilder
2025-06-27 20:17 ` [PATCH net-next v4 2/7] bonding: Adding extra_len field to struct bond_opt_value David Wilder
` (7 subsequent siblings)
8 siblings, 0 replies; 18+ messages in thread
From: David Wilder @ 2025-06-27 20:17 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 c4d53e8e7c15..ac654b384ea1 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3146,26 +3146,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;
}
@@ -3183,15 +3186,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);
}
}
@@ -6096,7 +6099,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;
@@ -6290,7 +6293,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 ac5e402c34bc..1a3d17754c0a 100644
--- a/drivers/net/bonding/bond_netlink.c
+++ b/drivers/net/bonding/bond_netlink.c
@@ -688,8 +688,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 91893c29b899..e4b7eb376575 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -1090,7 +1090,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) {
@@ -1118,20 +1118,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)) {
@@ -1166,7 +1166,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;
@@ -1185,20 +1185,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 18687ccf0638..0a7d690cb005 100644
--- a/include/net/bond_options.h
+++ b/include/net/bond_options.h
@@ -119,6 +119,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 95f67b308c19..5b4c43f02c89 100644
--- a/include/net/bonding.h
+++ b/include/net/bonding.h
@@ -135,7 +135,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;
@@ -274,11 +274,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
*
@@ -522,7 +517,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];
@@ -760,14 +755,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] 18+ messages in thread
* [PATCH net-next v4 2/7] bonding: Adding extra_len field to struct bond_opt_value.
2025-06-27 20:17 [PATCH net-next v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
2025-06-27 20:17 ` [PATCH net-next v4 1/7] bonding: Adding struct bond_arp_target David Wilder
@ 2025-06-27 20:17 ` David Wilder
2025-06-27 20:17 ` [PATCH net-next v4 3/7] bonding: arp_ip_target helpers David Wilder
` (6 subsequent siblings)
8 siblings, 0 replies; 18+ messages in thread
From: David Wilder @ 2025-06-27 20:17 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 0a7d690cb005..d5d59081a9ce 100644
--- a/include/net/bond_options.h
+++ b/include/net/bond_options.h
@@ -85,14 +85,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;
@@ -167,8 +168,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] 18+ messages in thread
* [PATCH net-next v4 3/7] bonding: arp_ip_target helpers.
2025-06-27 20:17 [PATCH net-next v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
2025-06-27 20:17 ` [PATCH net-next v4 1/7] bonding: Adding struct bond_arp_target David Wilder
2025-06-27 20:17 ` [PATCH net-next v4 2/7] bonding: Adding extra_len field to struct bond_opt_value David Wilder
@ 2025-06-27 20:17 ` David Wilder
2025-06-27 20:17 ` [PATCH net-next v4 4/7] bonding: Processing extended arp_ip_target from user space David Wilder
` (5 subsequent siblings)
8 siblings, 0 replies; 18+ messages in thread
From: David Wilder @ 2025-06-27 20:17 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 5b4c43f02c89..a111c50399d3 100644
--- a/include/net/bonding.h
+++ b/include/net/bonding.h
@@ -806,4 +806,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] 18+ messages in thread
* [PATCH net-next v4 4/7] bonding: Processing extended arp_ip_target from user space.
2025-06-27 20:17 [PATCH net-next v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
` (2 preceding siblings ...)
2025-06-27 20:17 ` [PATCH net-next v4 3/7] bonding: arp_ip_target helpers David Wilder
@ 2025-06-27 20:17 ` David Wilder
2025-06-27 20:17 ` [PATCH net-next v4 5/7] bonding: Update to bond_arp_send_all() to use supplied vlan tags David Wilder
` (4 subsequent siblings)
8 siblings, 0 replies; 18+ messages in thread
From: David Wilder @ 2025-06-27 20:17 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 1a3d17754c0a..23e27530c4d8 100644
--- a/drivers/net/bonding/bond_netlink.c
+++ b/drivers/net/bonding/bond_netlink.c
@@ -292,9 +292,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 e4b7eb376575..6e0611de1087 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,
@@ -1115,7 +1115,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;
@@ -1125,24 +1125,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;
}
@@ -1152,43 +1153,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;
@@ -1196,30 +1198,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;
}
@@ -1230,7 +1247,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] 18+ messages in thread
* [PATCH net-next v4 5/7] bonding: Update to bond_arp_send_all() to use supplied vlan tags
2025-06-27 20:17 [PATCH net-next v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
` (3 preceding siblings ...)
2025-06-27 20:17 ` [PATCH net-next v4 4/7] bonding: Processing extended arp_ip_target from user space David Wilder
@ 2025-06-27 20:17 ` David Wilder
2025-06-27 20:17 ` [PATCH net-next v4 6/7] bonding: Update to bond's sysfs and procfs for extended arp_ip_target format David Wilder
` (3 subsequent siblings)
8 siblings, 0 replies; 18+ messages in thread
From: David Wilder @ 2025-06-27 20:17 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 ac654b384ea1..92c64030b432 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3144,18 +3144,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,
@@ -3177,9 +3178,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;
@@ -3195,7 +3200,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);
}
}
@@ -6663,7 +6667,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] 18+ messages in thread
* [PATCH net-next v4 6/7] bonding: Update to bond's sysfs and procfs for extended arp_ip_target format.
2025-06-27 20:17 [PATCH net-next v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
` (4 preceding siblings ...)
2025-06-27 20:17 ` [PATCH net-next v4 5/7] bonding: Update to bond_arp_send_all() to use supplied vlan tags David Wilder
@ 2025-06-27 20:17 ` David Wilder
2025-07-02 18:32 ` Jay Vosburgh
2025-06-27 20:17 ` [PATCH net-next v4 7/7] bonding: Selftest and documentation for the arp_ip_target parameter David Wilder
` (2 subsequent siblings)
8 siblings, 1 reply; 18+ messages in thread
From: David Wilder @ 2025-06-27 20:17 UTC (permalink / raw)
To: netdev; +Cc: jv, wilder, pradeeps, pradeep, i.maximets, amorenoz, haliu
/sys/class/net/<bond>/bonding/arp_ip_target and
/proc/net/bonding/<bond> will display vlan tags if
they have been configured by the user
Signed-off-by: David Wilder <wilder@us.ibm.com>
---
drivers/net/bonding/bond_procfs.c | 5 ++++-
drivers/net/bonding/bond_sysfs.c | 9 ++++++---
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c
index 94e6fd7041ee..b07944396912 100644
--- a/drivers/net/bonding/bond_procfs.c
+++ b/drivers/net/bonding/bond_procfs.c
@@ -111,6 +111,7 @@ static void bond_info_show_master(struct seq_file *seq)
/* ARP information */
if (bond->params.arp_interval > 0) {
+ char pbuf[BOND_OPTION_STRING_MAX_SIZE];
int printed = 0;
seq_printf(seq, "ARP Polling Interval (ms): %d\n",
@@ -125,7 +126,9 @@ static void bond_info_show_master(struct seq_file *seq)
break;
if (printed)
seq_printf(seq, ",");
- seq_printf(seq, " %pI4", &bond->params.arp_targets[i].target_ip);
+ bond_arp_target_to_string(&bond->params.arp_targets[i],
+ pbuf, sizeof(pbuf));
+ seq_printf(seq, " %s", pbuf);
printed = 1;
}
seq_printf(seq, "\n");
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index d7c09e0a14dd..870e0d90b77c 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -286,13 +286,16 @@ static ssize_t bonding_show_arp_targets(struct device *d,
struct device_attribute *attr,
char *buf)
{
+ char pbuf[BOND_OPTION_STRING_MAX_SIZE];
struct bonding *bond = to_bond(d);
int i, res = 0;
for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
- if (bond->params.arp_targets[i].target_ip)
- res += sysfs_emit_at(buf, res, "%pI4 ",
- &bond->params.arp_targets[i].target_ip);
+ if (bond->params.arp_targets[i].target_ip) {
+ bond_arp_target_to_string(&bond->params.arp_targets[i],
+ pbuf, sizeof(pbuf));
+ res += sysfs_emit_at(buf, res, "%s ", pbuf);
+ }
}
if (res)
buf[res-1] = '\n'; /* eat the leftover space */
--
2.43.5
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH net-next v4 7/7] bonding: Selftest and documentation for the arp_ip_target parameter.
2025-06-27 20:17 [PATCH net-next v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
` (5 preceding siblings ...)
2025-06-27 20:17 ` [PATCH net-next v4 6/7] bonding: Update to bond's sysfs and procfs for extended arp_ip_target format David Wilder
@ 2025-06-27 20:17 ` David Wilder
2025-06-28 1:03 ` [PATCH net-next v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags Jakub Kicinski
2025-06-30 10:18 ` Hangbin Liu
8 siblings, 0 replies; 18+ messages in thread
From: David Wilder @ 2025-06-27 20:17 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 | 194 ++++++++++++++++++
3 files changed, 207 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 a4c1291d2561..aa76b94b1d88 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..89c698d28701
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/bonding/bond-arp-ip-target.sh
@@ -0,0 +1,194 @@
+#!/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")
+source ${lib_dir}/bond_topo_2d1c.sh
+
+DEBUG=${DEBUG:-0}
+test ${DEBUG} -ne 0 && set -x
+
+# vlan subnets
+s_ip4v10="192.10.2.1"
+s_ip4v20="192.20.2.1"
+s_ip4v30="192.30.2.1"
+c_ip4v10="192.10.2.10"
+c_ip4v20="192.20.2.10"
+c_ip4v30="192.30.2.10"
+
+ALL_TESTS="
+ no_vlan_hints
+ with_vlan_hints
+"
+
+# load bonding modules and set options.
+load_bonding() {
+ local bond_options="$*"
+
+ lsmod | grep bonding > /dev/null
+ if [ $? == 0 ]; then
+ rmmod bonding
+ fi
+ modprobe bonding ${bond_options}
+}
+
+# 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"
+
+ ip -n ${ns} link show ${interface} > /dev/null
+ if [[ $? -ne 0 ]] && RET=1; then
+ 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()
+{
+ load_bonding $*
+ setup_prepare
+ setup_wait
+ stack_vlans bond0 ${s_ns}
+ stack_vlans eth0 ${c_ns}
+}
+
+skip_with_vlan_hints()
+{
+ local skip=1
+
+ # check if iproute support prio option
+ ip -n ${s_ns} link add bond2 type bond arp_ip_target 10.0.0.1[10]
+ [[ $? -ne 0 ]] && skip=0
+ ip -n ${s_ns} link del bond2 2> /dev/null
+
+ return $skip
+}
+
+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" \
+ "Current 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 # dyndbg=+p
+tests_run
+
+exit $EXIT_STATUS
--
2.43.5
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags.
2025-06-27 20:17 [PATCH net-next v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
` (6 preceding siblings ...)
2025-06-27 20:17 ` [PATCH net-next v4 7/7] bonding: Selftest and documentation for the arp_ip_target parameter David Wilder
@ 2025-06-28 1:03 ` Jakub Kicinski
2025-06-30 10:18 ` Hangbin Liu
8 siblings, 0 replies; 18+ messages in thread
From: Jakub Kicinski @ 2025-06-28 1:03 UTC (permalink / raw)
To: David Wilder; +Cc: netdev, jv, pradeeps, pradeep, i.maximets, amorenoz, haliu
On Fri, 27 Jun 2025 13:17:13 -0700 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)
>
> The extended format of arp_ip_target is only supported by using the ip command when
> creating the bond. Module parameters and the sysfs file do not allow the use of the
> extended format.
>
> 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.
This appears to trigger the following warning when running the newly
added tests (BTW please run shellcheck on the test, too):
[ 1315.127007][ T9889] WARNING: CPU: 2 PID: 9889 at lib/vsprintf.c:2802 vsnprintf+0xa76/0x1050
[ 1315.127471][ T9889] Modules linked in: [last unloaded: netdevsim]
[ 1315.127908][ T9889] CPU: 2 UID: 0 PID: 9889 Comm: grep Not tainted 6.16.0-rc3-virtme #1 PREEMPT(full)
[ 1315.128709][ T9889] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011
[ 1315.129070][ T9889] RIP: 0010:vsnprintf+0xa76/0x1050
[ 1315.129378][ T9889] Code: 01 89 44 24 50 83 e8 01 89 44 24 7c 85 c0 7f c2 4c 89 f8 48 c1 e8 03 42 0f b6 04 08 84 c0 0f 85 72 fa ff ff e9 75 fa ff ff 90 <0f> 0b 90 e9 f1 f7 ff ff 48 8b 44 24 28 80 38 00 0f 85 a7 04 00 00
[ 1315.130388][ T9889] RSP: 0018:ffffc90001227970 EFLAGS: 00010286
[ 1315.130749][ T9889] RAX: 0000000000000000 RBX: fffff52000244f4c RCX: ffffc90001227a80
[ 1315.131233][ T9889] RDX: ffffffffb80db4e0 RSI: ffffffffffffffff RDI: 1ffff92000244f39
[ 1315.131654][ T9889] RBP: ffffc90001227a50 R08: ffffffffb80db4a1 R09: ffffffffb6e54d12
[ 1315.132073][ T9889] R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000
[ 1315.132509][ T9889] R13: 000000000000000c R14: ffffffffb6e54ce0 R15: ffffc90001227ba0
[ 1315.132937][ T9889] FS: 00007f554d21e740(0000) GS:ffff88807bb4d000(0000) knlGS:0000000000000000
[ 1315.133437][ T9889] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1315.133794][ T9889] CR2: 000055c1198c67f8 CR3: 000000000ca1b001 CR4: 0000000000772ef0
[ 1315.134244][ T9889] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 1315.134968][ T9889] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[ 1315.135406][ T9889] PKRU: 55555554
[ 1315.135626][ T9889] Call Trace:
[ 1315.135843][ T9889] <TASK>
[ 1315.136005][ T9889] ? __pfx_vsnprintf+0x10/0x10
[ 1315.136310][ T9889] ? __pfx_bond_opt_parse+0x10/0x10
[ 1315.136602][ T9889] snprintf+0xa1/0xd0
[ 1315.136823][ T9889] ? __pfx_snprintf+0x10/0x10
[ 1315.137133][ T9889] ? bond_opt_parse+0x32/0x6e0
[ 1315.137414][ T9889] ? bond_opt_parse+0x30/0x6e0
[ 1315.137696][ T9889] bond_info_show_master+0x84c/0x1140
[ 1315.137977][ T9889] ? bond_opt_parse+0x32/0x6e0
[ 1315.138276][ T9889] ? __pfx_bond_info_show_master+0x10/0x10
[ 1315.138625][ T9889] ? __pfx_seq_printf+0x10/0x10
[ 1315.138917][ T9889] ? __pfx_bond_info_seq_start+0x10/0x10
[ 1315.139218][ T9889] bond_info_seq_show+0x43/0x50
[ 1315.139507][ T9889] seq_read_iter+0x40e/0x1090
[ 1315.139805][ T9889] proc_reg_read_iter+0x1a3/0x270
[ 1315.140100][ T9889] vfs_read+0x75a/0xce0
[ 1315.140324][ T9889] ? vfs_getattr_nosec+0x2c0/0x3e0
[ 1315.140608][ T9889] ? __pfx_vfs_read+0x10/0x10
[ 1315.140896][ T9889] ? __do_sys_newfstat+0x7b/0xc0
[ 1315.141201][ T9889] ksys_read+0xf7/0x1d0
--
pw-bot: cr
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags.
2025-06-27 20:17 [PATCH net-next v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
` (7 preceding siblings ...)
2025-06-28 1:03 ` [PATCH net-next v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags Jakub Kicinski
@ 2025-06-30 10:18 ` Hangbin Liu
2025-06-30 16:19 ` David Wilder
8 siblings, 1 reply; 18+ messages in thread
From: Hangbin Liu @ 2025-06-30 10:18 UTC (permalink / raw)
To: David Wilder; +Cc: netdev, jv, pradeeps, pradeep, i.maximets, amorenoz, haliu
On Fri, Jun 27, 2025 at 01:17:13PM -0700, David Wilder wrote:
> I have run into issues with the ns_ip6_target feature. I am unable to get
> the existing code to function with vlans. Therefor I am unable to support
> A this change for ns_ip6_target.
Any reason why this is incompatible with ns_ip6_target?
Thanks
Hangbin
^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [PATCH net-next v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags.
2025-06-30 10:18 ` Hangbin Liu
@ 2025-06-30 16:19 ` David Wilder
2025-07-01 7:13 ` Hangbin Liu
0 siblings, 1 reply; 18+ messages in thread
From: David Wilder @ 2025-06-30 16:19 UTC (permalink / raw)
To: Hangbin Liu
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: Hangbin Liu <liuhangbin@gmail.com>
Sent: Monday, June 30, 2025 3:18 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 v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags.
> On Fri, Jun 27, 2025 at 01:17:13PM -0700, David Wilder wrote:
> I have run into issues with the ns_ip6_target feature. I am unable to get
> the existing code to function with vlans. Therefor I am unable to support
> A this change for ns_ip6_target.
> Any reason why this is incompatible with ns_ip6_target?
Hi Hangbin
I am unable to get the existing ns_ip6_target code to function when the target
is in a vlan. If the existing code is not working with vlans it makes no
sense to specify the vlan tags.
This is what I think is happening:
In ns_send_all() we have this bit of code:
dst = ip6_route_output(dev_net(bond->dev), NULL, &fl6);
if (dst->error) {
dst_release(dst);
/* there's no route to target - try to send arp
* probe to generate any traffic (arp_validate=0)
*/
if (bond->params.arp_validate)
bond_ns_send(slave, &targets[i], &in6addr_any, tags);
<.......>
continue;
}
ip6_route_output() is returning an error as there is no neighbor entry for
the target. A ns is then sent with no vlan header. I found that the
multicast ns (with no vlan header) is not passed to the vlan siblings
with the target address so no reply is sent.
The ipv4 code is simmiler but the arp is sent as a brodcast. The broadcast arp
will be propagated to the vlan sibling (in the linux vlan code).
This could be a testing issue, I am unsure. Can you help with
a test case with the target in a vlan?
Thanks
David Wilder
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags.
2025-06-30 16:19 ` David Wilder
@ 2025-07-01 7:13 ` Hangbin Liu
2025-08-07 4:38 ` Hangbin Liu
0 siblings, 1 reply; 18+ messages in thread
From: Hangbin Liu @ 2025-07-01 7:13 UTC (permalink / raw)
To: David Wilder
Cc: Hangbin Liu, netdev@vger.kernel.org, jv@jvosburgh.net,
pradeeps@linux.vnet.ibm.com, Pradeep Satyanarayana,
i.maximets@ovn.org, Adrian Moreno Zapata
On Mon, Jun 30, 2025 at 04:19:22PM +0000, David Wilder wrote:
>
>
>
> ________________________________________
> From: Hangbin Liu <liuhangbin@gmail.com>
> Sent: Monday, June 30, 2025 3:18 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 v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags.
>
> > On Fri, Jun 27, 2025 at 01:17:13PM -0700, David Wilder wrote:
> > I have run into issues with the ns_ip6_target feature. I am unable to get
> > the existing code to function with vlans. Therefor I am unable to support
> > A this change for ns_ip6_target.
>
> > Any reason why this is incompatible with ns_ip6_target?
>
> Hi Hangbin
>
> I am unable to get the existing ns_ip6_target code to function when the target
> is in a vlan. If the existing code is not working with vlans it makes no
> sense to specify the vlan tags.
>
> This is what I think is happening:
>
> In ns_send_all() we have this bit of code:
>
> dst = ip6_route_output(dev_net(bond->dev), NULL, &fl6);
> if (dst->error) {
> dst_release(dst);
> /* there's no route to target - try to send arp
> * probe to generate any traffic (arp_validate=0)
> */
> if (bond->params.arp_validate)
> bond_ns_send(slave, &targets[i], &in6addr_any, tags);
> <.......>
> continue;
> }
>
> ip6_route_output() is returning an error as there is no neighbor entry for
> the target. A ns is then sent with no vlan header. I found that the
> multicast ns (with no vlan header) is not passed to the vlan siblings
> with the target address so no reply is sent.
>
> The ipv4 code is simmiler but the arp is sent as a brodcast. The broadcast arp
> will be propagated to the vlan sibling (in the linux vlan code).
>
> This could be a testing issue, I am unsure. Can you help with
> a test case with the target in a vlan?
I can reproduce this issue. I guess it's because the IPv6 route code is
different with IPv4. I will check this issue.
Thanks
Hangbin
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 6/7] bonding: Update to bond's sysfs and procfs for extended arp_ip_target format.
2025-06-27 20:17 ` [PATCH net-next v4 6/7] bonding: Update to bond's sysfs and procfs for extended arp_ip_target format David Wilder
@ 2025-07-02 18:32 ` Jay Vosburgh
2025-07-03 18:07 ` David Wilder
0 siblings, 1 reply; 18+ messages in thread
From: Jay Vosburgh @ 2025-07-02 18:32 UTC (permalink / raw)
To: David Wilder; +Cc: netdev, pradeeps, pradeep, i.maximets, amorenoz, haliu
David Wilder <wilder@us.ibm.com> wrote:
>/sys/class/net/<bond>/bonding/arp_ip_target and
>/proc/net/bonding/<bond> will display vlan tags if
>they have been configured by the user
I don't think we need to do any of this, the sysfs and proc APIs
to bonding should not be updated to support new functionality. Netlink
and /sbin/ip must do the right thing, but the other APIs are more or
less frozen in the past.
-J
>Signed-off-by: David Wilder <wilder@us.ibm.com>
>---
> drivers/net/bonding/bond_procfs.c | 5 ++++-
> drivers/net/bonding/bond_sysfs.c | 9 ++++++---
> 2 files changed, 10 insertions(+), 4 deletions(-)
>
>diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c
>index 94e6fd7041ee..b07944396912 100644
>--- a/drivers/net/bonding/bond_procfs.c
>+++ b/drivers/net/bonding/bond_procfs.c
>@@ -111,6 +111,7 @@ static void bond_info_show_master(struct seq_file *seq)
>
> /* ARP information */
> if (bond->params.arp_interval > 0) {
>+ char pbuf[BOND_OPTION_STRING_MAX_SIZE];
> int printed = 0;
>
> seq_printf(seq, "ARP Polling Interval (ms): %d\n",
>@@ -125,7 +126,9 @@ static void bond_info_show_master(struct seq_file *seq)
> break;
> if (printed)
> seq_printf(seq, ",");
>- seq_printf(seq, " %pI4", &bond->params.arp_targets[i].target_ip);
>+ bond_arp_target_to_string(&bond->params.arp_targets[i],
>+ pbuf, sizeof(pbuf));
>+ seq_printf(seq, " %s", pbuf);
> printed = 1;
> }
> seq_printf(seq, "\n");
>diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
>index d7c09e0a14dd..870e0d90b77c 100644
>--- a/drivers/net/bonding/bond_sysfs.c
>+++ b/drivers/net/bonding/bond_sysfs.c
>@@ -286,13 +286,16 @@ static ssize_t bonding_show_arp_targets(struct device *d,
> struct device_attribute *attr,
> char *buf)
> {
>+ char pbuf[BOND_OPTION_STRING_MAX_SIZE];
> struct bonding *bond = to_bond(d);
> int i, res = 0;
>
> for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
>- if (bond->params.arp_targets[i].target_ip)
>- res += sysfs_emit_at(buf, res, "%pI4 ",
>- &bond->params.arp_targets[i].target_ip);
>+ if (bond->params.arp_targets[i].target_ip) {
>+ bond_arp_target_to_string(&bond->params.arp_targets[i],
>+ pbuf, sizeof(pbuf));
>+ res += sysfs_emit_at(buf, res, "%s ", pbuf);
>+ }
> }
> if (res)
> buf[res-1] = '\n'; /* eat the leftover space */
>--
>2.43.5
>
---
-Jay Vosburgh, jv@jvosburgh.net
^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [PATCH net-next v4 6/7] bonding: Update to bond's sysfs and procfs for extended arp_ip_target format.
2025-07-02 18:32 ` Jay Vosburgh
@ 2025-07-03 18:07 ` David Wilder
0 siblings, 0 replies; 18+ messages in thread
From: David Wilder @ 2025-07-03 18:07 UTC (permalink / raw)
To: Jay Vosburgh
Cc: netdev@vger.kernel.org, pradeeps@linux.vnet.ibm.com,
Pradeep Satyanarayana, i.maximets@ovn.org, Adrian Moreno Zapata,
Hangbin Liu
________________________________________
From: Jay Vosburgh <jv@jvosburgh.net>
Sent: Wednesday, July 2, 2025 11:32 AM
To: David Wilder
Cc: netdev@vger.kernel.org; pradeeps@linux.vnet.ibm.com; Pradeep Satyanarayana; i.maximets@ovn.org; Adrian Moreno Zapata; Hangbin Liu
Subject: [EXTERNAL] Re: [PATCH net-next v4 6/7] bonding: Update to bond's sysfs and procfs for extended arp_ip_target format.
>David Wilder <wilder@us.ibm.com> wrote:
>
>>/sys/class/net/<bond>/bonding/arp_ip_target and
>>/proc/net/bonding/<bond> will display vlan tags if
>>they have been configured by the user
>
> I don't think we need to do any of this, the sysfs and proc APIs
>to bonding should not be updated to support new functionality. Netlink
>and /sbin/ip must do the right thing, but the other APIs are more or
>less frozen in the past.
ok, I can remove this patch from the set.
>
> -J
>
>>Signed-off-by: David Wilder <wilder@us.ibm.com>
>>---
>> drivers/net/bonding/bond_procfs.c | 5 ++++-
>> drivers/net/bonding/bond_sysfs.c | 9 ++++++---
>> 2 files changed, 10 insertions(+), 4 deletions(-)
>>
>>diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c
>>index 94e6fd7041ee..b07944396912 100644
>>--- a/drivers/net/bonding/bond_procfs.c
>>+++ b/drivers/net/bonding/bond_procfs.c
>>@@ -111,6 +111,7 @@ static void bond_info_show_master(struct seq_file *seq)
>>
>> /* ARP information */
>> if (bond->params.arp_interval > 0) {
>>+ char pbuf[BOND_OPTION_STRING_MAX_SIZE];
>> int printed = 0;
>>
>> seq_printf(seq, "ARP Polling Interval (ms): %d\n",
>>@@ -125,7 +126,9 @@ static void bond_info_show_master(struct seq_file *seq)
>> break;
>> if (printed)
>> seq_printf(seq, ",");
>>- seq_printf(seq, " %pI4", &bond->params.arp_targets[i].target_ip);
>>+ bond_arp_target_to_string(&bond->params.arp_targets[i],
>>+ pbuf, sizeof(pbuf));
>>+ seq_printf(seq, " %s", pbuf);
>> printed = 1;
>> }
>> seq_printf(seq, "\n");
>>diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
>>index d7c09e0a14dd..870e0d90b77c 100644
>>--- a/drivers/net/bonding/bond_sysfs.c
>>+++ b/drivers/net/bonding/bond_sysfs.c
>>@@ -286,13 +286,16 @@ static ssize_t bonding_show_arp_targets(struct device *d,
>> struct device_attribute *attr,
>> char *buf)
>> {
>>+ char pbuf[BOND_OPTION_STRING_MAX_SIZE];
>> struct bonding *bond = to_bond(d);
>> int i, res = 0;
>>
>> for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
>>- if (bond->params.arp_targets[i].target_ip)
>>- res += sysfs_emit_at(buf, res, "%pI4 ",
>>- &bond->params.arp_targets[i].target_ip);
>>+ if (bond->params.arp_targets[i].target_ip) {
>>+ bond_arp_target_to_string(&bond->params.arp_targets[i],
>>+ pbuf, sizeof(pbuf));
>>+ res += sysfs_emit_at(buf, res, "%s ", pbuf);
>>+ }
>> }
>> if (res)
>> buf[res-1] = '\n'; /* eat the leftover space */
>>--
>>2.43.5
>>
>
>---
> -Jay Vosburgh, jv@jvosburgh.net
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags.
2025-07-01 7:13 ` Hangbin Liu
@ 2025-08-07 4:38 ` Hangbin Liu
2025-08-07 16:24 ` David Wilder
0 siblings, 1 reply; 18+ messages in thread
From: Hangbin Liu @ 2025-08-07 4:38 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
Hi David,
On Tue, Jul 01, 2025 at 07:13:06AM +0000, Hangbin Liu wrote:
> > From: Hangbin Liu <liuhangbin@gmail.com>
> > Sent: Monday, June 30, 2025 3:18 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 v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags.
> >
> > > On Fri, Jun 27, 2025 at 01:17:13PM -0700, David Wilder wrote:
> > > I have run into issues with the ns_ip6_target feature. I am unable to get
> > > the existing code to function with vlans. Therefor I am unable to support
> > > A this change for ns_ip6_target.
> >
> > > Any reason why this is incompatible with ns_ip6_target?
> >
> > Hi Hangbin
> >
> > I am unable to get the existing ns_ip6_target code to function when the target
> > is in a vlan. If the existing code is not working with vlans it makes no
> > sense to specify the vlan tags.
> >
> > This is what I think is happening:
> >
> > In ns_send_all() we have this bit of code:
> >
> > dst = ip6_route_output(dev_net(bond->dev), NULL, &fl6);
> > if (dst->error) {
> > dst_release(dst);
> > /* there's no route to target - try to send arp
> > * probe to generate any traffic (arp_validate=0)
> > */
> > if (bond->params.arp_validate)
> > bond_ns_send(slave, &targets[i], &in6addr_any, tags);
> > <.......>
> > continue;
> > }
> >
> > ip6_route_output() is returning an error as there is no neighbor entry for
> > the target. A ns is then sent with no vlan header. I found that the
> > multicast ns (with no vlan header) is not passed to the vlan siblings
> > with the target address so no reply is sent.
> >
> > The ipv4 code is simmiler but the arp is sent as a brodcast. The broadcast arp
> > will be propagated to the vlan sibling (in the linux vlan code).
> >
> > This could be a testing issue, I am unsure. Can you help with
> > a test case with the target in a vlan?
I looked into this recently, and you are right — ip6_route_output() returns
an error dst. The root cause is that we cannot get the destination IPv6
address through the bond interface, because the source IPv6 address is
configured on other interfaces, the VLAN sub-interface.
This is a key difference between IPv6 and IPv4:
In IPv4, it's possible to get a destination route via the bond even when the
source IP is configured on a different interface. But in IPv6, the routing
mechanism is stricter in requiring the source address to be valid on the
outgoing interface.
I'm not sure how to fix this yet, as it's fundamentally tied to how IPv6
routing behaves.
Thanks
Hangbin
>
> I can reproduce this issue. I guess it's because the IPv6 route code is
> different with IPv4. I will check this issue.
>
> Thanks
> Hangbin
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [PATCH net-next v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags.
2025-08-07 4:38 ` Hangbin Liu
@ 2025-08-07 16:24 ` David Wilder
2025-08-07 18:10 ` Jay Vosburgh
0 siblings, 1 reply; 18+ messages in thread
From: David Wilder @ 2025-08-07 16:24 UTC (permalink / raw)
To: Hangbin Liu
Cc: netdev@vger.kernel.org, jv@jvosburgh.net,
pradeeps@linux.vnet.ibm.com, Pradeep Satyanarayana,
i.maximets@ovn.org, Adrian Moreno Zapata
________________________________________
From: Hangbin Liu <liuhangbin@gmail.com>
Sent: Wednesday, August 6, 2025 9:38 PM
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
Subject: [EXTERNAL] Re: [PATCH net-next v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags.
Hi Hangbin
> Hi David,
> On Tue, Jul 01, 2025 at 07:13:06AM +0000, Hangbin Liu wrote:
> > From: Hangbin Liu <liuhangbin@gmail.com>
> > Sent: Monday, June 30, 2025 3:18 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 v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags.
> >
> > > On Fri, Jun 27, 2025 at 01:17:13PM -0700, David Wilder wrote:
> > > I have run into issues with the ns_ip6_target feature. I am unable to get
> > > the existing code to function with vlans. Therefor I am unable to support
> > > A this change for ns_ip6_target.
> >
> > > Any reason why this is incompatible with ns_ip6_target?
> >
> > Hi Hangbin
> >
> > I am unable to get the existing ns_ip6_target code to function when the target
> > is in a vlan. If the existing code is not working with vlans it makes no
> > sense to specify the vlan tags.
> >
> > This is what I think is happening:
> >
> > In ns_send_all() we have this bit of code:
> >
> > dst = ip6_route_output(dev_net(bond->dev), NULL, &fl6);
> > if (dst->error) {
> > dst_release(dst);
> > /* there's no route to target - try to send arp
> > * probe to generate any traffic (arp_validate=0)
> > */
> > if (bond->params.arp_validate)
> > bond_ns_send(slave, &targets[i], &in6addr_any, tags);
> > <.......>
> > continue;
> > }
> >
> > ip6_route_output() is returning an error as there is no neighbor entry for
> > the target. A ns is then sent with no vlan header. I found that the
> > multicast ns (with no vlan header) is not passed to the vlan siblings
> > with the target address so no reply is sent.
> >
> > The ipv4 code is simmiler but the arp is sent as a brodcast. The broadcast arp
> > will be propagated to the vlan sibling (in the linux vlan code).
> >
> > This could be a testing issue, I am unsure. Can you help with
> > a test case with the target in a vlan?
> I looked into this recently, and you are right — ip6_route_output() returns
> an error dst. The root cause is that we cannot get the destination IPv6
> address through the bond interface, because the source IPv6 address is
> configured on other interfaces, the VLAN sub-interface.
>
> This is a key difference between IPv6 and IPv4:
> In IPv4, it's possible to get a destination route via the bond even when the
> source IP is configured on a different interface. But in IPv6, the routing
> mechanism is stricter in requiring the source address to be valid on the
> outgoing interface.
>
> I'm not sure how to fix this yet, as it's fundamentally tied to how IPv6
> routing behaves.
I am thinking that we don't need to do a route lookup as if we are sending
from the bonding interface. We only need to find the interface we should
send the packet through. As if we ran "ip route get <dest addr>".
David Wilder
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags.
2025-08-07 16:24 ` David Wilder
@ 2025-08-07 18:10 ` Jay Vosburgh
2025-08-08 10:17 ` Hangbin Liu
0 siblings, 1 reply; 18+ messages in thread
From: Jay Vosburgh @ 2025-08-07 18:10 UTC (permalink / raw)
To: David Wilder
Cc: Hangbin Liu, netdev@vger.kernel.org, pradeeps@linux.vnet.ibm.com,
Pradeep Satyanarayana, i.maximets@ovn.org, Adrian Moreno Zapata
David Wilder <wilder@us.ibm.com> wrote:
>From: Hangbin Liu <liuhangbin@gmail.com>
>Sent: Wednesday, August 6, 2025 9:38 PM
>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
>Subject: [EXTERNAL] Re: [PATCH net-next v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags.
>
>Hi Hangbin
>
>> Hi David,
>> On Tue, Jul 01, 2025 at 07:13:06AM +0000, Hangbin Liu wrote:
>> > From: Hangbin Liu <liuhangbin@gmail.com>
>> > Sent: Monday, June 30, 2025 3:18 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 v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags.
>> >
>> > > On Fri, Jun 27, 2025 at 01:17:13PM -0700, David Wilder wrote:
>> > > I have run into issues with the ns_ip6_target feature. I am unable to get
>> > > the existing code to function with vlans. Therefor I am unable to support
>> > > A this change for ns_ip6_target.
>> >
>> > > Any reason why this is incompatible with ns_ip6_target?
>> >
>> > Hi Hangbin
>> >
>> > I am unable to get the existing ns_ip6_target code to function when the target
>> > is in a vlan. If the existing code is not working with vlans it makes no
>> > sense to specify the vlan tags.
>> >
>> > This is what I think is happening:
>> >
>> > In ns_send_all() we have this bit of code:
>> >
>> > dst = ip6_route_output(dev_net(bond->dev), NULL, &fl6);
>> > if (dst->error) {
>> > dst_release(dst);
>> > /* there's no route to target - try to send arp
>> > * probe to generate any traffic (arp_validate=0)
>> > */
>> > if (bond->params.arp_validate)
>> > bond_ns_send(slave, &targets[i], &in6addr_any, tags);
>> > <.......>
>> > continue;
>> > }
>> >
>> > ip6_route_output() is returning an error as there is no neighbor entry for
>> > the target. A ns is then sent with no vlan header. I found that the
>> > multicast ns (with no vlan header) is not passed to the vlan siblings
>> > with the target address so no reply is sent.
>> >
>> > The ipv4 code is simmiler but the arp is sent as a brodcast. The broadcast arp
>> > will be propagated to the vlan sibling (in the linux vlan code).
>> >
>> > This could be a testing issue, I am unsure. Can you help with
>> > a test case with the target in a vlan?
>
>> I looked into this recently, and you are right — ip6_route_output() returns
>> an error dst. The root cause is that we cannot get the destination IPv6
>> address through the bond interface, because the source IPv6 address is
>> configured on other interfaces, the VLAN sub-interface.
>>
>> This is a key difference between IPv6 and IPv4:
>> In IPv4, it's possible to get a destination route via the bond even when the
>> source IP is configured on a different interface. But in IPv6, the routing
>> mechanism is stricter in requiring the source address to be valid on the
>> outgoing interface.
>>
>> I'm not sure how to fix this yet, as it's fundamentally tied to how IPv6
>> routing behaves.
>
>I am thinking that we don't need to do a route lookup as if we are sending
>from the bonding interface. We only need to find the interface we should
>send the packet through. As if we ran "ip route get <dest addr>".
Assuming I'm following correctly, the whole point of the route
lookup is to determine which interface the ARP (or NS for IPv6) should
nominally sent through (based on the destination address). This serves
two purposes:
- collecting the VLAN tags,
- insuring that the ARP / NS won't be sent on a logically
incorrect interface (e.g., its address corresponds to some totally
unrelated interface).
So, really, I'm agreed that what we're really looking for is
"what is the proper output interface to use to send to destination X,"
which we can then check to see if that interface is logically connected
to the bond (e.g., a VLAN atop the bond).
Is the solution to call ip6_route_output() with the flowi6_oif
set to zero? That seems to be what happens for the "ip route get" case
in inet6_rtm_getroute() (he says, looking at the code but not running
actual tests).
-J
---
-Jay Vosburgh, jv@jvosburgh.net
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags.
2025-08-07 18:10 ` Jay Vosburgh
@ 2025-08-08 10:17 ` Hangbin Liu
0 siblings, 0 replies; 18+ messages in thread
From: Hangbin Liu @ 2025-08-08 10:17 UTC (permalink / raw)
To: Jay Vosburgh
Cc: David Wilder, netdev@vger.kernel.org, pradeeps@linux.vnet.ibm.com,
Pradeep Satyanarayana, i.maximets@ovn.org, Adrian Moreno Zapata
On Thu, Aug 07, 2025 at 11:10:20AM -0700, Jay Vosburgh wrote:
> >> This is a key difference between IPv6 and IPv4:
> >> In IPv4, it's possible to get a destination route via the bond even when the
> >> source IP is configured on a different interface. But in IPv6, the routing
> >> mechanism is stricter in requiring the source address to be valid on the
> >> outgoing interface.
> >>
> >> I'm not sure how to fix this yet, as it's fundamentally tied to how IPv6
> >> routing behaves.
> >
> >I am thinking that we don't need to do a route lookup as if we are sending
> >from the bonding interface. We only need to find the interface we should
> >send the packet through. As if we ran "ip route get <dest addr>".
>
> Assuming I'm following correctly, the whole point of the route
> lookup is to determine which interface the ARP (or NS for IPv6) should
> nominally sent through (based on the destination address). This serves
> two purposes:
>
> - collecting the VLAN tags,
>
> - insuring that the ARP / NS won't be sent on a logically
> incorrect interface (e.g., its address corresponds to some totally
> unrelated interface).
>
> So, really, I'm agreed that what we're really looking for is
> "what is the proper output interface to use to send to destination X,"
> which we can then check to see if that interface is logically connected
> to the bond (e.g., a VLAN atop the bond).
>
> Is the solution to call ip6_route_output() with the flowi6_oif
> set to zero? That seems to be what happens for the "ip route get" case
> in inet6_rtm_getroute() (he says, looking at the code but not running
> actual tests).
Looks reasonable to me. We can find the dst interface first and check
if it's an upper link of the bond interface.
Thanks
Hangbin
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2025-08-08 10:17 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-27 20:17 [PATCH net-next v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
2025-06-27 20:17 ` [PATCH net-next v4 1/7] bonding: Adding struct bond_arp_target David Wilder
2025-06-27 20:17 ` [PATCH net-next v4 2/7] bonding: Adding extra_len field to struct bond_opt_value David Wilder
2025-06-27 20:17 ` [PATCH net-next v4 3/7] bonding: arp_ip_target helpers David Wilder
2025-06-27 20:17 ` [PATCH net-next v4 4/7] bonding: Processing extended arp_ip_target from user space David Wilder
2025-06-27 20:17 ` [PATCH net-next v4 5/7] bonding: Update to bond_arp_send_all() to use supplied vlan tags David Wilder
2025-06-27 20:17 ` [PATCH net-next v4 6/7] bonding: Update to bond's sysfs and procfs for extended arp_ip_target format David Wilder
2025-07-02 18:32 ` Jay Vosburgh
2025-07-03 18:07 ` David Wilder
2025-06-27 20:17 ` [PATCH net-next v4 7/7] bonding: Selftest and documentation for the arp_ip_target parameter David Wilder
2025-06-28 1:03 ` [PATCH net-next v4 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags Jakub Kicinski
2025-06-30 10:18 ` Hangbin Liu
2025-06-30 16:19 ` David Wilder
2025-07-01 7:13 ` Hangbin Liu
2025-08-07 4:38 ` Hangbin Liu
2025-08-07 16:24 ` David Wilder
2025-08-07 18:10 ` Jay Vosburgh
2025-08-08 10:17 ` Hangbin Liu
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).