From: David Wilder <wilder@us.ibm.com>
To: netdev@vger.kernel.org
Cc: jv@jvosburgh.net, wilder@us.ibm.com, pradeep@us.ibm.com,
i.maximets@ovn.org, amorenoz@redhat.com, haliu@redhat.com,
stephen@networkplumber.org, horms@kernel.org, kuba@kernel.org,
pabeni@redhat.com, andrew+netdev@lunn.ch, edumazet@google.com,
razor@blackwall.org, shuah@kernel.org, corbet@lwn.net,
linux-kselftest@vger.kernel.org, linux-doc@vger.kernel.org
Subject: [PATCH net-next v14 4/7] bonding: Processing extended arp_ip_target from user space.
Date: Wed, 22 Oct 2025 11:25:31 -0700 [thread overview]
Message-ID: <20251022182721.2567561-5-wilder@us.ibm.com> (raw)
In-Reply-To: <20251022182721.2567561-1-wilder@us.ibm.com>
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 | 132 +++++++++++++++++++++++------
2 files changed, 107 insertions(+), 30 deletions(-)
diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
index 566a11bb7f1e..15782745fa4d 100644
--- a/drivers/net/bonding/bond_netlink.c
+++ b/drivers/net/bonding/bond_netlink.c
@@ -307,9 +307,10 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
if (nla_len(attr) < sizeof(target))
return -EINVAL;
- target = nla_get_be32(attr);
+ bond_opt_initextra(&newval,
+ (__force void *)nla_data(attr),
+ nla_len(attr));
- bond_opt_initval(&newval, (__force u64)target);
err = __bond_opt_set(bond, BOND_OPT_ARP_TARGETS,
&newval,
data[IFLA_BOND_ARP_IP_TARGET],
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index 91d57ba968d6..9b930a6880b0 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -13,6 +13,7 @@
#include <linux/ctype.h>
#include <linux/inet.h>
#include <linux/sched/signal.h>
+#include <linux/if_vlan.h>
#include <net/bonding.h>
#include <net/ndisc.h>
@@ -31,8 +32,10 @@ static int bond_option_use_carrier_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_arp_interval_set(struct bonding *bond,
const struct bond_opt_value *newval);
-static int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target);
-static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target);
+static int bond_option_arp_ip_target_add(struct bonding *bond,
+ const struct bond_arp_target *target);
+static int bond_option_arp_ip_target_rem(struct bonding *bond,
+ const struct bond_arp_target *target);
static int bond_option_arp_ip_targets_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_ns_ip6_targets_set(struct bonding *bond,
@@ -1150,7 +1153,7 @@ static int bond_option_arp_interval_set(struct bonding *bond,
}
static void _bond_options_arp_ip_target_set(struct bonding *bond, int slot,
- __be32 target,
+ const struct bond_arp_target *target,
unsigned long last_rx)
{
struct bond_arp_target *targets = bond->params.arp_targets;
@@ -1160,24 +1163,26 @@ static void _bond_options_arp_ip_target_set(struct bonding *bond, int slot,
if (slot >= 0 && slot < BOND_MAX_ARP_TARGETS) {
bond_for_each_slave(bond, slave, iter)
slave->target_last_arp_rx[slot] = last_rx;
- targets[slot].target_ip = target;
+ memcpy(&targets[slot], target, sizeof(struct bond_arp_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,
+ const struct bond_arp_target *target)
{
struct bond_arp_target *targets = bond->params.arp_targets;
+ char pbuf[BOND_OPTION_STRING_MAX_SIZE];
int ind;
- if (!bond_is_ip_target_ok(target)) {
+ if (!bond_is_ip_target_ok(target->target_ip)) {
netdev_err(bond->dev, "invalid ARP target %pI4 specified for addition\n",
- &target);
+ &target->target_ip);
return -EINVAL;
}
- if (bond_get_targets_ip(targets, target) != -1) { /* dup */
+ if (bond_get_targets_ip(targets, target->target_ip) != -1) { /* dup */
netdev_err(bond->dev, "ARP target %pI4 is already present\n",
- &target);
+ &target->target_ip);
return -EINVAL;
}
@@ -1187,43 +1192,46 @@ static int _bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
return -EINVAL;
}
- netdev_dbg(bond->dev, "Adding ARP target %pI4\n", &target);
+ netdev_dbg(bond->dev, "Adding ARP target %s\n",
+ bond_arp_target_to_string(target, pbuf, sizeof(pbuf)));
_bond_options_arp_ip_target_set(bond, ind, target, jiffies);
return 0;
}
-static int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
+static int bond_option_arp_ip_target_add(struct bonding *bond,
+ const 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,
+ const struct bond_arp_target *target)
{
struct bond_arp_target *targets = bond->params.arp_targets;
+ unsigned long *targets_rx;
struct list_head *iter;
struct slave *slave;
- unsigned long *targets_rx;
int ind, i;
- if (!bond_is_ip_target_ok(target)) {
+ if (!bond_is_ip_target_ok(target->target_ip)) {
netdev_err(bond->dev, "invalid ARP target %pI4 specified for removal\n",
- &target);
+ &target->target_ip);
return -EINVAL;
}
- ind = bond_get_targets_ip(targets, target);
+ ind = bond_get_targets_ip(targets, target->target_ip);
if (ind == -1) {
netdev_err(bond->dev, "unable to remove nonexistent ARP target %pI4\n",
- &target);
+ &target->target_ip);
return -EINVAL;
}
if (ind == 0 && !targets[1].target_ip && bond->params.arp_interval)
netdev_warn(bond->dev, "Removing last arp target with arp_interval on\n");
- netdev_dbg(bond->dev, "Removing ARP target %pI4\n", &target);
+ netdev_dbg(bond->dev, "Removing ARP target %pI4\n", &target->target_ip);
bond_for_each_slave(bond, slave, iter) {
targets_rx = slave->target_last_arp_rx;
@@ -1231,42 +1239,110 @@ static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target)
targets_rx[i] = targets_rx[i+1];
targets_rx[i] = 0;
}
- for (i = ind; (i < BOND_MAX_ARP_TARGETS - 1) && targets[i + 1].target_ip; i++)
- targets[i] = targets[i+1];
+
+ bond_free_vlan_tag(&targets[ind]);
+
+ for (i = ind; (i < BOND_MAX_ARP_TARGETS - 1) && targets[i + 1].target_ip; i++) {
+ targets[i].target_ip = targets[i + 1].target_ip;
+ targets[i].tags = targets[i + 1].tags;
+ targets[i].flags = targets[i + 1].flags;
+ }
targets[i].target_ip = 0;
+ targets[i].flags = 0;
+ targets[i].tags = NULL;
return 0;
}
void bond_option_arp_ip_targets_clear(struct bonding *bond)
{
+ struct bond_arp_target empty_target = {};
int i;
for (i = 0; i < BOND_MAX_ARP_TARGETS; i++)
- _bond_options_arp_ip_target_set(bond, i, 0, 0);
+ _bond_options_arp_ip_target_set(bond, i, &empty_target, 0);
+}
+
+/**
+ * bond_validate_tags - validate an array of bond_vlan_tag.
+ * @tags: the array to validate
+ * @len: the length in bytes of @tags
+ *
+ * Validate that @tags points to a valid array of struct bond_vlan_tag.
+ * Returns: the length of the validated bytes in the array or -1 if no
+ * valid list is found.
+ */
+static int bond_validate_tags(struct bond_vlan_tag *tags, size_t len)
+{
+ size_t i, ntags = 0;
+
+ if (len == 0 || !tags)
+ return 0;
+
+ if (len % sizeof(struct bond_vlan_tag) != 0)
+ return -1;
+
+ for (i = 0; i <= len; i = i + sizeof(struct bond_vlan_tag)) {
+ if (ntags > BOND_MAX_VLAN_TAGS)
+ break;
+
+ if (tags->vlan_proto == BOND_VLAN_PROTO_NONE)
+ return i + sizeof(struct bond_vlan_tag);
+
+ if (!tags->vlan_id || tags->vlan_id >= VLAN_VID_MASK)
+ break;
+ tags++;
+ ntags++;
+ }
+ return -1;
}
static int bond_option_arp_ip_targets_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
- int ret = -EPERM;
- __be32 target;
+ size_t len = (size_t)newval->extra_len;
+ char *extra = (char *)newval->extra;
+ struct bond_arp_target target = {};
+ int size, ret = -EPERM;
if (newval->string) {
+ /* Adding or removing arp_ip_target from sysfs */
if (strlen(newval->string) < 1 ||
- !in4_pton(newval->string + 1, -1, (u8 *)&target, -1, NULL)) {
+ !in4_pton(newval->string + 1, -1, (u8 *)&target.target_ip,
+ -1, NULL)) {
netdev_err(bond->dev, "invalid ARP target specified\n");
return ret;
}
if (newval->string[0] == '+')
- ret = bond_option_arp_ip_target_add(bond, target);
+ ret = bond_option_arp_ip_target_add(bond, &target);
else if (newval->string[0] == '-')
- ret = bond_option_arp_ip_target_rem(bond, target);
+ ret = bond_option_arp_ip_target_rem(bond, &target);
else
netdev_err(bond->dev, "no command found in arp_ip_targets file - use +<addr> or -<addr>\n");
} else {
- target = newval->value;
- ret = bond_option_arp_ip_target_add(bond, target);
+ /* Adding arp_ip_target from netlink. aka: ip command */
+ memcpy(&target.target_ip, newval->extra, sizeof(__be32));
+ len = len - sizeof(target.target_ip);
+ extra = extra + sizeof(target.target_ip);
+
+ size = bond_validate_tags((struct bond_vlan_tag *)extra, len);
+
+ if (size > 0) {
+ target.tags = kmalloc((size_t)size, GFP_ATOMIC);
+ if (!target.tags)
+ return -ENOMEM;
+ memcpy(target.tags, extra, size);
+ target.flags |= BOND_TARGET_USERTAGS;
+ } else if (size == -1) {
+ netdev_err(bond->dev, "Invalid list of vlans provided with %pI4\n",
+ &target.target_ip);
+ return -EINVAL;
+ }
+
+ ret = bond_option_arp_ip_target_add(bond, &target);
+
+ if (ret)
+ kfree(target.tags);
}
return ret;
--
2.50.1
next prev parent reply other threads:[~2025-10-22 18:28 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-10-22 18:25 [PATCH net-next v14 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags David Wilder
2025-10-22 18:25 ` [PATCH net-next v14 1/7] bonding: Adding struct bond_arp_target David Wilder
2025-10-22 18:25 ` [PATCH net-next v14 2/7] bonding: Adding extra_len field to struct bond_opt_value David Wilder
2025-10-22 18:25 ` [PATCH net-next v14 3/7] bonding: arp_ip_target helpers David Wilder
2025-10-22 18:25 ` David Wilder [this message]
2025-10-22 18:25 ` [PATCH net-next v14 5/7] bonding: Update to bond_arp_send_all() to use supplied vlan tags David Wilder
2025-10-22 18:25 ` [PATCH net-next v14 6/7] bonding: Update for extended arp_ip_target format David Wilder
2025-10-22 18:25 ` [PATCH net-next v14 7/7] bonding: Selftest and documentation for the arp_ip_target parameter David Wilder
2025-10-23 0:50 ` [PATCH net-next v14 0/7] bonding: Extend arp_ip_target format to allow for a list of vlan tags Jakub Kicinski
2025-10-25 3:44 ` Jay Vosburgh
2025-11-12 6:44 ` Hangbin Liu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251022182721.2567561-5-wilder@us.ibm.com \
--to=wilder@us.ibm.com \
--cc=amorenoz@redhat.com \
--cc=andrew+netdev@lunn.ch \
--cc=corbet@lwn.net \
--cc=edumazet@google.com \
--cc=haliu@redhat.com \
--cc=horms@kernel.org \
--cc=i.maximets@ovn.org \
--cc=jv@jvosburgh.net \
--cc=kuba@kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=pradeep@us.ibm.com \
--cc=razor@blackwall.org \
--cc=shuah@kernel.org \
--cc=stephen@networkplumber.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox