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

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