aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2010-11-14 11:25:23 -0500
committerGerrit Renker <gerrit@erg.abdn.ac.uk>2010-11-15 01:11:59 -0500
commit3802408644515e29fb723d51a5317301b212cf3a (patch)
tree834533b0cf43366747ea237b43f06e4462aed94e
parent5753fdfe8bd8e9a2ff9e5af19b0ffc78bfcd502a (diff)
dccp ccid-2: Update code for the Ack Vector input/registration routine
This patch updates the code which registers new packets as received, using the new circular buffer interface. It contributes a new algorithm which * supports both tail/head pointers and buffer wrap-around and * deals with overflow (head/tail move in lock-step). Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
-rw-r--r--net/dccp/ackvec.c150
-rw-r--r--net/dccp/ackvec.h4
2 files changed, 154 insertions, 0 deletions
diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c
index e9a0f66e4afe..f7e647e608bb 100644
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -131,6 +131,156 @@ u16 dccp_ackvec_buflen(const struct dccp_ackvec *av)
131 return __ackvec_idx_sub(av->av_buf_tail, av->av_buf_head); 131 return __ackvec_idx_sub(av->av_buf_tail, av->av_buf_head);
132} 132}
133 133
134/**
135 * dccp_ackvec_update_old - Update previous state as per RFC 4340, 11.4.1
136 * @av: non-empty buffer to update
137 * @distance: negative or zero distance of @seqno from buf_ackno downward
138 * @seqno: the (old) sequence number whose record is to be updated
139 * @state: state in which packet carrying @seqno was received
140 */
141static void dccp_ackvec_update_old(struct dccp_ackvec *av, s64 distance,
142 u64 seqno, enum dccp_ackvec_states state)
143{
144 u16 ptr = av->av_buf_head;
145
146 BUG_ON(distance > 0);
147 if (unlikely(dccp_ackvec_is_empty(av)))
148 return;
149
150 do {
151 u8 runlen = dccp_ackvec_runlen(av->av_buf + ptr);
152
153 if (distance + runlen >= 0) {
154 /*
155 * Only update the state if packet has not been received
156 * yet. This is OK as per the second table in RFC 4340,
157 * 11.4.1; i.e. here we are using the following table:
158 * RECEIVED
159 * 0 1 3
160 * S +---+---+---+
161 * T 0 | 0 | 0 | 0 |
162 * O +---+---+---+
163 * R 1 | 1 | 1 | 1 |
164 * E +---+---+---+
165 * D 3 | 0 | 1 | 3 |
166 * +---+---+---+
167 * The "Not Received" state was set by reserve_seats().
168 */
169 if (av->av_buf[ptr] == DCCPAV_NOT_RECEIVED)
170 av->av_buf[ptr] = state;
171 else
172 dccp_pr_debug("Not changing %llu state to %u\n",
173 (unsigned long long)seqno, state);
174 break;
175 }
176
177 distance += runlen + 1;
178 ptr = __ackvec_idx_add(ptr, 1);
179
180 } while (ptr != av->av_buf_tail);
181}
182
183/* Mark @num entries after buf_head as "Not yet received". */
184static void dccp_ackvec_reserve_seats(struct dccp_ackvec *av, u16 num)
185{
186 u16 start = __ackvec_idx_add(av->av_buf_head, 1),
187 len = DCCPAV_MAX_ACKVEC_LEN - start;
188
189 /* check for buffer wrap-around */
190 if (num > len) {
191 memset(av->av_buf + start, DCCPAV_NOT_RECEIVED, len);
192 start = 0;
193 num -= len;
194 }
195 if (num)
196 memset(av->av_buf + start, DCCPAV_NOT_RECEIVED, num);
197}
198
199/**
200 * dccp_ackvec_add_new - Record one or more new entries in Ack Vector buffer
201 * @av: container of buffer to update (can be empty or non-empty)
202 * @num_packets: number of packets to register (must be >= 1)
203 * @seqno: sequence number of the first packet in @num_packets
204 * @state: state in which packet carrying @seqno was received
205 */
206static void dccp_ackvec_add_new(struct dccp_ackvec *av, u32 num_packets,
207 u64 seqno, enum dccp_ackvec_states state)
208{
209 u32 num_cells = num_packets;
210
211 if (num_packets > DCCPAV_BURST_THRESH) {
212 u32 lost_packets = num_packets - 1;
213
214 DCCP_WARN("Warning: large burst loss (%u)\n", lost_packets);
215 /*
216 * We received 1 packet and have a loss of size "num_packets-1"
217 * which we squeeze into num_cells-1 rather than reserving an
218 * entire byte for each lost packet.
219 * The reason is that the vector grows in O(burst_length); when
220 * it grows too large there will no room left for the payload.
221 * This is a trade-off: if a few packets out of the burst show
222 * up later, their state will not be changed; it is simply too
223 * costly to reshuffle/reallocate/copy the buffer each time.
224 * Should such problems persist, we will need to switch to a
225 * different underlying data structure.
226 */
227 for (num_packets = num_cells = 1; lost_packets; ++num_cells) {
228 u8 len = min(lost_packets, (u32)DCCPAV_MAX_RUNLEN);
229
230 av->av_buf_head = __ackvec_idx_sub(av->av_buf_head, 1);
231 av->av_buf[av->av_buf_head] = DCCPAV_NOT_RECEIVED | len;
232
233 lost_packets -= len;
234 }
235 }
236
237 if (num_cells + dccp_ackvec_buflen(av) >= DCCPAV_MAX_ACKVEC_LEN) {
238 DCCP_CRIT("Ack Vector buffer overflow: dropping old entries\n");
239 av->av_overflow = true;
240 }
241
242 av->av_buf_head = __ackvec_idx_sub(av->av_buf_head, num_packets);
243 if (av->av_overflow)
244 av->av_buf_tail = av->av_buf_head;
245
246 av->av_buf[av->av_buf_head] = state;
247 av->av_buf_ackno = seqno;
248
249 if (num_packets > 1)
250 dccp_ackvec_reserve_seats(av, num_packets - 1);
251}
252
253/**
254 * dccp_ackvec_input - Register incoming packet in the buffer
255 */
256void dccp_ackvec_input(struct dccp_ackvec *av, struct sk_buff *skb)
257{
258 u64 seqno = DCCP_SKB_CB(skb)->dccpd_seq;
259 enum dccp_ackvec_states state = DCCPAV_RECEIVED;
260
261 if (dccp_ackvec_is_empty(av)) {
262 dccp_ackvec_add_new(av, 1, seqno, state);
263 av->av_tail_ackno = seqno;
264
265 } else {
266 s64 num_packets = dccp_delta_seqno(av->av_buf_ackno, seqno);
267 u8 *current_head = av->av_buf + av->av_buf_head;
268
269 if (num_packets == 1 &&
270 dccp_ackvec_state(current_head) == state &&
271 dccp_ackvec_runlen(current_head) < DCCPAV_MAX_RUNLEN) {
272
273 *current_head += 1;
274 av->av_buf_ackno = seqno;
275
276 } else if (num_packets > 0) {
277 dccp_ackvec_add_new(av, num_packets, seqno, state);
278 } else {
279 dccp_ackvec_update_old(av, num_packets, seqno, state);
280 }
281 }
282}
283
134/* 284/*
135 * If several packets are missing, the HC-Receiver may prefer to enter multiple 285 * If several packets are missing, the HC-Receiver may prefer to enter multiple
136 * bytes with run length 0, rather than a single byte with a larger run length; 286 * bytes with run length 0, rather than a single byte with a larger run length;
diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h
index 3f7008187b8e..21c4212d1be0 100644
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -29,6 +29,9 @@
29/* Estimated minimum average Ack Vector length - used for updating MPS */ 29/* Estimated minimum average Ack Vector length - used for updating MPS */
30#define DCCPAV_MIN_OPTLEN 16 30#define DCCPAV_MIN_OPTLEN 16
31 31
32/* Threshold for coping with large bursts of losses */
33#define DCCPAV_BURST_THRESH (DCCPAV_MAX_ACKVEC_LEN / 8)
34
32enum dccp_ackvec_states { 35enum dccp_ackvec_states {
33 DCCPAV_RECEIVED = 0x00, 36 DCCPAV_RECEIVED = 0x00,
34 DCCPAV_ECN_MARKED = 0x40, 37 DCCPAV_ECN_MARKED = 0x40,
@@ -116,6 +119,7 @@ extern int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb,
116 u64 *ackno, const u8 opt, 119 u64 *ackno, const u8 opt,
117 const u8 *value, const u8 len); 120 const u8 *value, const u8 len);
118 121
122extern void dccp_ackvec_input(struct dccp_ackvec *av, struct sk_buff *skb);
119extern int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8 sum); 123extern int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8 sum);
120extern void dccp_ackvec_clear_state(struct dccp_ackvec *av, const u64 ackno); 124extern void dccp_ackvec_clear_state(struct dccp_ackvec *av, const u64 ackno);
121extern u16 dccp_ackvec_buflen(const struct dccp_ackvec *av); 125extern u16 dccp_ackvec_buflen(const struct dccp_ackvec *av);