aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2008-09-04 01:30:19 -0400
committerGerrit Renker <gerrit@erg.abdn.ac.uk>2008-09-04 01:45:37 -0400
commite28fe59f9c82ef55fc9b55e745531c9fed86f00a (patch)
tree3b469804ebeb8e772c9f935015381706495cdd18 /net/dccp
parent68b1de15765f2b0e0925e692dab2b2fa2abd93fc (diff)
dccp ccid-2: Update code for the Ack Vector input/registration routine
This patch uupdates 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). The updated code is also partioned differently, into 1. dealing with the empty buffer, 2. adding new packets into non-empty buffer, 3. reserving space when encountering a `hole' in the sequence space, 4. updating old state and deciding when old state is irrelevant. Protection against large burst losses: With regard to (3), it is too costly to reserve space when there are large bursts of losses. When bursts get too large, the code does no longer reserve space and just fills in cells normally. This measure reduces space consumption by a factor of 63. The code reuses in part the previous implementation by Arnaldo de Melo. Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Diffstat (limited to 'net/dccp')
-rw-r--r--net/dccp/ackvec.c150
-rw-r--r--net/dccp/ackvec.h9
2 files changed, 159 insertions, 0 deletions
diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c
index f1341a617f96..bf9cb7d7549d 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 b757e9b4110f..36ca2e9e5c84 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,
@@ -117,6 +120,7 @@ extern int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb,
117 u64 *ackno, const u8 opt, 120 u64 *ackno, const u8 opt,
118 const u8 *value, const u8 len); 121 const u8 *value, const u8 len);
119 122
123extern void dccp_ackvec_input(struct dccp_ackvec *av, struct sk_buff *skb);
120extern int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8 sum); 124extern int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8 sum);
121extern void dccp_ackvec_clear_state(struct dccp_ackvec *av, const u64 ackno); 125extern void dccp_ackvec_clear_state(struct dccp_ackvec *av, const u64 ackno);
122extern u16 dccp_ackvec_buflen(const struct dccp_ackvec *av); 126extern u16 dccp_ackvec_buflen(const struct dccp_ackvec *av);
@@ -144,6 +148,11 @@ static inline void dccp_ackvec_free(struct dccp_ackvec *av)
144{ 148{
145} 149}
146 150
151static inline void dccp_ackvec_input(struct dccp_ackvec *av, struct sk_buff *skb)
152{
153
154}
155
147static inline int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk, 156static inline int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
148 const u64 ackno, const u8 state) 157 const u64 ackno, const u8 state)
149{ 158{