diff options
author | Vlad Yasevich <vladislav.yasevich@hp.com> | 2010-04-30 22:41:10 -0400 |
---|---|---|
committer | Vlad Yasevich <vladislav.yasevich@hp.com> | 2010-04-30 22:41:10 -0400 |
commit | bfa0d9843ac5feb9667990706b4524390fee4df9 (patch) | |
tree | 93b3f84efdc8a01ed76c70f8edec0d2f412d9d04 /net | |
parent | ea862c8d1f4a0d193979c7412c3b946f600721ce (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')
-rw-r--r-- | net/sctp/outqueue.c | 42 |
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 | ||
67 | static void sctp_mark_missing(struct sctp_outq *q, | 67 | static 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. */ | ||
1113 | static __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); |