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

[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
...@@ -156,26 +156,6 @@ static inline void ccid3_hc_tx_set_state(struct sock *sk, ...@@ -156,26 +156,6 @@ static inline void ccid3_hc_tx_set_state(struct sock *sk,
hctx->ccid3hctx_state = state; 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_ARRSIZE 500
#define CALCX_SPLIT 50000 #define CALCX_SPLIT 50000
...@@ -816,18 +796,22 @@ static void ccid3_hc_tx_update_x(struct sock *sk) ...@@ -816,18 +796,22 @@ static void ccid3_hc_tx_update_x(struct sock *sk)
2 * hctx->ccid3hctx_x_recv), 2 * hctx->ccid3hctx_x_recv),
(hctx->ccid3hctx_s / (hctx->ccid3hctx_s /
TFRC_MAX_BACK_OFF_TIME)); TFRC_MAX_BACK_OFF_TIME));
} else if (now_delta(hctx->ccid3hctx_t_ld) >= hctx->ccid3hctx_rtt) { } else {
u32 rtt = hctx->ccid3hctx_rtt; struct timeval now;
if (rtt < 10) {
rtt = 10; do_gettimeofday(&now);
} /* avoid divide by zero below */ 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, hctx->ccid3hctx_x = max_t(u32, min_t(u32, 2 * hctx->ccid3hctx_x_recv,
2 * hctx->ccid3hctx_x), 2 * hctx->ccid3hctx_x),
((hctx->ccid3hctx_s * 100000) / ((hctx->ccid3hctx_s * 100000) /
(rtt / 10))); (rtt / 10)));
/* Using 100000 and 10 to avoid 32 bit overflow for jumbo frames */ /* 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) { if (hctx->ccid3hctx_x == 0) {
...@@ -999,14 +983,15 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, ...@@ -999,14 +983,15 @@ static int ccid3_hc_tx_send_packet(struct sock *sk,
/* Set nominal send time for initial packet */ /* Set nominal send time for initial packet */
hctx->ccid3hctx_t_nom = now; hctx->ccid3hctx_t_nom = now;
(hctx->ccid3hctx_t_nom).tv_usec += hctx->ccid3hctx_t_ipi; timeval_add_usecs(&hctx->ccid3hctx_t_nom,
timeval_fix(&(hctx->ccid3hctx_t_nom)); hctx->ccid3hctx_t_ipi);
ccid3_calc_new_delta(hctx); ccid3_calc_new_delta(hctx);
rc = 0; rc = 0;
break; break;
case TFRC_SSTATE_NO_FBACK: case TFRC_SSTATE_NO_FBACK:
case TFRC_SSTATE_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); ccid3_pr_debug("send_packet delay=%ld\n", delay);
delay /= -1000; delay /= -1000;
/* divide by -1000 is to convert to ms and get sign right */ /* 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) ...@@ -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 * Algorithm in "8.1. Window Counter Valuer" in
* draft-ietf-dccp-ccid3-11.txt * 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); (hctx->ccid3hctx_rtt / 4);
if (quarter_rtt > 0) { if (quarter_rtt > 0) {
hctx->ccid3hctx_t_last_win_count = now; 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) ...@@ -1102,8 +1087,8 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, int len)
hctx->ccid3hctx_t_nom = now; hctx->ccid3hctx_t_nom = now;
ccid3_calc_new_t_ipi(hctx); ccid3_calc_new_t_ipi(hctx);
ccid3_calc_new_delta(hctx); ccid3_calc_new_delta(hctx);
(hctx->ccid3hctx_t_nom).tv_usec += hctx->ccid3hctx_t_ipi; timeval_add_usecs(&hctx->ccid3hctx_t_nom,
timeval_fix(&(hctx->ccid3hctx_t_nom)); hctx->ccid3hctx_t_ipi);
} }
break; break;
default: default:
...@@ -1167,7 +1152,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) ...@@ -1167,7 +1152,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
} }
/* Update RTT */ /* Update RTT */
r_sample = now_delta(packet->dccphtx_tstamp); r_sample = timeval_now_delta(&packet->dccphtx_tstamp);
/* FIXME: */ /* FIXME: */
// r_sample -= usecs_to_jiffies(t_elapsed * 10); // 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) ...@@ -1224,15 +1209,11 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
ccid3_hc_tx_update_x(sk); ccid3_hc_tx_update_x(sk);
/* Update next send time */ /* Update next send time */
if (hctx->ccid3hctx_t_ipi > (hctx->ccid3hctx_t_nom).tv_usec) { timeval_sub_usecs(&hctx->ccid3hctx_t_nom,
hctx->ccid3hctx_t_nom.tv_usec += USEC_PER_SEC; hctx->ccid3hctx_t_ipi);
(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;
ccid3_calc_new_t_ipi(hctx); ccid3_calc_new_t_ipi(hctx);
(hctx->ccid3hctx_t_nom).tv_usec += hctx->ccid3hctx_t_ipi; timeval_add_usecs(&hctx->ccid3hctx_t_nom,
timeval_fix(&(hctx->ccid3hctx_t_nom)); hctx->ccid3hctx_t_ipi);
ccid3_calc_new_delta(hctx); ccid3_calc_new_delta(hctx);
/* remove all packets older than the one acked from history */ /* remove all packets older than the one acked from history */
...@@ -1559,20 +1540,24 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk) ...@@ -1559,20 +1540,24 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk)
struct dccp_sock *dp = dccp_sk(sk); struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private; struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
struct dccp_rx_hist_entry *packet; struct dccp_rx_hist_entry *packet;
struct timeval now;
ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk); ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
do_gettimeofday(&now);
switch (hcrx->ccid3hcrx_state) { switch (hcrx->ccid3hcrx_state) {
case TFRC_RSTATE_NO_DATA: case TFRC_RSTATE_NO_DATA:
hcrx->ccid3hcrx_x_recv = 0; hcrx->ccid3hcrx_x_recv = 0;
break; break;
case TFRC_RSTATE_DATA: { 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 * 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; break;
default: default:
...@@ -1590,13 +1575,14 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk) ...@@ -1590,13 +1575,14 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk)
return; return;
} }
do_gettimeofday(&(hcrx->ccid3hcrx_tstamp_last_feedback)); hcrx->ccid3hcrx_tstamp_last_feedback = now;
hcrx->ccid3hcrx_last_counter = packet->dccphrx_ccval; hcrx->ccid3hcrx_last_counter = packet->dccphrx_ccval;
hcrx->ccid3hcrx_seqno_last_counter = packet->dccphrx_seqno; hcrx->ccid3hcrx_seqno_last_counter = packet->dccphrx_seqno;
hcrx->ccid3hcrx_bytes_recv = 0; hcrx->ccid3hcrx_bytes_recv = 0;
/* Convert to multiples of 10us */ /* 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) if (hcrx->ccid3hcrx_p == 0)
hcrx->ccid3hcrx_pinv = ~0; hcrx->ccid3hcrx_pinv = ~0;
else else
...@@ -1676,7 +1662,7 @@ static u32 ccid3_hc_rx_calc_first_li(struct sock *sk) ...@@ -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 ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
struct dccp_rx_hist_entry *entry, *next, *tail = NULL; struct dccp_rx_hist_entry *entry, *next, *tail = NULL;
u32 rtt, delta, x_recv, fval, p, tmp2; u32 rtt, delta, x_recv, fval, p, tmp2;
struct timeval tstamp = { 0 }, tmp_tv; struct timeval tstamp = { 0, };
int interval = 0; int interval = 0;
int win_count = 0; int win_count = 0;
int step = 0; int step = 0;
...@@ -1718,18 +1704,16 @@ static u32 ccid3_hc_rx_calc_first_li(struct sock *sk) ...@@ -1718,18 +1704,16 @@ static u32 ccid3_hc_rx_calc_first_li(struct sock *sk)
interval = 1; interval = 1;
} }
found: found:
timeval_sub(tstamp,tail->dccphrx_tstamp,&tmp_tv); rtt = timeval_delta(&tstamp, &tail->dccphrx_tstamp) * 4 / interval;
rtt = (tmp_tv.tv_sec * USEC_PER_SEC + tmp_tv.tv_usec) * 4 / interval;
ccid3_pr_debug("%s, sk=%p, approximated RTT to %uus\n", ccid3_pr_debug("%s, sk=%p, approximated RTT to %uus\n",
dccp_role(sk), sk, rtt); dccp_role(sk), sk, rtt);
if (rtt == 0) if (rtt == 0)
rtt = 1; rtt = 1;
delta = now_delta(hcrx->ccid3hcrx_tstamp_last_feedback); delta = timeval_now_delta(&hcrx->ccid3hcrx_tstamp_last_feedback);
if (delta == 0) x_recv = hcrx->ccid3hcrx_bytes_recv * USEC_PER_SEC;
delta = 1; if (likely(delta > 1))
x_recv /= delta;
x_recv = (hcrx->ccid3hcrx_bytes_recv * USEC_PER_SEC) / delta;
tmp1 = (u64)x_recv * (u64)rtt; tmp1 = (u64)x_recv * (u64)rtt;
do_div(tmp1,10000000); do_div(tmp1,10000000);
...@@ -1926,7 +1910,6 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) ...@@ -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; const struct dccp_options_received *opt_recv;
struct dccp_rx_hist_entry *packet; struct dccp_rx_hist_entry *packet;
struct timeval now; struct timeval now;
u32 now_usecs;
u8 win_count; u8 win_count;
u32 p_prev; u32 p_prev;
int ins; int ins;
...@@ -1948,8 +1931,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) ...@@ -1948,8 +1931,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
break; break;
p_prev = hcrx->ccid3hcrx_rtt; p_prev = hcrx->ccid3hcrx_rtt;
do_gettimeofday(&now); do_gettimeofday(&now);
now_usecs = now.tv_sec * USEC_PER_SEC + now.tv_usec; hcrx->ccid3hcrx_rtt = timeval_usecs(&now) -
hcrx->ccid3hcrx_rtt = now_usecs -
(opt_recv->dccpor_timestamp_echo - (opt_recv->dccpor_timestamp_echo -
opt_recv->dccpor_elapsed_time) * 10; opt_recv->dccpor_elapsed_time) * 10;
if (p_prev != hcrx->ccid3hcrx_rtt) if (p_prev != hcrx->ccid3hcrx_rtt)
...@@ -1994,15 +1976,16 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) ...@@ -1994,15 +1976,16 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
case TFRC_RSTATE_DATA: case TFRC_RSTATE_DATA:
hcrx->ccid3hcrx_bytes_recv += skb->len - hcrx->ccid3hcrx_bytes_recv += skb->len -
dccp_hdr(skb)->dccph_doff * 4; dccp_hdr(skb)->dccph_doff * 4;
if (ins == 0) { if (ins != 0)
if (now_delta(hcrx->ccid3hcrx_tstamp_last_ack) >= break;
do_gettimeofday(&now);
if (timeval_delta(&now, &hcrx->ccid3hcrx_tstamp_last_ack) >=
hcrx->ccid3hcrx_rtt) { hcrx->ccid3hcrx_rtt) {
do_gettimeofday(&hcrx->ccid3hcrx_tstamp_last_ack); hcrx->ccid3hcrx_tstamp_last_ack = now;
ccid3_hc_rx_send_feedback(sk); ccid3_hc_rx_send_feedback(sk);
} }
return; return;
}
break;
default: default:
printk(KERN_CRIT "%s: %s, sk=%p, Illegal state (%d)!\n", printk(KERN_CRIT "%s: %s, sk=%p, Illegal state (%d)!\n",
__FUNCTION__, dccp_role(sk), sk, hcrx->ccid3hcrx_state); __FUNCTION__, dccp_role(sk), sk, hcrx->ccid3hcrx_state);
......
...@@ -429,17 +429,53 @@ extern int dccp_ackpkts_add(struct dccp_ackpkts *ap, u64 ackno, u8 state); ...@@ -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, extern void dccp_ackpkts_check_rcv_ackno(struct dccp_ackpkts *ap,
struct sock *sk, u64 ackno); 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 * Returns the difference in usecs between timeval
* passed in and current time * 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; struct timeval now;
do_gettimeofday(&now); do_gettimeofday(&now);
return (now.tv_sec - tv.tv_sec) * USEC_PER_SEC + return timeval_delta(&now, tv);
(now.tv_usec - tv.tv_usec);
} }
#ifdef CONFIG_IP_DCCP_DEBUG #ifdef CONFIG_IP_DCCP_DEBUG
......
...@@ -359,7 +359,7 @@ static void dccp_insert_option_ack_vector(struct sock *sk, struct sk_buff *skb) ...@@ -359,7 +359,7 @@ static void dccp_insert_option_ack_vector(struct sock *sk, struct sk_buff *skb)
#endif #endif
struct dccp_ackpkts *ap = dp->dccps_hc_rx_ackpkts; struct dccp_ackpkts *ap = dp->dccps_hc_rx_ackpkts;
int len = ap->dccpap_buf_vector_len + 2; 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; unsigned char *to, *from;
if (elapsed_time != 0) if (elapsed_time != 0)
...@@ -451,7 +451,8 @@ static void dccp_insert_option_timestamp_echo(struct sock *sk, ...@@ -451,7 +451,8 @@ static void dccp_insert_option_timestamp_echo(struct sock *sk,
"CLIENT TX opt: " : "server TX opt: "; "CLIENT TX opt: " : "server TX opt: ";
#endif #endif
u32 tstamp_echo; 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 elapsed_time_len = dccp_elapsed_time_len(elapsed_time);
const int len = 6 + elapsed_time_len; const int len = 6 + elapsed_time_len;
unsigned char *to; unsigned char *to;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment