aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2010-11-10 15:21:35 -0500
committerGerrit Renker <gerrit@erg.abdn.ac.uk>2010-11-10 15:21:35 -0500
commitb3d14bff12a38ad13a174eb0cc83d2ac7169eee4 (patch)
tree2248e4d994ce857113c34ce5f754c554e17d8d9e /net
parent7d870936602533836bba821bd5c679c62c52a95f (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 length 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. Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Diffstat (limited to 'net')
-rw-r--r--net/dccp/ackvec.c31
-rw-r--r--net/dccp/ackvec.h10
-rw-r--r--net/dccp/dccp.h11
-rw-r--r--net/dccp/options.c10
4 files changed, 50 insertions, 12 deletions
diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c
index af976fca407a..abaf241c7353 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 3e894a0173a7..23880be8fc29 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};
@@ -112,9 +117,10 @@ extern int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb,
112 const u8 *value, const u8 len); 117 const u8 *value, const u8 len);
113 118
114extern int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8 sum); 119extern int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8 sum);
120extern u16 dccp_ackvec_buflen(const struct dccp_ackvec *av);
115 121
116static inline int dccp_ackvec_pending(const struct dccp_ackvec *av) 122static inline bool dccp_ackvec_is_empty(const struct dccp_ackvec *av)
117{ 123{
118 return av->av_vec_len; 124 return av->av_overflow == 0 && av->av_buf_head == av->av_buf_tail;
119} 125}
120#endif /* _ACKVEC_H */ 126#endif /* _ACKVEC_H */
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index a8ed459508b2..19fafd597465 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -457,12 +457,15 @@ static inline void dccp_update_gss(struct sock *sk, u64 seq)
457 dp->dccps_awh = dp->dccps_gss; 457 dp->dccps_awh = dp->dccps_gss;
458} 458}
459 459
460static inline int dccp_ackvec_pending(const struct sock *sk)
461{
462 return dccp_sk(sk)->dccps_hc_rx_ackvec != NULL &&
463 !dccp_ackvec_is_empty(dccp_sk(sk)->dccps_hc_rx_ackvec);
464}
465
460static inline int dccp_ack_pending(const struct sock *sk) 466static inline int dccp_ack_pending(const struct sock *sk)
461{ 467{
462 const struct dccp_sock *dp = dccp_sk(sk); 468 return dccp_ackvec_pending(sk) || inet_csk_ack_scheduled(sk);
463 return (dp->dccps_hc_rx_ackvec != NULL &&
464 dccp_ackvec_pending(dp->dccps_hc_rx_ackvec)) ||
465 inet_csk_ack_scheduled(sk);
466} 469}
467 470
468extern int dccp_feat_finalise_settings(struct dccp_sock *dp); 471extern int dccp_feat_finalise_settings(struct dccp_sock *dp);
diff --git a/net/dccp/options.c b/net/dccp/options.c
index f4ff0a308269..5adeeed5e0d2 100644
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -429,9 +429,10 @@ static int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
429{ 429{
430 struct dccp_sock *dp = dccp_sk(sk); 430 struct dccp_sock *dp = dccp_sk(sk);
431 struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; 431 struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec;
432 const u16 buflen = dccp_ackvec_buflen(av);
432 /* Figure out how many options do we need to represent the ackvec */ 433 /* Figure out how many options do we need to represent the ackvec */
433 const u8 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_SINGLE_OPT_MAXLEN); 434 const u8 nr_opts = DIV_ROUND_UP(buflen, DCCP_SINGLE_OPT_MAXLEN);
434 u16 len = av->av_vec_len + 2 * nr_opts; 435 u16 len = buflen + 2 * nr_opts;
435 u8 i, nonce = 0; 436 u8 i, nonce = 0;
436 const unsigned char *tail, *from; 437 const unsigned char *tail, *from;
437 unsigned char *to; 438 unsigned char *to;
@@ -442,7 +443,7 @@ static int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
442 DCCP_SKB_CB(skb)->dccpd_opt_len += len; 443 DCCP_SKB_CB(skb)->dccpd_opt_len += len;
443 444
444 to = skb_push(skb, len); 445 to = skb_push(skb, len);
445 len = av->av_vec_len; 446 len = buflen;
446 from = av->av_buf + av->av_buf_head; 447 from = av->av_buf + av->av_buf_head;
447 tail = av->av_buf + DCCPAV_MAX_ACKVEC_LEN; 448 tail = av->av_buf + DCCPAV_MAX_ACKVEC_LEN;
448 449
@@ -580,8 +581,7 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
580 if (dccp_insert_option_timestamp(skb)) 581 if (dccp_insert_option_timestamp(skb))
581 return -1; 582 return -1;
582 583
583 } else if (dp->dccps_hc_rx_ackvec != NULL && 584 } else if (dccp_ackvec_pending(sk) &&
584 dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) &&
585 dccp_insert_option_ackvec(sk, skb)) { 585 dccp_insert_option_ackvec(sk, skb)) {
586 return -1; 586 return -1;
587 } 587 }