packet_history.c 9.5 KB
Newer Older
1
/*
I
Ian McDonald 已提交
2
 *  net/dccp/packet_history.c
3
 *
4 5
 *  Copyright (c) 2007   The University of Aberdeen, Scotland, UK
 *  Copyright (c) 2005-7 The University of Waikato, Hamilton, New Zealand.
6 7 8 9 10
 *
 *  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/
11
 *  or e-mail Ian McDonald - ian.mcdonald@jandi.co.nz
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
 *
 *  This code also uses code from Lulea University, rereleased as GPL by its
 *  authors:
 *  Copyright (c) 2003 Nils-Erik Mattsson, Joacim Haggmark, Magnus Erixzon
 *
 *  Changes to meet Linux coding standards, to make it meet latest ccid3 draft
 *  and to make it work as a loadable module in the DCCP stack written by
 *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>.
 *
 *  Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <linux/string.h>
39
#include <linux/slab.h>
40
#include "packet_history.h"
41
#include "../../dccp.h"
42

43 44 45 46 47 48 49 50 51 52 53 54
/**
 *  tfrc_tx_hist_entry  -  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_entry {
	struct tfrc_tx_hist_entry *next;
	u64			  seqno;
	ktime_t			  stamp;
};

55
/*
56
 * Transmitter History Routines
57
 */
58
static struct kmem_cache *tfrc_tx_hist_slab;
59

60
static struct tfrc_tx_hist_entry *
61
	tfrc_tx_hist_find_entry(struct tfrc_tx_hist_entry *head, u64 seqno)
62
{
63 64
	while (head != NULL && head->seqno != seqno)
		head = head->next;
65

66
	return head;
67 68
}

69
int tfrc_tx_hist_add(struct tfrc_tx_hist_entry **headp, u64 seqno)
70
{
71
	struct tfrc_tx_hist_entry *entry = kmem_cache_alloc(tfrc_tx_hist_slab, gfp_any());
72 73 74 75 76 77 78 79

	if (entry == NULL)
		return -ENOBUFS;
	entry->seqno = seqno;
	entry->stamp = ktime_get_real();
	entry->next  = *headp;
	*headp	     = entry;
	return 0;
80
}
81
EXPORT_SYMBOL_GPL(tfrc_tx_hist_add);
82

83
void tfrc_tx_hist_purge(struct tfrc_tx_hist_entry **headp)
84
{
85
	struct tfrc_tx_hist_entry *head = *headp;
86

87 88
	while (head != NULL) {
		struct tfrc_tx_hist_entry *next = head->next;
89

90
		kmem_cache_free(tfrc_tx_hist_slab, head);
91
		head = next;
92 93
	}

94 95 96
	*headp = NULL;
}
EXPORT_SYMBOL_GPL(tfrc_tx_hist_purge);
97

98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
u32 tfrc_tx_hist_rtt(struct tfrc_tx_hist_entry *head, const u64 seqno,
		     const ktime_t now)
{
	u32 rtt = 0;
	struct tfrc_tx_hist_entry *packet = tfrc_tx_hist_find_entry(head, seqno);

	if (packet != NULL) {
		rtt = ktime_us_delta(now, packet->stamp);
		/*
		 * Garbage-collect older (irrelevant) entries:
		 */
		tfrc_tx_hist_purge(&packet->next);
	}

	return rtt;
}
EXPORT_SYMBOL_GPL(tfrc_tx_hist_rtt);

116

G
Gerrit Renker 已提交
117 118 119 120 121
/*
 * 	Receiver History Routines
 */
static struct kmem_cache *tfrc_rx_hist_slab;

122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
/**
 * tfrc_rx_hist_index - index to reach n-th entry after loss_start
 */
static inline u8 tfrc_rx_hist_index(const struct tfrc_rx_hist *h, const u8 n)
{
	return (h->loss_start + n) & TFRC_NDUPACK;
}

/**
 * tfrc_rx_hist_last_rcv - entry with highest-received-seqno so far
 */
static inline struct tfrc_rx_hist_entry *
			tfrc_rx_hist_last_rcv(const struct tfrc_rx_hist *h)
{
	return h->ring[tfrc_rx_hist_index(h, h->loss_count)];
}

void tfrc_rx_hist_add_packet(struct tfrc_rx_hist *h,
			     const struct sk_buff *skb,
			     const u32 ndp)
