From f17a37c9b8c4b32c01e501a84fa6f30e344c6110 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 10 Nov 2010 21:20:07 +0100 Subject: dccp ccid-2: Ack Vector interface clean-up This patch brings the Ack Vector interface up to date. Its main purpose is to lay the basis for the subsequent patches of this set, which will use the new data structure fields and routines. There are no real algorithmic changes, rather an adaptation: (1) Replaced the static Ack Vector size (2) with a #define so that it can be adapted (with low loss / Ack Ratio, a value of 1 works, so 2 seems to be sufficient for the moment) and added a solution so that computing the ECN nonce will continue to work - even with larger Ack Vectors. (2) Replaced the #defines for Ack Vector states with a complete enum. (3) Replaced #defines to compute Ack Vector length and state with general purpose routines (inlines), and updated code to use these. (4) Added a `tail' field (conversion to circular buffer in subsequent patch). (5) Updated the (outdated) documentation for Ack Vector struct. (6) All sequence number containers now trimmed to 48 bits. (7) Removal of unused bits: * removed dccpav_ack_nonce from struct dccp_ackvec, since this is already redundantly stored in the `dccpavr_ack_nonce' (of Ack Vector record); * removed Elapsed Time for Ack Vectors (it was nowhere used); * replaced semantics of dccpavr_sent_len with dccpavr_ack_runlen, since the code needs to be able to remember the old run length; * reduced the de-/allocation routines (redundant / duplicate tests). Signed-off-by: Gerrit Renker --- net/dccp/ackvec.h | 103 +++++++++++++++++++++++++++++------------------------- 1 file changed, 56 insertions(+), 47 deletions(-) (limited to 'net/dccp/ackvec.h') diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h index 7ea557b..ebcbbc7 100644 --- a/net/dccp/ackvec.h +++ b/net/dccp/ackvec.h @@ -3,9 +3,9 @@ /* * net/dccp/ackvec.h * - * An implementation of the DCCP protocol + * An implementation of Ack Vectors for the DCCP protocol + * Copyright (c) 2007 University of Aberdeen, Scotland, UK * Copyright (c) 2005 Arnaldo Carvalho de Melo - * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. @@ -13,75 +13,84 @@ #include #include -#include #include #include -/* We can spread an ack vector across multiple options */ -#define DCCP_MAX_ACKVEC_LEN (DCCP_SINGLE_OPT_MAXLEN * 2) +/* + * Ack Vector buffer space is static, in multiples of %DCCP_SINGLE_OPT_MAXLEN, + * the maximum size of a single Ack Vector. Setting %DCCPAV_NUM_ACKVECS to 1 + * will be sufficient for most cases of low Ack Ratios, using a value of 2 gives + * more headroom if Ack Ratio is higher or when the sender acknowledges slowly. + */ +#define DCCPAV_NUM_ACKVECS 2 +#define DCCPAV_MAX_ACKVEC_LEN (DCCP_SINGLE_OPT_MAXLEN * DCCPAV_NUM_ACKVECS) /* Estimated minimum average Ack Vector length - used for updating MPS */ #define DCCPAV_MIN_OPTLEN 16 -#define DCCP_ACKVEC_STATE_RECEIVED 0 -#define DCCP_ACKVEC_STATE_ECN_MARKED (1 << 6) -#define DCCP_ACKVEC_STATE_NOT_RECEIVED (3 << 6) +enum dccp_ackvec_states { + DCCPAV_RECEIVED = 0x00, + DCCPAV_ECN_MARKED = 0x40, + DCCPAV_RESERVED = 0x80, + DCCPAV_NOT_RECEIVED = 0xC0 +}; +#define DCCPAV_MAX_RUNLEN 0x3F -#define DCCP_ACKVEC_STATE_MASK 0xC0 /* 11000000 */ -#define DCCP_ACKVEC_LEN_MASK 0x3F /* 00111111 */ +static inline u8 dccp_ackvec_runlen(const u8 *cell) +{ + return *cell & DCCPAV_MAX_RUNLEN; +} -/** struct dccp_ackvec - ack vector - * - * This data structure is the one defined in RFC 4340, Appendix A. - * - * @av_buf_head - circular buffer head - * @av_buf_tail - circular buffer tail - * @av_buf_ackno - ack # of the most recent packet acknowledgeable in the - * buffer (i.e. %av_buf_head) - * @av_buf_nonce - the one-bit sum of the ECN Nonces on all packets acked - * by the buffer with State 0 - * - * Additionally, the HC-Receiver must keep some information about the - * Ack Vectors it has recently sent. For each packet sent carrying an - * Ack Vector, it remembers four variables: +static inline u8 dccp_ackvec_state(const u8 *cell) +{ + return *cell & ~DCCPAV_MAX_RUNLEN; +} + +/** struct dccp_ackvec - Ack Vector main data structure * - * @av_records - list of dccp_ackvec_record - * @av_ack_nonce - the one-bit sum of the ECN Nonces for all State 0. + * This implements a fixed-size circular buffer within an array and is largely + * based on Appendix A of RFC 4340. * - * @av_time - the time in usecs - * @av_buf - circular buffer of acknowledgeable packets + * @av_buf: circular buffer storage area + * @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_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_records: list of %dccp_ackvec_record (Ack Vectors sent previously) + * @av_veclen: length of the live portion of @av_buf */ struct dccp_ackvec { - u64 av_buf_ackno; - struct list_head av_records; - ktime_t av_time; + u8 av_buf[DCCPAV_MAX_ACKVEC_LEN]; u16 av_buf_head; + u16 av_buf_tail; + u64 av_buf_ackno:48; + bool av_buf_nonce[DCCPAV_NUM_ACKVECS]; + struct list_head av_records; u16 av_vec_len; - u8 av_buf_nonce; - u8 av_ack_nonce; - u8 av_buf[DCCP_MAX_ACKVEC_LEN]; }; -/** struct dccp_ackvec_record - ack vector record +/** struct dccp_ackvec_record - Records information about sent Ack Vectors * - * ACK vector record as defined in Appendix A of spec. + * These list entries define the additional information which the HC-Receiver + * keeps about recently-sent Ack Vectors; again refer to RFC 4340, Appendix A. * - * The list is sorted by avr_ack_seqno + * @avr_node: the list node in @av_records + * @avr_ack_seqno: sequence number of the packet the Ack Vector was sent on + * @avr_ack_ackno: the Ack number that this record/Ack Vector refers to + * @avr_ack_ptr: pointer into @av_buf where this record starts + * @avr_ack_runlen: run length of @avr_ack_ptr at the time of sending + * @avr_ack_nonce: the sum of @av_buf_nonce's at the time this record was sent * - * @avr_node - node in av_records - * @avr_ack_seqno - sequence number of the packet this record was sent on - * @avr_ack_ackno - sequence number being acknowledged - * @avr_ack_ptr - pointer into av_buf where this record starts - * @avr_ack_nonce - av_ack_nonce at the time this record was sent - * @avr_sent_len - lenght of the record in av_buf + * The list as a whole is sorted in descending order by @avr_ack_seqno. */ struct dccp_ackvec_record { struct list_head avr_node; - u64 avr_ack_seqno; - u64 avr_ack_ackno; + u64 avr_ack_seqno:48; + u64 avr_ack_ackno:48; u16 avr_ack_ptr; - u16 avr_sent_len; - u8 avr_ack_nonce; + u8 avr_ack_runlen; + u8 avr_ack_nonce:1; }; struct sock; -- cgit v1.1 From 7d870936602533836bba821bd5c679c62c52a95f Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 10 Nov 2010 21:21:02 +0100 Subject: dccp ccid-2: Separate internals of Ack Vectors from option-parsing code This patch * separates Ack Vector housekeeping code from option-insertion code; * shifts option-specific code from ackvec.c into options.c; * introduces a dedicated routine to take care of the Ack Vector records; * simplifies the dccp_ackvec_insert_avr() routine: the BUG_ON was redundant, since the list is automatically arranged in descending order of ack_seqno. Signed-off-by: Gerrit Renker --- net/dccp/ackvec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/dccp/ackvec.h') diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h index ebcbbc7..3e894a0 100644 --- a/net/dccp/ackvec.h +++ b/net/dccp/ackvec.h @@ -111,7 +111,7 @@ extern int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb, u64 *ackno, const u8 opt, const u8 *value, const u8 len); -extern int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb); +extern int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8 sum); static inline int dccp_ackvec_pending(const struct dccp_ackvec *av) { -- cgit v1.1 From b3d14bff12a38ad13a174eb0cc83d2ac7169eee4 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 10 Nov 2010 21:21:35 +0100 Subject: 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 --- net/dccp/ackvec.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'net/dccp/ackvec.h') diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h index 3e894a0..23880be 100644 --- a/net/dccp/ackvec.h +++ b/net/dccp/ackvec.h @@ -21,6 +21,7 @@ * the maximum size of a single Ack Vector. Setting %DCCPAV_NUM_ACKVECS to 1 * will be sufficient for most cases of low Ack Ratios, using a value of 2 gives * more headroom if Ack Ratio is higher or when the sender acknowledges slowly. + * The maximum value is bounded by the u16 types for indices and functions. */ #define DCCPAV_NUM_ACKVECS 2 #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) * @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 */ @@ -65,7 +68,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; }; @@ -112,9 +117,10 @@ extern int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb, const u8 *value, const u8 len); extern int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8 sum); +extern u16 dccp_ackvec_buflen(const struct dccp_ackvec *av); -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; } #endif /* _ACKVEC_H */ -- cgit v1.1 From 5753fdfe8bd8e9a2ff9e5af19b0ffc78bfcd502a Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Sun, 14 Nov 2010 17:25:11 +0100 Subject: dccp ccid-2: Algorithm to update buffer state This provides a routine to consistently update the buffer state when the peer acknowledges receipt of Ack Vectors; updating state in the list of Ack Vectors as well as in the circular buffer. While based on RFC 4340, several additional (and necessary) precautions were added to protect the consistency of the buffer state. These additions are essential, since analysis and experience showed that the basic algorithm was insufficient for this task (which lead to problems that were hard to debug). The algorithm now * deals with HC-sender acknowledging to HC-receiver and vice versa, * keeps track of the last unacknowledged but received seqno in tail_ackno, * has special cases to reset the overflow condition when appropriate, * is protected against receiving older information (would mess up buffer state). Signed-off-by: Gerrit Renker --- net/dccp/ackvec.h | 1 + 1 file changed, 1 insertion(+) (limited to 'net/dccp/ackvec.h') diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h index 23880be..3f70081 100644 --- a/net/dccp/ackvec.h +++ b/net/dccp/ackvec.h @@ -117,6 +117,7 @@ extern int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb, const u8 *value, const u8 len); 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); extern u16 dccp_ackvec_buflen(const struct dccp_ackvec *av); static inline bool dccp_ackvec_is_empty(const struct dccp_ackvec *av) -- cgit v1.1 From 3802408644515e29fb723d51a5317301b212cf3a Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Sun, 14 Nov 2010 17:25:23 +0100 Subject: dccp ccid-2: Update code for the Ack Vector input/registration routine This patch updates 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). Signed-off-by: Gerrit Renker --- net/dccp/ackvec.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net/dccp/ackvec.h') diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h index 3f70081..21c4212 100644 --- a/net/dccp/ackvec.h +++ b/net/dccp/ackvec.h @@ -29,6 +29,9 @@ /* Estimated minimum average Ack Vector length - used for updating MPS */ #define DCCPAV_MIN_OPTLEN 16 +/* Threshold for coping with large bursts of losses */ +#define DCCPAV_BURST_THRESH (DCCPAV_MAX_ACKVEC_LEN / 8) + enum dccp_ackvec_states { DCCPAV_RECEIVED = 0x00, DCCPAV_ECN_MARKED = 0x40, @@ -116,6 +119,7 @@ extern int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb, u64 *ackno, const u8 opt, const u8 *value, const u8 len); +extern void dccp_ackvec_input(struct dccp_ackvec *av, struct sk_buff *skb); 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); extern u16 dccp_ackvec_buflen(const struct dccp_ackvec *av); -- cgit v1.1 From 52394eecec4e6fa677a61af26f0bd35de665344e Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Sun, 14 Nov 2010 17:26:02 +0100 Subject: dccp ccid-2: Remove old infrastructure This removes * functions for which updates have been provided in the preceding patches and * the @av_vec_len field - it is no longer necessary since the buffer length is now always computed dynamically. Signed-off-by: Gerrit Renker --- net/dccp/ackvec.h | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'net/dccp/ackvec.h') diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h index 21c4212..e19b8d5 100644 --- a/net/dccp/ackvec.h +++ b/net/dccp/ackvec.h @@ -64,7 +64,6 @@ static inline u8 dccp_ackvec_state(const u8 *cell) * %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 */ struct dccp_ackvec { u8 av_buf[DCCPAV_MAX_ACKVEC_LEN]; @@ -75,7 +74,6 @@ struct dccp_ackvec { bool av_buf_nonce[DCCPAV_NUM_ACKVECS]; u8 av_overflow:1; struct list_head av_records; - u16 av_vec_len; }; /** struct dccp_ackvec_record - Records information about sent Ack Vectors @@ -101,24 +99,12 @@ struct dccp_ackvec_record { u8 avr_ack_nonce:1; }; -struct sock; -struct sk_buff; - extern int dccp_ackvec_init(void); extern void dccp_ackvec_exit(void); extern struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority); extern void dccp_ackvec_free(struct dccp_ackvec *av); -extern int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk, - const u64 ackno, const u8 state); - -extern void dccp_ackvec_check_rcv_ackno(struct dccp_ackvec *av, - struct sock *sk, const u64 ackno); -extern int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb, - u64 *ackno, const u8 opt, - const u8 *value, const u8 len); - extern void dccp_ackvec_input(struct dccp_ackvec *av, struct sk_buff *skb); 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); -- cgit v1.1 From 7e87fe84303cc54ecf3c7b688cb08ca24322a41d Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Sun, 14 Nov 2010 17:26:13 +0100 Subject: dccp ccid-2: Separate option parsing from CCID processing This patch replaces an almost identical replication of code: large parts of dccp_parse_options() re-appeared as ccid2_ackvector() in ccid2.c. Apart from the duplication, this caused two more problems: 1. CCIDs should not need to be concerned with parsing header options; 2. one can not assume that Ack Vectors appear as a contiguous area within an skb, it is legal to insert other options and/or padding in between. The current code would throw an error and stop reading in such a case. Since Ack Vectors provide CCID-specific information, they are now processed by the CCID directly, separating this functionality from the main DCCP code. Signed-off-by: Gerrit Renker --- net/dccp/ackvec.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'net/dccp/ackvec.h') diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h index e19b8d5..e2ab062 100644 --- a/net/dccp/ackvec.h +++ b/net/dccp/ackvec.h @@ -114,4 +114,23 @@ static inline bool dccp_ackvec_is_empty(const struct dccp_ackvec *av) { return av->av_overflow == 0 && av->av_buf_head == av->av_buf_tail; } + +/** + * struct dccp_ackvec_parsed - Record offsets of Ack Vectors in skb + * @vec: start of vector (offset into skb) + * @len: length of @vec + * @nonce: whether @vec had an ECN nonce of 0 or 1 + * @node: FIFO - arranged in descending order of ack_ackno + * This structure is used by CCIDs to access Ack Vectors in a received skb. + */ +struct dccp_ackvec_parsed { + u8 *vec, + len, + nonce:1; + struct list_head node; +}; + +extern int dccp_ackvec_parsed_add(struct list_head *head, + u8 *vec, u8 len, u8 nonce); +extern void dccp_ackvec_parsed_cleanup(struct list_head *parsed_chunks); #endif /* _ACKVEC_H */ -- cgit v1.1