Exemplo n.º 1
0
/*
 * Update the fraction of marked bytes represented as 'alpha'.
 * Also initialize several internal parameters at the end of this function.
 */
static void
dctcp_update_alpha(struct cc_var *ccv)
{
	struct dctcp *dctcp_data;
	int alpha_prev;

	dctcp_data = ccv->cc_data;
	alpha_prev = dctcp_data->alpha;
	dctcp_data->bytes_total = max(dctcp_data->bytes_total, 1);

	/*
	 * Update alpha: alpha = (1 - g) * alpha + g * F.
	 * Here:
	 * g is weight factor
	 *	recommaded to be set to 1/16
	 *	small g = slow convergence between competitive DCTCP flows
	 *	large g = impacts low utilization of bandwidth at switches
	 * F is fraction of marked segments in last RTT
	 *	updated every RTT
	 * Alpha must be round to 0 - MAX_ALPHA_VALUE.
	 */
	dctcp_data->alpha = min(alpha_prev - (alpha_prev >> V_dctcp_shift_g) +
	    (dctcp_data->bytes_ecn << (10 - V_dctcp_shift_g)) /
	    dctcp_data->bytes_total, MAX_ALPHA_VALUE);

	/* Initialize internal parameters for next alpha calculation */
	dctcp_data->bytes_ecn = 0;
	dctcp_data->bytes_total = 0;
	dctcp_data->save_sndnxt = CCV(ccv, snd_nxt);
}
Exemplo n.º 2
0
/*
 * Perform any necessary tasks before we exit congestion recovery.
 */
static void
dctcp_post_recovery(struct cc_var *ccv)
{
	dctcp_cc_algo.post_recovery = newreno_cc_algo.post_recovery;

	if (CCV(ccv, t_flags) & TF_ECN_PERMIT)
		dctcp_update_alpha(ccv);
}
Exemplo n.º 3
0
/*
 * Perform any necessary tasks before we exit congestion recovery.
 */
