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 | b552c6231f19d50165bbf59e8b34d3f713ab5c01 (patch) | |
tree | 7ef572ce7356789e3152120a5b9b8621954e02af /net | |
parent | 5b5d0e704880addfd979c262e6441f126708539c (diff) |
dccp ccid-3: Fix a loss detection bug
This fixes a bug in the logic of the TFRC loss detection:
* new_loss_indicated() should not be called while a loss is pending;
* but the code allows this;
* thus, for two subsequent gaps in the sequence space, when loss_count
has not yet reached NDUPACK=3, the loss_count is falsely reduced to 1.
To avoid further and similar problems, all loss handling and loss detection is
now done inside tfrc_rx_hist_handle_loss(), using an appropriate routine to
track new losses.
Further changes:
----------------
* added a reminder that no RX history operations should be performed when
rx_handle_loss() has identified a (new) loss, since the function takes
care of packet reordering during loss detection;
* made tfrc_rx_hist_loss_pending() bool (thanks to an earlier suggestion
by Arnaldo);
* removed unused functions.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Diffstat (limited to 'net')
-rw-r--r-- | net/dccp/ccids/ccid3.c | 12 | ||||
-rw-r--r-- | net/dccp/ccids/lib/packet_history.c | 24 | ||||
-rw-r--r-- | net/dccp/ccids/lib/packet_history.h | 24 |
3 files changed, 27 insertions, 33 deletions
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 523db262c18f..f6756e0c9e69 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c | |||
@@ -825,18 +825,16 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
825 | } | 825 | } |
826 | 826 | ||
827 | /* | 827 | /* |
828 | * Handle pending losses and otherwise check for new loss | 828 | * Perform loss detection and handle pending losses |
829 | */ | 829 | */ |
830 | if (tfrc_rx_hist_loss_pending(&hcrx->ccid3hcrx_hist) && | 830 | if (tfrc_rx_handle_loss(&hcrx->ccid3hcrx_hist, &hcrx->ccid3hcrx_li_hist, |
831 | tfrc_rx_handle_loss(&hcrx->ccid3hcrx_hist, | 831 | skb, ndp, ccid3_first_li, sk)) { |
832 | &hcrx->ccid3hcrx_li_hist, | ||
833 | skb, ndp, ccid3_first_li, sk) ) { | ||
834 | do_feedback = CCID3_FBACK_PARAM_CHANGE; | 832 | do_feedback = CCID3_FBACK_PARAM_CHANGE; |
835 | goto done_receiving; | 833 | goto done_receiving; |
836 | } | 834 | } |
837 | 835 | ||
838 | if (tfrc_rx_hist_new_loss_indicated(&hcrx->ccid3hcrx_hist, skb, ndp)) | 836 | if (tfrc_rx_hist_loss_pending(&hcrx->ccid3hcrx_hist)) |
839 | goto update_records; | 837 | return; /* done receiving */ |
840 | 838 | ||
841 | /* | 839 | /* |
842 | * Handle data packets: RTT sampling and monitoring p | 840 | * Handle data packets: RTT sampling and monitoring p |
diff --git a/net/dccp/ccids/lib/packet_history.c b/net/dccp/ccids/lib/packet_history.c index 712930564c38..6cc108afdc3b 100644 --- a/net/dccp/ccids/lib/packet_history.c +++ b/net/dccp/ccids/lib/packet_history.c | |||
@@ -206,10 +206,21 @@ static void tfrc_rx_hist_swap(struct tfrc_rx_hist *h, const u8 a, const u8 b) | |||
206 | * | 206 | * |
207 | * In the descriptions, `Si' refers to the sequence number of entry number i, | 207 | * In the descriptions, `Si' refers to the sequence number of entry number i, |
208 | * whose NDP count is `Ni' (lower case is used for variables). | 208 | * whose NDP count is `Ni' (lower case is used for variables). |
209 | * Note: All __after_loss functions expect that a test against duplicates has | 209 | * Note: All __xxx_loss functions expect that a test against duplicates has been |
210 | * been performed already: the seqno of the skb must not be less than the | 210 | * performed already: the seqno of the skb must not be less than the seqno |
211 | * seqno of loss_prev; and it must not equal that of any valid hist_entry. | 211 | * of loss_prev; and it must not equal that of any valid history entry. |
212 | */ | 212 | */ |
213 | static void __do_track_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u64 n1) | ||
214 | { | ||
215 | u64 s0 = tfrc_rx_hist_loss_prev(h)->tfrchrx_seqno, | ||
216 | s1 = DCCP_SKB_CB(skb)->dccpd_seq; | ||
217 | |||
218 | if (!dccp_loss_free(s0, s1, n1)) { /* gap between S0 and S1 */ | ||
219 | h->loss_count = 1; | ||
220 | tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 1), skb, n1); | ||
221 | } | ||
222 | } | ||
223 | |||
213 | static void __one_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n2) | 224 | static void __one_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n2) |
214 | { | 225 | { |
215 | u64 s0 = tfrc_rx_hist_loss_prev(h)->tfrchrx_seqno, | 226 | u64 s0 = tfrc_rx_hist_loss_prev(h)->tfrchrx_seqno, |
@@ -353,6 +364,9 @@ static void __three_after_loss(struct tfrc_rx_hist *h) | |||
353 | * Chooses action according to pending loss, updates LI database when a new | 364 | * Chooses action according to pending loss, updates LI database when a new |
354 | * loss was detected, and does required post-processing. Returns 1 when caller | 365 | * loss was detected, and does required post-processing. Returns 1 when caller |
355 | * should send feedback, 0 otherwise. | 366 | * should send feedback, 0 otherwise. |
367 | * Since it also takes care of reordering during loss detection and updates the | ||
368 | * records accordingly, the caller should not perform any more RX history | ||
369 | * operations when loss_count is greater than 0 after calling this function. | ||
356 | */ | 370 | */ |
357 | int tfrc_rx_handle_loss(struct tfrc_rx_hist *h, | 371 | int tfrc_rx_handle_loss(struct tfrc_rx_hist *h, |
358 | struct tfrc_loss_hist *lh, | 372 | struct tfrc_loss_hist *lh, |
@@ -361,7 +375,9 @@ int tfrc_rx_handle_loss(struct tfrc_rx_hist *h, | |||
361 | { | 375 | { |
362 | int is_new_loss = 0; | 376 | int is_new_loss = 0; |
363 | 377 | ||
364 | if (h->loss_count == 1) { | 378 | if (h->loss_count == 0) { |
379 | __do_track_loss(h, skb, ndp); | ||
380 | } else if (h->loss_count == 1) { | ||
365 | __one_after_loss(h, skb, ndp); | 381 | __one_after_loss(h, skb, ndp); |
366 | } else if (h->loss_count != 2) { | 382 | } else if (h->loss_count != 2) { |
367 | DCCP_BUG("invalid loss_count %d", h->loss_count); | 383 | DCCP_BUG("invalid loss_count %d", h->loss_count); |
diff --git a/net/dccp/ccids/lib/packet_history.h b/net/dccp/ccids/lib/packet_history.h index 6976156cda3c..461cc91cce88 100644 --- a/net/dccp/ccids/lib/packet_history.h +++ b/net/dccp/ccids/lib/packet_history.h | |||
@@ -118,30 +118,10 @@ static inline struct tfrc_rx_hist_entry * | |||
118 | return h->ring[h->loss_start]; | 118 | return h->ring[h->loss_start]; |
119 | } | 119 | } |
120 | 120 | ||
121 | /* initialise loss detection and disable RTT sampling */ | ||
122 | static inline void tfrc_rx_hist_loss_indicated(struct tfrc_rx_hist *h) | ||
123 | { | ||
124 | h->loss_count = 1; | ||
125 | } | ||
126 | |||
127 | /* indicate whether previously a packet was detected missing */ | 121 | /* indicate whether previously a packet was detected missing */ |
128 | static inline int tfrc_rx_hist_loss_pending(const struct tfrc_rx_hist *h) | 122 | static inline bool tfrc_rx_hist_loss_pending(const struct tfrc_rx_hist *h) |
129 | { | ||
130 | return h->loss_count; | ||
131 | } | ||
132 | |||
133 | /* any data packets missing between last reception and skb ? */ | ||
134 | static inline int tfrc_rx_hist_new_loss_indicated(struct tfrc_rx_hist *h, | ||
135 | const struct sk_buff *skb, | ||
136 | u32 ndp) | ||
137 | { | 123 | { |
138 | int delta = dccp_delta_seqno(tfrc_rx_hist_last_rcv(h)->tfrchrx_seqno, | 124 | return h->loss_count > 0; |
139 | DCCP_SKB_CB(skb)->dccpd_seq); | ||
140 | |||
141 | if (delta > 1 && ndp < delta) | ||
142 | tfrc_rx_hist_loss_indicated(h); | ||
143 | |||
144 | return tfrc_rx_hist_loss_pending(h); | ||
145 | } | 125 | } |
146 | 126 | ||
147 | extern void tfrc_rx_hist_add_packet(struct tfrc_rx_hist *h, | 127 | extern void tfrc_rx_hist_add_packet(struct tfrc_rx_hist *h, |