[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1198074355-18842-10-git-send-email-gerrit@erg.abdn.ac.uk>
Date: Wed, 19 Dec 2007 14:25:50 +0000
From: Gerrit Renker <gerrit@....abdn.ac.uk>
To: acme@...hat.com
Cc: dccp@...r.kernel.org, netdev@...r.kernel.org,
Gerrit Renker <gerrit@....abdn.ac.uk>
Subject: [PATCH 09/14] [ACKVEC]: Support for circular Ack Vector buffer with overflow handling
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 <gerrit@....abdn.ac.uk>
---
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 majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists