[RFC net-next v2 3/3] bonding: use skb_vlan_push() for probe tags

From: Xiang Mei (Microsoft)

Date: Wed Jul 29 2026 - 19:03:07 EST


bond_handle_vlan() open-coded the VLAN stacking with
vlan_insert_tag_set_proto() for the inner tags and
__vlan_hwaccel_put_tag() for the outer one. Now that the callers push
the link-layer header before tagging (arp_create() for ARP,
bond_ns_add_llhdr() for NS), the tags can be inserted with
skb_vlan_push(), which handles both the inline and the offloaded tag
and grows the headroom as needed.

Walk the tags from the innermost so each skb_vlan_push() moves the
previous tag into the frame, and free the skb on failure
(skb_vlan_push() does not). Reset the MAC header in bond_arp_send()
so skb_vlan_push() finds skb->data at the Ethernet header.

Signed-off-by: Xiang Mei (Microsoft) <xmei5@xxxxxxx>
---
drivers/net/bonding/bond_main.c | 38 ++++++++++++++-------------------
1 file changed, 16 insertions(+), 22 deletions(-)

diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index d5a7a7dd1eb2..0da57e9bb47c 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -2973,37 +2973,28 @@ static bool bond_handle_vlan(struct slave *slave, struct bond_vlan_tag *tags,
{
struct net_device *bond_dev = slave->bond->dev;
struct net_device *slave_dev = slave->dev;
- struct bond_vlan_tag *outer_tag = tags;
+ int i;

if (!tags || tags->vlan_proto == BOND_VLAN_PROTO_NONE)
return true;

- tags++;
+ for (i = 0; tags[i].vlan_proto != BOND_VLAN_PROTO_NONE; i++)
+ ;

- /* Go through all the tags backwards and add them to the packet */
- while (tags->vlan_proto != BOND_VLAN_PROTO_NONE) {
- if (!tags->vlan_id) {
- tags++;
+ /* tags[0] is the outermost tag; push inner-first so each skb_vlan_push()
+ * moves the previous tag into the frame.
+ */
+ while (i--) {
+ if (!tags[i].vlan_id)
continue;
- }

- slave_dbg(bond_dev, slave_dev, "inner tag: proto %X vid %X\n",
- ntohs(outer_tag->vlan_proto), tags->vlan_id);
- skb = vlan_insert_tag_set_proto(skb, tags->vlan_proto,
- tags->vlan_id);
- if (!skb) {
- net_err_ratelimited("failed to insert inner VLAN tag\n");
+ slave_dbg(bond_dev, slave_dev, "tag: proto %X vid %X\n",
+ ntohs(tags[i].vlan_proto), tags[i].vlan_id);
+ if (skb_vlan_push(skb, tags[i].vlan_proto, tags[i].vlan_id)) {
+ net_err_ratelimited("failed to insert VLAN tag\n");
+ kfree_skb(skb);
return false;
}
-
- tags++;
- }
- /* Set the outer tag */
- if (outer_tag->vlan_id) {
- slave_dbg(bond_dev, slave_dev, "outer tag: proto %X vid %X\n",
- ntohs(outer_tag->vlan_proto), outer_tag->vlan_id);
- __vlan_hwaccel_put_tag(skb, outer_tag->vlan_proto,
- outer_tag->vlan_id);
}

return true;
@@ -3031,6 +3022,9 @@ static void bond_arp_send(struct slave *slave, int arp_op, __be32 dest_ip,
return;
}

+ /* arp_create() has already pushed the link-layer header */
+ skb_reset_mac_header(skb);
+
if (bond_handle_vlan(slave, tags, skb)) {
slave_update_last_tx(slave);
arp_xmit(skb);
--
2.43.0