Skip to content

Commit

Permalink
[tcp] Allow out-of-order receive queue to be discarded
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
mcb30 committed Jul 21, 2010
1 parent 9dc51af commit 1d3b661
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 3 deletions.
12 changes: 12 additions & 0 deletions src/include/ipxe/list.h
Expand Up @@ -162,6 +162,18 @@ static inline int list_empty ( const struct list_head *head ) {
&pos->member != (head); \
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
*
Expand Down
41 changes: 38 additions & 3 deletions src/net/tcp.c
Expand Up @@ -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 ) {
struct io_buffer *iobuf;
struct io_buffer *tmp;
struct tcp_rx_queued_header *tcpqhdr;
uint32_t seq;
unsigned int flags;
size_t len;

/* Process all applicable received buffers */
list_for_each_entry_safe ( iobuf, tmp, &tcp->rx_queue, list ) {
/* Process all applicable received buffers. Note that we
* 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;
if ( tcp_cmp ( tcpqhdr->seq, tcp->rcv_ack ) > 0 )
break;
Expand Down Expand Up @@ -1183,6 +1190,34 @@ struct tcpip_protocol tcp_protocol __tcpip_protocol = {
.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
Expand Down

0 comments on commit 1d3b661

Please sign in to comment.