142
{
143 144 145 146 147 148 149 150
	struct tfrc_rx_hist_entry *entry = tfrc_rx_hist_last_rcv(h);
	const struct dccp_hdr *dh = dccp_hdr(skb);

	entry->tfrchrx_seqno = DCCP_SKB_CB(skb)->dccpd_seq;
	entry->tfrchrx_ccval = dh->dccph_ccval;
	entry->tfrchrx_type  = dh->dccph_type;
	entry->tfrchrx_ndp   = ndp;
	entry->tfrchrx_tstamp = ktime_get_real();
151
}
152
EXPORT_SYMBOL_GPL(tfrc_rx_hist_add_packet);
153

154 155 156 157 158
/**
 * tfrc_rx_hist_entry - return the n-th history entry after loss_start
 */
static inline struct tfrc_rx_hist_entry *
		tfrc_rx_hist_entry(const struct tfrc_rx_hist *h, const u8 n)
159
{
160 161
	return h->ring[tfrc_rx_hist_index(h, n)];
}
162

163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
/**
 * tfrc_rx_hist_loss_prev - entry with highest-received-seqno before loss was detected
 */
static inline struct tfrc_rx_hist_entry *
			tfrc_rx_hist_loss_prev(const struct tfrc_rx_hist *h)
{
	return h->ring[h->loss_start];
}

/* has the packet contained in skb been seen before? */
int tfrc_rx_hist_duplicate(struct tfrc_rx_hist *h, struct sk_buff *skb)
{
	const u64 seq = DCCP_SKB_CB(skb)->dccpd_seq;
	int i;

	if (dccp_delta_seqno(tfrc_rx_hist_loss_prev(h)->tfrchrx_seqno, seq) <= 0)
		return 1;
180

181 182 183
	for (i = 1; i <= h->loss_count; i++)
		if (tfrc_rx_hist_entry(h, i)->tfrchrx_seqno == seq)
			return 1;
184

185
	return 0;
186
}
187
EXPORT_SYMBOL_GPL(tfrc_rx_hist_duplicate);
188

189 190
/* initialise loss detection and disable RTT sampling */
static inline void tfrc_rx_hist_loss_indicated(struct tfrc_rx_hist *h)
191
{
192 193
	h->loss_count = 1;
}
194

195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
/* indicate whether previously a packet was detected missing */
static inline int tfrc_rx_hist_loss_pending(const struct tfrc_rx_hist *h)
{
	return h->loss_count;
}

/* any data packets missing between last reception and skb ? */
int tfrc_rx_hist_new_loss_indicated(struct tfrc_rx_hist *h,
				    const struct sk_buff *skb, u32 ndp)
{
	int delta = dccp_delta_seqno(tfrc_rx_hist_last_rcv(h)->tfrchrx_seqno,
				     DCCP_SKB_CB(skb)->dccpd_seq);

	if (delta > 1 && ndp < delta)
		tfrc_rx_hist_loss_indicated(h);
210

211
	return tfrc_rx_hist_loss_pending(h);
212
}
213
EXPORT_SYMBOL_GPL(tfrc_rx_hist_new_loss_indicated);
214

215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
int tfrc_rx_hist_alloc(struct tfrc_rx_hist *h)
{
	int i;

	for (i = 0; i <= TFRC_NDUPACK; i++) {
		h->ring[i] = kmem_cache_alloc(tfrc_rx_hist_slab, GFP_ATOMIC);
		if (h->ring[i] == NULL)
			goto out_free;
	}

	h->loss_count = h->loss_start = 0;
	return 0;

out_free:
	while (i-- != 0) {
		kmem_cache_free(tfrc_rx_hist_slab, h->ring[i]);
		h->ring[i] = NULL;
	}
	return -ENOBUFS;
}
EXPORT_SYMBOL_GPL(tfrc_rx_hist_alloc);
236

237
void tfrc_rx_hist_purge(struct tfrc_rx_hist *h)
238
{
239 240 241 242 243 244
	int i;

	for (i = 0; i <= TFRC_NDUPACK; ++i)
		if (h->ring[i] != NULL) {
			kmem_cache_free(tfrc_rx_hist_slab, h->ring[i]);
			h->ring[i] = NULL;
245 246
		}
}
247
EXPORT_SYMBOL_GPL(tfrc_rx_hist_purge);
248

249 250 251 252 253 254 255 256
/**
 * tfrc_rx_hist_rtt_last_s - reference entry to compute RTT samples against
 */
static inline struct tfrc_rx_hist_entry *
			tfrc_rx_hist_rtt_last_s(const struct tfrc_rx_hist *h)
{
	return h->ring[0];
}
257

