Siyuan,

> The FIN_SENT flag seems OK because an incoming TCP message won't
> override this flag, while the other control flag like the TIMER_REXMIT
> and RTT are more complex which need case by case analysis. There is
> no DPC mechanism when writing the first revision TCP code, so I think
> we need to review the TCP code for the similar cases to make it more
> robust.

Thanks for the analysis - can I interpret your response that the REXMIT and RTT 
stuff are at risk for incorrect behavior today?

> For your question, why not update DPC "such that DPCs at the same
> TPL didn't preempt each other", the answer is that's the reason why
> DPC is introduced. The design intention of DPC is to interrupt current
> code when the preempted code is in the same TPL level with the code
> being interrupted.

> You can see that we must allow some event at same TPL level with the
> current running code to preempt, otherwise there is a deadlock.

Thanks for the explanation - this makes sense.  So the fundamental problem to 
be solved is that while blocking we need DPC callbacks to run to make progress 
on the operation.  I might argue that the current DPC design causes more 
nesting than is necessary to achieve that goal.  Consider the case where we saw 
14 levels of nested DPC processing including overlapping TCP processing.

We have been testing a change where nesting of DPCs is prevented - in 
DispatchDPC we check if we are already processing a dispatch and exit if we 
are.  (We also modified the dispatch loop to keep looping until the DPC queues 
are emptied.)  With this approach we still meet the same-TPL async execution 
but avoid the whole mess of nesting.

So our original example that looked like this:

TcpTicking
DpcDispatchDpc TPL=CALLBACK
    TcpTickingDpc
    TcpTickingDpc Tcb: 0x49a42dd0, DelayedAck=1, CtrlFlag: 0x1019
    TcpTickingDpc call TcpSendAck delayed is: 1
    TcpSendAck  Seq=158464588 Ack=4152002304
    TcpTransmitSegment DelayedAck = 0
    Nbuf SendIpPacket: DestPort=62462 Seq=158464588 Ack=4152002304 Window=19840
    MnpSyncSendPacket call DispatchDpc
    DpcDispatchDpc TPL=CALLBACK
        Ip4AccpetFrame call DispatchDpc
        DpcDispatchDpc TPL=CALLBACK
            Ip4FreeTxToken call DispatchDpc
            DpcDispatchDpc TPL=CALLBACK
                TcpInput: DestPort=8816 Seq=4152002304 Ack=158464588 Len=1460
                TcpClearTimer Tcb: 0x49a42dd0

Would become something like this:

TcpTicking
DpcDispatchDpc TPL=CALLBACK
    TcpTickingDpc
    TcpTickingDpc Tcb: 0x49a42dd0, DelayedAck=1, CtrlFlag: 0x1019
    TcpTickingDpc call TcpSendAck delayed is: 1
    TcpSendAck  Seq=158464588 Ack=4152002304
    TcpTransmitSegment DelayedAck = 0
    Nbuf SendIpPacket: DestPort=62462 Seq=158464588 Ack=4152002304 Window=19840
    MnpSyncSendPacket call DispatchDpc <- SUPPRESS, DPC ALREADY IN PROGRESS
<next DPC queued item>
    Ip4AccpetFrame call DispatchDpc <- SUPPRESS, DPC ALREADY IN PROGRESS
<next DPC queued item>
    Ip4FreeTxToken call DispatchDpc DispatchDpc <- SUPPRESS, DPC ALREADY IN 
PROGRESS
<next DPC queued item>
    TcpInput: DestPort=8816 Seq=4152002304 Ack=158464588 Len=1460
    TcpClearTimer Tcb: 0x49a42dd0

As you can see the nesting is removed - specifically the troublesome 
overlapping TCP operations are separated into distinct calls.

I've included the patch for this change for your consideration.

--

This resolves acknowledgement issues seen in TCP4 when overlapping
packet processing occurs for the same connection.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Eugene Cohen <[email protected]>
---
 MdeModulePkg/Universal/Network/DpcDxe/Dpc.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/MdeModulePkg/Universal/Network/DpcDxe/Dpc.c 
b/MdeModulePkg/Universal/Network/DpcDxe/Dpc.c
index c605f72..bb3f6f2 100644
--- a/MdeModulePkg/Universal/Network/DpcDxe/Dpc.c
+++ b/MdeModulePkg/Universal/Network/DpcDxe/Dpc.c
@@ -40,6 +40,11 @@ UINTN  mDpcQueueDepth = 0;
 UINTN  mMaxDpcQueueDepth = 0;
 
 //
+// Global variable used to indicate that DPC dispatch is occurring
+//
+BOOLEAN mDpcDispatchActive = FALSE;
+
+//
 // Free list of DPC entries.  As DPCs are queued, entries are removed from this
 // free list.  As DPC entries are dispatched, DPC entries are added to the 
free list.
 // If the free list is empty and a DPC is queued, the free list is grown by 
allocating
@@ -236,10 +241,18 @@ DpcDispatchDpc (
   //
   OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
 
+  // If DPC dispatching is already in progress exit to prevent nested DPC 
invocations
+  if (mDpcDispatchActive) {
+    gBS->RestoreTPL (OriginalTpl);
+    return EFI_NOT_FOUND;
+  }
+
+  mDpcDispatchActive = TRUE;
+
   //
   // Check to see if there are 1 or more DPCs currently queued
   //
-  if (mDpcQueueDepth > 0) {
+  while (mDpcQueueDepth > 0) {
     //
     // Loop from TPL_HIGH_LEVEL down to the current TPL value
     //
@@ -291,6 +304,8 @@ DpcDispatchDpc (
     }
   }
 
+  mDpcDispatchActive = FALSE;
+  
   //
   // Restore the original TPL level when this function was called
   //
-- 
1.9.5.msysgit.0

_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to