Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b6ee3d4a authored by Arnaldo Carvalho de Melo's avatar Arnaldo Carvalho de Melo Committed by David S. Miller
Browse files

[CCID3]: Reorganise timeval handling



Introducing functions to add to or subtract from a timeval variable
and renaming now_delta to timeval_new_delta that calls do_gettimeofday
and then timeval_delta, that should be used when there are several
deltas made relative to the current time or setting variables to it,
so as to avoid calling do_gettimeofday excessively.

I'm leaving these "timeval_" prefixed funcions internal to DCCP for a
while till we're sure there are no subtle bugs in it.

It also is more correct as it checks if the number of usecs added to
or subtracted from a tv_usec field is more than 2 seconds.

Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1f2333ae
Loading
Loading
Loading
Loading
+55 −72
Original line number Diff line number Diff line
@@ -156,26 +156,6 @@ static inline void ccid3_hc_tx_set_state(struct sock *sk,
	hctx->ccid3hctx_state = state;
}

static void timeval_sub(struct timeval large, struct timeval small,
			struct timeval *result)
{
	result->tv_sec = large.tv_sec-small.tv_sec;
	if (large.tv_usec < small.tv_usec) {
		(result->tv_sec)--;
		result->tv_usec = USEC_PER_SEC +
				  large.tv_usec - small.tv_usec;
	} else
		result->tv_usec = large.tv_usec-small.tv_usec;
}

static inline void timeval_fix(struct timeval *tv)
{
	if (tv->tv_usec >= USEC_PER_SEC) {
		tv->tv_sec++;
		tv->tv_usec -= USEC_PER_SEC;
	}
}

#define CALCX_ARRSIZE 500

#define CALCX_SPLIT 50000
@@ -816,18 +796,22 @@ static void ccid3_hc_tx_update_x(struct sock *sk)
							  2 * hctx->ccid3hctx_x_recv),
					       (hctx->ccid3hctx_s /
					        TFRC_MAX_BACK_OFF_TIME));
	} else if (now_delta(hctx->ccid3hctx_t_ld) >= hctx->ccid3hctx_rtt) {
		u32 rtt = hctx->ccid3hctx_rtt;
		if (rtt < 10) {
			rtt = 10;
		} /* avoid divide by zero below */
	} else {
		struct timeval now;

		do_gettimeofday(&now);
	       	if (timeval_delta(&now, &hctx->ccid3hctx_t_ld) >=
		    hctx->ccid3hctx_rtt) {
			/* Avoid divide by zero below */
			const u32 rtt = max_t(u32, hctx->ccid3hctx_rtt, 10);
			
			hctx->ccid3hctx_x = max_t(u32, min_t(u32, 2 * hctx->ccid3hctx_x_recv,
								  2 * hctx->ccid3hctx_x),
						       ((hctx->ccid3hctx_s * 100000) /
							(rtt / 10)));
			/* Using 100000 and 10 to avoid 32 bit overflow for jumbo frames */
		do_gettimeofday(&hctx->ccid3hctx_t_ld);
			hctx->ccid3hctx_t_ld = now;
		}
	}

	if (hctx->ccid3hctx_x == 0) {
@@ -999,14 +983,15 @@ static int ccid3_hc_tx_send_packet(struct sock *sk,

		/* Set nominal send time for initial packet */
		hctx->ccid3hctx_t_nom = now;
		(hctx->ccid3hctx_t_nom).tv_usec += hctx->ccid3hctx_t_ipi;
		timeval_fix(&(hctx->ccid3hctx_t_nom));
		timeval_add_usecs(&hctx->ccid3hctx_t_nom,
				  hctx->ccid3hctx_t_ipi);
		ccid3_calc_new_delta(hctx);
		rc = 0;
		break;
	case TFRC_SSTATE_NO_FBACK:
	case TFRC_SSTATE_FBACK:
		delay = now_delta(hctx->ccid3hctx_t_nom) - hctx->ccid3hctx_delta;
		delay = (timeval_delta(&now, &hctx->ccid3hctx_t_nom) -
		         hctx->ccid3hctx_delta);
		ccid3_pr_debug("send_packet delay=%ld\n", delay);
		delay /= -1000;
		/* divide by -1000 is to convert to ms and get sign right */
@@ -1068,7 +1053,7 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, int len)
		 * Algorithm in "8.1. Window Counter Valuer" in
		 * draft-ietf-dccp-ccid3-11.txt
		 */
		quarter_rtt = now_delta(hctx->ccid3hctx_t_last_win_count) /
		quarter_rtt = timeval_delta(&now, &hctx->ccid3hctx_t_last_win_count) /
			      (hctx->ccid3hctx_rtt / 4);
		if (quarter_rtt > 0) {
			hctx->ccid3hctx_t_last_win_count = now;
@@ -1102,8 +1087,8 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, int len)
			hctx->ccid3hctx_t_nom = now;
			ccid3_calc_new_t_ipi(hctx);
			ccid3_calc_new_delta(hctx);
			(hctx->ccid3hctx_t_nom).tv_usec += hctx->ccid3hctx_t_ipi;
			timeval_fix(&(hctx->ccid3hctx_t_nom));
			timeval_add_usecs(&hctx->ccid3hctx_t_nom,
					  hctx->ccid3hctx_t_ipi);
		}
		break;
	default:
