diff mbox series

[net] net: hsr: remove seqnr_lock

Message ID 20240904133725.1073963-1-edumazet@google.com (mailing list archive)
State Accepted
Commit b3c9e65eb227269ed72a115ba22f4f51b4e62b4d
Delegated to: Netdev Maintainers
Headers show
Series [net] net: hsr: remove seqnr_lock | expand

Checks

Context Check Description
netdev/series_format success Single patches do not need cover letters
netdev/tree_selection success Clearly marked for net
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag present in non-next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 16 this patch: 16
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers warning 2 maintainers not CCed: lukma@denx.de horms@kernel.org
netdev/build_clang success Errors and warnings before: 16 this patch: 16
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success Fixes tag looks correct
netdev/build_allmodconfig_warn success Errors and warnings before: 16 this patch: 16
netdev/checkpatch warning WARNING: line length of 84 exceeds 80 columns WARNING: line length of 87 exceeds 80 columns WARNING: line length of 88 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
netdev/contest success net-next-2024-09-07--06-00 (tests: 722)

Commit Message

Eric Dumazet Sept. 4, 2024, 1:37 p.m. UTC
syzbot found a new splat [1].

Instead of adding yet another spin_lock_bh(&hsr->seqnr_lock) /
spin_unlock_bh(&hsr->seqnr_lock) pair, remove seqnr_lock
and use atomic_t for hsr->sequence_nr and hsr->sup_sequence_nr.

This also avoid a race in hsr_fill_info().

Also remove interlink_sequence_nr which is unused.

[1]
 WARNING: CPU: 1 PID: 9723 at net/hsr/hsr_forward.c:602 handle_std_frame+0x247/0x2c0 net/hsr/hsr_forward.c:602
Modules linked in:
CPU: 1 UID: 0 PID: 9723 Comm: syz.0.1657 Not tainted 6.11.0-rc6-syzkaller-00026-g88fac17500f4 #0
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
 RIP: 0010:handle_std_frame+0x247/0x2c0 net/hsr/hsr_forward.c:602
Code: 49 8d bd b0 01 00 00 be ff ff ff ff e8 e2 58 25 00 31 ff 89 c5 89 c6 e8 47 53 a8 f6 85 ed 0f 85 5a ff ff ff e8 fa 50 a8 f6 90 <0f> 0b 90 e9 4c ff ff ff e8 cc e7 06 f7 e9 8f fe ff ff e8 52 e8 06
RSP: 0018:ffffc90000598598 EFLAGS: 00010246
RAX: 0000000000000000 RBX: ffffc90000598670 RCX: ffffffff8ae2c919
RDX: ffff888024e94880 RSI: ffffffff8ae2c926 RDI: 0000000000000005
RBP: 0000000000000000 R08: 0000000000000005 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000003
R13: ffff8880627a8cc0 R14: 0000000000000000 R15: ffff888012b03c3a
FS:  0000000000000000(0000) GS:ffff88802b700000(0063) knlGS:00000000f5696b40
CS:  0010 DS: 002b ES: 002b CR0: 0000000080050033
CR2: 0000000020010000 CR3: 00000000768b4000 CR4: 0000000000350ef0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Call Trace:
 <IRQ>
  hsr_fill_frame_info+0x2c8/0x360 net/hsr/hsr_forward.c:630
  fill_frame_info net/hsr/hsr_forward.c:700 [inline]
  hsr_forward_skb+0x7df/0x25c0 net/hsr/hsr_forward.c:715
  hsr_handle_frame+0x603/0x850 net/hsr/hsr_slave.c:70
  __netif_receive_skb_core.constprop.0+0xa3d/0x4330 net/core/dev.c:5555
  __netif_receive_skb_list_core+0x357/0x950 net/core/dev.c:5737
  __netif_receive_skb_list net/core/dev.c:5804 [inline]
  netif_receive_skb_list_internal+0x753/0xda0 net/core/dev.c:5896
  gro_normal_list include/net/gro.h:515 [inline]
  gro_normal_list include/net/gro.h:511 [inline]
  napi_complete_done+0x23f/0x9a0 net/core/dev.c:6247
  gro_cell_poll+0x162/0x210 net/core/gro_cells.c:66
  __napi_poll.constprop.0+0xb7/0x550 net/core/dev.c:6772
  napi_poll net/core/dev.c:6841 [inline]
  net_rx_action+0xa92/0x1010 net/core/dev.c:6963
  handle_softirqs+0x216/0x8f0 kernel/softirq.c:554
  do_softirq kernel/softirq.c:455 [inline]
  do_softirq+0xb2/0xf0 kernel/softirq.c:442
 </IRQ>
 <TASK>

Fixes: 06afd2c31d33 ("hsr: Synchronize sending frames to have always incremented outgoing seq nr.")
Fixes: f421436a591d ("net/hsr: Add support for the High-availability Seamless Redundancy protocol (HSRv0)")
Reported-by: syzbot <syzkaller@googlegroups.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
 net/hsr/hsr_device.c  | 35 ++++++++++-------------------------
 net/hsr/hsr_forward.c |  4 +---
 net/hsr/hsr_main.h    |  6 ++----
 net/hsr/hsr_netlink.c |  2 +-
 4 files changed, 14 insertions(+), 33 deletions(-)

Comments

Simon Horman Sept. 5, 2024, 10:54 a.m. UTC | #1
On Wed, Sep 04, 2024 at 01:37:25PM +0000, Eric Dumazet wrote:
> syzbot found a new splat [1].
> 
> Instead of adding yet another spin_lock_bh(&hsr->seqnr_lock) /
> spin_unlock_bh(&hsr->seqnr_lock) pair, remove seqnr_lock
> and use atomic_t for hsr->sequence_nr and hsr->sup_sequence_nr.
> 
> This also avoid a race in hsr_fill_info().
> 
> Also remove interlink_sequence_nr which is unused.
> 
> [1]
>  WARNING: CPU: 1 PID: 9723 at net/hsr/hsr_forward.c:602 handle_std_frame+0x247/0x2c0 net/hsr/hsr_forward.c:602
> Modules linked in:
> CPU: 1 UID: 0 PID: 9723 Comm: syz.0.1657 Not tainted 6.11.0-rc6-syzkaller-00026-g88fac17500f4 #0
> Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
>  RIP: 0010:handle_std_frame+0x247/0x2c0 net/hsr/hsr_forward.c:602
> Code: 49 8d bd b0 01 00 00 be ff ff ff ff e8 e2 58 25 00 31 ff 89 c5 89 c6 e8 47 53 a8 f6 85 ed 0f 85 5a ff ff ff e8 fa 50 a8 f6 90 <0f> 0b 90 e9 4c ff ff ff e8 cc e7 06 f7 e9 8f fe ff ff e8 52 e8 06
> RSP: 0018:ffffc90000598598 EFLAGS: 00010246
> RAX: 0000000000000000 RBX: ffffc90000598670 RCX: ffffffff8ae2c919
> RDX: ffff888024e94880 RSI: ffffffff8ae2c926 RDI: 0000000000000005
> RBP: 0000000000000000 R08: 0000000000000005 R09: 0000000000000000
> R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000003
> R13: ffff8880627a8cc0 R14: 0000000000000000 R15: ffff888012b03c3a
> FS:  0000000000000000(0000) GS:ffff88802b700000(0063) knlGS:00000000f5696b40
> CS:  0010 DS: 002b ES: 002b CR0: 0000000080050033
> CR2: 0000000020010000 CR3: 00000000768b4000 CR4: 0000000000350ef0
> DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
> Call Trace:
>  <IRQ>
>   hsr_fill_frame_info+0x2c8/0x360 net/hsr/hsr_forward.c:630
>   fill_frame_info net/hsr/hsr_forward.c:700 [inline]
>   hsr_forward_skb+0x7df/0x25c0 net/hsr/hsr_forward.c:715
>   hsr_handle_frame+0x603/0x850 net/hsr/hsr_slave.c:70
>   __netif_receive_skb_core.constprop.0+0xa3d/0x4330 net/core/dev.c:5555
>   __netif_receive_skb_list_core+0x357/0x950 net/core/dev.c:5737
>   __netif_receive_skb_list net/core/dev.c:5804 [inline]
>   netif_receive_skb_list_internal+0x753/0xda0 net/core/dev.c:5896
>   gro_normal_list include/net/gro.h:515 [inline]
>   gro_normal_list include/net/gro.h:511 [inline]
>   napi_complete_done+0x23f/0x9a0 net/core/dev.c:6247
>   gro_cell_poll+0x162/0x210 net/core/gro_cells.c:66
>   __napi_poll.constprop.0+0xb7/0x550 net/core/dev.c:6772
>   napi_poll net/core/dev.c:6841 [inline]
>   net_rx_action+0xa92/0x1010 net/core/dev.c:6963
>   handle_softirqs+0x216/0x8f0 kernel/softirq.c:554
>   do_softirq kernel/softirq.c:455 [inline]
>   do_softirq+0xb2/0xf0 kernel/softirq.c:442
>  </IRQ>
>  <TASK>
> 
> Fixes: 06afd2c31d33 ("hsr: Synchronize sending frames to have always incremented outgoing seq nr.")
> Fixes: f421436a591d ("net/hsr: Add support for the High-availability Seamless Redundancy protocol (HSRv0)")
> Reported-by: syzbot <syzkaller@googlegroups.com>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
> Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

