Adding some maintainers... We are looking forward to a response.
Thanks, Eugene > -----Original Message----- > From: edk2-devel [mailto:[email protected]] On Behalf Of > Cohen, Eugene > Sent: Friday, May 20, 2016 2:11 PM > To: [email protected] > Cc: Vaughn, Gregory (IPG LJ Printer Lab) <[email protected]> > Subject: [edk2] TCP4: Failure to Acknowledge due to DPC Dispatch Nesting > > > We have isolated a problem where the TCP4 driver fails to acknowledge > received data under certain circumstances. > > Background on DPCs: The DPC mechanism allows functions to be called at a > later point in time at a requested TPL level. Functions are queued through > the DPC Protocol's QueueDpc interface. DPCs are dispatched anytime a > module calls the DispatchDpc function in the DPC protocol. The dispatch > process will execute all queued DPCs that were registered to execute at or > above the caller's TPL level (e.g. if caller is at TPL_CALLBACK the DPC > dispatch > will execute anything between CALLBACK and HIGH_LEVEL). > > The stack depends on DispatchDpc being called at appropriate preemption > points to advance packet processing. The dispatch function is called in > multiple layers as you can see by searching for DispatchDpc with calls > originating from ArpDxe, Ip4Dxe, MnpDxe, Udp4Dxe, UefiPxeBcDxe, > DnsDxe, HttpDxe, Ip6Dxe and Udp6Dxe. > > Currently it's possible for DPC dispatching to occur in a nested manner. > Imagine a case where an upper network stack layer queues a DPC (for > example the TCP layer's TcpTickingDpc) and in the DPC handler it makes use > of lower layers (like sending a packet through IP+MNP). As part of packet > processing these lower layers will call DispatchDpc resulting in nested DPCs > execution. > > > Here's an example of the DPC nesting, the indent level indicates the level of > nesting for the DPC > > 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 > > Notice how the process of sending the TCP ACK via IP then MNP causes > another DispatchDpc to occur before the TCP segment transmit call returns. > This nesting continues on and a whole bunch of code has executed (all at > CALLBACK TPL). You can see near the end that we even begin processing > another TCP packet. > > > If we look in detail what the TcpSendAck does there are two key steps: > > if (TcpTransmitSegment (Tcb, Nbuf) == 0) { > TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW); > Tcb->DelayedAck = 0; > } > > It transmits the segment and after the transmit returns it clears the > DelayedAck counter since the presumption is that we sent an ACK for the > most recent segment and we are caught up. But because DPCs are > dispatched within TcpTransmitSegment the assumption that this transmit > was the last one is incorrect. > > > Here is a portion of a trace illustrating the problem: > > TcpTicking > DpcDispatchDpc TPL=CALLBACK > TcpTickingDpc > TcpTickingDpc Tcb: 0x49a42dd0, DelayedAck=1, CtrlFlag: 0x1019 > TcpTickingDpc call TcpSendAck delayed is: 1 > TcpSndAck Seq=158464588 Ack=4152002304 > TcpTransmitSegment DelayedAck = 0 > Nbuf SendIpPacket: DestPort=62462 Seq=158464588 Ack=4152002304 > Window=19840 > MnpSyncSendPacket call DispatchDpc > DpcDispatchDpc TPL=CALLBACK > > [snip - a bunch of nested DPC processing removed] > > DpcDispatchDpc Tpl= TPL=CALLBACK > TcpInput: DestPort=8816 Seq=4152019824 Ack=158464588 Len=1460 > TcpClearTimer Tcb: 0x49a42dd0 > TcpInput Seq=4152019824 Tcb: 0x49a42dd0, Tcb->DupAck = 0 > TcpToSendAck add to delayedack Seq=158464588 Ack=4152021284 > TcpToSendAck add to delayedack Tcb: 0x49a42dd0, Seq=158464588 > Ack=4152021284, DelayedAck=1 > ^^ NOTE: the DelayedAck flag has been set to one indicating that we > haven't acknowledged yet and need to soon > > [we return from 14 nested DPC calls !!] > > TcpSndAck Tcb->DelayedAck = 0 > ^^ But when the Dispatch returns from the TcpTransmitSegment we clear > DelayedAck back to zero such that we never acknowledge the last packet we > received. > > TcpTickingDpc No timer active or expired > TcpTickingDpc Tcb: 0x49918bd0, DelayedAck=0, CtrlFlag: 0x1019 > TcpTickingDpc No timer active or expired > > In cases where TCP is waiting for more data from the remote endpoint and > the endpoint is waiting for acknowledgement (like a situation where the > sliding window is small or closed) the remote endpoint will retransmit the > last > packet but for reasons I don't yet understand duplicate acks aren't sent (I > think there's another bug around retransmitting acks but I haven't isolated > it). The result is that the connection is reset by the remote endpoint > after a > timeout period elapses. > > > This seems kind of like a critical section / locking problem around the > DelayedAck member. I'm not sure if the issue stems from the fact that the > DPC model allows a form of preemption at the same TPL level (in this case we > have TCP4 at TPL_CALLBACK effectively preempting TCP4 at TPL_CALLBACK) > or if the issue is that the TCP4 driver is not managing the DelayedAck > variable > correctly given the rules for DPC routines (btw: what are the rules?). > > > I'd like an explanation for what the expected DPC preemption model is - are > we really supposed to be nesting dispatch calls and are all network > components expected to handle this level or reentrancy? > > We are testing a change to remove DPC nesting which we believe should > resolve this issue. We would be happy to provide the patch if there's > agreement that this is the right way to resolve this. > > I'd be open to a phone call / Lync meeting with the maintainers if you feel it > would be helpful. > > Thanks, > > Eugene > > _______________________________________________ > edk2-devel mailing list > [email protected] > https://lists.01.org/mailman/listinfo/edk2-devel _______________________________________________ edk2-devel mailing list [email protected] https://lists.01.org/mailman/listinfo/edk2-devel