258 259 260 261 262
/**
 * tfrc_rx_hist_rtt_prev_s: previously suitable (wrt rtt_last_s) RTT-sampling entry
 */
static inline struct tfrc_rx_hist_entry *
			tfrc_rx_hist_rtt_prev_s(const struct tfrc_rx_hist *h)
263
{
264 265
	return h->ring[h->rtt_sample_prev];
}
266

267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
/**
 * tfrc_rx_hist_sample_rtt  -  Sample RTT from timestamp / CCVal
 * Based on ideas presented in RFC 4342, 8.1. Returns 0 if it was not able
 * to compute a sample with given data - calling function should check this.
 */
u32 tfrc_rx_hist_sample_rtt(struct tfrc_rx_hist *h, const struct sk_buff *skb)
{
	u32 sample = 0,
	    delta_v = SUB16(dccp_hdr(skb)->dccph_ccval,
			    tfrc_rx_hist_rtt_last_s(h)->tfrchrx_ccval);

	if (delta_v < 1 || delta_v > 4) {	/* unsuitable CCVal delta */
		if (h->rtt_sample_prev == 2) {	/* previous candidate stored */
			sample = SUB16(tfrc_rx_hist_rtt_prev_s(h)->tfrchrx_ccval,
				       tfrc_rx_hist_rtt_last_s(h)->tfrchrx_ccval);
			if (sample)
				sample = 4 / sample *
				         ktime_us_delta(tfrc_rx_hist_rtt_prev_s(h)->tfrchrx_tstamp,
							tfrc_rx_hist_rtt_last_s(h)->tfrchrx_tstamp);
			else    /*
				 * FIXME: This condition is in principle not
				 * possible but occurs when CCID is used for
				 * two-way data traffic. I have tried to trace
				 * it, but the cause does not seem to be here.
				 */
				DCCP_BUG("please report to dccp@vger.kernel.org"
					 " => prev = %u, last = %u",
					 tfrc_rx_hist_rtt_prev_s(h)->tfrchrx_ccval,
					 tfrc_rx_hist_rtt_last_s(h)->tfrchrx_ccval);
		} else if (delta_v < 1) {
			h->rtt_sample_prev = 1;
			goto keep_ref_for_next_time;
		}

	} else if (delta_v == 4) /* optimal match */
		sample = ktime_to_us(net_timedelta(tfrc_rx_hist_rtt_last_s(h)->tfrchrx_tstamp));
	else {			 /* suboptimal match */
		h->rtt_sample_prev = 2;
		goto keep_ref_for_next_time;
306 307
	}

308 309 310 311 312 313 314 315 316 317 318
	if (unlikely(sample > DCCP_SANE_RTT_MAX)) {
		DCCP_WARN("RTT sample %u too large, using max\n", sample);
		sample = DCCP_SANE_RTT_MAX;
	}

	h->rtt_sample_prev = 0;	       /* use current entry as next reference */
keep_ref_for_next_time:

	return sample;
}
EXPORT_SYMBOL_GPL(tfrc_rx_hist_sample_rtt);
319

320
__init int packet_history_init(void)
321
{
322 323 324
	tfrc_tx_hist_slab = kmem_cache_create("tfrc_tx_hist",
					      sizeof(struct tfrc_tx_hist_entry), 0,
					      SLAB_HWCACHE_ALIGN, NULL);
325 326
	if (tfrc_tx_hist_slab == NULL)
		goto out_err;
327

328
	tfrc_rx_hist_slab = kmem_cache_create("tfrc_rx_hist",
329
					      sizeof(struct tfrc_rx_hist_entry), 0,
330 331 332 333 334 335 336 337 338 339 340
					      SLAB_HWCACHE_ALIGN, NULL);
	if (tfrc_rx_hist_slab == NULL)
		goto out_free_tx;

	return 0;

out_free_tx:
	kmem_cache_destroy(tfrc_tx_hist_slab);
	tfrc_tx_hist_slab = NULL;
out_err:
	return -ENOBUFS;
341 342
}

343
void packet_history_exit(void)
344
{
345 346 347
	if (tfrc_tx_hist_slab != NULL) {
		kmem_cache_destroy(tfrc_tx_hist_slab);
		tfrc_tx_hist_slab = NULL;
348
	}
349 350 351 352 353

	if (tfrc_rx_hist_slab != NULL) {
		kmem_cache_destroy(tfrc_rx_hist_slab);
		tfrc_rx_hist_slab = NULL;
	}
354
}