Thanks Eric,

I see that;

1) The stack trace above is for a call path where
   hsr_forward_skb(), and in turn handle_std_frame(),
   is called without hsr->seqnr_lock held, which explains the splat.

2) Access to hsr->sequence_nr in hsr_fill_info() is not synchronised
   with other accesses to it.

3) hsr->interlink_sequence_nr is set but otherwise unknown

And that this patch addresses all of the above.

Reviewed-by: Simon Horman <horms@kernel.org>
Sebastian Andrzej Siewior Sept. 5, 2024, 12:17 p.m. UTC | #2
On 2024-09-04 13:37:25 [+0000], Eric Dumazet wrote:
> syzbot found a new splat [1].
> 
> Instead of adding yet another spin_lock_bh(&hsr->seqnr_lock) /
> spin_unlock_bh(&hsr->seqnr_lock) pair, remove seqnr_lock
> and use atomic_t for hsr->sequence_nr and hsr->sup_sequence_nr.
> 
> This also avoid a race in hsr_fill_info().

You obtain to sequence nr without locking so two CPUs could submit skbs
at the same time. Wouldn't this allow the race I described in commit
   06afd2c31d338 ("hsr: Synchronize sending frames to have always incremented outgoing seq nr.")

to happen again? Then one skb would be dropped while sending because it
has lower sequence nr but in fact it was not yet sent.

Sebastian
Eric Dumazet Sept. 5, 2024, 12:26 p.m. UTC | #3
On Thu, Sep 5, 2024 at 2:17 PM Sebastian Andrzej Siewior
<bigeasy@linutronix.de> wrote:
>
> On 2024-09-04 13:37:25 [+0000], Eric Dumazet wrote:
> > syzbot found a new splat [1].
> >
> > Instead of adding yet another spin_lock_bh(&hsr->seqnr_lock) /
> > spin_unlock_bh(&hsr->seqnr_lock) pair, remove seqnr_lock
> > and use atomic_t for hsr->sequence_nr and hsr->sup_sequence_nr.
> >
> > This also avoid a race in hsr_fill_info().
>
> You obtain to sequence nr without locking so two CPUs could submit skbs
> at the same time. Wouldn't this allow the race I described in commit
>    06afd2c31d338 ("hsr: Synchronize sending frames to have always incremented outgoing seq nr.")
>
> to happen again? Then one skb would be dropped while sending because it
> has lower sequence nr but in fact it was not yet sent.
>

A network protocol unable to cope with reorders can not live really.

