mptcp耦合式拥塞控制

 [1]中关于耦合式的拥塞控制算法中,α\alpha的计算很是吓人。尝试推导。
 为什么放着原有的TCP拥塞控制不用,非要提出一个耦合式的拥塞控制呢。耦合式的拥塞控制导致发送端的吞吐量小于两条路径分别采用拥塞控制的吞吐量。[1]里面有个解释,就是不作恶。

Goal 1 (Improve Throughput) A multipath flow should perform at least as well as a single path flow would on the best of the paths available to it.
Goal 2 (Do no harm) A multipath flow should not take up more capacity from any of the resources shared by its different path than if it were a single flow using only one of these paths. This guarantees it will not unduly harm other flows.
Goal 3 (Balance congestion) A multipath flow should move as much traffic as possible off its most congested paths, subject to meeting the first two goals.

 本质原因在这里:可以发paper。
 [2]中简单推导了单径TCP拥塞控制的微分方程:
x˙=1prtt2x2p2=xrtt{I(1p)Dp} \dot x=\frac{1-p}{rtt^2}-\frac{x^2p}{2}=\frac{x}{rtt}\{I(1-p)-Dp\}
 使x˙=0\dot x=0,单径TCP的稳定点的吞吐量,x=1rtt2(1p)px=\frac{1}{rtt}\sqrt{\frac{2(1-p)}{p}}
 这是在每收到一个ack后,拥塞控制窗口ww+Iw\gets w+I;每次丢包,wDw\gets D推导出来的。I=1wI=\frac{1}{w}D=w2D=\frac{w}{2}
 那么,应该怎样控制mptcp的窗口变化,可以do not harm呢? [1]的作者可能盯着II的公式研究了很久,给出了这样一个控制公式:
Imptcp=maxwrrttr2(kSwkrttk)2=maxwrrttr2(kSxk)2 I_{mptcp}=\frac{\max \frac{w_r}{rtt_r^2}}{(\sum_{k\in S}{\frac{w_k}{rtt_k}})^2}=\frac{\max \frac{w_r}{rtt_r^2}}{(\sum_{k\in S}{x_k})^2}
 在稳定态:I(1p)=Dp=wp2I(1-p)=Dp=\frac{wp}{2}ImptcpI_{mptcp}带入,就可以得到:
kSxk=1rtt2(1p)p \sum_{k\in S} x_k=\frac{1}{rtt}\sqrt{\frac{2(1-p)}{p}}
 多径吞吐量,同只用最好路径的吞吐量差不多。
 费了老大劲,干什么呢!假设mptcp实用,肯定会选各路径独立的拥塞控制。
 关于α\alpha也就大致理解了,
α=maxwrrttr2(kSwkrttk)2=wbest(kSwkrttbestrttk)2 \alpha=\frac{\max \frac{w_r}{rtt_r^2}}{(\sum_{k\in S}{\frac{w_k}{rtt_k}})^2}=\frac{w_{best}}{(\sum_{k\in S}{\frac{w_k*rtt_{best}}{rtt_k}})^2}
 内核中[3]的实现,则会乘以一些系数。

static void mptcp_ccc_recalc_alpha(const struct sock *sk)
{
	const struct mptcp_cb *mpcb = tcp_sk(sk)->mpcb;
	const struct mptcp_tcp_sock *mptcp;
	int best_cwnd = 0, best_rtt = 0, can_send = 0;
	u64 max_numerator = 0, sum_denominator = 0, alpha = 1;

	if (!mpcb)
		return;

	/* Do regular alpha-calculation for multiple subflows */

	/* Find the max numerator of the alpha-calculation */
	mptcp_for_each_sub(mpcb, mptcp) {
		const struct sock *sub_sk = mptcp_to_sock(mptcp);
		struct tcp_sock *sub_tp = tcp_sk(sub_sk);
		u64 tmp;

		if (!mptcp_ccc_sk_can_send(sub_sk))
			continue;

		can_send++;

		/* We need to look for the path, that provides the max-value.
		 * Integer-overflow is not possible here, because
		 * tmp will be in u64.
		 */
		tmp = div64_u64(mptcp_ccc_scale(sub_tp->snd_cwnd,
				alpha_scale_num), (u64)sub_tp->srtt_us * sub_tp->srtt_us);

		if (tmp >= max_numerator) {
			max_numerator = tmp;
			best_cwnd = sub_tp->snd_cwnd;
			best_rtt = sub_tp->srtt_us;
		}
	}

	/* No subflow is able to send - we don't care anymore */
	if (unlikely(!can_send))
		goto exit;

	/* Calculate the denominator */
	mptcp_for_each_sub(mpcb, mptcp) {
		const struct sock *sub_sk = mptcp_to_sock(mptcp);
		struct tcp_sock *sub_tp = tcp_sk(sub_sk);

		if (!mptcp_ccc_sk_can_send(sub_sk))
			continue;

		sum_denominator += div_u64(
				mptcp_ccc_scale(sub_tp->snd_cwnd,
						alpha_scale_den) * best_rtt,
						sub_tp->srtt_us);
	}
	sum_denominator *= sum_denominator;
	if (unlikely(!sum_denominator)) {
		pr_err("%s: sum_denominator == 0\n", __func__);
		mptcp_for_each_sub(mpcb, mptcp) {
			const struct sock *sub_sk = mptcp_to_sock(mptcp);
			struct tcp_sock *sub_tp = tcp_sk(sub_sk);
			pr_err("%s: pi:%d, state:%d\n, rtt:%u, cwnd: %u",
			       __func__, sub_tp->mptcp->path_index,
			       sub_sk->sk_state, sub_tp->srtt_us,
			       sub_tp->snd_cwnd);
		}
	}

	alpha = div64_u64(mptcp_ccc_scale(best_cwnd, alpha_scale_num), sum_denominator);

	if (unlikely(!alpha))
		alpha = 1;

exit:
	mptcp_set_alpha(mptcp_meta_sk(sk), alpha);
}

[1] Coupled Congestion Control for Multipath Transport Protocols
[2] AIMD吞吐量公式的推导
[3] mptcp_coupled.c https://github.com/multipath-tcp/mptcp/blob/mptcp_v0.95/net/mptcp/mptcp_coupled.c

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章