[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAFJzfF9UxBkvDkuSOG2AVd_mr3mkJ9yMa3D0s6rFvFdiMDKvPA@mail.gmail.com>
Date: Wed, 26 Nov 2025 18:39:50 -0500
From: Ian MacDonald <ian@...statz.com>
To: Mika Westerberg <mika.westerberg@...ux.intel.com>
Cc: Mika Westerberg <westeri@...nel.org>, Yehezkel Bernat <YehezkelShB@...il.com>, netdev@...r.kernel.org,
linux-kernel@...r.kernel.org, 1121032@...s.debian.org
Subject: Re: net: thunderbolt: missing ndo_set_mac_address breaks 802.3ad bonding
Hi Mika,
Following up on the previous discussion, your patch enabling MAC address
changes allowed bonding to enslave thunderbolt_net devices, but 802.3ad
still could not form an aggregator because the driver does not report
link speed or duplex via ethtool. Bonding logs:
bond0: (slave thunderbolt0): failed to get link speed/duplex
Bonding (802.3ad) requires non-zero speed/duplex values for LACP port
key calculation.
The patch below adds a minimal get_link_ksettings() implementation and
registers ethtool_ops. It reports a fixed 10Gbps full-duplex link,
which is sufficient for LACP and seems consistent with ThunderboltIP
host-to-host bandwidth with the USB4v1/TB3 hardware I am using.
With this change, 802.3ad bonding comes up correctly on my USB4/TB
host-to-host setup. I also added link mode bitmaps, though they are not
strictly required for LACP/802.3ad.
Signed-off-by: Ian MacDonald <ian@...statz.com>
---
drivers/net/thunderbolt/main.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/drivers/net/thunderbolt/main.c b/drivers/net/thunderbolt/main.c
index 4f4694db6..b9e276693 100644
--- a/drivers/net/thunderbolt/main.c
+++ b/drivers/net/thunderbolt/main.c
@@ -15,6 +15,7 @@
#include <linux/jhash.h>
#include <linux/module.h>
#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
#include <linux/rtnetlink.h>
#include <linux/sizes.h>
#include <linux/thunderbolt.h>
@@ -1257,6 +1258,28 @@ static void tbnet_get_stats64(struct net_device *dev,
stats->rx_missed_errors = net->stats.rx_missed_errors;
}
+static int tbnet_get_link_ksettings(struct net_device *dev,
+ struct ethtool_link_ksettings *cmd)
+{
+ /* ThunderboltIP is a software-only full-duplex network tunnel.
+ * We report fixed link settings to satisfy bonding (802.3ad)
+ * requirements for LACP port key calculation. Speed is set to
+ * 10Gbps as a conservative baseline.
+ */
+ ethtool_link_ksettings_zero_link_mode(cmd, supported);
+ ethtool_link_ksettings_add_link_mode(cmd, supported, 10000baseT_Full);
+
+ ethtool_link_ksettings_zero_link_mode(cmd, advertising);
+ ethtool_link_ksettings_add_link_mode(cmd, advertising, 10000baseT_Full);
+
+ cmd->base.speed = SPEED_10000;
+ cmd->base.duplex = DUPLEX_FULL;
+ cmd->base.autoneg = AUTONEG_DISABLE;
+ cmd->base.port = PORT_NONE;
+
+ return 0;
+}
+
static const struct net_device_ops tbnet_netdev_ops = {
.ndo_open = tbnet_open,
.ndo_stop = tbnet_stop,
@@ -1265,6 +1288,10 @@ static const struct net_device_ops tbnet_netdev_ops = {
.ndo_get_stats64 = tbnet_get_stats64,
};
+static const struct ethtool_ops tbnet_ethtool_ops = {
+ .get_link_ksettings = tbnet_get_link_ksettings,
+};
+
static void tbnet_generate_mac(struct net_device *dev)
{
const struct tbnet *net = netdev_priv(dev);
@@ -1315,6 +1342,7 @@ static int tbnet_probe(struct tb_service *svc,
const struct tb_service_id *id)
strcpy(dev->name, "thunderbolt%d");
dev->netdev_ops = &tbnet_netdev_ops;
+ dev->ethtool_ops = &tbnet_ethtool_ops;
/* ThunderboltIP takes advantage of TSO packets but instead of
* segmenting them we just split the packet into Thunderbolt
--
2.47.3
> On Fri, Nov 21, 2025 at 3:11 AM Mika Westerberg
> <mika.westerberg@...ux.intel.com> wrote:
> > The below allows me to change it using "ip link set" command. I wonder if
> > you could try it with the bonding case and see it that makes any
> > difference?
> >
> > diff --git a/drivers/net/thunderbolt/main.c b/drivers/net/thunderbolt/main.c
> > index dcaa62377808..57b226afeb84 100644
> > --- a/drivers/net/thunderbolt/main.c
> > +++ b/drivers/net/thunderbolt/main.c
> > @@ -1261,6 +1261,7 @@ static const struct net_device_ops tbnet_netdev_ops = {
> > .ndo_open = tbnet_open,
> > .ndo_stop = tbnet_stop,
> > .ndo_start_xmit = tbnet_start_xmit,
> > + .ndo_set_mac_address = eth_mac_addr,
> > .ndo_get_stats64 = tbnet_get_stats64,
> > };
> >
> > @@ -1281,6 +1282,9 @@ static void tbnet_generate_mac(struct net_device *dev)
> > hash = jhash2((u32 *)xd->local_uuid, 4, hash);
> > addr[5] = hash & 0xff;
> > eth_hw_addr_set(dev, addr);
> > +
> > + /* Allow changing it if needed */
> > + dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
> > }
> >
> > static int tbnet_probe(struct tb_service *svc, const struct tb_service_id *id)
Basic testing below on Debian with kernel 6.17.8 shows aggregate
speeds within the expected range.
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID][Role] Interval Transfer Bitrate Retr
[ 5][TX-C] 0.00-10.07 sec 5.58 GBytes 4.76 Gbits/sec 0
sender
[ 5][TX-C] 0.00-10.07 sec 5.58 GBytes 4.76 Gbits/sec
receiver
[ 7][TX-C] 0.00-10.07 sec 5.58 GBytes 4.76 Gbits/sec 0
sender
[ 7][TX-C] 0.00-10.07 sec 5.58 GBytes 4.76 Gbits/sec
receiver
[ 9][TX-C] 0.00-10.07 sec 5.59 GBytes 4.77 Gbits/sec 0
sender
[ 9][TX-C] 0.00-10.07 sec 5.59 GBytes 4.77 Gbits/sec
receiver
[ 11][TX-C] 0.00-10.07 sec 5.59 GBytes 4.77 Gbits/sec 0
sender
[ 11][TX-C] 0.00-10.07 sec 5.59 GBytes 4.77 Gbits/sec
receiver
[SUM][TX-C] 0.00-10.07 sec 22.3 GBytes 19.1 Gbits/sec 0
sender
[SUM][TX-C] 0.00-10.07 sec 22.3 GBytes 19.1 Gbits/sec
receiver
[ 13][RX-C] 0.00-10.07 sec 3.72 GBytes 3.18 Gbits/sec 1
sender
[ 13][RX-C] 0.00-10.07 sec 3.72 GBytes 3.17 Gbits/sec
receiver
[ 15][RX-C] 0.00-10.07 sec 11.1 GBytes 9.50 Gbits/sec 4
sender
[ 15][RX-C] 0.00-10.07 sec 11.1 GBytes 9.50 Gbits/sec
receiver
[ 17][RX-C] 0.00-10.07 sec 3.72 GBytes 3.18 Gbits/sec 1
sender
[ 17][RX-C] 0.00-10.07 sec 3.72 GBytes 3.17 Gbits/sec
receiver
[ 19][RX-C] 0.00-10.07 sec 3.73 GBytes 3.18 Gbits/sec 1
sender
[ 19][RX-C] 0.00-10.07 sec 3.73 GBytes 3.18 Gbits/sec
receiver
[SUM][RX-C] 0.00-10.07 sec 22.3 GBytes 19.0 Gbits/sec 7
sender
[SUM][RX-C] 0.00-10.07 sec 22.3 GBytes 19.0 Gbits/sec
receiver
iperf Done.
ai2:~# iperf3 --bidir -c 10.10.13.1 -P 4 -t 10
ai2:~# networkctl status bond0
● 3: bond0
NetDev File: /etc/systemd/network/50-bond0.netdev
Link File: /usr/lib/systemd/network/99-default.link
Network File: /etc/systemd/network/53-bond0.network
State: routable (configured)
Online state: online
Type: bond
Kind: bond
Driver: bonding
Hardware Address: 82:36:12:ad:a1:c0
MTU: 1500 (min: 68, max: 65535)
QDisc: noqueue
IPv6 Address Generation Mode: eui64
Mode: 802.3ad
Miimon: 500ms
Updelay: 0
Downdelay: 0
Number of Queues (Tx/Rx): 16/16
Auto negotiation: no
Speed: 20Gbps
Duplex: full
Address: 10.10.13.2
fe80::8036:12ff:fead:a1c0
Activation Policy: up
Required For Online: yes
DHCPv6 Client DUID: DUID-EN/Vendor:0000ab111c6e5c59896f0172
Nov 26 22:46:11 ai2 systemd-networkd[641]: bond0: netdev ready
Nov 26 22:46:11 ai2 systemd-networkd[641]: bond0: Configuring with
/etc/systemd/network/53-bond0.network.
Nov 26 22:46:11 ai2 systemd-networkd[641]: bond0: Link UP
Nov 26 17:46:52 ai2 systemd-networkd[641]: bond0: Gained carrier
Nov 26 17:46:53 ai2 systemd-networkd[641]: bond0: Gained IPv6LL
ai2:~# ethtool thunderbolt0
Settings for thunderbolt0:
Supported ports: [ ]
Supported link modes: 10000baseT/Full
Supported pause frame use: No
Supports auto-negotiation: No
Supported FEC modes: Not reported
Advertised link modes: 10000baseT/Full
Advertised pause frame use: No
Advertised auto-negotiation: No
Advertised FEC modes: Not reported
Speed: 10000Mb/s
Duplex: Full
Auto-negotiation: off
Port: None
PHYAD: 0
Transceiver: internal
Powered by blists - more mailing lists