Browse Source

[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>
tags/v1.20.1
Michael Brown 14 years ago
parent
commit
1d3b6619e5
2 changed files with 50 additions and 3 deletions
  1. 12
    0
      src/include/ipxe/list.h
  2. 38
    3
      src/net/tcp.c

+ 12
- 0
src/include/ipxe/list.h View File

162
 	      &pos->member != (head);					      \
162
 	      &pos->member != (head);					      \
163
 	      pos = list_entry ( pos->member.next, typeof ( *pos ), member ) )
163
 	      pos = list_entry ( pos->member.next, typeof ( *pos ), member ) )
164
 
164
 
165
+/**
166
+ * Iterate over entries in a list in reverse order
167
+ *
168
+ * @v pos	The type * to use as a loop counter
169
+ * @v head	The head for your list
170
+ * @v member	The name of the list_struct within the struct
171
+ */
172
+#define list_for_each_entry_reverse( pos, head, member )		      \
173
+	for ( pos = list_entry ( (head)->prev, typeof ( *pos ), member );     \
174
+	      &pos->member != (head);					      \
175
+	      pos = list_entry ( pos->member.prev, typeof ( *pos ), member ) )
176
+
165
 /**
177
 /**
166
  * Iterate over entries in a list, safe against deletion of entries
178
  * Iterate over entries in a list, safe against deletion of entries
167
  *
179
  *

+ 38
- 3
src/net/tcp.c View File

1004
  */
1004
  */
1005
 static void tcp_process_rx_queue ( struct tcp_connection *tcp ) {
1005
 static void tcp_process_rx_queue ( struct tcp_connection *tcp ) {
1006
 	struct io_buffer *iobuf;
1006
 	struct io_buffer *iobuf;
1007
-	struct io_buffer *tmp;
1008
 	struct tcp_rx_queued_header *tcpqhdr;
1007
 	struct tcp_rx_queued_header *tcpqhdr;
1009
 	uint32_t seq;
1008
 	uint32_t seq;
1010
 	unsigned int flags;
1009
 	unsigned int flags;
1011
 	size_t len;
1010
 	size_t len;
1012
 
1011
 
1013
-	/* Process all applicable received buffers */
1014
-	list_for_each_entry_safe ( iobuf, tmp, &tcp->rx_queue, list ) {
1012
+	/* Process all applicable received buffers.  Note that we
1013
+	 * cannot use list_for_each_entry() to iterate over the RX
1014
+	 * queue, since tcp_discard() may remove packets from the RX
1015
+	 * queue while we are processing.
1016
+	 */
1017
+	while ( ! list_empty ( &tcp->rx_queue ) ) {
1018
+		list_for_each_entry ( iobuf, &tcp->rx_queue, list )
1019
+			break;
1020
+
1021
+		/* Stop processing when we hit the first gap */
1015
 		tcpqhdr = iobuf->data;
1022
 		tcpqhdr = iobuf->data;
1016
 		if ( tcp_cmp ( tcpqhdr->seq, tcp->rcv_ack ) > 0 )
1023
 		if ( tcp_cmp ( tcpqhdr->seq, tcp->rcv_ack ) > 0 )
1017
 			break;
1024
 			break;
1183
 	.tcpip_proto = IP_TCP,
1190
 	.tcpip_proto = IP_TCP,
1184
 };
1191
 };
1185
 
1192
 
1193
+/**
1194
+ * Discard some cached TCP data
1195
+ *
1196
+ * @ret discarded	Number of cached items discarded
1197
+ */
1198
+static unsigned int tcp_discard ( void ) {
1199
+	struct tcp_connection *tcp;
1200
+	struct io_buffer *iobuf;
1201
+	unsigned int discarded = 0;
1202
+
1203
+	/* Try to drop one queued RX packet from each connection */
1204
+	list_for_each_entry ( tcp, &tcp_conns, list ) {
1205
+		list_for_each_entry_reverse ( iobuf, &tcp->rx_queue, list ) {
1206
+			list_del ( &iobuf->list );
1207
+			free_iob ( iobuf );
1208
+			discarded++;
1209
+			break;
1210
+		}
1211
+	}
1212
+
1213
+	return discarded;
1214
+}
1215
+
1216
+/** TCP cache discarder */
1217
+struct cache_discarder tcp_cache_discarder __cache_discarder = {
1218
+	.discard = tcp_discard,
1219
+};
1220
+
1186
 /***************************************************************************
1221
 /***************************************************************************
1187
  *
1222
  *
1188
  * Data transfer interface
1223
  * Data transfer interface

Loading…
Cancel
Save