Patch "hsr: Synchronize sending frames to have always incremented outgoing seq nr." has been added to the 5.10-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    hsr: Synchronize sending frames to have always incremented outgoing seq nr.

to the 5.10-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     hsr-synchronize-sending-frames-to-have-always-increm.patch
and it can be found in the queue-5.10 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 7f78b376ce3c2fcc196ac6ac33e782a32a6e6502
Author: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx>
Date:   Tue Nov 29 17:48:12 2022 +0100

    hsr: Synchronize sending frames to have always incremented outgoing seq nr.
    
    [ Upstream commit 06afd2c31d338fa762548580c1bf088703dd1e03 ]
    
    Sending frames via the hsr (master) device requires a sequence number
    which is tracked in hsr_priv::sequence_nr and protected by
    hsr_priv::seqnr_lock. Each time a new frame is sent, it will obtain a
    new id and then send it via the slave devices.
    Each time a packet is sent (via hsr_forward_do()) the sequence number is
    checked via hsr_register_frame_out() to ensure that a frame is not
    handled twice. This make sense for the receiving side to ensure that the
    frame is not injected into the stack twice after it has been received
    from both slave ports.
    
    There is no locking to cover the sending path which means the following
    scenario is possible:
    
      CPU0                          CPU1
      hsr_dev_xmit(skb1)            hsr_dev_xmit(skb2)
       fill_frame_info()             fill_frame_info()
        hsr_fill_frame_info()         hsr_fill_frame_info()
         handle_std_frame()            handle_std_frame()
          skb1's sequence_nr = 1
                                        skb2's sequence_nr = 2
       hsr_forward_do()              hsr_forward_do()
    
                                       hsr_register_frame_out(, 2)  // okay, send)
    
        hsr_register_frame_out(, 1) // stop, lower seq duplicate
    
    Both skbs (or their struct hsr_frame_info) received an unique id.
    However since skb2 was sent before skb1, the higher sequence number was
    recorded in hsr_register_frame_out() and the late arriving skb1 was
    dropped and never sent.
    
    This scenario has been observed in a three node HSR setup, with node1 +
    node2 having ping and iperf running in parallel. From time to time ping
    reported a missing packet. Based on tracing that missing ping packet did
    not leave the system.
    
    It might be possible (didn't check) to drop the sequence number check on
    the sending side. But if the higher sequence number leaves on wire
    before the lower does and the destination receives them in that order
    and it will drop the packet with the lower sequence number and never
    inject into the stack.
    Therefore it seems the only way is to lock the whole path from obtaining
    the sequence number and sending via dev_queue_xmit() and assuming the
    packets leave on wire in the same order (and don't get reordered by the
    NIC).
    
    Cover the whole path for the master interface from obtaining the ID
    until after it has been forwarded via hsr_forward_skb() to ensure the
    skbs are sent to the NIC in the order of the assigned sequence numbers.
    
    Fixes: f421436a591d3 ("net/hsr: Add support for the High-availability Seamless Redundancy protocol (HSRv0)")
    Signed-off-by: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx>
    Signed-off-by: Jakub Kicinski <kuba@xxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
index 037ad39564a4..84e6ef4f3525 100644
--- a/net/hsr/hsr_device.c
+++ b/net/hsr/hsr_device.c
@@ -219,7 +219,9 @@ 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 {
 		atomic_long_inc(&dev->tx_dropped);
 		dev_kfree_skb_any(skb);
@@ -306,7 +308,6 @@ static void send_hsr_supervision_frame(struct hsr_port *master,
 		hsr_stag->sequence_nr = htons(hsr->sequence_nr);
 		hsr->sequence_nr++;
 	}
-	spin_unlock_bh(&hsr->seqnr_lock);
 
 	hsr_stag->HSR_TLV_type = type;
 	/* TODO: Why 12 in HSRv0? */
@@ -317,11 +318,13 @@ static void send_hsr_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))
+	if (skb_put_padto(skb, ETH_ZLEN)) {
+		spin_unlock_bh(&hsr->seqnr_lock);
 		return;
+	}
 
 	hsr_forward_skb(skb, master);
-
+	spin_unlock_bh(&hsr->seqnr_lock);
 	return;
 }
 
@@ -360,9 +363,8 @@ static void send_prp_supervision_frame(struct hsr_port *master,
 		return;
 	}
 
-	spin_unlock_bh(&hsr->seqnr_lock);
-
 	hsr_forward_skb(skb, master);
+	spin_unlock_bh(&hsr->seqnr_lock);
 }
 
 /* Announce (supervision frame) timer function
diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c
index 142bed7f1fea..aec48e670fb6 100644
--- a/net/hsr/hsr_forward.c
+++ b/net/hsr/hsr_forward.c
@@ -446,10 +446,9 @@ static void handle_std_frame(struct sk_buff *skb,
 		frame->is_from_san = true;
 	} else {
 		/* Sequence nr for the master node */
-		spin_lock_bh(&hsr->seqnr_lock);
+		lockdep_assert_held(&hsr->seqnr_lock);
 		frame->sequence_nr = hsr->sequence_nr;
 		hsr->sequence_nr++;
-		spin_unlock_bh(&hsr->seqnr_lock);
 	}
 }
 



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux