diff options
author | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2008-07-13 06:51:40 -0400 |
---|---|---|
committer | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2008-07-13 06:51:40 -0400 |
commit | 2013c7e35aeba39777f9b3eef8a70207b3931152 (patch) | |
tree | 5d63ce9f8c512ffd17b8084002e6dc0e0f998b84 /net/dccp | |
parent | 79d16385c7f287a33ea771c4dbe60ae43f791b49 (diff) |
dccp ccid-3: Fix error in loss detection
The TFRC loss detection code used the wrong loss condition (RFC 4340, 7.7.1):
* the difference between sequence numbers s1 and s2 instead of
* the number of packets missing between s1 and s2 (one less than the distance).
Since this condition appears in many places of the code, it has been put into a
separate function, dccp_loss_free().
Further changes:
----------------
* tidied up incorrect typing (it was using `int' for u64/s64 types);
* optimised conditional statements for common case of non-reordered packets;
* rewrote comments/documentation to match the changes.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Diffstat (limited to 'net/dccp')
-rw-r--r-- | net/dccp/ccids/lib/packet_history.c | 73 | ||||
-rw-r--r-- | net/dccp/dccp.h | 15 |
2 files changed, 43 insertions, 45 deletions
diff --git a/net/dccp/ccids/lib/packet_history.c b/net/dccp/ccids/lib/packet_history.c index 20af1a693427..8b5c41ec7ee1 100644 --- a/net/dccp/ccids/lib/packet_history.c +++ b/net/dccp/ccids/lib/packet_history.c | |||
@@ -215,22 +215,19 @@ static void __one_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n2 | |||
215 | u64 s0 = tfrc_rx_hist_loss_prev(h)->tfrchrx_seqno, | 215 | u64 s0 = tfrc_rx_hist_loss_prev(h)->tfrchrx_seqno, |
216 | s1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_seqno, | 216 | s1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_seqno, |
217 | s2 = DCCP_SKB_CB(skb)->dccpd_seq; | 217 | s2 = DCCP_SKB_CB(skb)->dccpd_seq; |
218 | int n1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_ndp, | ||
219 | d12 = dccp_delta_seqno(s1, s2), d2; | ||
220 | 218 | ||
221 | if (d12 > 0) { /* S1 < S2 */ | 219 | if (likely(dccp_delta_seqno(s1, s2) > 0)) { /* S1 < S2 */ |
222 | h->loss_count = 2; | 220 | h->loss_count = 2; |
223 | tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 2), skb, n2); | 221 | tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 2), skb, n2); |
224 | return; | 222 | return; |
225 | } | 223 | } |
226 | 224 | ||
227 | /* S0 < S2 < S1 */ | 225 | /* S0 < S2 < S1 */ |
228 | d2 = dccp_delta_seqno(s0, s2); | ||
229 | 226 | ||
230 | if (d2 == 1 || n2 >= d2) { /* S2 is direct successor of S0 */ | 227 | if (dccp_loss_free(s0, s2, n2)) { |
231 | int d21 = -d12; | 228 | u64 n1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_ndp; |
232 | 229 | ||
233 | if (d21 == 1 || n1 >= d21) { | 230 | if (dccp_loss_free(s2, s1, n1)) { |
234 | /* hole is filled: S0, S2, and S1 are consecutive */ | 231 | /* hole is filled: S0, S2, and S1 are consecutive */ |
235 | h->loss_count = 0; | 232 | h->loss_count = 0; |
236 | h->loss_start = tfrc_rx_hist_index(h, 1); | 233 | h->loss_start = tfrc_rx_hist_index(h, 1); |
@@ -238,9 +235,9 @@ static void __one_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n2 | |||
238 | /* gap between S2 and S1: just update loss_prev */ | 235 | /* gap between S2 and S1: just update loss_prev */ |
239 | tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_loss_prev(h), skb, n2); | 236 | tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_loss_prev(h), skb, n2); |
240 | 237 | ||
241 | } else { /* hole between S0 and S2 */ | 238 | } else { /* gap between S0 and S2 */ |
242 | /* | 239 | /* |
243 | * Reorder history to insert S2 between S0 and s1 | 240 | * Reorder history to insert S2 between S0 and S1 |
244 | */ | 241 | */ |
245 | tfrc_rx_hist_swap(h, 0, 3); | 242 | tfrc_rx_hist_swap(h, 0, 3); |
246 | h->loss_start = tfrc_rx_hist_index(h, 3); | 243 | h->loss_start = tfrc_rx_hist_index(h, 3); |
@@ -256,22 +253,18 @@ static int __two_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n3) | |||
256 | s1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_seqno, | 253 | s1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_seqno, |
257 | s2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_seqno, | 254 | s2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_seqno, |
258 | s3 = DCCP_SKB_CB(skb)->dccpd_seq; | 255 | s3 = DCCP_SKB_CB(skb)->dccpd_seq; |
259 | int n1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_ndp, | ||
260 | d23 = dccp_delta_seqno(s2, s3), d13, d3, d31; | ||
261 | 256 | ||
262 | if (d23 > 0) { /* S2 < S3 */ | 257 | if (likely(dccp_delta_seqno(s2, s3) > 0)) { /* S2 < S3 */ |
263 | h->loss_count = 3; | 258 | h->loss_count = 3; |
264 | tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 3), skb, n3); | 259 | tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 3), skb, n3); |
265 | return 1; | 260 | return 1; |
266 | } | 261 | } |
267 | 262 | ||
268 | /* S3 < S2 */ | 263 | /* S3 < S2 */ |
269 | d13 = dccp_delta_seqno(s1, s3); | ||
270 | 264 | ||
271 | if (d13 > 0) { | 265 | if (dccp_delta_seqno(s1, s3) > 0) { /* S1 < S3 < S2 */ |
272 | /* | 266 | /* |
273 | * The sequence number order is S1, S3, S2 | 267 | * Reorder history to insert S3 between S1 and S2 |
274 | * Reorder history to insert entry between S1 and S2 | ||
275 | */ | 268 | */ |
276 | tfrc_rx_hist_swap(h, 2, 3); | 269 | tfrc_rx_hist_swap(h, 2, 3); |
277 | tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 2), skb, n3); | 270 | tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 2), skb, n3); |
@@ -280,17 +273,15 @@ static int __two_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n3) | |||
280 | } | 273 | } |
281 | 274 | ||
282 | /* S0 < S3 < S1 */ | 275 | /* S0 < S3 < S1 */ |
283 | d31 = -d13; | ||
284 | d3 = dccp_delta_seqno(s0, s3); | ||
285 | 276 | ||
286 | if (d3 == 1 || n3 >= d3) { /* S3 is a successor of S0 */ | 277 | if (dccp_loss_free(s0, s3, n3)) { |
278 | u64 n1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_ndp; | ||
287 | 279 | ||
288 | if (d31 == 1 || n1 >= d31) { | 280 | if (dccp_loss_free(s3, s1, n1)) { |
289 | /* hole between S0 and S1 filled by S3 */ | 281 | /* hole between S0 and S1 filled by S3 */ |
290 | int d2 = dccp_delta_seqno(s1, s2), | 282 | u64 n2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_ndp; |
291 | n2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_ndp; | ||
292 | 283 | ||
293 | if (d2 == 1 || n2 >= d2) { | 284 | if (dccp_loss_free(s1, s2, n2)) { |
294 | /* entire hole filled by S0, S3, S1, S2 */ | 285 | /* entire hole filled by S0, S3, S1, S2 */ |
295 | h->loss_start = tfrc_rx_hist_index(h, 2); | 286 | h->loss_start = tfrc_rx_hist_index(h, 2); |
296 | h->loss_count = 0; | 287 | h->loss_count = 0; |
@@ -307,8 +298,8 @@ static int __two_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n3) | |||
307 | } | 298 | } |
308 | 299 | ||
309 | /* | 300 | /* |
310 | * The remaining case: S3 is not a successor of S0. | 301 | * The remaining case: S0 < S3 < S1 < S2; gap between S0 and S3 |
311 | * Sequence order is S0, S3, S1, S2; reorder to insert between S0 and S1 | 302 | * Reorder history to insert S3 between S0 and S1. |
312 | */ | 303 | */ |
313 | tfrc_rx_hist_swap(h, 0, 3); | 304 | tfrc_rx_hist_swap(h, 0, 3); |
314 | h->loss_start = tfrc_rx_hist_index(h, 3); | 305 | h->loss_start = tfrc_rx_hist_index(h, 3); |
@@ -318,33 +309,25 @@ static int __two_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n3) | |||
318 | return 1; | 309 | return 1; |
319 | } | 310 | } |
320 | 311 | ||
321 | /* return the signed modulo-2^48 sequence number distance from entry e1 to e2 */ | ||
322 | static s64 tfrc_rx_hist_delta_seqno(struct tfrc_rx_hist *h, u8 e1, u8 e2) | ||
323 | { | ||
324 | DCCP_BUG_ON(e1 > h->loss_count || e2 > h->loss_count); | ||
325 | |||
326 | return dccp_delta_seqno(tfrc_rx_hist_entry(h, e1)->tfrchrx_seqno, | ||
327 | tfrc_rx_hist_entry(h, e2)->tfrchrx_seqno); | ||
328 | } | ||
329 | |||
330 | /* recycle RX history records to continue loss detection if necessary */ | 312 | /* recycle RX history records to continue loss detection if necessary */ |
331 | static void __three_after_loss(struct tfrc_rx_hist *h) | 313 | static void __three_after_loss(struct tfrc_rx_hist *h) |
332 | { | 314 | { |
333 | /* | 315 | /* |
334 | * The distance between S0 and S1 is always greater than 1 and the NDP | 316 | * At this stage we know already that there is a gap between S0 and S1 |
335 | * count of S1 is smaller than this distance. Otherwise there would | 317 | * (since S0 was the highest sequence number received before detecting |
336 | * have been no loss. Hence it is only necessary to see whether there | 318 | * the loss). To recycle the loss record, it is thus only necessary to |
337 | * are further missing data packets between S1/S2 and S2/S3. | 319 | * check for other possible gaps between S1/S2 and between S2/S3. |
338 | */ | 320 | */ |
339 | int d2 = tfrc_rx_hist_delta_seqno(h, 1, 2), | 321 | u64 s1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_seqno, |
340 | d3 = tfrc_rx_hist_delta_seqno(h, 2, 3), | 322 | s2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_seqno, |
341 | n2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_ndp, | 323 | s3 = tfrc_rx_hist_entry(h, 3)->tfrchrx_seqno; |
324 | u64 n2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_ndp, | ||
342 | n3 = tfrc_rx_hist_entry(h, 3)->tfrchrx_ndp; | 325 | n3 = tfrc_rx_hist_entry(h, 3)->tfrchrx_ndp; |
343 | 326 | ||
344 | if (d2 == 1 || n2 >= d2) { /* S2 is successor to S1 */ | 327 | if (dccp_loss_free(s1, s2, n2)) { |
345 | 328 | ||
346 | if (d3 == 1 || n3 >= d3) { | 329 | if (dccp_loss_free(s2, s3, n3)) { |
347 | /* S3 is successor of S2: entire hole is filled */ | 330 | /* no gap between S2 and S3: entire hole is filled */ |
348 | h->loss_start = tfrc_rx_hist_index(h, 3); | 331 | h->loss_start = tfrc_rx_hist_index(h, 3); |
349 | h->loss_count = 0; | 332 | h->loss_count = 0; |
350 | } else { | 333 | } else { |
@@ -353,7 +336,7 @@ static void __three_after_loss(struct tfrc_rx_hist *h) | |||
353 | h->loss_count = 1; | 336 | h->loss_count = 1; |
354 | } | 337 | } |
355 | 338 | ||
356 | } else { /* gap between S1 and S2 */ | 339 | } else { /* gap between S1 and S2 */ |
357 | h->loss_start = tfrc_rx_hist_index(h, 1); | 340 | h->loss_start = tfrc_rx_hist_index(h, 1); |
358 | h->loss_count = 2; | 341 | h->loss_count = 2; |
359 | } | 342 | } |
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 1b2cea244e12..32617e0576cb 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h | |||
@@ -153,6 +153,21 @@ static inline u64 max48(const u64 seq1, const u64 seq2) | |||
153 | return after48(seq1, seq2) ? seq1 : seq2; | 153 | return after48(seq1, seq2) ? seq1 : seq2; |
154 | } | 154 | } |
155 | 155 | ||
156 | /** | ||
157 | * dccp_loss_free - Evaluates condition for data loss from RFC 4340, 7.7.1 | ||
158 | * @s1: start sequence number | ||
159 | * @s2: end sequence number | ||
160 | * @ndp: NDP count on packet with sequence number @s2 | ||
161 | * Returns true if the sequence range s1...s2 has no data loss. | ||
162 | */ | ||
163 | static inline bool dccp_loss_free(const u64 s1, const u64 s2, const u64 ndp) | ||
164 | { | ||
165 | s64 delta = dccp_delta_seqno(s1, s2); | ||
166 | |||
167 | BUG_TRAP(delta >= 0); | ||
168 | return (u64)delta <= ndp + 1; | ||
169 | } | ||
170 | |||
156 | enum { | 171 | enum { |
157 | DCCP_MIB_NUM = 0, | 172 | DCCP_MIB_NUM = 0, |
158 | DCCP_MIB_ACTIVEOPENS, /* ActiveOpens */ | 173 | DCCP_MIB_ACTIVEOPENS, /* ActiveOpens */ |