If this is an issue, this should be fixed at the receiving side.
Sebastian Andrzej Siewior Sept. 5, 2024, 1:18 p.m. UTC | #4
On 2024-09-05 14:26:30 [+0200], Eric Dumazet wrote:
> On Thu, Sep 5, 2024 at 2:17 PM Sebastian Andrzej Siewior
> <bigeasy@linutronix.de> wrote:
> >
> > On 2024-09-04 13:37:25 [+0000], Eric Dumazet wrote:
> > > syzbot found a new splat [1].
> > >
> > > Instead of adding yet another spin_lock_bh(&hsr->seqnr_lock) /
> > > spin_unlock_bh(&hsr->seqnr_lock) pair, remove seqnr_lock
> > > and use atomic_t for hsr->sequence_nr and hsr->sup_sequence_nr.
> > >
> > > This also avoid a race in hsr_fill_info().
> >
> > You obtain to sequence nr without locking so two CPUs could submit skbs
> > at the same time. Wouldn't this allow the race I described in commit
> >    06afd2c31d338 ("hsr: Synchronize sending frames to have always incremented outgoing seq nr.")
> >
> > to happen again? Then one skb would be dropped while sending because it
> > has lower sequence nr but in fact it was not yet sent.
> >
> 
> A network protocol unable to cope with reorders can not live really.
> 
> If this is an issue, this should be fixed at the receiving side.

The standard/ network protocol just says there has to be seq nr to avoid
processing a packet multiple times. The Linux implementation increments
the counter and assumes everything lower than the current counter has
already been seen. Therefore the sequence lock is held during the entire
sending process.
This is not a protocol but implementation issue ;)
I am aware of a FPGA implementation of HSR which tracks the last 20
sequence numbers instead. This would help because it would allow
reorders to happen.

Looking at it, the code chain never held the lock while I was playing
with it and I did not see this. So this might be just a consequence of
using gro here. I don't remember disabling it so it must have been of by
default or syzbot found a way to enable it (or has better hardware).

Would it make sense to disable this for HSR interfaces?

Sebastian
Eric Dumazet Sept. 5, 2024, 1:26 p.m. UTC | #5
On Thu, Sep 5, 2024 at 3:18 PM Sebastian Andrzej Siewior
<bigeasy@linutronix.de> wrote:
>
> On 2024-09-05 14:26:30 [+0200], Eric Dumazet wrote:
> > On Thu, Sep 5, 2024 at 2:17 PM Sebastian Andrzej Siewior
> > <bigeasy@linutronix.de> wrote:
> > >
> > > On 2024-09-04 13:37:25 [+0000], Eric Dumazet wrote:
> > > > syzbot found a new splat [1].
> > > >
> > > > Instead of adding yet another spin_lock_bh(&hsr->seqnr_lock) /
> > > > spin_unlock_bh(&hsr->seqnr_lock) pair, remove seqnr_lock
> > > > and use atomic_t for hsr->sequence_nr and hsr->sup_sequence_nr.
> > > >
> > > > This also avoid a race in hsr_fill_info().
> > >
> > > You obtain to sequence nr without locking so two CPUs could submit skbs
> > > at the same time. Wouldn't this allow the race I described in commit
> > >    06afd2c31d338 ("hsr: Synchronize sending frames to have always incremented outgoing seq nr.")
> > >
> > > to happen again? Then one skb would be dropped while sending because it
> > > has lower sequence nr but in fact it was not yet sent.
> > >
> >
> > A network protocol unable to cope with reorders can not live really.
> >
> > If this is an issue, this should be fixed at the receiving side.
>
> The standard/ network protocol just says there has to be seq nr to avoid
> processing a packet multiple times. The Linux implementation increments
> the counter and assumes everything lower than the current counter has
> already been seen. Therefore the sequence lock is held during the entire
> sending process.
> This is not a protocol but implementation issue ;)

These packets are sent on a physical network, reorders are inevitable.

> I am aware of a FPGA implementation of HSR which tracks the last 20
> sequence numbers instead. This would help because it would allow
> reorders to happen.
>
> Looking at it, the code chain never held the lock while I was playing
> with it and I did not see this. So this might be just a consequence of
> using gro here. I don't remember disabling it so it must have been of by
> default or syzbot found a way to enable it (or has better hardware).
>
> Would it make sense to disable this for HSR interfaces?

This has nothing to do with GRO.

Look at this alternative patch, perhaps you will see the problem ?

diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c
index af6cf64a00e081c777db5f7786e8a27ea6f62e14..3971dbc0644ab8d32c04c262dbba7b1c950ebea9
100644
--- a/net/hsr/hsr_slave.c
+++ b/net/hsr/hsr_slave.c
@@ -67,7 +67,9 @@ static rx_handler_result_t hsr_handle_frame(struct
sk_buff **pskb)
                skb_set_network_header(skb, ETH_HLEN + HSR_HLEN);
        skb_reset_mac_len(skb);

+       spin_lock_bh(&hsr->seqnr_lock);
        hsr_forward_skb(skb, port);
+       spin_unlock_bh(&hsr->seqnr_lock);

 finish_consume:
        return RX_HANDLER_CONSUMED;


I am surprised we even have a discussion considering HSR has Orphan
status in MAINTAINERS...

I do not know how to test HSR, I am not sure the alternative patch is correct.

Removing the seqnr_lock seems the safest to me.
Sebastian Andrzej Siewior Sept. 5, 2024, 1:40 p.m. UTC | #6
On 2024-09-05 15:26:27 [+0200], Eric Dumazet wrote:
> diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c
> index af6cf64a00e081c777db5f7786e8a27ea6f62e14..3971dbc0644ab8d32c04c262dbba7b1c950ebea9
> 100644
> --- a/net/hsr/hsr_slave.c
> +++ b/net/hsr/hsr_slave.c
> @@ -67,7 +67,9 @@ static rx_handler_result_t hsr_handle_frame(struct
> sk_buff **pskb)
>                 skb_set_network_header(skb, ETH_HLEN + HSR_HLEN);
>         skb_reset_mac_len(skb);
> 
> +       spin_lock_bh(&hsr->seqnr_lock);
>         hsr_forward_skb(skb, port);
> +       spin_unlock_bh(&hsr->seqnr_lock);
> 
>  finish_consume:
>         return RX_HANDLER_CONSUMED;
> 
> 
> I am surprised we even have a discussion considering HSR has Orphan
> status in MAINTAINERS...
> 
> I do not know how to test HSR, I am not sure the alternative patch is correct.

I did submit something to tests somewhere. I will try to test this and
let you know.

> Removing the seqnr_lock seems the safest to me.
Consider this as ack if you don't hear back from me.

Sebastian
Sebastian Andrzej Siewior Sept. 5, 2024, 8:47 p.m. UTC | #7
On 2024-09-05 15:26:27 [+0200], Eric Dumazet wrote:
> 
> This has nothing to do with GRO.
> 
> Look at this alternative patch, perhaps you will see the problem ?
> 
> diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c
> index af6cf64a00e081c777db5f7786e8a27ea6f62e14..3971dbc0644ab8d32c04c262dbba7b1c950ebea9
> 100644
> --- a/net/hsr/hsr_slave.c
> +++ b/net/hsr/hsr_slave.c
> @@ -67,7 +67,9 @@ static rx_handler_result_t hsr_handle_frame(struct
> sk_buff **pskb)
>                 skb_set_network_header(skb, ETH_HLEN + HSR_HLEN);
>         skb_reset_mac_len(skb);
> 
> +       spin_lock_bh(&hsr->seqnr_lock);
>         hsr_forward_skb(skb, port);
> +       spin_unlock_bh(&hsr->seqnr_lock);
> 
>  finish_consume:
>         return RX_HANDLER_CONSUMED;
> 

This does not trigger any warning while testing (warning as in recursion
or so). The other invocations have the lock so it should work.

This did not trigger earlier because hsr_handle_frame() is invoked from
the Slave-Interfaces which don't assign a seq-nr.
syzkaller might have managed to receive the packet from the
master interface. Or it is the interlink which is new and was added in
commit 5055cccfc2d1c ("net: hsr: Provide RedBox support (HSR-SAN)").

Did the bot leave a reproducer? I'm wondering if the packet is dropped
later in process. I can't test interlink right now, my `ip' seems not
recent enough.

Assuming it is a interlink packet, I would suggest to acquire that lock
as you suggested. I can send a patch if you wish. Added Lukasz Majewski
on Cc who added interlink support, maybe he can say if this is a legal
path.

Sebastian
patchwork-bot+netdevbpf@kernel.org Sept. 9, 2024, 9:30 a.m. UTC | #8
Hello:

This patch was applied to netdev/net.git (main)
by David S. Miller <davem@davemloft.net>:

