This adds missing bits to complete the implementation of a circular buffer for
Ack Vector information, with the following changes:

 (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
     more gracefully with overflowing Ack Vector buffers (if that ever happens).

 (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/ .)

This further allowed to simplify dccp_ackvec_pending() - 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 get its data, only because of an Ack Vector problem.

 Furthermore, overflow may be transient, so that the application later
 recovers from the overflow. Recovering from lost 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 <[EMAIL PROTECTED]>
---
 net/dccp/ackvec.c  |   11 ++++++++++-
 net/dccp/ackvec.h  |   12 ++++++++----
 net/dccp/dccp.h    |   14 +++++++-------
 net/dccp/options.c |    5 ++---
 4 files changed, 27 insertions(+), 15 deletions(-)

--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -53,8 +53,10 @@ static inline u8 dccp_ackvec_state(const u8 *cell)
  * @av_buf_head:   head index; begin of live portion in @av_buf
  * @av_buf_tail:   tail index; first index _after_ the live portion in @av_buf
  * @av_buf_ackno:  highest seqno of acknowledgeable packet recorded in @av_buf
+ * @av_tail_ackno: lowest  seqno of acknowledgeable packet recorded in @av_buf
  * @av_buf_nonce:  ECN nonce sums, each covering subsequent segments of up to
  *                %DCCP_SINGLE_OPT_MAXLEN cells in the live portion of @av_buf
+ * @av_overflow:   if 1 then buf_head == buf_tail indicates buffer wraparound
  * @av_records:           list of %dccp_ackvec_record (Ack Vectors sent 
previously)
  * @av_veclen:    length of the live portion of @av_buf
  */
@@ -63,7 +65,9 @@ struct dccp_ackvec {
        u16                     av_buf_head;
        u16                     av_buf_tail;
        u64                     av_buf_ackno:48;
+       u64                     av_tail_ackno:48;
        bool                    av_buf_nonce[DCCPAV_NUM_ACKVECS];
+       u8                      av_overflow:1;
        struct list_head        av_records;
        u16                     av_vec_len;
 };
@@ -107,9 +111,9 @@ extern int dccp_ackvec_add(struct dccp_ackvec *av, const 
struct sock *sk,
 extern int  dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8 
sum);
 extern void dccp_ackvec_clear_state(struct dccp_ackvec *av, const u64 ackno);
 
-static inline int dccp_ackvec_pending(const struct dccp_ackvec *av)
+static inline bool dccp_ackvec_is_empty(const struct dccp_ackvec *av)
 {
-       return av->av_vec_len;
+       return av->av_overflow == 0 && av->av_buf_head == av->av_buf_tail;
 }
 #else /* CONFIG_IP_DCCP_ACKVEC */
 static inline int dccp_ackvec_init(void)
@@ -145,9 +149,9 @@ static inline int dccp_ackvec_update_records(struct 
dccp_ackvec *av, u64 seq, u8
        return -1;
 }
 
-static inline int dccp_ackvec_pending(const struct dccp_ackvec *av)
+static inline bool dccp_ackvec_is_empty(const struct dccp_ackvec *av)
 {
-       return 0;
+       return true;
 }
 #endif /* CONFIG_IP_DCCP_ACKVEC */
 #endif /* _ACKVEC_H */
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -29,7 +29,8 @@ struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority)
        struct dccp_ackvec *av = kmem_cache_alloc(dccp_ackvec_slab, priority);
 
        if (av != NULL) {
-               av->av_buf_head  = DCCPAV_MAX_ACKVEC_LEN - 1;
+               av->av_buf_head = av->av_buf_tail = DCCPAV_MAX_ACKVEC_LEN - 1;
+               av->av_overflow = 0;
                av->av_vec_len   = 0;
                memset(av->av_buf_nonce, 0, sizeof(av->av_buf_nonce));
                INIT_LIST_HEAD(&av->av_records);
@@ -74,6 +75,14 @@ int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 
seqno, u8 nonce_sum)
        avr->avr_ack_nonce  = nonce_sum;
        avr->avr_ack_runlen = dccp_ackvec_runlen(av->av_buf + av->av_buf_head);
        /*
+        * When the buffer overflows, we keep no more than one record. This is
+        * the simplest way of disambiguating sender-Acks dating from before the
+        * overflow from sender-Acks which refer to after the overflow; a simple
+        * solution is preferable here since we are handling an exception.
+        */
+       if (av->av_overflow)
+               dccp_ackvec_purge_records(av);
+       /*
         * Since GSS is incremented for each packet, the list is automatically
         * arranged in descending order of @ack_seqno.
         */
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -410,15 +410,15 @@ static inline void dccp_schedule_ack(struct sock *sk)
        inet_csk_schedule_ack(sk);
 }
 
+static inline int dccp_ackvec_pending(const struct sock *sk)
+{
+       return dccp_sk(sk)->dccps_hc_rx_ackvec != NULL &&
+              !dccp_ackvec_is_empty(dccp_sk(sk)->dccps_hc_rx_ackvec);
+}
+
 static inline int dccp_ack_pending(const struct sock *sk)
 {
-       const struct dccp_sock *dp = dccp_sk(sk);
-       return
-#ifdef CONFIG_IP_DCCP_ACKVEC
-              (dp->dccps_hc_rx_ackvec != NULL &&
-               dccp_ackvec_pending(dp->dccps_hc_rx_ackvec)) ||
-#endif
-              inet_csk_ack_scheduled(sk);
+       return dccp_ackvec_pending(sk) || inet_csk_ack_scheduled(sk);
 }
 
 extern int  dccp_feat_signal_nn_change(struct sock *sk, u8 feat, u64 nn_val);
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -589,9 +589,8 @@ int dccp_insert_options(struct sock *sk, struct sk_buff 
*skb)
                        if (dccp_insert_option_timestamp(sk, skb))
                                return -1;
 
-               } else if (dp->dccps_hc_rx_ackvec != NULL &&
-                          dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) &&
-                          dccp_insert_option_ackvec(sk, skb)            ) {
+               } else if (dccp_ackvec_pending(sk) &&
+                          dccp_insert_option_ackvec(sk, skb)) {
                                return -1;
                }
        }
-- 
1.5.3.GIT

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to