The patch set migrates TFRC TX history to a singly-linked list. The details are: * use of a consistent naming scheme (all TFRC functions now begin with `tfrc_'); * allocation and cleanup are taken care of internally; * provision of a lookup function, which is used by the CCID TX infrastructure to determine the time a packet was sent (in turn used for RTT sampling); * integration of the new interface with the present use in CCID3.
Signed-off-by: Gerrit Renker <[EMAIL PROTECTED]> Signed-off-by: Ian McDonald <[EMAIL PROTECTED]> --- net/dccp/ccids/ccid3.c | 53 ++++++------------- net/dccp/ccids/ccid3.h | 3 +- net/dccp/ccids/lib/packet_history.c | 100 +++++++++++++++++++++++++++++++++- net/dccp/ccids/lib/packet_history.h | 42 ++++++++++++++- 4 files changed, 155 insertions(+), 43 deletions(-) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index e07d817..51fd07b 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -49,7 +49,7 @@ static int ccid3_debug; #define ccid3_pr_debug(format, a...) #endif -static struct dccp_tx_hist *ccid3_tx_hist; +DECLARE_TFRC_TX_CACHE(ccid3_tx_hist); static struct dccp_rx_hist *ccid3_rx_hist; /* @@ -389,29 +389,18 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len) { struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); - struct dccp_tx_hist_entry *packet; ccid3_hc_tx_update_s(hctx, len); - packet = dccp_tx_hist_entry_new(ccid3_tx_hist, GFP_ATOMIC); - if (unlikely(packet == NULL)) { + if (tfrc_tx_hist_add(&hctx->ccid3hctx_hist, dccp_sk(sk)->dccps_gss)) DCCP_CRIT("packet history - out of memory!"); - return; - } - dccp_tx_hist_add_entry(&hctx->ccid3hctx_hist, packet); - - packet->dccphtx_tstamp = ktime_get_real(); - packet->dccphtx_seqno = dccp_sk(sk)->dccps_gss; - packet->dccphtx_rtt = hctx->ccid3hctx_rtt; - packet->dccphtx_sent = 1; } static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) { struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); struct ccid3_options_received *opt_recv; - struct dccp_tx_hist_entry *packet; - ktime_t now; + ktime_t t_send, now; unsigned long t_nfb; u32 pinv, r_sample; @@ -425,14 +414,12 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) switch (hctx->ccid3hctx_state) { case TFRC_SSTATE_NO_FBACK: case TFRC_SSTATE_FBACK: - /* get packet from history to look up t_recvdata */ - packet = dccp_tx_hist_find_entry(&hctx->ccid3hctx_hist, - DCCP_SKB_CB(skb)->dccpd_ack_seq); - if (unlikely(packet == NULL)) { - DCCP_WARN("%s(%p), seqno %llu(%s) doesn't exist " - "in history!\n", dccp_role(sk), sk, - (unsigned long long)DCCP_SKB_CB(skb)->dccpd_ack_seq, - dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type)); + /* estimate RTT from history if ACK number is valid */ + if (! tfrc_tx_hist_when(&t_send, &hctx->ccid3hctx_hist, + DCCP_SKB_CB(skb)->dccpd_ack_seq)) { + DCCP_WARN("%s(%p): %s with bogus ACK-%llu\n", dccp_role(sk), sk, + dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type), + (unsigned long long)DCCP_SKB_CB(skb)->dccpd_ack_seq); return; } @@ -451,7 +438,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) /* * Calculate new RTT sample and update moving average */ - r_sample = dccp_sample_rtt(sk, ktime_us_delta(now, packet->dccphtx_tstamp)); + r_sample = dccp_sample_rtt(sk, ktime_us_delta(now, t_send)); hctx->ccid3hctx_rtt = tfrc_ewma(hctx->ccid3hctx_rtt, r_sample, 9); if (hctx->ccid3hctx_state == TFRC_SSTATE_NO_FBACK) { @@ -493,9 +480,6 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) /* unschedule no feedback timer */ sk_stop_timer(sk, &hctx->ccid3hctx_no_feedback_timer); - /* remove all packets older than the one acked from history */ - dccp_tx_hist_purge_older(ccid3_tx_hist, - &hctx->ccid3hctx_hist, packet); /* * As we have calculated new ipi, delta, t_nom it is possible * that we now can send a packet, so wake up dccp_wait_for_ccid @@ -598,7 +582,7 @@ static int ccid3_hc_tx_init(struct ccid *ccid, struct sock *sk) struct ccid3_hc_tx_sock *hctx = ccid_priv(ccid); hctx->ccid3hctx_state = TFRC_SSTATE_NO_SENT; - INIT_LIST_HEAD(&hctx->ccid3hctx_hist); + tfrc_tx_hist_init(&hctx->ccid3hctx_hist, ccid3_tx_hist); hctx->ccid3hctx_no_feedback_timer.function = ccid3_hc_tx_no_feedback_timer; @@ -616,7 +600,7 @@ static void ccid3_hc_tx_exit(struct sock *sk) sk_stop_timer(sk, &hctx->ccid3hctx_no_feedback_timer); /* Empty packet history */ - dccp_tx_hist_purge(ccid3_tx_hist, &hctx->ccid3hctx_hist); + tfrc_tx_hist_cleanup(&hctx->ccid3hctx_hist); } static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info) @@ -1039,8 +1023,7 @@ static __init int ccid3_module_init(void) if (ccid3_rx_hist == NULL) goto out; - ccid3_tx_hist = dccp_tx_hist_new("ccid3"); - if (ccid3_tx_hist == NULL) + if (tfrc_tx_cache_init(&ccid3_tx_hist, "ccid3")) goto out_free_rx; rc = ccid_register(&ccid3); @@ -1050,8 +1033,7 @@ out: return rc; out_free_tx: - dccp_tx_hist_delete(ccid3_tx_hist); - ccid3_tx_hist = NULL; + tfrc_tx_cache_cleanup(ccid3_tx_hist); out_free_rx: dccp_rx_hist_delete(ccid3_rx_hist); ccid3_rx_hist = NULL; @@ -1063,10 +1045,9 @@ static __exit void ccid3_module_exit(void) { ccid_unregister(&ccid3); - if (ccid3_tx_hist != NULL) { - dccp_tx_hist_delete(ccid3_tx_hist); - ccid3_tx_hist = NULL; - } + if (ccid3_tx_hist != NULL) + tfrc_tx_cache_cleanup(ccid3_tx_hist); + if (ccid3_rx_hist != NULL) { dccp_rx_hist_delete(ccid3_rx_hist); ccid3_rx_hist = NULL; diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h index 36eca34..fd363f0 100644 --- a/net/dccp/ccids/ccid3.h +++ b/net/dccp/ccids/ccid3.h @@ -40,6 +40,7 @@ #include <linux/list.h> #include <linux/types.h> #include <linux/tfrc.h> +#include "lib/packet_history.h" #include "../ccid.h" /* Two seconds as per RFC 3448 4.2 */ @@ -111,7 +112,7 @@ struct ccid3_hc_tx_sock { ktime_t ccid3hctx_t_ld; ktime_t ccid3hctx_t_nom; u32 ccid3hctx_delta; - struct list_head ccid3hctx_hist; + struct tfrc_tx_hist_head ccid3hctx_hist; struct ccid3_options_received ccid3hctx_options_received; }; diff --git a/net/dccp/ccids/lib/packet_history.c b/net/dccp/ccids/lib/packet_history.c index 34c4f60..5651de4 100644 --- a/net/dccp/ccids/lib/packet_history.c +++ b/net/dccp/ccids/lib/packet_history.c @@ -1,7 +1,8 @@ /* * net/dccp/packet_history.c * - * Copyright (c) 2005-6 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2007 The University of Aberdeen, Scotland, UK + * Copyright (c) 2005-7 The University of Waikato, Hamilton, New Zealand. * * An implementation of the DCCP protocol * @@ -41,6 +42,37 @@ /* * Transmitter History Routines */ +int tfrc_tx_cache_init(struct kmem_cache **cache, const char *name) +{ + static const char dccp_tx_hist_mask[] = "tx_hist_%s"; + char *slab_name; + + slab_name = kmalloc(strlen(name) + sizeof(dccp_tx_hist_mask) - 1, + GFP_ATOMIC); + if (slab_name == NULL) + goto fail; + + sprintf(slab_name, dccp_tx_hist_mask, name); + *cache = kmem_cache_create(slab_name, sizeof(struct tfrc_tx_hist), + 0, SLAB_HWCACHE_ALIGN, NULL); + if (*cache != NULL) + return 0; + + kfree(slab_name); +fail: + return -ENOBUFS; +} +EXPORT_SYMBOL_GPL(tfrc_tx_cache_init); + +void tfrc_tx_cache_cleanup(struct kmem_cache *cache) +{ + const char* name = kmem_cache_name(cache); + + kmem_cache_destroy(cache); + kfree(name); +} +EXPORT_SYMBOL_GPL(tfrc_tx_cache_cleanup); + struct dccp_tx_hist *dccp_tx_hist_new(const char *name) { struct dccp_tx_hist *hist = kmalloc(sizeof(*hist), GFP_ATOMIC); @@ -101,6 +133,69 @@ struct dccp_tx_hist_entry * EXPORT_SYMBOL_GPL(dccp_tx_hist_find_entry); +int tfrc_tx_hist_add(struct tfrc_tx_hist_head *head, u64 seqno) +{ + struct tfrc_tx_hist *new = kmem_cache_alloc(head->cache, gfp_any()); + + if (new == NULL) + return -ENOBUFS; + new->seqno = seqno; + new->stamp = ktime_get_real(); + new->next = head->first; + + head->first = new; + return 0; +} +EXPORT_SYMBOL_GPL(tfrc_tx_hist_add); + +static void tfrc_tx_hist_remove_tail(struct tfrc_tx_hist **pptr, + struct kmem_cache *cache) +{ + struct tfrc_tx_hist *ptr; + + for (ptr = *pptr; ptr != NULL; ptr = *pptr) { + *pptr = ptr->next; + kmem_cache_free(cache, ptr); + } +} + +void tfrc_tx_hist_cleanup(struct tfrc_tx_hist_head *head) +{ + tfrc_tx_hist_remove_tail(&head->first, head->cache); +} +EXPORT_SYMBOL_GPL(tfrc_tx_hist_cleanup); + +static struct tfrc_tx_hist + *tfrc_tx_hist_lookup(struct tfrc_tx_hist_head *head, u64 seqno) +{ + struct tfrc_tx_hist *entry; + + for (entry = head->first; entry != NULL; entry = entry->next) + if (entry->seqno == seqno) + return entry; + return NULL; +} + +/** + * tfrc_tx_hist_when - Retrieve send time of past packet + * @stamp: send time to look up (returns value result) + * @head: TX history to search in + * @ackno: ACK number which indicates the sent packet's sequence number + * If successful, it garbage-collects older (irrelevant) entries and returns 1. + */ +int tfrc_tx_hist_when(ktime_t *stamp, struct tfrc_tx_hist_head *head, u64 ackno) +{ + struct tfrc_tx_hist *entry = tfrc_tx_hist_lookup(head, ackno); + + if (entry != NULL) { + *stamp = entry->stamp; + tfrc_tx_hist_remove_tail(&entry->next, head->cache); + return 1; + } + return 0; +} +EXPORT_SYMBOL_GPL(tfrc_tx_hist_when); + void dccp_tx_hist_purge(struct dccp_tx_hist *hist, struct list_head *list) { struct dccp_tx_hist_entry *entry, *next; @@ -147,8 +242,7 @@ struct dccp_rx_hist *dccp_rx_hist_new(const char *name) sprintf(slab_name, dccp_rx_hist_mask, name); hist->dccprxh_slab = kmem_cache_create(slab_name, sizeof(struct dccp_rx_hist_entry), - 0, SLAB_HWCACHE_ALIGN, - NULL); + 0, SLAB_HWCACHE_ALIGN, NULL); if (hist->dccprxh_slab == NULL) goto out_free_slab_name; out: diff --git a/net/dccp/ccids/lib/packet_history.h b/net/dccp/ccids/lib/packet_history.h index 032bb61..bb253f1 100644 --- a/net/dccp/ccids/lib/packet_history.h +++ b/net/dccp/ccids/lib/packet_history.h @@ -1,10 +1,9 @@ /* - * net/dccp/packet_history.h + * Packet RX/TX history data structures and routines for TFRC-based protocols. * + * Copyright (c) 2007 The University of Aberdeen, Scotland, UK * Copyright (c) 2005-6 The University of Waikato, Hamilton, New Zealand. * - * An implementation of the DCCP protocol - * * This code has been developed by the University of Waikato WAND * research group. For further information please see http://www.wand.net.nz/ * or e-mail Ian McDonald - [EMAIL PROTECTED] @@ -52,6 +51,11 @@ /* * Transmitter History data structures and declarations */ +#define DECLARE_TFRC_TX_CACHE(name) static struct kmem_cache *(name); + +extern int tfrc_tx_cache_init(struct kmem_cache **cache, const char *name); +extern void tfrc_tx_cache_cleanup(struct kmem_cache *cache); + struct dccp_tx_hist_entry { struct list_head dccphtx_node; u64 dccphtx_seqno:48, @@ -67,6 +71,35 @@ struct dccp_tx_hist { extern struct dccp_tx_hist *dccp_tx_hist_new(const char *name); extern void dccp_tx_hist_delete(struct dccp_tx_hist *hist); +/** + * tfrc_tx_hist - Simple singly-linked TX history list + * @next: next oldest entry (LIFO order) + * @seqno: sequence number of this entry + * @stamp: send time of packet with sequence number @seqno + */ +struct tfrc_tx_hist { + struct tfrc_tx_hist *next; + u64 seqno; + ktime_t stamp; +}; + +/** + * tfrc_tx_hist_head - Head of TX history + * @first: begin of the list + * @cache: where list entries are allocated from + */ +struct tfrc_tx_hist_head { + struct tfrc_tx_hist *first; + struct kmem_cache *cache; +}; + +static inline void tfrc_tx_hist_init(struct tfrc_tx_hist_head *head, + struct kmem_cache *cache) +{ + head->first = NULL; + head->cache = cache; +} + static inline struct dccp_tx_hist_entry * dccp_tx_hist_entry_new(struct dccp_tx_hist *hist, const gfp_t prio) @@ -94,6 +127,9 @@ static inline struct dccp_tx_hist_entry * extern struct dccp_tx_hist_entry * dccp_tx_hist_find_entry(const struct list_head *list, const u64 seq); +extern int tfrc_tx_hist_add(struct tfrc_tx_hist_head *head, u64 seqno); +extern int tfrc_tx_hist_when(ktime_t *, struct tfrc_tx_hist_head *, u64); +extern void tfrc_tx_hist_cleanup(struct tfrc_tx_hist_head *head); static inline void dccp_tx_hist_add_entry(struct list_head *list, struct dccp_tx_hist_entry *entry) -- 1.5.2.2.238.g7cbf2f2-dirty - To unsubscribe from this list: send the line "unsubscribe dccp" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html