On Wed,  4 Sep 2024 13:37:25 +0000 you wrote:
> syzbot found a new splat [1].
> 
> Instead of adding yet another spin_lock_bh(&hsr->seqnr_lock) /
> spin_unlock_bh(&hsr->seqnr_lock) pair, remove seqnr_lock
> and use atomic_t for hsr->sequence_nr and hsr->sup_sequence_nr.
> 
> This also avoid a race in hsr_fill_info().
> 
> [...]

Here is the summary with links:
  - [net] net: hsr: remove seqnr_lock
    https://git.kernel.org/netdev/net/c/b3c9e65eb227

You are awesome, thank you!
diff mbox series

Patch

diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
index e4cc6b78dcfc40643ad386780573a53dd089bb54..ac56784c327c0293fef13e3ecfa9fc32ca1ab839 100644
--- a/net/hsr/hsr_device.c
+++ b/net/hsr/hsr_device.c
@@ -231,9 +231,7 @@  static netdev_tx_t hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev)
 		skb->dev = master->dev;
 		skb_reset_mac_header(skb);
 		skb_reset_mac_len(skb);
-		spin_lock_bh(&hsr->seqnr_lock);
 		hsr_forward_skb(skb, master);
-		spin_unlock_bh(&hsr->seqnr_lock);
 	} else {
 		dev_core_stats_tx_dropped_inc(dev);
 		dev_kfree_skb_any(skb);
@@ -314,14 +312,10 @@  static void send_hsr_supervision_frame(struct hsr_port *port,
 	set_hsr_stag_HSR_ver(hsr_stag, hsr->prot_version);
 
 	/* From HSRv1 on we have separate supervision sequence numbers. */
-	spin_lock_bh(&hsr->seqnr_lock);
-	if (hsr->prot_version > 0) {
-		hsr_stag->sequence_nr = htons(hsr->sup_sequence_nr);
-		hsr->sup_sequence_nr++;
-	} else {
-		hsr_stag->sequence_nr = htons(hsr->sequence_nr);
-		hsr->sequence_nr++;
-	}
+	if (hsr->prot_version > 0)
+		hsr_stag->sequence_nr = htons(atomic_inc_return(&hsr->sup_sequence_nr));
+	else
+		hsr_stag->sequence_nr = htons(atomic_inc_return(&hsr->sequence_nr));
 
 	hsr_stag->tlv.HSR_TLV_type = type;
 	/* TODO: Why 12 in HSRv0? */
@@ -343,13 +337,11 @@  static void send_hsr_supervision_frame(struct hsr_port *port,
 		ether_addr_copy(hsr_sp->macaddress_A, hsr->macaddress_redbox);
 	}
 
-	if (skb_put_padto(skb, ETH_ZLEN)) {
-		spin_unlock_bh(&hsr->seqnr_lock);
+	if (skb_put_padto(skb, ETH_ZLEN))
 		return;
-	}
 
 	hsr_forward_skb(skb, port);
-	spin_unlock_bh(&hsr->seqnr_lock);
+
 	return;
 }
 
@@ -374,9 +366,7 @@  static void send_prp_supervision_frame(struct hsr_port *master,
 	set_hsr_stag_HSR_ver(hsr_stag, (hsr->prot_version ? 1 : 0));
 
 	/* From HSRv1 on we have separate supervision sequence numbers. */
-	spin_lock_bh(&hsr->seqnr_lock);
-	hsr_stag->sequence_nr = htons(hsr->sup_sequence_nr);
-	hsr->sup_sequence_nr++;
+	hsr_stag->sequence_nr = htons(atomic_inc_return(&hsr->sup_sequence_nr));
 	hsr_stag->tlv.HSR_TLV_type = PRP_TLV_LIFE_CHECK_DD;
 	hsr_stag->tlv.HSR_TLV_length = sizeof(struct hsr_sup_payload);
 
@@ -384,13 +374,10 @@  static void send_prp_supervision_frame(struct hsr_port *master,
 	hsr_sp = skb_put(skb, sizeof(struct hsr_sup_payload));
 	ether_addr_copy(hsr_sp->macaddress_A, master->dev->dev_addr);
 
-	if (skb_put_padto(skb, ETH_ZLEN)) {
-		spin_unlock_bh(&hsr->seqnr_lock);
+	if (skb_put_padto(skb, ETH_ZLEN))
 		return;
-	}
 
 	hsr_forward_skb(skb, master);
-	spin_unlock_bh(&hsr->seqnr_lock);
 }
 
 /* Announce (supervision frame) timer function
@@ -621,11 +608,9 @@  int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
 	if (res < 0)
 		return res;
 
-	spin_lock_init(&hsr->seqnr_lock);
 	/* Overflow soon to find bugs easier: */
-	hsr->sequence_nr = HSR_SEQNR_START;
-	hsr->sup_sequence_nr = HSR_SUP_SEQNR_START;
-	hsr->interlink_sequence_nr = HSR_SEQNR_START;
+	atomic_set(&hsr->sequence_nr, HSR_SEQNR_START);
+	atomic_set(&hsr->sup_sequence_nr, HSR_SUP_SEQNR_START);
 
 	timer_setup(&hsr->announce_timer, hsr_announce, 0);
 	timer_setup(&hsr->prune_timer, hsr_prune_nodes, 0);
diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c
index b38060246e62e8a8d94d78d32a530e3820e752a1..6f63c8a775c41195c7cde5b27c83ffb91733d5c8 100644
--- a/net/hsr/hsr_forward.c
+++ b/net/hsr/hsr_forward.c
@@ -599,9 +599,7 @@  static void handle_std_frame(struct sk_buff *skb,
 	if (port->type == HSR_PT_MASTER ||
 	    port->type == HSR_PT_INTERLINK) {
 		/* Sequence nr for the master/interlink node */
-		lockdep_assert_held(&hsr->seqnr_lock);
-		frame->sequence_nr = hsr->sequence_nr;
-		hsr->sequence_nr++;
+		frame->sequence_nr = atomic_inc_return(&hsr->sequence_nr);
 	}
 }
 
diff --git a/net/hsr/hsr_main.h b/net/hsr/hsr_main.h
index ab1f8d35d9dcf507f0b2f90b0cede6dd24a51f2a..6f7bbf01f3e4f3033446860fb584402cb81df336 100644
--- a/net/hsr/hsr_main.h
+++ b/net/hsr/hsr_main.h
@@ -202,11 +202,9 @@  struct hsr_priv {
 	struct timer_list	prune_timer;
 	struct timer_list	prune_proxy_timer;
 	int announce_count;
-	u16 sequence_nr;
-	u16 interlink_sequence_nr; /* Interlink port seq_nr */
-	u16 sup_sequence_nr;	/* For HSRv1 separate seq_nr for supervision */
+	atomic_t sequence_nr;
+	atomic_t sup_sequence_nr;	/* For HSRv1 separate seq_nr for supervision */
 	enum hsr_version prot_version;	/* Indicate if HSRv0, HSRv1 or PRPv1 */
-	spinlock_t seqnr_lock;	/* locking for sequence_nr */
 	spinlock_t list_lock;	/* locking for node list */
 	struct hsr_proto_ops	*proto_ops;
 #define PRP_LAN_ID	0x5     /* 0x1010 for A and 0x1011 for B. Bit 0 is set
diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c
index f6ff0b61e08a966254625ad13fd3b97e99329cf7..8aea4ff5f49e305555773e6e8cc7be570f946ada 100644
--- a/net/hsr/hsr_netlink.c
+++ b/net/hsr/hsr_netlink.c
@@ -163,7 +163,7 @@  static int hsr_fill_info(struct sk_buff *skb, const struct net_device *dev)
 
 	if (nla_put(skb, IFLA_HSR_SUPERVISION_ADDR, ETH_ALEN,
 		    hsr->sup_multicast_addr) ||
-	    nla_put_u16(skb, IFLA_HSR_SEQ_NR, hsr->sequence_nr))
+	    nla_put_u16(skb, IFLA_HSR_SEQ_NR, atomic_read(&hsr->sequence_nr)))
 		goto nla_put_failure;
 	if (hsr->prot_version == PRP_V1)
 		proto = HSR_PROTOCOL_PRP;