static void
newreno_post_recovery(struct cc_var *ccv)
{
	int pipe;
	pipe = 0;

	if (IN_FASTRECOVERY(CCV(ccv, t_flags))) {
		/*
		 * Fast recovery will conclude after returning from this
		 * function. Window inflation should have left us with
		 * approximately snd_ssthresh outstanding data. But in case we
		 * would be inclined to send a burst, better to do it via the
		 * slow start mechanism.
		 *
		 * XXXLAS: Find a way to do this without needing curack
		 */
		if (V_tcp_do_rfc6675_pipe)
			pipe = tcp_compute_pipe(ccv->ccvc.tcp);
		else
			pipe = CCV(ccv, snd_max) - ccv->curack;

		if (pipe < CCV(ccv, snd_ssthresh))
			CCV(ccv, snd_cwnd) = pipe + CCV(ccv, t_maxseg);
		else
			CCV(ccv, snd_cwnd) = CCV(ccv, snd_ssthresh);
	}
}
Exemplo n.º 4
0
static void
dctcp_ecnpkt_handler(struct cc_var *ccv)
{
	struct dctcp *dctcp_data;
	uint32_t ccflag;
	int delay_ack;

	dctcp_data = ccv->cc_data;
	ccflag = ccv->flags;
	delay_ack = 1;

	/*
	 * DCTCP responses an ACK immediately when the CE state
	 * in between this segment and the last segment is not same.
	 */
	if (ccflag & CCF_IPHDR_CE) {
		if (!dctcp_data->ce_prev && (ccflag & CCF_DELACK))
			delay_ack = 0;
		dctcp_data->ce_prev = 1;
		CCV(ccv, t_flags) |= TF_ECN_SND_ECE;
	} else {
		if (dctcp_data->ce_prev && (ccflag & CCF_DELACK))
			delay_ack = 0;
		dctcp_data->ce_prev = 0;
		CCV(ccv, t_flags) &= ~TF_ECN_SND_ECE;
	}

	/* DCTCP sets delayed ack when this segment sets the CWR flag. */
	if ((ccflag & CCF_DELACK) && (ccflag & CCF_TCPHDR_CWR))
		delay_ack = 1;

	if (delay_ack == 0)
		ccv->flags |= CCF_ACKNOW;
	else
		ccv->flags &= ~CCF_ACKNOW;
}
Exemplo n.º 5
0
static void
dctcp_after_idle(struct cc_var *ccv)
{
	struct dctcp *dctcp_data;

	dctcp_data = ccv->cc_data;

	/* Initialize internal parameters after idle time */
	dctcp_data->bytes_ecn = 0;
	dctcp_data->bytes_total = 0;
	dctcp_data->save_sndnxt = CCV(ccv, snd_nxt);
	dctcp_data->alpha = V_dctcp_alpha;
	dctcp_data->ece_curr = 0;
	dctcp_data->ece_prev = 0;
	dctcp_data->num_cong_events = 0;

	dctcp_cc_algo.after_idle = newreno_cc_algo.after_idle;
}
Exemplo n.º 6
0
static void
newreno_ack_received(struct cc_var *ccv, uint16_t type)
{
	if (type == CC_ACK && !IN_RECOVERY(CCV(ccv, t_flags)) &&
	    (ccv->flags & CCF_CWND_LIMITED)) {
		u_int cw = CCV(ccv, snd_cwnd);
		u_int incr = CCV(ccv, t_maxseg);

		/*
		 * Regular in-order ACK, open the congestion window.
		 * Method depends on which congestion control state we're
		 * in (slow start or cong avoid) and if ABC (RFC 3465) is
		 * enabled.
		 *
		 * slow start: cwnd <= ssthresh
		 * cong avoid: cwnd > ssthresh
		 *
		 * slow start and ABC (RFC 3465):
		 *   Grow cwnd exponentially by the amount of data
		 *   ACKed capping the max increment per ACK to
		 *   (abc_l_var * maxseg) bytes.
		 *
		 * slow start without ABC (RFC 5681):
		 *   Grow cwnd exponentially by maxseg per ACK.
		 *
		 * cong avoid and ABC (RFC 3465):
		 *   Grow cwnd linearly by maxseg per RTT for each
		 *   cwnd worth of ACKed data.
		 *
		 * cong avoid without ABC (RFC 5681):
		 *   Grow cwnd linearly by approximately maxseg per RTT using
		 *   maxseg^2 / cwnd per ACK as the increment.
		 *   If cwnd > maxseg^2, fix the cwnd increment at 1 byte to
		 *   avoid capping cwnd.
		 */
		if (cw > CCV(ccv, snd_ssthresh)) {
			if (V_tcp_do_rfc3465) {
				if (ccv->flags & CCF_ABC_SENTAWND)
					ccv->flags &= ~CCF_ABC_SENTAWND;
				else
					incr = 0;
			} else
				incr = max((incr * incr / cw), 1);
		} else if (V_tcp_do_rfc3465) {
			/*
			 * In slow-start with ABC enabled and no RTO in sight?
			 * (Must not use abc_l_var > 1 if slow starting after
			 * an RTO. On RTO, snd_nxt = snd_una, so the
			 * snd_nxt == snd_max check is sufficient to
			 * handle this).
			 *
			 * XXXLAS: Find a way to signal SS after RTO that
			 * doesn't rely on tcpcb vars.
			 */
			if (CCV(ccv, snd_nxt) == CCV(ccv, snd_max))
				incr = min(ccv->bytes_this_ack,
				    V_tcp_abc_l_var * CCV(ccv, t_maxseg));
			else
				incr = min(ccv->bytes_this_ack, CCV(ccv, t_maxseg));
		}
		/* ABC is on by default, so incr equals 0 frequently. */
		if (incr > 0)
			CCV(ccv, snd_cwnd) = min(cw + incr,
			    TCP_MAXWIN << CCV(ccv, snd_scale));
	}
}
Exemplo n.º 7
0
/*
 * Perform any necessary tasks before we enter congestion recovery.
 */
static void
newreno_cong_signal(struct cc_var *ccv, uint32_t type)
{
	u_int win;

	/* Catch algos which mistakenly leak private signal types. */
	KASSERT((type & CC_SIGPRIVMASK) == 0,
	    ("%s: congestion signal type 0x%08x is private\n", __func__, type));

	win = max(CCV(ccv, snd_cwnd) / 2 / CCV(ccv, t_maxseg), 2) *
	    CCV(ccv, t_maxseg);

	switch (type) {
	case CC_NDUPACK:
		if (!IN_FASTRECOVERY(CCV(ccv, t_flags))) {
			if (!IN_CONGRECOVERY(CCV(ccv, t_flags)))
				CCV(ccv, snd_ssthresh) = win;
			ENTER_RECOVERY(CCV(ccv, t_flags));
		}
		break;
	case CC_ECN:
		if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) {
			CCV(ccv, snd_ssthresh) = win;
			CCV(ccv, snd_cwnd) = win;
			ENTER_CONGRECOVERY(CCV(ccv, t_flags));
		}
		break;
	}
}
Exemplo n.º 8
0
/*
 * Perform any necessary tasks before we enter congestion recovery.
 */
static void
newreno_cong_signal(struct cc_var *ccv, uint32_t type)
{
	uint32_t cwin, ssthresh_on_loss;
	u_int mss;

	cwin = CCV(ccv, snd_cwnd);
	mss = CCV(ccv, t_maxseg);
	ssthresh_on_loss =
	    max((CCV(ccv, snd_max) - CCV(ccv, snd_una)) / 2 / mss, 2)
		* mss;

	/* Catch algos which mistakenly leak private signal types. */
	KASSERT((type & CC_SIGPRIVMASK) == 0,
	    ("%s: congestion signal type 0x%08x is private\n", __func__, type));

	cwin = max(cwin / 2 / mss, 2) * mss;

	switch (type) {
	case CC_NDUPACK:
		if (!IN_FASTRECOVERY(CCV(ccv, t_flags))) {
			if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) {
				CCV(ccv, snd_ssthresh) = ssthresh_on_loss;
				CCV(ccv, snd_cwnd) = cwin;
			}
			ENTER_RECOVERY(CCV(ccv, t_flags));
		}
		break;
	case CC_ECN:
		if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) {
			CCV(ccv, snd_ssthresh) = ssthresh_on_loss;
			CCV(ccv, snd_cwnd) = cwin;
			ENTER_CONGRECOVERY(CCV(ccv, t_flags));
		}
		break;
	case CC_RTO:
		CCV(ccv, snd_ssthresh) = ssthresh_on_loss;
		CCV(ccv, snd_cwnd) = mss;
		break;
	}
}
Exemplo n.º 9
0
/*
 * Perform any necessary tasks before we enter congestion recovery.
 */