@@ -1167,7 +1152,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
		}

		/* Update RTT */
		r_sample = now_delta(packet->dccphtx_tstamp);
		r_sample = timeval_now_delta(&packet->dccphtx_tstamp);
		/* FIXME: */
		// r_sample -= usecs_to_jiffies(t_elapsed * 10);

@@ -1224,15 +1209,11 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
		ccid3_hc_tx_update_x(sk);

		/* Update next send time */
		if (hctx->ccid3hctx_t_ipi > (hctx->ccid3hctx_t_nom).tv_usec) {
			hctx->ccid3hctx_t_nom.tv_usec += USEC_PER_SEC;
			(hctx->ccid3hctx_t_nom).tv_sec--;
		}
		/* FIXME - if no feedback then t_ipi can go > 1 second */
		(hctx->ccid3hctx_t_nom).tv_usec -= hctx->ccid3hctx_t_ipi;
		timeval_sub_usecs(&hctx->ccid3hctx_t_nom,
				  hctx->ccid3hctx_t_ipi);
		ccid3_calc_new_t_ipi(hctx);
		(hctx->ccid3hctx_t_nom).tv_usec += hctx->ccid3hctx_t_ipi;
		timeval_fix(&(hctx->ccid3hctx_t_nom));
		timeval_add_usecs(&hctx->ccid3hctx_t_nom,
				  hctx->ccid3hctx_t_ipi);
		ccid3_calc_new_delta(hctx);

		/* remove all packets older than the one acked from history */
@@ -1559,20 +1540,24 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk)
	struct dccp_sock *dp = dccp_sk(sk);
	struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
	struct dccp_rx_hist_entry *packet;
	struct timeval now;

	ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);

	do_gettimeofday(&now);

	switch (hcrx->ccid3hcrx_state) {
	case TFRC_RSTATE_NO_DATA:
		hcrx->ccid3hcrx_x_recv = 0;
		break;
	case TFRC_RSTATE_DATA: {
		u32 delta = now_delta(hcrx->ccid3hcrx_tstamp_last_feedback);
		const u32 delta = timeval_delta(&now,
					&hcrx->ccid3hcrx_tstamp_last_feedback);

		if (delta == 0)
			delta = 1; /* to prevent divide by zero */
		hcrx->ccid3hcrx_x_recv = (hcrx->ccid3hcrx_bytes_recv *
					  USEC_PER_SEC) / delta;
					  USEC_PER_SEC);
		if (likely(delta > 1))
			hcrx->ccid3hcrx_x_recv /= delta;
	}
		break;
	default:
@@ -1590,13 +1575,14 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk)
		return;
	}

	do_gettimeofday(&(hcrx->ccid3hcrx_tstamp_last_feedback));
	hcrx->ccid3hcrx_tstamp_last_feedback = now;
	hcrx->ccid3hcrx_last_counter	     = packet->dccphrx_ccval;
	hcrx->ccid3hcrx_seqno_last_counter   = packet->dccphrx_seqno;
	hcrx->ccid3hcrx_bytes_recv	     = 0;

	/* Convert to multiples of 10us */
	hcrx->ccid3hcrx_elapsed_time = now_delta(packet->dccphrx_tstamp) / 10;
	hcrx->ccid3hcrx_elapsed_time =
			timeval_delta(&now, &packet->dccphrx_tstamp) / 10;
	if (hcrx->ccid3hcrx_p == 0)
		hcrx->ccid3hcrx_pinv = ~0;
	else
@@ -1676,7 +1662,7 @@ static u32 ccid3_hc_rx_calc_first_li(struct sock *sk)
	struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
	struct dccp_rx_hist_entry *entry, *next, *tail = NULL;
	u32 rtt, delta, x_recv, fval, p, tmp2;
	struct timeval tstamp = { 0 }, tmp_tv;
	struct timeval tstamp = { 0, };
	int interval = 0;
	int win_count = 0;
	int step = 0;
@@ -1718,18 +1704,16 @@ static u32 ccid3_hc_rx_calc_first_li(struct sock *sk)
		interval = 1;
	}
found:
	timeval_sub(tstamp,tail->dccphrx_tstamp,&tmp_tv);
	rtt = (tmp_tv.tv_sec * USEC_PER_SEC + tmp_tv.tv_usec) * 4 / interval;
	rtt = timeval_delta(&tstamp, &tail->dccphrx_tstamp) * 4 / interval;
	ccid3_pr_debug("%s, sk=%p, approximated RTT to %uus\n",
		       dccp_role(sk), sk, rtt);
	if (rtt == 0)
		rtt = 1;

	delta = now_delta(hcrx->ccid3hcrx_tstamp_last_feedback);
	if (delta == 0)
		delta = 1;

	x_recv = (hcrx->ccid3hcrx_bytes_recv * USEC_PER_SEC) / delta;
	delta = timeval_now_delta(&hcrx->ccid3hcrx_tstamp_last_feedback);
	x_recv = hcrx->ccid3hcrx_bytes_recv * USEC_PER_SEC;
	if (likely(delta > 1))
		x_recv /= delta;

	tmp1 = (u64)x_recv * (u64)rtt;
	do_div(tmp1,10000000);
@@ -1926,7 +1910,6 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
	const struct dccp_options_received *opt_recv;
	struct dccp_rx_hist_entry *packet;
	struct timeval now;
	u32 now_usecs;
	u8 win_count;
	u32 p_prev;
	int ins;
@@ -1948,8 +1931,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
			break;
		p_prev = hcrx->ccid3hcrx_rtt;
		do_gettimeofday(&now);
		now_usecs = now.tv_sec * USEC_PER_SEC + now.tv_usec;
		hcrx->ccid3hcrx_rtt = now_usecs -
		hcrx->ccid3hcrx_rtt = timeval_usecs(&now) -
				     (opt_recv->dccpor_timestamp_echo -
				      opt_recv->dccpor_elapsed_time) * 10;
		if (p_prev != hcrx->ccid3hcrx_rtt)
