⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 loss_interval.c

📁 linux 内核源代码
💻 C
字号:
/* *  net/dccp/ccids/lib/loss_interval.c * *  Copyright (c) 2005-7 The University of Waikato, Hamilton, New Zealand. *  Copyright (c) 2005-7 Ian McDonald <ian.mcdonald@jandi.co.nz> *  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. */#include <linux/module.h>#include <net/sock.h>#include "../../dccp.h"#include "loss_interval.h"#include "packet_history.h"#include "tfrc.h"#define DCCP_LI_HIST_IVAL_F_LENGTH  8struct dccp_li_hist_entry {	struct list_head dccplih_node;	u64		 dccplih_seqno:48,			 dccplih_win_count:4;	u32		 dccplih_interval;};static struct kmem_cache *dccp_li_cachep __read_mostly;static inline struct dccp_li_hist_entry *dccp_li_hist_entry_new(const gfp_t prio){	return kmem_cache_alloc(dccp_li_cachep, prio);}static inline void dccp_li_hist_entry_delete(struct dccp_li_hist_entry *entry){	if (entry != NULL)		kmem_cache_free(dccp_li_cachep, entry);}void dccp_li_hist_purge(struct list_head *list){	struct dccp_li_hist_entry *entry, *next;	list_for_each_entry_safe(entry, next, list, dccplih_node) {		list_del_init(&entry->dccplih_node);		kmem_cache_free(dccp_li_cachep, entry);	}}EXPORT_SYMBOL_GPL(dccp_li_hist_purge);/* Weights used to calculate loss event rate *//* * These are integers as per section 8 of RFC3448. We can then divide by 4 * * when we use it. */static const int dccp_li_hist_w[DCCP_LI_HIST_IVAL_F_LENGTH] = {	4, 4, 4, 4, 3, 2, 1, 1,};u32 dccp_li_hist_calc_i_mean(struct list_head *list){	struct dccp_li_hist_entry *li_entry, *li_next;	int i = 0;	u32 i_tot;	u32 i_tot0 = 0;	u32 i_tot1 = 0;	u32 w_tot  = 0;	list_for_each_entry_safe(li_entry, li_next, list, dccplih_node) {		if (li_entry->dccplih_interval != ~0U) {			i_tot0 += li_entry->dccplih_interval * dccp_li_hist_w[i];			w_tot  += dccp_li_hist_w[i];			if (i != 0)				i_tot1 += li_entry->dccplih_interval * dccp_li_hist_w[i - 1];		}		if (++i > DCCP_LI_HIST_IVAL_F_LENGTH)			break;	}	if (i != DCCP_LI_HIST_IVAL_F_LENGTH)		return 0;	i_tot = max(i_tot0, i_tot1);	if (!w_tot) {		DCCP_WARN("w_tot = 0\n");		return 1;	}	return i_tot / w_tot;}EXPORT_SYMBOL_GPL(dccp_li_hist_calc_i_mean);static int dccp_li_hist_interval_new(struct list_head *list,				     const u64 seq_loss, const u8 win_loss){	struct dccp_li_hist_entry *entry;	int i;	for (i = 0; i < DCCP_LI_HIST_IVAL_F_LENGTH; i++) {		entry = dccp_li_hist_entry_new(GFP_ATOMIC);		if (entry == NULL) {			dccp_li_hist_purge(list);			DCCP_BUG("loss interval list entry is NULL");			return 0;		}		entry->dccplih_interval = ~0;		list_add(&entry->dccplih_node, list);	}	entry->dccplih_seqno     = seq_loss;	entry->dccplih_win_count = win_loss;	return 1;}/* calculate first loss interval * * returns estimated loss interval in usecs */static u32 dccp_li_calc_first_li(struct sock *sk,				 struct list_head *hist_list,				 ktime_t last_feedback,				 u16 s, u32 bytes_recv,				 u32 previous_x_recv){	struct dccp_rx_hist_entry *entry, *next, *tail = NULL;	u32 x_recv, p;	suseconds_t rtt, delta;	ktime_t tstamp = ktime_set(0, 0);	int interval = 0;	int win_count = 0;	int step = 0;	u64 fval;	list_for_each_entry_safe(entry, next, hist_list, dccphrx_node) {		if (dccp_rx_hist_entry_data_packet(entry)) {			tail = entry;			switch (step) {			case 0:				tstamp	  = entry->dccphrx_tstamp;				win_count = entry->dccphrx_ccval;				step = 1;				break;			case 1:				interval = win_count - entry->dccphrx_ccval;				if (interval < 0)					interval += TFRC_WIN_COUNT_LIMIT;				if (interval > 4)					goto found;				break;			}		}	}	if (unlikely(step == 0)) {		DCCP_WARN("%s(%p), packet history has no data packets!\n",			  dccp_role(sk), sk);		return ~0;	}	if (unlikely(interval == 0)) {		DCCP_WARN("%s(%p), Could not find a win_count interval > 0. "			  "Defaulting to 1\n", dccp_role(sk), sk);		interval = 1;	}found:	if (!tail) {		DCCP_CRIT("tail is null\n");		return ~0;	}	delta = ktime_us_delta(tstamp, tail->dccphrx_tstamp);	DCCP_BUG_ON(delta < 0);	rtt = delta * 4 / interval;	dccp_pr_debug("%s(%p), approximated RTT to %dus\n",		      dccp_role(sk), sk, (int)rtt);	/*	 * Determine the length of the first loss interval via inverse lookup.	 * Assume that X_recv can be computed by the throughput equation	 *		    s	 *	X_recv = --------	 *		 R * fval	 * Find some p such that f(p) = fval; return 1/p [RFC 3448, 6.3.1].	 */	if (rtt == 0) {			/* would result in divide-by-zero */		DCCP_WARN("RTT==0\n");		return ~0;	}	delta = ktime_us_delta(ktime_get_real(), last_feedback);	DCCP_BUG_ON(delta <= 0);	x_recv = scaled_div32(bytes_recv, delta);	if (x_recv == 0) {		/* would also trigger divide-by-zero */		DCCP_WARN("X_recv==0\n");		if (previous_x_recv == 0) {			DCCP_BUG("stored value of X_recv is zero");			return ~0;		}		x_recv = previous_x_recv;	}	fval = scaled_div(s, rtt);	fval = scaled_div32(fval, x_recv);	p = tfrc_calc_x_reverse_lookup(fval);	dccp_pr_debug("%s(%p), receive rate=%u bytes/s, implied "		      "loss rate=%u\n", dccp_role(sk), sk, x_recv, p);	if (p == 0)		return ~0;	else		return 1000000 / p;}void dccp_li_update_li(struct sock *sk,		       struct list_head *li_hist_list,		       struct list_head *hist_list,		       ktime_t last_feedback, u16 s, u32 bytes_recv,		       u32 previous_x_recv, u64 seq_loss, u8 win_loss){	struct dccp_li_hist_entry *head;	u64 seq_temp;	if (list_empty(li_hist_list)) {		if (!dccp_li_hist_interval_new(li_hist_list, seq_loss,					       win_loss))			return;		head = list_entry(li_hist_list->next, struct dccp_li_hist_entry,				  dccplih_node);		head->dccplih_interval = dccp_li_calc_first_li(sk, hist_list,							       last_feedback,							       s, bytes_recv,							       previous_x_recv);	} else {		struct dccp_li_hist_entry *entry;		struct list_head *tail;		head = list_entry(li_hist_list->next, struct dccp_li_hist_entry,				  dccplih_node);		/* FIXME win count check removed as was wrong */		/* should make this check with receive history */		/* and compare there as per section 10.2 of RFC4342 */		/* new loss event detected */		/* calculate last interval length */		seq_temp = dccp_delta_seqno(head->dccplih_seqno, seq_loss);		entry = dccp_li_hist_entry_new(GFP_ATOMIC);		if (entry == NULL) {			DCCP_BUG("out of memory - can not allocate entry");			return;		}		list_add(&entry->dccplih_node, li_hist_list);		tail = li_hist_list->prev;		list_del(tail);		kmem_cache_free(dccp_li_cachep, tail);		/* Create the newest interval */		entry->dccplih_seqno = seq_loss;		entry->dccplih_interval = seq_temp;		entry->dccplih_win_count = win_loss;	}}EXPORT_SYMBOL_GPL(dccp_li_update_li);static __init int dccp_li_init(void){	dccp_li_cachep = kmem_cache_create("dccp_li_hist",					   sizeof(struct dccp_li_hist_entry),					   0, SLAB_HWCACHE_ALIGN, NULL);	return dccp_li_cachep == NULL ? -ENOBUFS : 0;}static __exit void dccp_li_exit(void){	kmem_cache_destroy(dccp_li_cachep);}module_init(dccp_li_init);module_exit(dccp_li_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -