From: "Łukasz Majewski" <lukma@nabladev.com>
To: "Luka Gejak" <luka.gejak@linux.dev>
Cc: "Fernando Fernandez Mancera" <fmancera@suse.de>,
"Fernando Fernandez Mancera" <ffmancera@riseup.net>,
<netdev@vger.kernel.org>, <edumazet@google.com>,
<pabeni@redhat.com>, <shannon.nelson@amd.com>, <horms@kernel.org>,
<kuba@kernel.org>
Subject: Re: [PATCH v3 net-next] net: hsr: sync hw addr of slave2 according to slave1 hw addr on PRP
Date: Mon, 30 Mar 2026 10:28:12 +0200 [thread overview]
Message-ID: <20260330102812.214f27f4@wsk> (raw)
In-Reply-To: <DHFG26KI6L23.1YCOVQ5SSYMO5@linux.dev>
Hi Luka,
> On Sun Mar 29, 2026 at 7:22 PM CEST, Fernando Fernandez Mancera wrote:
> > On 3/29/26 6:58 PM, Fernando Fernandez Mancera wrote:
> >> On 3/29/26 5:07 PM, Luka Gejak wrote:
> >>> On Wed Apr 9, 2025 at 12:19 PM CEST, Fernando Fernandez Mancera
> >>> wrote:
> >>>> In order to work properly PRP requires slave1 and slave2 to
> >>>> share the same MAC address. To ease the configuration process on
> >>>> userspace tools, sync the slave2 MAC address with slave1. In
> >>>> addition, when deleting the port from the list, restore the
> >>>> original MAC address.
> >>>>
> >>>> Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
> >>>> ---
> >>>> v3: restore the original MAC address on slave removal.
> >>>> ---
> >>>> net/hsr/hsr_device.c | 5 +++++
> >>>> net/hsr/hsr_main.c | 9 +++++++++
> >>>> net/hsr/hsr_main.h | 1 +
> >>>> net/hsr/hsr_slave.c | 2 ++
> >>>> 4 files changed, 17 insertions(+)
> >>>>
> >>>> diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
> >>>> index 439cfb7ad5d1..e8922e8d9398 100644
> >>>> --- a/net/hsr/hsr_device.c
> >>>> +++ b/net/hsr/hsr_device.c
> >>>> @@ -761,6 +761,11 @@ int hsr_dev_finalize(struct net_device
> >>>> *hsr_dev, struct net_device *slave[2],
> >>>> if (res)
> >>>> goto err_unregister;
> >>>> + if (protocol_version == PRP_V1) {
> >>>> + eth_hw_addr_set(slave[1], slave[0]->dev_addr);
> >>>> + call_netdevice_notifiers(NETDEV_CHANGEADDR, slave[1]);
> >>>> + }
> >>>> +
> >>>> if (interlink) {
> >>>> res = hsr_add_port(hsr, interlink, HSR_PT_INTERLINK,
> >>>> extack); if (res)
> >>>> diff --git a/net/hsr/hsr_main.c b/net/hsr/hsr_main.c
> >>>> index d7ae32473c41..192893c3f2ec 100644
> >>>> --- a/net/hsr/hsr_main.c
> >>>> +++ b/net/hsr/hsr_main.c
> >>>> @@ -78,6 +78,15 @@ static int hsr_netdev_notify(struct
> >>>> notifier_block *nb, unsigned long event,
> >>>> eth_hw_addr_set(master->dev, dev->dev_addr);
> >>>> call_netdevice_notifiers(NETDEV_CHANGEADDR,
> >>>> master->dev);
> >>>> +
> >>>> + if (hsr->prot_version == PRP_V1) {
> >>>> + port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B);
> >>>> + if (port) {
> >>>> + eth_hw_addr_set(port->dev, dev->dev_addr);
> >>>> + call_netdevice_notifiers(NETDEV_CHANGEADDR,
> >>>> + port->dev);
> >>>> + }
> >>>> + }
> >>>> }
> >>>> /* Make sure we recognize frames from ourselves in
> >>>> hsr_rcv() */
> >>>> diff --git a/net/hsr/hsr_main.h b/net/hsr/hsr_main.h
> >>>> index 1bc47b17a296..135ec5fce019 100644
> >>>> --- a/net/hsr/hsr_main.h
> >>>> +++ b/net/hsr/hsr_main.h
> >>>> @@ -155,6 +155,7 @@ struct hsr_port {
> >>>> struct hsr_priv *hsr;
> >>>> enum hsr_port_type type;
> >>>> struct rcu_head rcu;
> >>>> + unsigned char original_macaddress[ETH_ALEN];
> >>>> };
> >>>> struct hsr_frame_info;
> >>>> diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c
> >>>> index 2a802a5de2ac..b87b6a6fe070 100644
> >>>> --- a/net/hsr/hsr_slave.c
> >>>> +++ b/net/hsr/hsr_slave.c
> >>>> @@ -196,6 +196,7 @@ int hsr_add_port(struct hsr_priv *hsr,
> >>>> struct net_device *dev,
> >>>> port->hsr = hsr;
> >>>> port->dev = dev;
> >>>> port->type = type;
> >>>> + ether_addr_copy(port->original_macaddress, dev->dev_addr);
> >>>> if (type != HSR_PT_MASTER) {
> >>>> res = hsr_portdev_setup(hsr, dev, port, extack);
> >>>> @@ -232,6 +233,7 @@ void hsr_del_port(struct hsr_port *port)
> >>>> if (!port->hsr->fwd_offloaded)
> >>>> dev_set_promiscuity(port->dev, -1);
> >>>> netdev_upper_dev_unlink(port->dev, master->dev);
> >>>> + eth_hw_addr_set(port->dev, port->original_macaddress);
> >>>> }
> >>>> kfree_rcu(port, rcu);
> >>>
> >>> Hi Fernando,
> >>>
> >>> Thanks for the patch. The logic to sync the slave2 MAC address
> >>> with slave1 for PRP is sound, but there are a few implementation
> >>> issues here that will cause hardware filtering problems and style
> >>> violations.
> >>>
> >>> 1. Hardware MAC Filtering
> >>> In your current implementation:
> >>>
> >>> if (protocol_version == PRP_V1) {
> >>>
> >>> eth_hw_addr_set(slave[1], slave[0]->dev_addr);
> >>>
> >>> call_netdevice_notifiers(NETDEV_CHANGEADDR, slave[1]);
> >>>
> >>> }
> >>>
> >>> eth_hw_addr_set() is appropriate for virtual devices (like the
> >>> hsr_dev itself), but slave[1] is a physical net_device. By using
> >>> this helper, you are bypassing
> >>> dev->netdev_ops->ndo_set_mac_address. This means the physical
> >>> NIC's hardware MAC filter will not be programmed, and it will
> >>> silently drop unicast traffic destined for the new PRP MAC
> >>> address unless the interface happens to be in promiscuous mode.
> >>> You should use dev_set_mac_address() here instead. Note that
> >>> unlike eth_hw_addr_set(), dev_set_mac_address() can fail and
> >>> returns an error code, so you will need to check its return value
> >>> and handle the error path accordingly.
> >>>
> >>> 2. Teardown Notifiers
> >>> In hsr_del_port():
> >>>
> >>> netdev_upper_dev_unlink(port->dev, master->dev);
> >>> eth_hw_addr_set(port->dev, port->original_macaddress);
> >>>
> >>> You have the same issue with eth_hw_addr_set() here. Additionally,
> >>> unlike the setup paths, this version omits
> >>> call_netdevice_notifiers (NETDEV_CHANGEADDR, port->dev).
> >>> Switching to dev_set_mac_address() for the restoration will
> >>> handle both the hardware programming and the notifier chain
> >>> automatically.
> >>
> >> These points makes sense. I guess I didn't notice the that
> >> eth_hw_addr_set() due to my interface being set to promiscuous
> >> mode at hsr_slave.c.
> >>
> >> Let me research a bit more about the impact here and will get back
> >> to you either with a new patch or an reply here.
> >>
> >
> > Does this actually makes sense? I am not an expert on how hardware
> > is handling offloading here. But if I am not wrong, as the
> > interface is set on promiscuous or offload enabled. For promiscuous
> > this does not matter and for the offloaded scenario shouldn't the
> > decision be handled by hardware and not depend on
> > ndo_set_mac_address()?
> >
> > Let me know if I am missing something here.
> >
> >
> > Anyway, the missing notification makes sense and should be fixed
> > for SLAVE_B.
> >
> > Thanks,
> > Fernando.
>
> Hi Fernando,
> You raise a fair point, and I should have looked more carefully at
> the existing code paths.
>
> You are correct that in the non-offloaded case, hsr_slave.c already
> sets promiscuous mode via dev_set_promiscuity(dev, 1), so the
> hardware MAC filter is bypassed and eth_hw_addr_set() is sufficient
> for frame reception.
>
> For the offloaded case, the comment in hsr_portdev_setup() notes that
> "L2 frame forward happens at the offloaded hardware" — so the
> hardware is configured through its own HSR/PRP offload mechanisms,
> not through ndo_set_mac_address().
>
> So the practical impact of my original concern is limited to edge
> cases where promiscuous mode might be disabled or fail. The more
> important issue, which you've already acknowledged, is the missing
> notifier in hsr_del_port(). That should definitely be fixed for
> correctness.
>
> One additional consideration: even though promiscuous mode handles
> the receive path, dev->dev_addr is still used as the source MAC for
> outgoing frames. Using dev_set_mac_address() would ensure the
> software state (dev->dev_addr) and any driver-level state remain
> consistent. But I agree this is less critical than I initially
> suggested. Thanks for pushing back on this — it's a good
> clarification.
>
Thanks for your patches - as denx.de is not operational anymore (now I
do work for nabladev.com) I've just stumbled upon your patches.
I'm very happy that PRP now also gains support :-)
> Best regards,
> Luka
--
Best regards,
Lukasz Majewski
--
Nabla Software Engineering GmbH
HRB 40522 Augsburg
Phone: +49 821 45592596
E-Mail: office@nabladev.com
Managing Director : Stefano Babic
prev parent reply other threads:[~2026-03-30 8:28 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-09 10:19 [PATCH v3 net-next] net: hsr: sync hw addr of slave2 according to slave1 hw addr on PRP Fernando Fernandez Mancera
2025-04-14 11:51 ` patchwork-bot+netdevbpf
2026-03-29 15:07 ` Luka Gejak
2026-03-29 16:58 ` Fernando Fernandez Mancera
2026-03-29 17:19 ` Luka Gejak
2026-03-29 17:22 ` Fernando Fernandez Mancera
2026-03-29 17:32 ` Luka Gejak
2026-03-29 17:46 ` Fernando Fernandez Mancera
2026-03-30 8:28 ` Łukasz Majewski [this message]
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=20260330102812.214f27f4@wsk \
--to=lukma@nabladev.com \
--cc=edumazet@google.com \
--cc=ffmancera@riseup.net \
--cc=fmancera@suse.de \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=luka.gejak@linux.dev \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=shannon.nelson@amd.com \
/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