tcp-reno拥塞控制算法

这个是tcp拥塞控制的接口,有些是必须实现的

struct tcp_congestion_ops {
	struct list_head list;
	u32 key;
	u32 flags;

	/* initialize private data (optional) */
	void (*init)(struct sock *sk);
	/* cleanup private data  (optional) */
	void (*release)(struct sock *sk);

	/* return slow start threshold (required) */
	u32 (*ssthresh)(struct sock *sk);
	/* do new cwnd calculation (required) */
	void (*cong_avoid)(struct sock *sk, u32 ack, u32 acked);
	/* call before changing ca_state (optional) */
	void (*set_state)(struct sock *sk, u8 new_state);
	/* call when cwnd event occurs (optional) */
	void (*cwnd_event)(struct sock *sk, enum tcp_ca_event ev);
	/* call when ack arrives (optional) */
	void (*in_ack_event)(struct sock *sk, u32 flags);
	/* new value of cwnd after loss (required) */
	u32 (*undo_cwnd)(struct sock *sk);
	/* hook for packet ack accounting (optional) */
	void (*pkts_acked)(struct sock *sk, const struct ack_sample *sample);
	/* override sysctl_tcp_min_tso_segs */
	u32 (*min_tso_segs)(struct sock *sk);
	/* returns the multiplier used in tcp_sndbuf_expand (optional) */
	u32 (*sndbuf_expand)(struct sock *sk);
	/* call when packets are delivered to update cwnd and pacing rate,
	 * after all the ca_state processing. (optional)
	 */
	void (*cong_control)(struct sock *sk, const struct rate_sample *rs);
	/* get info for inet_diag (optional) */
	size_t (*get_info)(struct sock *sk, u32 ext, int *attr,
			   union tcp_cc_info *info);

	char name[TCP_CA_NAME_MAX];
	struct module *owner;
};
struct tcp_congestion_ops tcp_reno = {
	.flags = TCP_CONG_NON_RESTRICTED,
	.name = "reno",
	.owner = THIS_MODULE,
	.ssthresh = tcp_reno_ssthresh,
	.cong_avoid = tcp_reno_cong_avoid,
	.undo_cwnd = tcp_reno_undo_cwnd,
};

这里表示实现了tcp拥塞控制接口操作集,
.ssthresh.cong_avoid\undo_cwnd

//本函数功能是返回慢启动阈值
u32 tcp_reno_ssthresh(struct sock *sk)
{
	const struct tcp_sock *tp = tcp_sk(sk);

	return max(tp->snd_cwnd >> 1U, 2U);//表示窗口减半,但是不能低于2
}
EXPORT_SYMBOL_GPL(tcp_reno_ssthresh);

TCP套接口在进入TCP_CA_CWR/Recovery/Loss拥塞状态时,将执行tcp_congestion_ops拥塞结构的成员函数ssthresh,更新慢启动阈值。如下所示,将拥塞窗口减半,但是,不低于2。

//拥塞避免函数
 void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 acked)
{
	struct tcp_sock *tp = tcp_sk(sk);
	// 函数返回1说明拥塞窗口被限制,我们需要增加拥塞窗口,否则的话,就不需要增加拥塞窗口
	if (!tcp_is_cwnd_limited(sk))
		return;

	/* In "safe" area, increase. */
	if (tcp_in_slow_start(tp)) {
		acked = tcp_slow_start(tp,acked); //返回值acked表示:慢启动结束后,还剩余的确认报文数量
		if (!acked)
			return;
	}
	/* In dangerous area, increase slowly. */
	tcp_cong_avoid_ai(tp, tp->snd_cwnd, acked);//表明还有需要确认的报文,进入拥塞避免阶段
}
EXPORT_SYMBOL_GPL(tcp_reno_cong_avoid);

在拥接收到ACK确认报文时,调用cong_avoid指针函数,即tcp_reno_cong_avoid。如果当前拥塞窗口足够使用,不进行处理。如果TCP套接口处于慢启动阶段,由函数tcp_slow_start处理拥塞窗口的增长,返回值acked表示慢启动结束后,还剩余的确认报文数量,这部分剩余数量用于拥塞避免阶段的窗口处理,即函数tcp_cong_avoid_ai。

u32 tcp_slow_start(struct tcp_sock *tp, u32 acked)
{
	u32 cwnd = min(tp->snd_cwnd + acked, tp->snd_ssthresh);
	acked -= cwnd - tp->snd_cwnd;
	tp->snd_cwnd = min(cwnd, tp->snd_cwnd_clamp);

	return acked;
}
EXPORT_SYMBOL_GPL(tcp_slow_start);

在慢启动阶段,新的拥塞窗口等于原窗口加上ACK确认的报文数量,但是,如果结果值超过慢启动阈值ssthresh,超出部分不执行窗口增加操作,交由拥塞避免阶段算法处理

void tcp_cong_avoid_ai(struct tcp_sock *tp, u32 w, u32 acked)
{
	/* If credits accumulated at a higher w, apply them gently now. */
	if (tp->snd_cwnd_cnt >=  w) { //如果本轮收到的确认包大于了拥塞窗口,本轮结束
		tp->snd_cwnd_cnt = 0; //确认包计数器重置0
		tp->snd_cwnd++; //窗口+1
	}
	//否则计数器将已经确认的数据包个数累加
	tp->snd_cwnd_cnt += acked;
	if (tp->snd_cwnd_cnt >=
	    w) { //如果本轮收到的确认包大于了拥塞窗口,本轮结束
		u32 delta = tp->snd_cwnd_cnt / w; //

		tp->snd_cwnd_cnt -= delta * w; //cnt=cnt-(delta*w)
		tp->snd_cwnd += delta; //cwnd=cwnd+delta
	}
	tp->snd_cwnd = min(tp->snd_cwnd, tp->snd_cwnd_clamp);
}
EXPORT_SYMBOL_GPL(tcp_cong_avoid_ai);

在拥塞避免阶段,如果拥塞计数snd_cwnd_cnt大于当前窗口,清空计数,将当前拥塞窗口加一(snd_cwnd)。反之,如果拥塞计数snd_cwnd_cnt小于当前窗口,将计数增加acked,如果增加之后,计数大于等于当前窗口w,新的拥塞窗口(snd_cwnd)增加值为计数除以当前窗口的整数值,余数还保存在窗口计数变量中(snd_cwnd_cnt)。拥塞避免阶段,对于每个ACK报文,窗口增长遵循以下公式:
cwnd=cwnd+1/cwnd

u32 tcp_reno_undo_cwnd(struct sock *sk)
{
	const struct tcp_sock *tp = tcp_sk(sk);

	return max(tp->snd_cwnd, tp->prior_cwnd);
}
EXPORT_SYMBOL_GPL(tcp_reno_undo_cwnd);

Reno处理拥塞撤销的函数tcp_reno_undo_cwnd,返回当前拥塞窗口和拥塞发生前窗口两者之间的最大值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值