aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/outqueue.c
diff options
context:
space:
mode:
authorVlad Yasevich <vladislav.yasevich@hp.com>2010-04-30 22:41:10 -0400
committerVlad Yasevich <vladislav.yasevich@hp.com>2010-04-30 22:41:10 -0400
commitbfa0d9843ac5feb9667990706b4524390fee4df9 (patch)
tree93b3f84efdc8a01ed76c70f8edec0d2f412d9d04 /net/sctp/outqueue.c
parentea862c8d1f4a0d193979c7412c3b946f600721ce (diff)
sctp: Optimize computation of highest new tsn in SACK.
Right now, if the highest tsn in the SACK doesn't change, we'll end up scanning the transmitted lists on the transports twice: once for locating the highest _new_ tsn, and once for actually tagging chunks as acked. This is a waste, since we can record the highest _new_ tsn at the same time as tagging chunks. Long ago this was not possible because we would try to mark chunks as missing at the same time as tagging them acked and this approach didn't work. Now that the two steps are separate, we can re-use the old approach. Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Diffstat (limited to 'net/sctp/outqueue.c')
-rw-r--r--net/sctp/outqueue.c42
1 files changed, 7 insertions, 35 deletions
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index b491a1aac3e4..5d057178ce0c 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -62,7 +62,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
62 struct list_head *transmitted_queue, 62 struct list_head *transmitted_queue,
63 struct sctp_transport *transport, 63 struct sctp_transport *transport,
64 struct sctp_sackhdr *sack, 64 struct sctp_sackhdr *sack,
65 __u32 highest_new_tsn); 65 __u32 *highest_new_tsn);
66 66
67static void sctp_mark_missing(struct sctp_outq *q, 67static void sctp_mark_missing(struct sctp_outq *q,
68 struct list_head *transmitted_queue, 68 struct list_head *transmitted_queue,
@@ -1109,32 +1109,6 @@ static void sctp_sack_update_unack_data(struct sctp_association *assoc,
1109 assoc->unack_data = unack_data; 1109 assoc->unack_data = unack_data;
1110} 1110}
1111 1111
1112/* Return the highest new tsn that is acknowledged by the given SACK chunk. */
1113static __u32 sctp_highest_new_tsn(struct sctp_sackhdr *sack,
1114 struct sctp_association *asoc)
1115{
1116 struct sctp_transport *transport;
1117 struct sctp_chunk *chunk;
1118 __u32 highest_new_tsn, tsn;
1119 struct list_head *transport_list = &asoc->peer.transport_addr_list;
1120
1121 highest_new_tsn = ntohl(sack->cum_tsn_ack);
1122
1123 list_for_each_entry(transport, transport_list, transports) {
1124 list_for_each_entry(chunk, &transport->transmitted,
1125 transmitted_list) {
1126 tsn = ntohl(chunk->subh.data_hdr->tsn);
1127
1128 if (!chunk->tsn_gap_acked &&
1129 TSN_lt(highest_new_tsn, tsn) &&
1130 sctp_acked(sack, tsn))
1131 highest_new_tsn = tsn;
1132 }
1133 }
1134
1135 return highest_new_tsn;
1136}
1137
1138/* This is where we REALLY process a SACK. 1112/* This is where we REALLY process a SACK.
1139 * 1113 *
1140 * Process the SACK against the outqueue. Mostly, this just frees 1114 * Process the SACK against the outqueue. Mostly, this just frees
@@ -1203,18 +1177,15 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
1203 if (gap_ack_blocks) 1177 if (gap_ack_blocks)
1204 highest_tsn += ntohs(frags[gap_ack_blocks - 1].gab.end); 1178 highest_tsn += ntohs(frags[gap_ack_blocks - 1].gab.end);
1205 1179
1206 if (TSN_lt(asoc->highest_sacked, highest_tsn)) { 1180 if (TSN_lt(asoc->highest_sacked, highest_tsn))
1207 highest_new_tsn = highest_tsn;
1208 asoc->highest_sacked = highest_tsn; 1181 asoc->highest_sacked = highest_tsn;
1209 } else {
1210 highest_new_tsn = sctp_highest_new_tsn(sack, asoc);
1211 }
1212 1182
1183 highest_new_tsn = sack_ctsn;
1213 1184
1214 /* Run through the retransmit queue. Credit bytes received 1185 /* Run through the retransmit queue. Credit bytes received
1215 * and free those chunks that we can. 1186 * and free those chunks that we can.
1216 */ 1187 */
1217 sctp_check_transmitted(q, &q->retransmit, NULL, sack, highest_new_tsn); 1188 sctp_check_transmitted(q, &q->retransmit, NULL, sack, &highest_new_tsn);
1218 1189
1219 /* Run through the transmitted queue. 1190 /* Run through the transmitted queue.
1220 * Credit bytes received and free those chunks which we can. 1191 * Credit bytes received and free those chunks which we can.
@@ -1223,7 +1194,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
1223 */ 1194 */
1224 list_for_each_entry(transport, transport_list, transports) { 1195 list_for_each_entry(transport, transport_list, transports) {
1225 sctp_check_transmitted(q, &transport->transmitted, 1196 sctp_check_transmitted(q, &transport->transmitted,
1226 transport, sack, highest_new_tsn); 1197 transport, sack, &highest_new_tsn);
1227 /* 1198 /*
1228 * SFR-CACC algorithm: 1199 * SFR-CACC algorithm:
1229 * C) Let count_of_newacks be the number of 1200 * C) Let count_of_newacks be the number of
@@ -1331,7 +1302,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
1331 struct list_head *transmitted_queue, 1302 struct list_head *transmitted_queue,
1332 struct sctp_transport *transport, 1303 struct sctp_transport *transport,
1333 struct sctp_sackhdr *sack, 1304 struct sctp_sackhdr *sack,
1334 __u32 highest_new_tsn_in_sack) 1305 __u32 *highest_new_tsn_in_sack)
1335{ 1306{
1336 struct list_head *lchunk; 1307 struct list_head *lchunk;
1337 struct sctp_chunk *tchunk; 1308 struct sctp_chunk *tchunk;
@@ -1419,6 +1390,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
1419 */ 1390 */
1420 if (!tchunk->tsn_gap_acked) { 1391 if (!tchunk->tsn_gap_acked) {
1421 tchunk->tsn_gap_acked = 1; 1392 tchunk->tsn_gap_acked = 1;
1393 *highest_new_tsn_in_sack = tsn;
1422 bytes_acked += sctp_data_size(tchunk); 1394 bytes_acked += sctp_data_size(tchunk);
1423 if (!tchunk->transport) 1395 if (!tchunk->transport)
1424 migrate_bytes += sctp_data_size(tchunk); 1396 migrate_bytes += sctp_data_size(tchunk);