mirror of https://github.com/ipxe/ipxe.git
[tcp] Allow out-of-order receive queue to be discarded
Allow packets in the receive queue to be discarded in order to free up memory. This avoids a potential deadlock condition in which the missing packet can never be received because the receive queue is occupying all of the memory available for further RX buffers. Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/1/head
parent
9dc51afa2c
commit
1d3b6619e5
|
@ -162,6 +162,18 @@ static inline int list_empty ( const struct list_head *head ) {
|
||||||
&pos->member != (head); \
|
&pos->member != (head); \
|
||||||
pos = list_entry ( pos->member.next, typeof ( *pos ), member ) )
|
pos = list_entry ( pos->member.next, typeof ( *pos ), member ) )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterate over entries in a list in reverse order
|
||||||
|
*
|
||||||
|
* @v pos The type * to use as a loop counter
|
||||||
|
* @v head The head for your list
|
||||||
|
* @v member The name of the list_struct within the struct
|
||||||
|
*/
|
||||||
|
#define list_for_each_entry_reverse( pos, head, member ) \
|
||||||
|
for ( pos = list_entry ( (head)->prev, typeof ( *pos ), member ); \
|
||||||
|
&pos->member != (head); \
|
||||||
|
pos = list_entry ( pos->member.prev, typeof ( *pos ), member ) )
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterate over entries in a list, safe against deletion of entries
|
* Iterate over entries in a list, safe against deletion of entries
|
||||||
*
|
*
|
||||||
|
|
|
@ -1004,14 +1004,21 @@ static void tcp_rx_enqueue ( struct tcp_connection *tcp, uint32_t seq,
|
||||||
*/
|
*/
|
||||||
static void tcp_process_rx_queue ( struct tcp_connection *tcp ) {
|
static void tcp_process_rx_queue ( struct tcp_connection *tcp ) {
|
||||||
struct io_buffer *iobuf;
|
struct io_buffer *iobuf;
|
||||||
struct io_buffer *tmp;
|
|
||||||
struct tcp_rx_queued_header *tcpqhdr;
|
struct tcp_rx_queued_header *tcpqhdr;
|
||||||
uint32_t seq;
|
uint32_t seq;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
/* Process all applicable received buffers */
|
/* Process all applicable received buffers. Note that we
|
||||||
list_for_each_entry_safe ( iobuf, tmp, &tcp->rx_queue, list ) {
|
* cannot use list_for_each_entry() to iterate over the RX
|
||||||
|
* queue, since tcp_discard() may remove packets from the RX
|
||||||
|
* queue while we are processing.
|
||||||
|
*/
|
||||||
|
while ( ! list_empty ( &tcp->rx_queue ) ) {
|
||||||
|
list_for_each_entry ( iobuf, &tcp->rx_queue, list )
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Stop processing when we hit the first gap */
|
||||||
tcpqhdr = iobuf->data;
|
tcpqhdr = iobuf->data;
|
||||||
if ( tcp_cmp ( tcpqhdr->seq, tcp->rcv_ack ) > 0 )
|
if ( tcp_cmp ( tcpqhdr->seq, tcp->rcv_ack ) > 0 )
|
||||||
break;
|
break;
|
||||||
|
@ -1183,6 +1190,34 @@ struct tcpip_protocol tcp_protocol __tcpip_protocol = {
|
||||||
.tcpip_proto = IP_TCP,
|
.tcpip_proto = IP_TCP,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discard some cached TCP data
|
||||||
|
*
|
||||||
|
* @ret discarded Number of cached items discarded
|
||||||
|
*/
|
||||||
|
static unsigned int tcp_discard ( void ) {
|
||||||
|
struct tcp_connection *tcp;
|
||||||
|
struct io_buffer *iobuf;
|
||||||
|
unsigned int discarded = 0;
|
||||||
|
|
||||||
|
/* Try to drop one queued RX packet from each connection */
|
||||||
|
list_for_each_entry ( tcp, &tcp_conns, list ) {
|
||||||
|
list_for_each_entry_reverse ( iobuf, &tcp->rx_queue, list ) {
|
||||||
|
list_del ( &iobuf->list );
|
||||||
|
free_iob ( iobuf );
|
||||||
|
discarded++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return discarded;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** TCP cache discarder */
|
||||||
|
struct cache_discarder tcp_cache_discarder __cache_discarder = {
|
||||||
|
.discard = tcp_discard,
|
||||||
|
};
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
*
|
*
|
||||||
* Data transfer interface
|
* Data transfer interface
|
||||||
|
|
Loading…
Reference in New Issue