@@ -1994,15 +1976,16 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
	case TFRC_RSTATE_DATA:
		hcrx->ccid3hcrx_bytes_recv += skb->len -
					      dccp_hdr(skb)->dccph_doff * 4;
		if (ins == 0) {
			if (now_delta(hcrx->ccid3hcrx_tstamp_last_ack) >=
		if (ins != 0)
			break;

		do_gettimeofday(&now);
		if (timeval_delta(&now, &hcrx->ccid3hcrx_tstamp_last_ack) >=
		    hcrx->ccid3hcrx_rtt) {
				do_gettimeofday(&hcrx->ccid3hcrx_tstamp_last_ack);
			hcrx->ccid3hcrx_tstamp_last_ack = now;
			ccid3_hc_rx_send_feedback(sk);
		}
		return;
		}
		break;
	default:
		printk(KERN_CRIT "%s: %s, sk=%p, Illegal state (%d)!\n",
		       __FUNCTION__, dccp_role(sk), sk, hcrx->ccid3hcrx_state);
+40 −4
Original line number Diff line number Diff line
@@ -429,17 +429,53 @@ extern int dccp_ackpkts_add(struct dccp_ackpkts *ap, u64 ackno, u8 state);
extern void dccp_ackpkts_check_rcv_ackno(struct dccp_ackpkts *ap,
					 struct sock *sk, u64 ackno);

static inline suseconds_t timeval_usecs(const struct timeval *tv)
{
	return tv->tv_sec * USEC_PER_SEC + tv->tv_usec;
}

static inline suseconds_t timeval_delta(const struct timeval *large,
					const struct timeval *small)
{
	time_t	    secs  = large->tv_sec  - small->tv_sec;
	suseconds_t usecs = large->tv_usec - small->tv_usec;

	if (usecs < 0) {
		secs--;
		usecs += USEC_PER_SEC;
	}
	return secs * USEC_PER_SEC + usecs;
}

static inline void timeval_add_usecs(struct timeval *tv,
				     const suseconds_t usecs)
{
	tv->tv_usec += usecs;
	while (tv->tv_usec >= USEC_PER_SEC) {
		tv->tv_sec++;
		tv->tv_usec -= USEC_PER_SEC;
	}
}

static inline void timeval_sub_usecs(struct timeval *tv,
				     const suseconds_t usecs)
{
	tv->tv_usec -= usecs;
	while (tv->tv_usec < 0) {
		tv->tv_sec--;
		tv->tv_usec += USEC_PER_SEC;
	}
}

/*
 * Returns the difference in usecs between timeval
 * passed in and current time
 */
static inline u32 now_delta(struct timeval tv)
static inline suseconds_t timeval_now_delta(const struct timeval *tv)
{
	struct timeval now;
	
	do_gettimeofday(&now);
	return (now.tv_sec  - tv.tv_sec) * USEC_PER_SEC +
	       (now.tv_usec - tv.tv_usec);
	return timeval_delta(&now, tv);
}

#ifdef CONFIG_IP_DCCP_DEBUG
+3 −2
Original line number Diff line number Diff line
@@ -359,7 +359,7 @@ static void dccp_insert_option_ack_vector(struct sock *sk, struct sk_buff *skb)
#endif
	struct dccp_ackpkts *ap = dp->dccps_hc_rx_ackpkts;
	int len = ap->dccpap_buf_vector_len + 2;
	const u32 elapsed_time = now_delta(ap->dccpap_time) / 10;
	const u32 elapsed_time = timeval_now_delta(&ap->dccpap_time) / 10;
	unsigned char *to, *from;

	if (elapsed_time != 0)
@@ -451,7 +451,8 @@ static void dccp_insert_option_timestamp_echo(struct sock *sk,
					"CLIENT TX opt: " : "server TX opt: ";
#endif
	u32 tstamp_echo;
	const u32 elapsed_time = now_delta(dp->dccps_timestamp_time) / 10;
	const u32 elapsed_time =
			timeval_now_delta(&dp->dccps_timestamp_time) / 10;
	const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time);
	const int len = 6 + elapsed_time_len;
	unsigned char *to;