aboutsummaryrefslogtreecommitdiffstats
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:36 -0400
commitd7dc7e5f49299739e610ea8febf9ea91a4dc1ae9 (patch)
tree30a2e1c3b9e99b1a386ca99efa71769415437885
parent4829007c7bc689cbc290fc09eccbe90bd52c2a5e (diff)
dccp ccid-2: Implementation of circular Ack Vector buffer with overflow handling
This completes the implementation of a circular buffer for Ack Vectors, by extending the current (linear array-based) implementation. The changes are: (a) An `overflow' flag to deal with the case of overflow. As before, dynamic growth of the buffer will not be supported; but code will be added to deal robustly with overflowing Ack Vector buffers. (b) A `tail_seqno' field. When naively implementing the algorithm of Appendix A in RFC 4340, problems arise whenever subsequent Ack Vector records overlap, which can bring the entire run length calculation completely out of synch. (This is documented on http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/\ ack_vectors/tracking_tail_ackno/ .) (c) The buffer lengthi is now computed dynamically (i.e. current fill level), as the span between head to tail. As a result, dccp_ackvec_pending() is now simpler - the #ifdef is no longer necessary since buf_empty is always true when IP_DCCP_ACKVEC is not configured. Note on overflow handling: ------------------------- The Ack Vector code previously simply started to drop packets when the Ack Vector buffer overflowed. This means that the userspace application will not be able to receive, only because of an Ack Vector storage problem. Furthermore, overflow may be transient, so that applications may later recover from the overflow. Recovering from dropped packets is more difficult (e.g. video key frames). Hence the patch uses a different policy: when the buffer overflows, the oldest entries are subsequently overwritten. This has a higher chance of recovery. Details are on http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/ack_vectors/ Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
-rw-r--r--net/dccp/ackvec.c31
-rw-r--r--net/dccp/ackvec.h17
-rw-r--r--net/dccp/dccp.h14
-rw-r--r--net/dccp/options.c10
4 files changed, 56 insertions, 16 deletions
diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c
index de84dd34c93f..1184d5e5dc96 100644
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -29,7 +29,7 @@ struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority)
29 struct dccp_ackvec *av = kmem_cache_zalloc(dccp_ackvec_slab, priority); 29 struct dccp_ackvec *av = kmem_cache_zalloc(dccp_ackvec_slab, priority);
30 30
31 if (av != NULL) { 31 if (av != NULL) {
32 av->av_buf_head = DCCPAV_MAX_ACKVEC_LEN - 1; 32 av->av_buf_head = av->av_buf_tail = DCCPAV_MAX_ACKVEC_LEN - 1;
33 INIT_LIST_HEAD(&av->av_records); 33 INIT_LIST_HEAD(&av->av_records);
34 } 34 }
35 return av; 35 return av;
@@ -72,6 +72,14 @@ int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seqno, u8 nonce_sum)
72 avr->avr_ack_nonce = nonce_sum; 72 avr->avr_ack_nonce = nonce_sum;
73 avr->avr_ack_runlen = dccp_ackvec_runlen(av->av_buf + av->av_buf_head); 73 avr->avr_ack_runlen = dccp_ackvec_runlen(av->av_buf + av->av_buf_head);
74 /* 74 /*
75 * When the buffer overflows, we keep no more than one record. This is
76 * the simplest way of disambiguating sender-Acks dating from before the
77 * overflow from sender-Acks which refer to after the overflow; a simple
78 * solution is preferable here since we are handling an exception.
79 */
80 if (av->av_overflow)
81 dccp_ackvec_purge_records(av);
82 /*
75 * Since GSS is incremented for each packet, the list is automatically 83 * Since GSS is incremented for each packet, the list is automatically
76 * arranged in descending order of @ack_seqno. 84 * arranged in descending order of @ack_seqno.
77 */ 85 */
@@ -85,6 +93,27 @@ int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seqno, u8 nonce_sum)
85} 93}
86 94
87/* 95/*
96 * Buffer index and length computation using modulo-buffersize arithmetic.
97 * Note that, as pointers move from right to left, head is `before' tail.
98 */
99static inline u16 __ackvec_idx_add(const u16 a, const u16 b)
100{
101 return (a + b) % DCCPAV_MAX_ACKVEC_LEN;
102}
103
104static inline u16 __ackvec_idx_sub(const u16 a, const u16 b)
105{
106 return __ackvec_idx_add(a, DCCPAV_MAX_ACKVEC_LEN - b);
107}
108
109u16 dccp_ackvec_buflen(const struct dccp_ackvec *av)
110{
111 if (unlikely(av->av_overflow))
112 return DCCPAV_MAX_ACKVEC_LEN;
113 return __ackvec_idx_sub(av->av_buf_tail, av->av_buf_head);
114}
115
116/*
88 * If several packets are missing, the HC-Receiver may prefer to enter multiple 117 * If several packets are missing, the HC-Receiver may prefer to enter multiple
89 * bytes with run length 0, rather than a single byte with a larger run length; 118 * bytes with run length 0, rather than a single byte with a larger run length;
90 * this simplifies table updates if one of the missing packets arrives. 119 * this simplifies table updates if one of the missing packets arrives.
diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h
index b34e5ed4c342..92f65b0fef5b 100644
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -21,6 +21,7 @@
21 * the maximum size of a single Ack Vector. Setting %DCCPAV_NUM_ACKVECS to 1 21 * the maximum size of a single Ack Vector. Setting %DCCPAV_NUM_ACKVECS to 1
22 * will be sufficient for most cases of low Ack Ratios, using a value of 2 gives 22 * will be sufficient for most cases of low Ack Ratios, using a value of 2 gives
23 * more headroom if Ack Ratio is higher or when the sender acknowledges slowly. 23 * more headroom if Ack Ratio is higher or when the sender acknowledges slowly.
24 * The maximum value is bounded by the u16 types for indices and functions.
24 */ 25 */
25#define DCCPAV_NUM_ACKVECS 2 26#define DCCPAV_NUM_ACKVECS 2
26#define DCCPAV_MAX_ACKVEC_LEN (DCCP_SINGLE_OPT_MAXLEN * DCCPAV_NUM_ACKVECS) 27#define DCCPAV_MAX_ACKVEC_LEN (DCCP_SINGLE_OPT_MAXLEN * DCCPAV_NUM_ACKVECS)
@@ -55,8 +56,10 @@ static inline u8 dccp_ackvec_state(const u8 *cell)
55 * @av_buf_head: head index; begin of live portion in @av_buf 56 * @av_buf_head: head index; begin of live portion in @av_buf
56 * @av_buf_tail: tail index; first index _after_ the live portion in @av_buf 57 * @av_buf_tail: tail index; first index _after_ the live portion in @av_buf
57 * @av_buf_ackno: highest seqno of acknowledgeable packet recorded in @av_buf 58 * @av_buf_ackno: highest seqno of acknowledgeable packet recorded in @av_buf
59 * @av_tail_ackno: lowest seqno of acknowledgeable packet recorded in @av_buf
58 * @av_buf_nonce: ECN nonce sums, each covering subsequent segments of up to 60 * @av_buf_nonce: ECN nonce sums, each covering subsequent segments of up to
59 * %DCCP_SINGLE_OPT_MAXLEN cells in the live portion of @av_buf 61 * %DCCP_SINGLE_OPT_MAXLEN cells in the live portion of @av_buf
62 * @av_overflow: if 1 then buf_head == buf_tail indicates buffer wraparound
60 * @av_records: list of %dccp_ackvec_record (Ack Vectors sent previously) 63 * @av_records: list of %dccp_ackvec_record (Ack Vectors sent previously)
61 * @av_veclen: length of the live portion of @av_buf 64 * @av_veclen: length of the live portion of @av_buf
62 */ 65 */
@@ -65,7 +68,9 @@ struct dccp_ackvec {
65 u16 av_buf_head; 68 u16 av_buf_head;
66 u16 av_buf_tail; 69 u16 av_buf_tail;
67 u64 av_buf_ackno:48; 70 u64 av_buf_ackno:48;
71 u64 av_tail_ackno:48;
68 bool av_buf_nonce[DCCPAV_NUM_ACKVECS]; 72 bool av_buf_nonce[DCCPAV_NUM_ACKVECS];
73 u8 av_overflow:1;
69 struct list_head av_records; 74 struct list_head av_records;
70 u16 av_vec_len; 75 u16 av_vec_len;
71}; 76};
@@ -113,10 +118,11 @@ extern int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb,
113 const u8 *value, const u8 len); 118 const u8 *value, const u8 len);
114 119
115extern int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8 sum); 120extern int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8 sum);
121extern u16 dccp_ackvec_buflen(const struct dccp_ackvec *av);
116 122
117static inline int dccp_ackvec_pending(const struct dccp_ackvec *av) 123static inline bool dccp_ackvec_is_empty(const struct dccp_ackvec *av)
118{ 124{
119 return av->av_vec_len; 125 return av->av_overflow == 0 && av->av_buf_head == av->av_buf_tail;
120} 126}
121#else /* CONFIG_IP_DCCP_ACKVEC */ 127#else /* CONFIG_IP_DCCP_ACKVEC */
122static inline int dccp_ackvec_init(void) 128static inline int dccp_ackvec_init(void)
@@ -160,9 +166,14 @@ static inline int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8
160 return -1; 166 return -1;
161} 167}
162 168
163static inline int dccp_ackvec_pending(const struct dccp_ackvec *av) 169static inline u16 dccp_ackvec_buflen(const struct dccp_ackvec *av)
164{ 170{
165 return 0; 171 return 0;
166} 172}
173
174static inline bool dccp_ackvec_is_empty(const struct dccp_ackvec *av)
175{
176 return true;
177}
167#endif /* CONFIG_IP_DCCP_ACKVEC */ 178#endif /* CONFIG_IP_DCCP_ACKVEC */
168#endif /* _ACKVEC_H */ 179#endif /* _ACKVEC_H */
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index e4d6e76ced41..1e65378eea3f 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -448,15 +448,15 @@ static inline void dccp_update_gss(struct sock *sk, u64 seq)
448 dp->dccps_awh = dp->dccps_gss; 448 dp->dccps_awh = dp->dccps_gss;
449} 449}
450 450
451static inline int dccp_ackvec_pending(const struct sock *sk)
452{
453 return dccp_sk(sk)->dccps_hc_rx_ackvec != NULL &&
454 !dccp_ackvec_is_empty(dccp_sk(sk)->dccps_hc_rx_ackvec);
455}
456
451static inline int dccp_ack_pending(const struct sock *sk) 457static inline int dccp_ack_pending(const struct sock *sk)
452{ 458{
453 const struct dccp_sock *dp = dccp_sk(sk); 459 return dccp_ackvec_pending(sk) || inet_csk_ack_scheduled(sk);
454 return
455#ifdef CONFIG_IP_DCCP_ACKVEC
456 (dp->dccps_hc_rx_ackvec != NULL &&
457 dccp_ackvec_pending(dp->dccps_hc_rx_ackvec)) ||
458#endif
459 inet_csk_ack_scheduled(sk);
460} 460}
461 461
462extern int dccp_feat_signal_nn_change(struct sock *sk, u8 feat, u64 nn_val); 462extern int dccp_feat_signal_nn_change(struct sock *sk, u8 feat, u64 nn_val);
diff --git a/net/dccp/options.c b/net/dccp/options.c
index 392d7db31342..3163ae980f16 100644
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -432,9 +432,10 @@ static int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
432{ 432{
433 struct dccp_sock *dp = dccp_sk(sk); 433 struct dccp_sock *dp = dccp_sk(sk);
434 struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; 434 struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec;
435 const u16 buflen = dccp_ackvec_buflen(av);
435 /* Figure out how many options do we need to represent the ackvec */ 436 /* Figure out how many options do we need to represent the ackvec */
436 const u8 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_SINGLE_OPT_MAXLEN); 437 const u8 nr_opts = DIV_ROUND_UP(buflen, DCCP_SINGLE_OPT_MAXLEN);
437 u16 len = av->av_vec_len + 2 * nr_opts; 438 u16 len = buflen + 2 * nr_opts;
438 u8 i, nonce = 0; 439 u8 i, nonce = 0;
439 const unsigned char *tail, *from; 440 const unsigned char *tail, *from;
440 unsigned char *to; 441 unsigned char *to;
@@ -445,7 +446,7 @@ static int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
445 DCCP_SKB_CB(skb)->dccpd_opt_len += len; 446 DCCP_SKB_CB(skb)->dccpd_opt_len += len;
446 447
447 to = skb_push(skb, len); 448 to = skb_push(skb, len);
448 len = av->av_vec_len; 449 len = buflen;
449 from = av->av_buf + av->av_buf_head; 450 from = av->av_buf + av->av_buf_head;
450 tail = av->av_buf + DCCPAV_MAX_ACKVEC_LEN; 451 tail = av->av_buf + DCCPAV_MAX_ACKVEC_LEN;
451 452
@@ -583,8 +584,7 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
583 if (dccp_insert_option_timestamp(sk, skb)) 584 if (dccp_insert_option_timestamp(sk, skb))
584 return -1; 585 return -1;
585 586
586 } else if (dp->dccps_hc_rx_ackvec != NULL && 587 } else if (dccp_ackvec_pending(sk) &&
587 dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) &&
588 dccp_insert_option_ackvec(sk, skb)) { 588 dccp_insert_option_ackvec(sk, skb)) {
589 return -1; 589 return -1;
590 } 590 }