static void
dctcp_cong_signal(struct cc_var *ccv, uint32_t type)
{
	struct dctcp *dctcp_data;
	u_int win, mss;

	dctcp_data = ccv->cc_data;
	win = CCV(ccv, snd_cwnd);
	mss = CCV(ccv, t_maxseg);

	switch (type) {
	case CC_NDUPACK:
		if (!IN_FASTRECOVERY(CCV(ccv, t_flags))) {
			if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) {
				CCV(ccv, snd_ssthresh) = mss *
				    max(win / 2 / mss, 2);
				dctcp_data->num_cong_events++;
			} else {
				/* cwnd has already updated as congestion
				 * recovery. Reverse cwnd value using
				 * snd_cwnd_prev and recalculate snd_ssthresh
				 */
				win = CCV(ccv, snd_cwnd_prev);
				CCV(ccv, snd_ssthresh) =
				    max(win / 2 / mss, 2) * mss;
			}
			ENTER_RECOVERY(CCV(ccv, t_flags));
		}
		break;
	case CC_ECN:
		/*
		 * Save current snd_cwnd when the host encounters both
		 * congestion recovery and fast recovery.
		 */
		CCV(ccv, snd_cwnd_prev) = win;
		if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) {
			if (V_dctcp_slowstart &&
			    dctcp_data->num_cong_events++ == 0) {
				CCV(ccv, snd_ssthresh) =
				    mss * max(win / 2 / mss, 2);
				dctcp_data->alpha = MAX_ALPHA_VALUE;
				dctcp_data->bytes_ecn = 0;
				dctcp_data->bytes_total = 0;
				dctcp_data->save_sndnxt = CCV(ccv, snd_nxt);
			} else
				CCV(ccv, snd_ssthresh) = max((win - ((win *
				    dctcp_data->alpha) >> 11)) / mss, 2) * mss;
			CCV(ccv, snd_cwnd) = CCV(ccv, snd_ssthresh);
			ENTER_CONGRECOVERY(CCV(ccv, t_flags));
		}
		dctcp_data->ece_curr = 1;
		break;
	case CC_RTO:
		if (CCV(ccv, t_flags) & TF_ECN_PERMIT) {
			CCV(ccv, t_flags) |= TF_ECN_SND_CWR;
			dctcp_update_alpha(ccv);
			dctcp_data->save_sndnxt += CCV(ccv, t_maxseg);
			dctcp_data->num_cong_events++;
		}
		break;
	}
}
Exemplo n.º 10
0
static void
dctcp_ack_received(struct cc_var *ccv, uint16_t type)
{
	struct dctcp *dctcp_data;
	int bytes_acked = 0;

	dctcp_data = ccv->cc_data;

	if (CCV(ccv, t_flags) & TF_ECN_PERMIT) {
		/*
		 * DCTCP doesn't treat receipt of ECN marked packet as a
		 * congestion event. Thus, DCTCP always executes the ACK
		 * processing out of congestion recovery.
		 */
		if (IN_CONGRECOVERY(CCV(ccv, t_flags))) {
			EXIT_CONGRECOVERY(CCV(ccv, t_flags));
			newreno_cc_algo.ack_received(ccv, type);
			ENTER_CONGRECOVERY(CCV(ccv, t_flags));
		} else
			newreno_cc_algo.ack_received(ccv, type);

		if (type == CC_DUPACK)
			bytes_acked = CCV(ccv, t_maxseg);

		if (type == CC_ACK)
			bytes_acked = ccv->bytes_this_ack;

		/* Update total bytes. */
		dctcp_data->bytes_total += bytes_acked;

		/* Update total marked bytes. */
		if (dctcp_data->ece_curr) {
			if (!dctcp_data->ece_prev
			    && bytes_acked > CCV(ccv, t_maxseg)) {
				dctcp_data->bytes_ecn +=
				    (bytes_acked - CCV(ccv, t_maxseg));
			} else
				dctcp_data->bytes_ecn += bytes_acked;
			dctcp_data->ece_prev = 1;
		} else {
			if (dctcp_data->ece_prev
			    && bytes_acked > CCV(ccv, t_maxseg))
				dctcp_data->bytes_ecn += CCV(ccv, t_maxseg);
			dctcp_data->ece_prev = 0;
		}
		dctcp_data->ece_curr = 0;

		/*
		 * Update the fraction of marked bytes at the end of
		 * current window size.
		 */
		if ((IN_FASTRECOVERY(CCV(ccv, t_flags)) &&
		    SEQ_GEQ(ccv->curack, CCV(ccv, snd_recover))) ||
		    (!IN_FASTRECOVERY(CCV(ccv, t_flags)) &&
		    SEQ_GT(ccv->curack, dctcp_data->save_sndnxt)))
			dctcp_update_alpha(ccv);
	} else
		newreno_cc_algo.ack_received(ccv, type);
}