2005-08-09 20:14:34 -07:00
/*
* net / dccp / ccids / ccid3 . c
*
* Copyright ( c ) 2005 The University of Waikato , Hamilton , New Zealand .
2006-08-26 19:01:30 -07:00
* Copyright ( c ) 2005 - 6 Ian McDonald < ian . mcdonald @ jandi . co . nz >
2005-08-09 20:14:34 -07:00
*
* An implementation of the DCCP protocol
*
* This code has been developed by the University of Waikato WAND
* research group . For further information please see http : //www.wand.net.nz/
*
* This code also uses code from Lulea University , rereleased as GPL by its
* authors :
* Copyright ( c ) 2003 Nils - Erik Mattsson , Joacim Haggmark , Magnus Erixzon
*
* Changes to meet Linux coding standards , to make it meet latest ccid3 draft
* and to make it work as a loadable module in the DCCP stack written by
* Arnaldo Carvalho de Melo < acme @ conectiva . com . br > .
*
* Copyright ( c ) 2005 Arnaldo Carvalho de Melo < acme @ conectiva . com . br >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "../ccid.h"
# include "../dccp.h"
2005-08-27 23:18:26 -03:00
# include "lib/packet_history.h"
2005-08-27 23:03:09 -03:00
# include "lib/loss_interval.h"
2005-08-28 00:47:15 -03:00
# include "lib/tfrc.h"
2005-08-09 20:14:34 -07:00
# include "ccid3.h"
2005-08-27 20:11:28 -03:00
/*
2005-09-09 02:28:47 -03:00
* Reason for maths here is to avoid 32 bit overflow when a is big .
* With this we get close to the limit .
2005-08-27 20:11:28 -03:00
*/
2006-03-20 21:58:56 -08:00
static u32 usecs_div ( const u32 a , const u32 b )
2005-08-27 20:11:28 -03:00
{
2005-09-09 02:28:47 -03:00
const u32 div = a < ( UINT_MAX / ( USEC_PER_SEC / 10 ) ) ? 10 :
a < ( UINT_MAX / ( USEC_PER_SEC / 50 ) ) ? 50 :
a < ( UINT_MAX / ( USEC_PER_SEC / 100 ) ) ? 100 :
a < ( UINT_MAX / ( USEC_PER_SEC / 500 ) ) ? 500 :
a < ( UINT_MAX / ( USEC_PER_SEC / 1000 ) ) ? 1000 :
a < ( UINT_MAX / ( USEC_PER_SEC / 5000 ) ) ? 5000 :
a < ( UINT_MAX / ( USEC_PER_SEC / 10000 ) ) ? 10000 :
a < ( UINT_MAX / ( USEC_PER_SEC / 50000 ) ) ? 50000 :
100000 ;
const u32 tmp = a * ( USEC_PER_SEC / div ) ;
return ( b > = 2 * div ) ? tmp / ( b / div ) : tmp ;
2005-08-27 20:11:28 -03:00
}
2005-08-27 20:20:37 -03:00
static int ccid3_debug ;
2005-08-09 20:14:34 -07:00
2005-08-27 20:20:37 -03:00
# ifdef CCID3_DEBUG
2005-08-09 20:14:34 -07:00
# define ccid3_pr_debug(format, a...) \
do { if ( ccid3_debug ) \
printk ( KERN_DEBUG " %s: " format , __FUNCTION__ , # # a ) ; \
} while ( 0 )
# else
# define ccid3_pr_debug(format, a...)
# endif
2005-08-13 22:42:25 -03:00
static struct dccp_tx_hist * ccid3_tx_hist ;
static struct dccp_rx_hist * ccid3_rx_hist ;
2005-08-27 23:03:09 -03:00
static struct dccp_li_hist * ccid3_li_hist ;
2005-08-09 20:14:34 -07:00
/* TFRC sender states */
enum ccid3_hc_tx_states {
TFRC_SSTATE_NO_SENT = 1 ,
TFRC_SSTATE_NO_FBACK ,
TFRC_SSTATE_FBACK ,
TFRC_SSTATE_TERM ,
} ;
# ifdef CCID3_DEBUG
static const char * ccid3_tx_state_name ( enum ccid3_hc_tx_states state )
{
static char * ccid3_state_names [ ] = {
[ TFRC_SSTATE_NO_SENT ] = " NO_SENT " ,
[ TFRC_SSTATE_NO_FBACK ] = " NO_FBACK " ,
[ TFRC_SSTATE_FBACK ] = " FBACK " ,
[ TFRC_SSTATE_TERM ] = " TERM " ,
} ;
return ccid3_state_names [ state ] ;
}
# endif
2006-03-20 21:58:56 -08:00
static void ccid3_hc_tx_set_state ( struct sock * sk ,
enum ccid3_hc_tx_states state )
2005-08-09 20:14:34 -07:00
{
2005-09-09 02:40:58 -03:00
struct ccid3_hc_tx_sock * hctx = ccid3_hc_tx_sk ( sk ) ;
2005-08-09 20:14:34 -07:00
enum ccid3_hc_tx_states oldstate = hctx - > ccid3hctx_state ;
ccid3_pr_debug ( " %s(%p) %-8.8s -> %s \n " ,
2005-08-27 03:51:58 -03:00
dccp_role ( sk ) , sk , ccid3_tx_state_name ( oldstate ) ,
ccid3_tx_state_name ( state ) ) ;
2005-08-09 20:14:34 -07:00
WARN_ON ( state = = oldstate ) ;
hctx - > ccid3hctx_state = state ;
}
/* Calculate new t_ipi (inter packet interval) by t_ipi = s / X_inst */
static inline void ccid3_calc_new_t_ipi ( struct ccid3_hc_tx_sock * hctx )
{
2005-08-27 20:11:28 -03:00
/*
* If no feedback spec says t_ipi is 1 second ( set elsewhere and then
* doubles after every no feedback timer ( separate function )
*/
if ( hctx - > ccid3hctx_state ! = TFRC_SSTATE_NO_FBACK )
hctx - > ccid3hctx_t_ipi = usecs_div ( hctx - > ccid3hctx_s ,
hctx - > ccid3hctx_x ) ;
2005-08-09 20:14:34 -07:00
}
/* Calculate new delta by delta = min(t_ipi / 2, t_gran / 2) */
static inline void ccid3_calc_new_delta ( struct ccid3_hc_tx_sock * hctx )
{
2005-08-27 03:51:58 -03:00
hctx - > ccid3hctx_delta = min_t ( u32 , hctx - > ccid3hctx_t_ipi / 2 ,
TFRC_OPSYS_HALF_TIME_GRAN ) ;
2005-08-09 20:14:34 -07:00
}
/*
* Update X by
* If ( p > 0 )
* x_calc = calcX ( s , R , p ) ;
* X = max ( min ( X_calc , 2 * X_recv ) , s / t_mbi ) ;
* Else
* If ( now - tld > = R )
* X = max ( min ( 2 * X , 2 * X_recv ) , s / R ) ;
* tld = now ;
*/
static void ccid3_hc_tx_update_x ( struct sock * sk )
{
2005-09-09 02:40:58 -03:00
struct ccid3_hc_tx_sock * hctx = ccid3_hc_tx_sk ( sk ) ;
2005-08-09 20:14:34 -07:00
2005-08-27 03:51:58 -03:00
/* To avoid large error in calcX */
if ( hctx - > ccid3hctx_p > = TFRC_SMALLEST_P ) {
2005-08-28 00:47:15 -03:00
hctx - > ccid3hctx_x_calc = tfrc_calc_x ( hctx - > ccid3hctx_s ,
hctx - > ccid3hctx_rtt ,
hctx - > ccid3hctx_p ) ;
2005-08-27 03:51:58 -03:00
hctx - > ccid3hctx_x = max_t ( u32 , min_t ( u32 , hctx - > ccid3hctx_x_calc ,
2 * hctx - > ccid3hctx_x_recv ) ,
( hctx - > ccid3hctx_s /
TFRC_MAX_BACK_OFF_TIME ) ) ;
2005-08-27 18:18:18 -03:00
} else {
struct timeval now ;
2005-09-09 02:38:35 -03:00
dccp_timestamp ( sk , & now ) ;
2005-08-27 18:18:18 -03:00
if ( timeval_delta ( & now , & hctx - > ccid3hctx_t_ld ) > =
hctx - > ccid3hctx_rtt ) {
2005-08-27 20:11:28 -03:00
hctx - > ccid3hctx_x = max_t ( u32 , min_t ( u32 , hctx - > ccid3hctx_x_recv ,
hctx - > ccid3hctx_x ) * 2 ,
usecs_div ( hctx - > ccid3hctx_s ,
hctx - > ccid3hctx_rtt ) ) ;
2005-08-27 18:18:18 -03:00
hctx - > ccid3hctx_t_ld = now ;
}
2005-08-09 20:14:34 -07:00
}
}
static void ccid3_hc_tx_no_feedback_timer ( unsigned long data )
{
struct sock * sk = ( struct sock * ) data ;
unsigned long next_tmout = 0 ;
2005-09-09 02:40:58 -03:00
struct ccid3_hc_tx_sock * hctx = ccid3_hc_tx_sk ( sk ) ;
2005-08-09 20:14:34 -07:00
bh_lock_sock ( sk ) ;
if ( sock_owned_by_user ( sk ) ) {
/* Try again later. */
/* XXX: set some sensible MIB */
2005-08-27 03:51:58 -03:00
sk_reset_timer ( sk , & hctx - > ccid3hctx_no_feedback_timer ,
jiffies + HZ / 5 ) ;
2005-08-09 20:14:34 -07:00
goto out ;
}
ccid3_pr_debug ( " %s, sk=%p, state=%s \n " , dccp_role ( sk ) , sk ,
ccid3_tx_state_name ( hctx - > ccid3hctx_state ) ) ;
switch ( hctx - > ccid3hctx_state ) {
case TFRC_SSTATE_TERM :
goto out ;
case TFRC_SSTATE_NO_FBACK :
/* Halve send rate */
hctx - > ccid3hctx_x / = 2 ;
2005-08-27 20:11:28 -03:00
if ( hctx - > ccid3hctx_x < ( hctx - > ccid3hctx_s /
TFRC_MAX_BACK_OFF_TIME ) )
2005-08-27 03:51:58 -03:00
hctx - > ccid3hctx_x = ( hctx - > ccid3hctx_s /
TFRC_MAX_BACK_OFF_TIME ) ;
2005-08-09 20:14:34 -07:00
2005-08-27 03:51:58 -03:00
ccid3_pr_debug ( " %s, sk=%p, state=%s, updated tx rate to %d "
" bytes/s \n " ,
dccp_role ( sk ) , sk ,
ccid3_tx_state_name ( hctx - > ccid3hctx_state ) ,
2005-08-09 20:14:34 -07:00
hctx - > ccid3hctx_x ) ;
2005-08-27 20:11:28 -03:00
next_tmout = max_t ( u32 , 2 * usecs_div ( hctx - > ccid3hctx_s ,
hctx - > ccid3hctx_x ) ,
2005-08-27 03:51:58 -03:00
TFRC_INITIAL_TIMEOUT ) ;
/*
* FIXME - not sure above calculation is correct . See section
* 5 of CCID3 11 should adjust tx_t_ipi and double that to
* achieve it really
*/
2005-08-09 20:14:34 -07:00
break ;
case TFRC_SSTATE_FBACK :
2005-08-27 03:51:58 -03:00
/*
* Check if IDLE since last timeout and recv rate is less than
* 4 packets per RTT
*/
if ( ! hctx - > ccid3hctx_idle | |
2005-08-27 20:11:28 -03:00
( hctx - > ccid3hctx_x_recv > =
4 * usecs_div ( hctx - > ccid3hctx_s , hctx - > ccid3hctx_rtt ) ) ) {
2005-08-27 03:51:58 -03:00
ccid3_pr_debug ( " %s, sk=%p, state=%s, not idle \n " ,
dccp_role ( sk ) , sk ,
2005-08-09 20:14:34 -07:00
ccid3_tx_state_name ( hctx - > ccid3hctx_state ) ) ;
/* Halve sending rate */
/* If (X_calc > 2 * X_recv)
* X_recv = max ( X_recv / 2 , s / ( 2 * t_mbi ) ) ;
* Else
* X_recv = X_calc / 4 ;
*/
2005-08-27 03:51:58 -03:00
BUG_ON ( hctx - > ccid3hctx_p > = TFRC_SMALLEST_P & &
hctx - > ccid3hctx_x_calc = = 0 ) ;
2005-08-09 20:14:34 -07:00
/* check also if p is zero -> x_calc is infinity? */
if ( hctx - > ccid3hctx_p < TFRC_SMALLEST_P | |
hctx - > ccid3hctx_x_calc > 2 * hctx - > ccid3hctx_x_recv )
hctx - > ccid3hctx_x_recv = max_t ( u32 , hctx - > ccid3hctx_x_recv / 2 ,
hctx - > ccid3hctx_s / ( 2 * TFRC_MAX_BACK_OFF_TIME ) ) ;
else
hctx - > ccid3hctx_x_recv = hctx - > ccid3hctx_x_calc / 4 ;
/* Update sending rate */
ccid3_hc_tx_update_x ( sk ) ;
}
2005-08-27 20:11:28 -03:00
/*
* Schedule no feedback timer to expire in
* max ( 4 * R , 2 * s / X )
*/
2005-08-21 05:07:37 -03:00
next_tmout = max_t ( u32 , hctx - > ccid3hctx_t_rto ,
2005-08-27 20:11:28 -03:00
2 * usecs_div ( hctx - > ccid3hctx_s ,
hctx - > ccid3hctx_x ) ) ;
2005-08-09 20:14:34 -07:00
break ;
default :
printk ( KERN_CRIT " %s: %s, sk=%p, Illegal state (%d)! \n " ,
__FUNCTION__ , dccp_role ( sk ) , sk , hctx - > ccid3hctx_state ) ;
dump_stack ( ) ;
goto out ;
}
sk_reset_timer ( sk , & hctx - > ccid3hctx_no_feedback_timer ,
2005-08-27 03:51:58 -03:00
jiffies + max_t ( u32 , 1 , usecs_to_jiffies ( next_tmout ) ) ) ;
2005-08-09 20:14:34 -07:00
hctx - > ccid3hctx_idle = 1 ;
out :
bh_unlock_sock ( sk ) ;
sock_put ( sk ) ;
}
2005-08-09 20:30:56 -07:00
static int ccid3_hc_tx_send_packet ( struct sock * sk ,
struct sk_buff * skb , int len )
2005-08-09 20:14:34 -07:00
{
struct dccp_sock * dp = dccp_sk ( sk ) ;
2005-09-09 02:40:58 -03:00
struct ccid3_hc_tx_sock * hctx = ccid3_hc_tx_sk ( sk ) ;
2005-08-10 12:59:38 -03:00
struct dccp_tx_hist_entry * new_packet ;
2005-08-09 20:14:34 -07:00
struct timeval now ;
2005-08-09 20:30:56 -07:00
long delay ;
2005-08-09 20:14:34 -07:00
int rc = - ENOTCONN ;
2005-09-09 20:01:25 -03:00
BUG_ON ( hctx = = NULL | | hctx - > ccid3hctx_state = = TFRC_SSTATE_TERM ) ;
2005-08-27 03:51:58 -03:00
2005-09-09 20:01:25 -03:00
/* Check if pure ACK or Terminating*/
2005-08-09 20:14:34 -07:00
/*
2005-08-27 03:51:58 -03:00
* XXX : We only call this function for DATA and DATAACK , on , these
* packets can have zero length , but why the comment about " pure ACK " ?
2005-08-09 20:14:34 -07:00
*/
2005-09-09 20:01:25 -03:00
if ( unlikely ( len = = 0 ) )
2005-08-09 20:14:34 -07:00
goto out ;
/* See if last packet allocated was not sent */
2005-08-10 12:59:38 -03:00
new_packet = dccp_tx_hist_head ( & hctx - > ccid3hctx_hist ) ;
if ( new_packet = = NULL | | new_packet - > dccphtx_sent ) {
2005-08-27 03:51:58 -03:00
new_packet = dccp_tx_hist_entry_new ( ccid3_tx_hist ,
SLAB_ATOMIC ) ;
2005-08-09 20:14:34 -07:00
rc = - ENOBUFS ;
2005-09-09 20:01:25 -03:00
if ( unlikely ( new_packet = = NULL ) ) {
LIMIT_NETDEBUG ( KERN_WARNING " %s: %s, sk=%p, not enough "
" mem to add to history, send refused \n " ,
__FUNCTION__ , dccp_role ( sk ) , sk ) ;
2005-08-09 20:14:34 -07:00
goto out ;
}
2005-08-10 12:59:38 -03:00
dccp_tx_hist_add_entry ( & hctx - > ccid3hctx_hist , new_packet ) ;
2005-08-09 20:14:34 -07:00
}
2005-09-09 02:38:35 -03:00
dccp_timestamp ( sk , & now ) ;
2005-08-09 20:14:34 -07:00
switch ( hctx - > ccid3hctx_state ) {
case TFRC_SSTATE_NO_SENT :
2005-08-27 03:51:58 -03:00
sk_reset_timer ( sk , & hctx - > ccid3hctx_no_feedback_timer ,
jiffies + usecs_to_jiffies ( TFRC_INITIAL_TIMEOUT ) ) ;
2005-08-09 20:14:34 -07:00
hctx - > ccid3hctx_last_win_count = 0 ;
hctx - > ccid3hctx_t_last_win_count = now ;
ccid3_hc_tx_set_state ( sk , TFRC_SSTATE_NO_FBACK ) ;
2005-09-09 19:58:18 -03:00
hctx - > ccid3hctx_t_ipi = TFRC_INITIAL_IPI ;
2005-08-09 20:14:34 -07:00
/* Set nominal send time for initial packet */
hctx - > ccid3hctx_t_nom = now ;
2005-08-27 18:18:18 -03:00
timeval_add_usecs ( & hctx - > ccid3hctx_t_nom ,
hctx - > ccid3hctx_t_ipi ) ;
2005-08-09 20:14:34 -07:00
ccid3_calc_new_delta ( hctx ) ;
rc = 0 ;
break ;
case TFRC_SSTATE_NO_FBACK :
case TFRC_SSTATE_FBACK :
2005-08-27 18:18:18 -03:00
delay = ( timeval_delta ( & now , & hctx - > ccid3hctx_t_nom ) -
hctx - > ccid3hctx_delta ) ;
2005-08-09 20:30:56 -07:00
delay / = - 1000 ;
2005-08-09 20:14:34 -07:00
/* divide by -1000 is to convert to ms and get sign right */
2005-08-27 03:06:35 -03:00
rc = delay > 0 ? delay : 0 ;
2005-08-09 20:14:34 -07:00
break ;
default :
printk ( KERN_CRIT " %s: %s, sk=%p, Illegal state (%d)! \n " ,
__FUNCTION__ , dccp_role ( sk ) , sk , hctx - > ccid3hctx_state ) ;
dump_stack ( ) ;
rc = - EINVAL ;
break ;
}
/* Can we send? if so add options and add to packet history */
2005-09-09 02:30:07 -03:00
if ( rc = = 0 ) {
dp - > dccps_hc_tx_insert_options = 1 ;
2005-08-13 20:34:23 -03:00
new_packet - > dccphtx_ccval =
2005-08-10 12:59:38 -03:00
DCCP_SKB_CB ( skb ) - > dccpd_ccval =
hctx - > ccid3hctx_last_win_count ;
2006-08-26 23:40:50 -07:00
timeval_add_usecs ( & hctx - > ccid3hctx_t_nom ,
hctx - > ccid3hctx_t_ipi ) ;
2005-09-09 02:30:07 -03:00
}
2005-08-09 20:14:34 -07:00
out :
return rc ;
}
static void ccid3_hc_tx_packet_sent ( struct sock * sk , int more , int len )
{
2005-09-09 02:40:58 -03:00
const struct dccp_sock * dp = dccp_sk ( sk ) ;
struct ccid3_hc_tx_sock * hctx = ccid3_hc_tx_sk ( sk ) ;
2005-08-09 20:14:34 -07:00
struct timeval now ;
2005-09-09 20:01:25 -03:00
BUG_ON ( hctx = = NULL | | hctx - > ccid3hctx_state = = TFRC_SSTATE_TERM ) ;
2005-08-09 20:14:34 -07:00
2005-09-09 02:38:35 -03:00
dccp_timestamp ( sk , & now ) ;
2005-08-09 20:14:34 -07:00
/* check if we have sent a data packet */
if ( len > 0 ) {
unsigned long quarter_rtt ;
2005-08-10 12:59:38 -03:00
struct dccp_tx_hist_entry * packet ;
2005-08-09 20:14:34 -07:00
2005-08-10 12:59:38 -03:00
packet = dccp_tx_hist_head ( & hctx - > ccid3hctx_hist ) ;
2005-09-09 20:01:25 -03:00
if ( unlikely ( packet = = NULL ) ) {
LIMIT_NETDEBUG ( KERN_WARNING " %s: packet doesn't "
" exists in history! \n " , __FUNCTION__ ) ;
2005-08-09 20:14:34 -07:00
return ;
}
2005-09-09 20:01:25 -03:00
if ( unlikely ( packet - > dccphtx_sent ) ) {
LIMIT_NETDEBUG ( KERN_WARNING " %s: no unsent packet in "
" history! \n " , __FUNCTION__ ) ;
2005-08-09 20:14:34 -07:00
return ;
}
2005-08-10 12:59:38 -03:00
packet - > dccphtx_tstamp = now ;
packet - > dccphtx_seqno = dp - > dccps_gss ;
2005-08-09 20:14:34 -07:00
/*
2005-08-27 03:51:58 -03:00
* Check if win_count have changed
* Algorithm in " 8.1. Window Counter Valuer " in
* draft - ietf - dccp - ccid3 - 11. txt
2005-08-09 20:14:34 -07:00
*/
2005-08-27 20:11:28 -03:00
quarter_rtt = timeval_delta ( & now , & hctx - > ccid3hctx_t_last_win_count ) ;
if ( likely ( hctx - > ccid3hctx_rtt > 8 ) )
quarter_rtt / = hctx - > ccid3hctx_rtt / 4 ;
2005-08-09 20:14:34 -07:00
if ( quarter_rtt > 0 ) {
hctx - > ccid3hctx_t_last_win_count = now ;
hctx - > ccid3hctx_last_win_count = ( hctx - > ccid3hctx_last_win_count +
min_t ( unsigned long , quarter_rtt , 5 ) ) % 16 ;
2005-08-27 03:51:58 -03:00
ccid3_pr_debug ( " %s, sk=%p, window changed from "
" %u to %u! \n " ,
2005-08-09 20:14:34 -07:00
dccp_role ( sk ) , sk ,
2005-08-13 20:34:23 -03:00
packet - > dccphtx_ccval ,
2005-08-09 20:14:34 -07:00
hctx - > ccid3hctx_last_win_count ) ;
}
2005-08-27 03:51:58 -03:00
2005-08-09 20:14:34 -07:00
hctx - > ccid3hctx_idle = 0 ;
2005-08-13 20:34:23 -03:00
packet - > dccphtx_rtt = hctx - > ccid3hctx_rtt ;
2005-08-10 12:59:38 -03:00
packet - > dccphtx_sent = 1 ;
2005-08-09 20:14:34 -07:00
} else
ccid3_pr_debug ( " %s, sk=%p, seqno=%llu NOT inserted! \n " ,
dccp_role ( sk ) , sk , dp - > dccps_gss ) ;
switch ( hctx - > ccid3hctx_state ) {
case TFRC_SSTATE_NO_SENT :
/* if first wasn't pure ack */
if ( len ! = 0 )
2005-08-27 03:51:58 -03:00
printk ( KERN_CRIT " %s: %s, First packet sent is noted "
" as a data packet \n " ,
2005-08-09 20:14:34 -07:00
__FUNCTION__ , dccp_role ( sk ) ) ;
return ;
case TFRC_SSTATE_NO_FBACK :
case TFRC_SSTATE_FBACK :
if ( len > 0 ) {
2006-08-26 23:40:50 -07:00
timeval_sub_usecs ( & hctx - > ccid3hctx_t_nom ,
hctx - > ccid3hctx_t_ipi ) ;
2005-08-09 20:14:34 -07:00
ccid3_calc_new_t_ipi ( hctx ) ;
ccid3_calc_new_delta ( hctx ) ;
2005-08-27 18:18:18 -03:00
timeval_add_usecs ( & hctx - > ccid3hctx_t_nom ,
hctx - > ccid3hctx_t_ipi ) ;
2005-08-09 20:14:34 -07:00
}
break ;
default :
printk ( KERN_CRIT " %s: %s, sk=%p, Illegal state (%d)! \n " ,
__FUNCTION__ , dccp_role ( sk ) , sk , hctx - > ccid3hctx_state ) ;
dump_stack ( ) ;
break ;
}
}
static void ccid3_hc_tx_packet_recv ( struct sock * sk , struct sk_buff * skb )
{
2005-09-09 02:40:58 -03:00
const struct dccp_sock * dp = dccp_sk ( sk ) ;
struct ccid3_hc_tx_sock * hctx = ccid3_hc_tx_sk ( sk ) ;
2005-08-09 20:14:34 -07:00
struct ccid3_options_received * opt_recv ;
2005-08-10 12:59:38 -03:00
struct dccp_tx_hist_entry * packet ;
2005-09-09 02:38:35 -03:00
struct timeval now ;
2005-08-09 20:14:34 -07:00
unsigned long next_tmout ;
2005-08-20 00:23:43 -03:00
u32 t_elapsed ;
2005-08-09 20:14:34 -07:00
u32 pinv ;
u32 x_recv ;
u32 r_sample ;
2005-08-27 03:51:58 -03:00
2005-09-09 20:01:25 -03:00
BUG_ON ( hctx = = NULL | | hctx - > ccid3hctx_state = = TFRC_SSTATE_TERM ) ;
2005-08-09 20:14:34 -07:00
/* we are only interested in ACKs */
if ( ! ( DCCP_SKB_CB ( skb ) - > dccpd_type = = DCCP_PKT_ACK | |
DCCP_SKB_CB ( skb ) - > dccpd_type = = DCCP_PKT_DATAACK ) )
return ;
opt_recv = & hctx - > ccid3hctx_options_received ;
2005-09-09 02:32:56 -03:00
t_elapsed = dp - > dccps_options_received . dccpor_elapsed_time * 10 ;
2005-08-09 20:14:34 -07:00
x_recv = opt_recv - > ccid3or_receive_rate ;
pinv = opt_recv - > ccid3or_loss_event_rate ;
switch ( hctx - > ccid3hctx_state ) {
case TFRC_SSTATE_NO_SENT :
/* FIXME: what to do here? */
return ;
case TFRC_SSTATE_NO_FBACK :
case TFRC_SSTATE_FBACK :
/* Calculate new round trip sample by
* R_sample = ( now - t_recvdata ) - t_delay */
/* get t_recvdata from history */
2005-08-10 12:59:38 -03:00
packet = dccp_tx_hist_find_entry ( & hctx - > ccid3hctx_hist ,
DCCP_SKB_CB ( skb ) - > dccpd_ack_seq ) ;
2005-09-09 20:01:25 -03:00
if ( unlikely ( packet = = NULL ) ) {
LIMIT_NETDEBUG ( KERN_WARNING " %s: %s, sk=%p, seqno "
" %llu(%s) does't exist in history! \n " ,
__FUNCTION__ , dccp_role ( sk ) , sk ,
( unsigned long long ) DCCP_SKB_CB ( skb ) - > dccpd_ack_seq ,
dccp_packet_name ( DCCP_SKB_CB ( skb ) - > dccpd_type ) ) ;
2005-08-09 20:14:34 -07:00
return ;
}
/* Update RTT */
2005-09-09 02:38:35 -03:00
dccp_timestamp ( sk , & now ) ;
r_sample = timeval_delta ( & now , & packet - > dccphtx_tstamp ) ;
2005-09-09 02:32:56 -03:00
if ( unlikely ( r_sample < = t_elapsed ) )
2005-09-09 20:01:25 -03:00
LIMIT_NETDEBUG ( KERN_WARNING " %s: r_sample=%uus, "
" t_elapsed=%uus \n " ,
2005-09-09 02:32:56 -03:00
__FUNCTION__ , r_sample , t_elapsed ) ;
else
r_sample - = t_elapsed ;
2005-08-09 20:14:34 -07:00
/* Update RTT estimate by
* If ( No feedback recv )
* R = R_sample ;
* Else
* R = q * R + ( 1 - q ) * R_sample ;
*
* q is a constant , RFC 3448 recomments 0.9
*/
if ( hctx - > ccid3hctx_state = = TFRC_SSTATE_NO_FBACK ) {
ccid3_hc_tx_set_state ( sk , TFRC_SSTATE_FBACK ) ;
hctx - > ccid3hctx_rtt = r_sample ;
} else
2005-08-27 03:51:58 -03:00
hctx - > ccid3hctx_rtt = ( hctx - > ccid3hctx_rtt * 9 ) / 10 +
r_sample / 10 ;
2005-08-09 20:14:34 -07:00
2005-08-27 03:51:58 -03:00
ccid3_pr_debug ( " %s, sk=%p, New RTT estimate=%uus, "
" r_sample=%us \n " , dccp_role ( sk ) , sk ,
hctx - > ccid3hctx_rtt , r_sample ) ;
2005-08-09 20:14:34 -07:00
/* Update timeout interval */
2005-08-21 05:07:37 -03:00
hctx - > ccid3hctx_t_rto = max_t ( u32 , 4 * hctx - > ccid3hctx_rtt ,
USEC_PER_SEC ) ;
2005-08-09 20:14:34 -07:00
/* Update receive rate */
2005-08-27 03:51:58 -03:00
hctx - > ccid3hctx_x_recv = x_recv ; /* X_recv in bytes per sec */
2005-08-09 20:14:34 -07:00
/* Update loss event rate */
if ( pinv = = ~ 0 | | pinv = = 0 )
hctx - > ccid3hctx_p = 0 ;
else {
hctx - > ccid3hctx_p = 1000000 / pinv ;
if ( hctx - > ccid3hctx_p < TFRC_SMALLEST_P ) {
hctx - > ccid3hctx_p = TFRC_SMALLEST_P ;
2005-08-27 03:51:58 -03:00
ccid3_pr_debug ( " %s, sk=%p, Smallest p used! \n " ,
dccp_role ( sk ) , sk ) ;
2005-08-09 20:14:34 -07:00
}
}
/* unschedule no feedback timer */
sk_stop_timer ( sk , & hctx - > ccid3hctx_no_feedback_timer ) ;
/* Update sending rate */
ccid3_hc_tx_update_x ( sk ) ;
/* Update next send time */
2005-08-27 18:18:18 -03:00
timeval_sub_usecs ( & hctx - > ccid3hctx_t_nom ,
hctx - > ccid3hctx_t_ipi ) ;
2005-08-09 20:14:34 -07:00
ccid3_calc_new_t_ipi ( hctx ) ;
2005-08-27 18:18:18 -03:00
timeval_add_usecs ( & hctx - > ccid3hctx_t_nom ,
hctx - > ccid3hctx_t_ipi ) ;
2005-08-09 20:14:34 -07:00
ccid3_calc_new_delta ( hctx ) ;
/* remove all packets older than the one acked from history */
2005-08-10 12:59:38 -03:00
dccp_tx_hist_purge_older ( ccid3_tx_hist ,
& hctx - > ccid3hctx_hist , packet ) ;
2005-08-29 02:15:54 -03:00
/*
* As we have calculated new ipi , delta , t_nom it is possible that
* we now can send a packet , so wake up dccp_wait_for_ccids .
*/
sk - > sk_write_space ( sk ) ;
2005-08-10 12:59:38 -03:00
2005-08-27 03:51:58 -03:00
/*
* Schedule no feedback timer to expire in
* max ( 4 * R , 2 * s / X )
*/
2005-08-21 05:07:37 -03:00
next_tmout = max ( hctx - > ccid3hctx_t_rto ,
2005-08-27 20:11:28 -03:00
2 * usecs_div ( hctx - > ccid3hctx_s ,
hctx - > ccid3hctx_x ) ) ;
2005-08-27 03:51:58 -03:00
ccid3_pr_debug ( " %s, sk=%p, Scheduled no feedback timer to "
" expire in %lu jiffies (%luus) \n " ,
dccp_role ( sk ) , sk ,
usecs_to_jiffies ( next_tmout ) , next_tmout ) ;
2005-08-09 20:14:34 -07:00
sk_reset_timer ( sk , & hctx - > ccid3hctx_no_feedback_timer ,
2005-08-27 03:51:58 -03:00
jiffies + max_t ( u32 , 1 , usecs_to_jiffies ( next_tmout ) ) ) ;
2005-08-09 20:14:34 -07:00
/* set idle flag */
hctx - > ccid3hctx_idle = 1 ;
break ;
default :
printk ( KERN_CRIT " %s: %s, sk=%p, Illegal state (%d)! \n " ,
__FUNCTION__ , dccp_role ( sk ) , sk , hctx - > ccid3hctx_state ) ;
dump_stack ( ) ;
break ;
}
}
2006-03-20 22:32:06 -08:00
static int ccid3_hc_tx_insert_options ( struct sock * sk , struct sk_buff * skb )
2005-08-09 20:14:34 -07:00
{
2005-09-09 20:01:25 -03:00
const struct ccid3_hc_tx_sock * hctx = ccid3_hc_tx_sk ( sk ) ;
2005-08-09 20:14:34 -07:00
2005-09-09 20:01:25 -03:00
BUG_ON ( hctx = = NULL ) ;
2006-03-20 22:32:06 -08:00
if ( sk - > sk_state = = DCCP_OPEN | | sk - > sk_state = = DCCP_PARTOPEN )
DCCP_SKB_CB ( skb ) - > dccpd_ccval = hctx - > ccid3hctx_last_win_count ;
return 0 ;
2005-08-09 20:14:34 -07:00
}
static int ccid3_hc_tx_parse_options ( struct sock * sk , unsigned char option ,
2005-08-27 03:51:58 -03:00
unsigned char len , u16 idx ,
unsigned char * value )
2005-08-09 20:14:34 -07:00
{
int rc = 0 ;
2005-09-09 02:40:58 -03:00
const struct dccp_sock * dp = dccp_sk ( sk ) ;
struct ccid3_hc_tx_sock * hctx = ccid3_hc_tx_sk ( sk ) ;
2005-08-09 20:14:34 -07:00
struct ccid3_options_received * opt_recv ;
2005-09-09 20:01:25 -03:00
BUG_ON ( hctx = = NULL ) ;
2005-08-09 20:14:34 -07:00
opt_recv = & hctx - > ccid3hctx_options_received ;
if ( opt_recv - > ccid3or_seqno ! = dp - > dccps_gsr ) {
opt_recv - > ccid3or_seqno = dp - > dccps_gsr ;
opt_recv - > ccid3or_loss_event_rate = ~ 0 ;
opt_recv - > ccid3or_loss_intervals_idx = 0 ;
opt_recv - > ccid3or_loss_intervals_len = 0 ;
opt_recv - > ccid3or_receive_rate = 0 ;
}
switch ( option ) {
case TFRC_OPT_LOSS_EVENT_RATE :
2005-09-09 20:01:25 -03:00
if ( unlikely ( len ! = 4 ) ) {
LIMIT_NETDEBUG ( KERN_WARNING " %s: %s, sk=%p, invalid "
" len for TFRC_OPT_LOSS_EVENT_RATE \n " ,
__FUNCTION__ , dccp_role ( sk ) , sk ) ;
2005-08-09 20:14:34 -07:00
rc = - EINVAL ;
} else {
2006-03-20 19:23:32 -08:00
opt_recv - > ccid3or_loss_event_rate = ntohl ( * ( __be32 * ) value ) ;
2005-08-09 20:14:34 -07:00
ccid3_pr_debug ( " %s, sk=%p, LOSS_EVENT_RATE=%u \n " ,
dccp_role ( sk ) , sk ,
opt_recv - > ccid3or_loss_event_rate ) ;
}
break ;
case TFRC_OPT_LOSS_INTERVALS :
opt_recv - > ccid3or_loss_intervals_idx = idx ;
opt_recv - > ccid3or_loss_intervals_len = len ;
ccid3_pr_debug ( " %s, sk=%p, LOSS_INTERVALS=(%u, %u) \n " ,
dccp_role ( sk ) , sk ,
opt_recv - > ccid3or_loss_intervals_idx ,
opt_recv - > ccid3or_loss_intervals_len ) ;
break ;
case TFRC_OPT_RECEIVE_RATE :
2005-09-09 20:01:25 -03:00
if ( unlikely ( len ! = 4 ) ) {
LIMIT_NETDEBUG ( KERN_WARNING " %s: %s, sk=%p, invalid "
" len for TFRC_OPT_RECEIVE_RATE \n " ,
__FUNCTION__ , dccp_role ( sk ) , sk ) ;
2005-08-09 20:14:34 -07:00
rc = - EINVAL ;
} else {
2006-03-20 19:23:32 -08:00
opt_recv - > ccid3or_receive_rate = ntohl ( * ( __be32 * ) value ) ;
2005-08-09 20:14:34 -07:00
ccid3_pr_debug ( " %s, sk=%p, RECEIVE_RATE=%u \n " ,
dccp_role ( sk ) , sk ,
opt_recv - > ccid3or_receive_rate ) ;
}
break ;
}
return rc ;
}
2006-03-20 19:21:44 -08:00
static int ccid3_hc_tx_init ( struct ccid * ccid , struct sock * sk )
2005-08-09 20:14:34 -07:00
{
struct dccp_sock * dp = dccp_sk ( sk ) ;
2006-03-20 19:21:44 -08:00
struct ccid3_hc_tx_sock * hctx = ccid_priv ( ccid ) ;
2005-08-09 20:14:34 -07:00
2005-08-28 04:51:32 -03:00
if ( dp - > dccps_packet_size > = TFRC_MIN_PACKET_SIZE & &
dp - > dccps_packet_size < = TFRC_MAX_PACKET_SIZE )
hctx - > ccid3hctx_s = dp - > dccps_packet_size ;
2005-08-09 20:14:34 -07:00
else
hctx - > ccid3hctx_s = TFRC_STD_PACKET_SIZE ;
2005-08-27 03:51:58 -03:00
/* Set transmission rate to 1 packet per second */
hctx - > ccid3hctx_x = hctx - > ccid3hctx_s ;
2005-08-21 05:07:37 -03:00
hctx - > ccid3hctx_t_rto = USEC_PER_SEC ;
2005-08-09 20:14:34 -07:00
hctx - > ccid3hctx_state = TFRC_SSTATE_NO_SENT ;
INIT_LIST_HEAD ( & hctx - > ccid3hctx_hist ) ;
2006-03-20 17:35:13 -08:00
hctx - > ccid3hctx_no_feedback_timer . function = ccid3_hc_tx_no_feedback_timer ;
hctx - > ccid3hctx_no_feedback_timer . data = ( unsigned long ) sk ;
2005-08-09 20:14:34 -07:00
init_timer ( & hctx - > ccid3hctx_no_feedback_timer ) ;
return 0 ;
}
static void ccid3_hc_tx_exit ( struct sock * sk )
{
2005-09-09 02:40:58 -03:00
struct ccid3_hc_tx_sock * hctx = ccid3_hc_tx_sk ( sk ) ;
2005-08-09 20:14:34 -07:00
BUG_ON ( hctx = = NULL ) ;
ccid3_hc_tx_set_state ( sk , TFRC_SSTATE_TERM ) ;
sk_stop_timer ( sk , & hctx - > ccid3hctx_no_feedback_timer ) ;
/* Empty packet history */
2005-08-10 12:59:38 -03:00
dccp_tx_hist_purge ( ccid3_tx_hist , & hctx - > ccid3hctx_hist ) ;
2005-08-09 20:14:34 -07:00
}
/*
* RX Half Connection methods
*/
/* TFRC receiver states */
enum ccid3_hc_rx_states {
TFRC_RSTATE_NO_DATA = 1 ,
TFRC_RSTATE_DATA ,
TFRC_RSTATE_TERM = 127 ,
} ;
# ifdef CCID3_DEBUG
static const char * ccid3_rx_state_name ( enum ccid3_hc_rx_states state )
{
static char * ccid3_rx_state_names [ ] = {
[ TFRC_RSTATE_NO_DATA ] = " NO_DATA " ,
[ TFRC_RSTATE_DATA ] = " DATA " ,
[ TFRC_RSTATE_TERM ] = " TERM " ,
} ;
return ccid3_rx_state_names [ state ] ;
}
# endif
2006-03-20 21:58:56 -08:00
static void ccid3_hc_rx_set_state ( struct sock * sk ,
enum ccid3_hc_rx_states state )
2005-08-09 20:14:34 -07:00
{
2005-09-09 02:40:58 -03:00
struct ccid3_hc_rx_sock * hcrx = ccid3_hc_rx_sk ( sk ) ;
2005-08-09 20:14:34 -07:00
enum ccid3_hc_rx_states oldstate = hcrx - > ccid3hcrx_state ;
ccid3_pr_debug ( " %s(%p) %-8.8s -> %s \n " ,
2005-08-27 03:51:58 -03:00
dccp_role ( sk ) , sk , ccid3_rx_state_name ( oldstate ) ,
ccid3_rx_state_name ( state ) ) ;
2005-08-09 20:14:34 -07:00
WARN_ON ( state = = oldstate ) ;
hcrx - > ccid3hcrx_state = state ;
}
static void ccid3_hc_rx_send_feedback ( struct sock * sk )
{
2005-09-09 02:40:58 -03:00
struct ccid3_hc_rx_sock * hcrx = ccid3_hc_rx_sk ( sk ) ;
2005-08-09 20:14:34 -07:00
struct dccp_sock * dp = dccp_sk ( sk ) ;
2005-08-10 12:59:38 -03:00
struct dccp_rx_hist_entry * packet ;
2005-08-27 18:18:18 -03:00
struct timeval now ;
2005-08-09 20:14:34 -07:00
ccid3_pr_debug ( " %s, sk=%p \n " , dccp_role ( sk ) , sk ) ;
2005-09-09 02:38:35 -03:00
dccp_timestamp ( sk , & now ) ;
2005-08-27 18:18:18 -03:00
2005-08-09 20:14:34 -07:00
switch ( hcrx - > ccid3hcrx_state ) {
case TFRC_RSTATE_NO_DATA :
hcrx - > ccid3hcrx_x_recv = 0 ;
break ;
case TFRC_RSTATE_DATA : {
2005-08-27 18:18:18 -03:00
const u32 delta = timeval_delta ( & now ,
& hcrx - > ccid3hcrx_tstamp_last_feedback ) ;
2005-09-09 02:31:07 -03:00
hcrx - > ccid3hcrx_x_recv = usecs_div ( hcrx - > ccid3hcrx_bytes_recv ,
delta ) ;
2005-08-09 20:14:34 -07:00
}
break ;
default :
printk ( KERN_CRIT " %s: %s, sk=%p, Illegal state (%d)! \n " ,
__FUNCTION__ , dccp_role ( sk ) , sk , hcrx - > ccid3hcrx_state ) ;
dump_stack ( ) ;
return ;
}
2005-08-10 12:59:38 -03:00
packet = dccp_rx_hist_find_data_packet ( & hcrx - > ccid3hcrx_hist ) ;
2005-09-09 20:01:25 -03:00
if ( unlikely ( packet = = NULL ) ) {
LIMIT_NETDEBUG ( KERN_WARNING " %s: %s, sk=%p, no data packet "
" in history! \n " ,
__FUNCTION__ , dccp_role ( sk ) , sk ) ;
2005-08-09 20:14:34 -07:00
return ;
}
2005-08-27 18:18:18 -03:00
hcrx - > ccid3hcrx_tstamp_last_feedback = now ;
2006-08-26 23:40:50 -07:00
hcrx - > ccid3hcrx_ccval_last_counter = packet - > dccphrx_ccval ;
2005-08-09 20:14:34 -07:00
hcrx - > ccid3hcrx_bytes_recv = 0 ;
/* Convert to multiples of 10us */
2005-08-27 18:18:18 -03:00
hcrx - > ccid3hcrx_elapsed_time =
timeval_delta ( & now , & packet - > dccphrx_tstamp ) / 10 ;
2005-08-09 20:14:34 -07:00
if ( hcrx - > ccid3hcrx_p = = 0 )
hcrx - > ccid3hcrx_pinv = ~ 0 ;
else
hcrx - > ccid3hcrx_pinv = 1000000 / hcrx - > ccid3hcrx_p ;
2005-09-09 02:30:07 -03:00
dp - > dccps_hc_rx_insert_options = 1 ;
2005-08-09 20:14:34 -07:00
dccp_send_ack ( sk ) ;
}
2006-03-20 22:32:06 -08:00
static int ccid3_hc_rx_insert_options ( struct sock * sk , struct sk_buff * skb )
2005-08-09 20:14:34 -07:00
{
2005-09-09 20:01:25 -03:00
const struct ccid3_hc_rx_sock * hcrx = ccid3_hc_rx_sk ( sk ) ;
2006-03-20 19:23:32 -08:00
__be32 x_recv , pinv ;
2005-08-09 20:14:34 -07:00
2005-09-09 20:01:25 -03:00
BUG_ON ( hcrx = = NULL ) ;
if ( ! ( sk - > sk_state = = DCCP_OPEN | | sk - > sk_state = = DCCP_PARTOPEN ) )
2006-03-20 22:32:06 -08:00
return 0 ;
2005-08-09 20:14:34 -07:00
2006-08-26 23:40:50 -07:00
DCCP_SKB_CB ( skb ) - > dccpd_ccval = hcrx - > ccid3hcrx_ccval_last_counter ;
2005-08-23 21:51:59 -07:00
if ( dccp_packet_without_ack ( skb ) )
2006-03-20 22:32:06 -08:00
return 0 ;
2005-08-23 21:51:59 -07:00
x_recv = htonl ( hcrx - > ccid3hcrx_x_recv ) ;
pinv = htonl ( hcrx - > ccid3hcrx_pinv ) ;
2006-03-20 22:32:06 -08:00
if ( ( hcrx - > ccid3hcrx_elapsed_time ! = 0 & &
dccp_insert_option_elapsed_time ( sk , skb ,
hcrx - > ccid3hcrx_elapsed_time ) ) | |
dccp_insert_option_timestamp ( sk , skb ) | |
dccp_insert_option ( sk , skb , TFRC_OPT_LOSS_EVENT_RATE ,
& pinv , sizeof ( pinv ) ) | |
dccp_insert_option ( sk , skb , TFRC_OPT_RECEIVE_RATE ,
& x_recv , sizeof ( x_recv ) ) )
return - 1 ;
return 0 ;
2005-08-09 20:14:34 -07:00
}
/* calculate first loss interval
*
* returns estimated loss interval in usecs */
static u32 ccid3_hc_rx_calc_first_li ( struct sock * sk )
{
2005-09-09 02:40:58 -03:00
struct ccid3_hc_rx_sock * hcrx = ccid3_hc_rx_sk ( sk ) ;
2005-08-10 12:59:38 -03:00
struct dccp_rx_hist_entry * entry , * next , * tail = NULL ;
2005-08-09 20:14:34 -07:00
u32 rtt , delta , x_recv , fval , p , tmp2 ;
2005-08-27 18:18:18 -03:00
struct timeval tstamp = { 0 , } ;
2005-08-09 20:14:34 -07:00
int interval = 0 ;
int win_count = 0 ;
int step = 0 ;
u64 tmp1 ;
2005-08-10 12:59:38 -03:00
list_for_each_entry_safe ( entry , next , & hcrx - > ccid3hcrx_hist ,
dccphrx_node ) {
if ( dccp_rx_hist_entry_data_packet ( entry ) ) {
2005-08-09 20:14:34 -07:00
tail = entry ;
switch ( step ) {
case 0 :
2005-08-10 12:59:38 -03:00
tstamp = entry - > dccphrx_tstamp ;
2005-08-13 20:34:23 -03:00
win_count = entry - > dccphrx_ccval ;
2005-08-09 20:14:34 -07:00
step = 1 ;
break ;
case 1 :
2005-08-13 20:34:23 -03:00
interval = win_count - entry - > dccphrx_ccval ;
2005-08-09 20:14:34 -07:00
if ( interval < 0 )
interval + = TFRC_WIN_COUNT_LIMIT ;
if ( interval > 4 )
goto found ;
break ;
}
}
}
2005-09-09 20:01:25 -03:00
if ( unlikely ( step = = 0 ) ) {
LIMIT_NETDEBUG ( KERN_WARNING " %s: %s, sk=%p, packet history "
" contains no data packets! \n " ,
__FUNCTION__ , dccp_role ( sk ) , sk ) ;
2005-08-09 20:14:34 -07:00
return ~ 0 ;
}
2005-09-09 20:01:25 -03:00
if ( unlikely ( interval = = 0 ) ) {
LIMIT_NETDEBUG ( KERN_WARNING " %s: %s, sk=%p, Could not find a "
" win_count interval > 0. Defaulting to 1 \n " ,
__FUNCTION__ , dccp_role ( sk ) , sk ) ;
2005-08-09 20:14:34 -07:00
interval = 1 ;
}
found :
2006-08-26 23:40:50 -07:00
if ( ! tail ) {
LIMIT_NETDEBUG ( KERN_WARNING " %s: tail is null \n " ,
__FUNCTION__ ) ;
return ~ 0 ;
}
2005-08-27 18:18:18 -03:00
rtt = timeval_delta ( & tstamp , & tail - > dccphrx_tstamp ) * 4 / interval ;
2005-08-09 20:14:34 -07:00
ccid3_pr_debug ( " %s, sk=%p, approximated RTT to %uus \n " ,
dccp_role ( sk ) , sk , rtt ) ;
if ( rtt = = 0 )
rtt = 1 ;
2005-09-09 02:38:35 -03:00
dccp_timestamp ( sk , & tstamp ) ;
delta = timeval_delta ( & tstamp , & hcrx - > ccid3hcrx_tstamp_last_feedback ) ;
x_recv = usecs_div ( hcrx - > ccid3hcrx_bytes_recv , delta ) ;
2005-08-09 20:14:34 -07:00
2006-08-26 23:40:50 -07:00
if ( x_recv = = 0 )
x_recv = hcrx - > ccid3hcrx_x_recv ;
2005-08-09 20:14:34 -07:00
tmp1 = ( u64 ) x_recv * ( u64 ) rtt ;
do_div ( tmp1 , 10000000 ) ;
tmp2 = ( u32 ) tmp1 ;
2006-08-26 23:40:50 -07:00
if ( ! tmp2 ) {
LIMIT_NETDEBUG ( KERN_WARNING " tmp2 = 0 "
" %s: x_recv = %u, rtt =%u \n " ,
__FUNCTION__ , x_recv , rtt ) ;
return ~ 0 ;
}
2005-08-09 20:14:34 -07:00
fval = ( hcrx - > ccid3hcrx_s * 100000 ) / tmp2 ;
/* do not alter order above or you will get overflow on 32 bit */
2005-08-28 00:47:15 -03:00
p = tfrc_calc_x_reverse_lookup ( fval ) ;
2005-08-27 03:51:58 -03:00
ccid3_pr_debug ( " %s, sk=%p, receive rate=%u bytes/s, implied "
" loss rate=%u \n " , dccp_role ( sk ) , sk , x_recv , p ) ;
2005-08-09 20:14:34 -07:00
if ( p = = 0 )
return ~ 0 ;
else
return 1000000 / p ;
}
static void ccid3_hc_rx_update_li ( struct sock * sk , u64 seq_loss , u8 win_loss )
{
2005-09-09 02:40:58 -03:00
struct ccid3_hc_rx_sock * hcrx = ccid3_hc_rx_sk ( sk ) ;
2006-08-29 17:50:19 -07:00
struct dccp_li_hist_entry * head ;
2006-08-26 23:40:50 -07:00
u64 seq_temp ;
2005-08-09 20:14:34 -07:00
2006-08-26 23:40:50 -07:00
if ( list_empty ( & hcrx - > ccid3hcrx_li_hist ) ) {
if ( ! dccp_li_hist_interval_new ( ccid3_li_hist ,
& hcrx - > ccid3hcrx_li_hist , seq_loss , win_loss ) )
return ;
2005-08-09 20:14:34 -07:00
2006-08-29 17:50:19 -07:00
head = list_entry ( hcrx - > ccid3hcrx_li_hist . next ,
struct dccp_li_hist_entry , dccplih_node ) ;
head - > dccplih_interval = ccid3_hc_rx_calc_first_li ( sk ) ;
2006-08-26 23:40:50 -07:00
} else {
struct dccp_li_hist_entry * entry ;
struct list_head * tail ;
2006-08-29 17:50:19 -07:00
head = list_entry ( hcrx - > ccid3hcrx_li_hist . next ,
struct dccp_li_hist_entry , dccplih_node ) ;
2006-08-26 23:40:50 -07:00
/* FIXME win count check removed as was wrong */
/* should make this check with receive history */
/* and compare there as per section 10.2 of RFC4342 */
/* new loss event detected */
/* calculate last interval length */
seq_temp = dccp_delta_seqno ( head - > dccplih_seqno , seq_loss ) ;
entry = dccp_li_hist_entry_new ( ccid3_li_hist , SLAB_ATOMIC ) ;
if ( entry = = NULL ) {
printk ( KERN_CRIT " %s: out of memory \n " , __FUNCTION__ ) ;
dump_stack ( ) ;
2005-08-27 23:03:09 -03:00
return ;
2006-08-26 23:40:50 -07:00
}
list_add ( & entry - > dccplih_node , & hcrx - > ccid3hcrx_li_hist ) ;
tail = hcrx - > ccid3hcrx_li_hist . prev ;
list_del ( tail ) ;
kmem_cache_free ( ccid3_li_hist - > dccplih_slab , tail ) ;
/* Create the newest interval */
entry - > dccplih_seqno = seq_loss ;
entry - > dccplih_interval = seq_temp ;
entry - > dccplih_win_count = win_loss ;
}
2005-08-09 20:14:34 -07:00
}
2006-08-26 23:40:50 -07:00
static int ccid3_hc_rx_detect_loss ( struct sock * sk ,
struct dccp_rx_hist_entry * packet )
2005-08-09 20:14:34 -07:00
{
2005-09-09 02:40:58 -03:00
struct ccid3_hc_rx_sock * hcrx = ccid3_hc_rx_sk ( sk ) ;
2006-08-26 23:40:50 -07:00
struct dccp_rx_hist_entry * rx_hist = dccp_rx_hist_head ( & hcrx - > ccid3hcrx_hist ) ;
u64 seqno = packet - > dccphrx_seqno ;
u64 tmp_seqno ;
int loss = 0 ;
u8 ccval ;
tmp_seqno = hcrx - > ccid3hcrx_seqno_nonloss ;
if ( ! rx_hist | |
follows48 ( packet - > dccphrx_seqno , hcrx - > ccid3hcrx_seqno_nonloss ) ) {
hcrx - > ccid3hcrx_seqno_nonloss = seqno ;
hcrx - > ccid3hcrx_ccval_nonloss = packet - > dccphrx_ccval ;
goto detect_out ;
}
2005-08-09 20:14:34 -07:00
2006-08-26 23:40:50 -07:00
while ( dccp_delta_seqno ( hcrx - > ccid3hcrx_seqno_nonloss , seqno )
> TFRC_RECV_NUM_LATE_LOSS ) {
loss = 1 ;
ccid3_hc_rx_update_li ( sk , hcrx - > ccid3hcrx_seqno_nonloss ,
hcrx - > ccid3hcrx_ccval_nonloss ) ;
tmp_seqno = hcrx - > ccid3hcrx_seqno_nonloss ;
dccp_inc_seqno ( & tmp_seqno ) ;
hcrx - > ccid3hcrx_seqno_nonloss = tmp_seqno ;
dccp_inc_seqno ( & tmp_seqno ) ;
while ( dccp_rx_hist_find_entry ( & hcrx - > ccid3hcrx_hist ,
tmp_seqno , & ccval ) ) {
hcrx - > ccid3hcrx_seqno_nonloss = tmp_seqno ;
hcrx - > ccid3hcrx_ccval_nonloss = ccval ;
dccp_inc_seqno ( & tmp_seqno ) ;
}
}
/* FIXME - this code could be simplified with above while */
/* but works at moment */
if ( follows48 ( packet - > dccphrx_seqno , hcrx - > ccid3hcrx_seqno_nonloss ) ) {
hcrx - > ccid3hcrx_seqno_nonloss = seqno ;
hcrx - > ccid3hcrx_ccval_nonloss = packet - > dccphrx_ccval ;
}
detect_out :
dccp_rx_hist_add_packet ( ccid3_rx_hist , & hcrx - > ccid3hcrx_hist ,
& hcrx - > ccid3hcrx_li_hist , packet ,
hcrx - > ccid3hcrx_seqno_nonloss ) ;
return loss ;
2005-08-09 20:14:34 -07:00
}
static void ccid3_hc_rx_packet_recv ( struct sock * sk , struct sk_buff * skb )
{
2005-09-09 02:40:58 -03:00
struct ccid3_hc_rx_sock * hcrx = ccid3_hc_rx_sk ( sk ) ;
2005-08-23 21:51:59 -07:00
const struct dccp_options_received * opt_recv ;
2005-08-10 12:59:38 -03:00
struct dccp_rx_hist_entry * packet ;
2005-08-09 20:14:34 -07:00
struct timeval now ;
u8 win_count ;
2006-08-26 23:40:50 -07:00
u32 p_prev , rtt_prev , r_sample , t_elapsed ;
int loss ;
2005-08-27 03:51:58 -03:00
2005-09-09 20:01:25 -03:00
BUG_ON ( hcrx = = NULL | |
! ( hcrx - > ccid3hcrx_state = = TFRC_RSTATE_NO_DATA | |
2005-08-09 20:14:34 -07:00
hcrx - > ccid3hcrx_state = = TFRC_RSTATE_DATA ) ) ;
2005-09-09 02:40:58 -03:00
opt_recv = & dccp_sk ( sk ) - > dccps_options_received ;
2005-08-23 21:51:59 -07:00
2005-08-09 20:14:34 -07:00
switch ( DCCP_SKB_CB ( skb ) - > dccpd_type ) {
case DCCP_PKT_ACK :
if ( hcrx - > ccid3hcrx_state = = TFRC_RSTATE_NO_DATA )
return ;
case DCCP_PKT_DATAACK :
2005-08-23 21:51:59 -07:00
if ( opt_recv - > dccpor_timestamp_echo = = 0 )
2005-08-09 20:14:34 -07:00
break ;
2006-08-26 23:40:50 -07:00
rtt_prev = hcrx - > ccid3hcrx_rtt ;
2005-09-09 02:38:35 -03:00
dccp_timestamp ( sk , & now ) ;
2005-09-09 02:34:10 -03:00
timeval_sub_usecs ( & now , opt_recv - > dccpor_timestamp_echo * 10 ) ;
r_sample = timeval_usecs ( & now ) ;
t_elapsed = opt_recv - > dccpor_elapsed_time * 10 ;
if ( unlikely ( r_sample < = t_elapsed ) )
2005-09-09 20:01:25 -03:00
LIMIT_NETDEBUG ( KERN_WARNING " %s: r_sample=%uus, "
" t_elapsed=%uus \n " ,
2005-09-09 02:34:10 -03:00
__FUNCTION__ , r_sample , t_elapsed ) ;
else
r_sample - = t_elapsed ;
if ( hcrx - > ccid3hcrx_state = = TFRC_RSTATE_NO_DATA )
hcrx - > ccid3hcrx_rtt = r_sample ;
else
hcrx - > ccid3hcrx_rtt = ( hcrx - > ccid3hcrx_rtt * 9 ) / 10 +
r_sample / 10 ;
2006-08-26 23:40:50 -07:00
if ( rtt_prev ! = hcrx - > ccid3hcrx_rtt )
ccid3_pr_debug ( " %s, New RTT=%uus, elapsed time=%u \n " ,
2005-08-23 21:51:59 -07:00
dccp_role ( sk ) , hcrx - > ccid3hcrx_rtt ,
opt_recv - > dccpor_elapsed_time ) ;
2005-08-09 20:14:34 -07:00
break ;
case DCCP_PKT_DATA :
break ;
2005-09-09 20:01:25 -03:00
default : /* We're not interested in other packet types, move along */
2005-08-09 20:14:34 -07:00
return ;
}
2005-09-09 02:38:35 -03:00
packet = dccp_rx_hist_entry_new ( ccid3_rx_hist , sk , opt_recv - > dccpor_ndp ,
2005-08-10 12:59:38 -03:00
skb , SLAB_ATOMIC ) ;
2005-09-09 20:01:25 -03:00
if ( unlikely ( packet = = NULL ) ) {
LIMIT_NETDEBUG ( KERN_WARNING " %s: %s, sk=%p, Not enough mem to "
" add rx packet to history, consider it lost! \n " ,
__FUNCTION__ , dccp_role ( sk ) , sk ) ;
2005-08-09 20:14:34 -07:00
return ;
}
2005-08-13 20:34:23 -03:00
win_count = packet - > dccphrx_ccval ;
2005-08-09 20:14:34 -07:00
2006-08-26 23:40:50 -07:00
loss = ccid3_hc_rx_detect_loss ( sk , packet ) ;
2005-08-09 20:14:34 -07:00
if ( DCCP_SKB_CB ( skb ) - > dccpd_type = = DCCP_PKT_ACK )
return ;
switch ( hcrx - > ccid3hcrx_state ) {
case TFRC_RSTATE_NO_DATA :
2005-08-27 03:51:58 -03:00
ccid3_pr_debug ( " %s, sk=%p(%s), skb=%p, sending initial "
" feedback \n " ,
dccp_role ( sk ) , sk ,
dccp_state_name ( sk - > sk_state ) , skb ) ;
2005-08-09 20:14:34 -07:00
ccid3_hc_rx_send_feedback ( sk ) ;
ccid3_hc_rx_set_state ( sk , TFRC_RSTATE_DATA ) ;
return ;
case TFRC_RSTATE_DATA :
2005-08-27 03:51:58 -03:00
hcrx - > ccid3hcrx_bytes_recv + = skb - > len -
dccp_hdr ( skb ) - > dccph_doff * 4 ;
2006-08-26 23:40:50 -07:00
if ( loss )
2005-08-27 18:18:18 -03:00
break ;
2005-09-09 02:38:35 -03:00
dccp_timestamp ( sk , & now ) ;
2005-08-27 18:18:18 -03:00
if ( timeval_delta ( & now , & hcrx - > ccid3hcrx_tstamp_last_ack ) > =
hcrx - > ccid3hcrx_rtt ) {
hcrx - > ccid3hcrx_tstamp_last_ack = now ;
ccid3_hc_rx_send_feedback ( sk ) ;
2005-08-09 20:14:34 -07:00
}
2005-08-27 18:18:18 -03:00
return ;
2005-08-09 20:14:34 -07:00
default :
printk ( KERN_CRIT " %s: %s, sk=%p, Illegal state (%d)! \n " ,
__FUNCTION__ , dccp_role ( sk ) , sk , hcrx - > ccid3hcrx_state ) ;
dump_stack ( ) ;
return ;
}
/* Dealing with packet loss */
2005-08-23 21:51:59 -07:00
ccid3_pr_debug ( " %s, sk=%p(%s), data loss! Reacting... \n " ,
dccp_role ( sk ) , sk , dccp_state_name ( sk - > sk_state ) ) ;
2005-08-09 20:14:34 -07:00
p_prev = hcrx - > ccid3hcrx_p ;
/* Calculate loss event rate */
2006-03-03 17:54:46 -08:00
if ( ! list_empty ( & hcrx - > ccid3hcrx_li_hist ) ) {
u32 i_mean = dccp_li_hist_calc_i_mean ( & hcrx - > ccid3hcrx_li_hist ) ;
2005-08-09 20:14:34 -07:00
/* Scaling up by 1000000 as fixed decimal */
2006-03-03 17:54:46 -08:00
if ( i_mean ! = 0 )
hcrx - > ccid3hcrx_p = 1000000 / i_mean ;
2006-08-26 23:40:50 -07:00
} else {
printk ( KERN_CRIT " %s: empty loss hist \n " , __FUNCTION__ ) ;
dump_stack ( ) ;
2006-03-03 17:54:46 -08:00
}
2005-08-09 20:14:34 -07:00
if ( hcrx - > ccid3hcrx_p > p_prev ) {
ccid3_hc_rx_send_feedback ( sk ) ;
return ;
}
}
2006-03-20 19:21:44 -08:00
static int ccid3_hc_rx_init ( struct ccid * ccid , struct sock * sk )
2005-08-09 20:14:34 -07:00
{
struct dccp_sock * dp = dccp_sk ( sk ) ;
2006-03-20 19:21:44 -08:00
struct ccid3_hc_rx_sock * hcrx = ccid_priv ( ccid ) ;
2005-08-09 20:14:34 -07:00
ccid3_pr_debug ( " %s, sk=%p \n " , dccp_role ( sk ) , sk ) ;
2005-08-28 04:51:32 -03:00
if ( dp - > dccps_packet_size > = TFRC_MIN_PACKET_SIZE & &
dp - > dccps_packet_size < = TFRC_MAX_PACKET_SIZE )
hcrx - > ccid3hcrx_s = dp - > dccps_packet_size ;
2005-08-09 20:14:34 -07:00
else
hcrx - > ccid3hcrx_s = TFRC_STD_PACKET_SIZE ;
hcrx - > ccid3hcrx_state = TFRC_RSTATE_NO_DATA ;
INIT_LIST_HEAD ( & hcrx - > ccid3hcrx_hist ) ;
2005-08-27 23:03:09 -03:00
INIT_LIST_HEAD ( & hcrx - > ccid3hcrx_li_hist ) ;
2005-09-09 02:38:35 -03:00
dccp_timestamp ( sk , & hcrx - > ccid3hcrx_tstamp_last_ack ) ;
2005-09-09 02:37:05 -03:00
hcrx - > ccid3hcrx_tstamp_last_feedback = hcrx - > ccid3hcrx_tstamp_last_ack ;
hcrx - > ccid3hcrx_rtt = 5000 ; /* XXX 5ms for now... */
2005-08-09 20:14:34 -07:00
return 0 ;
}
static void ccid3_hc_rx_exit ( struct sock * sk )
{
2005-09-09 02:40:58 -03:00
struct ccid3_hc_rx_sock * hcrx = ccid3_hc_rx_sk ( sk ) ;
2005-08-09 20:14:34 -07:00
2005-09-09 20:01:25 -03:00
BUG_ON ( hcrx = = NULL ) ;
2005-08-09 20:14:34 -07:00
ccid3_hc_rx_set_state ( sk , TFRC_RSTATE_TERM ) ;
/* Empty packet history */
2005-08-10 12:59:38 -03:00
dccp_rx_hist_purge ( ccid3_rx_hist , & hcrx - > ccid3hcrx_hist ) ;
2005-08-09 20:14:34 -07:00
/* Empty loss interval history */
2005-08-27 23:03:09 -03:00
dccp_li_hist_purge ( ccid3_li_hist , & hcrx - > ccid3hcrx_li_hist ) ;
2005-08-09 20:14:34 -07:00
}
[DCCP]: Introduce dccp_get_info
And also hc_tx and hc_rx get_info functions for the CCIDs to fill in
information that is specific to them.
For now reusing struct tcp_info, later I'll try to figure out a better
solution, for now its really nice to get this kind of info:
[root@qemu ~]# ./ss -danemi
State Recv-Q Send-Q Local Addr:Port Peer Addr:Port
LISTEN 0 0 *:5001 *:* ino:628 sk:c1340040
mem:(r0,w0,f0,t0) cwnd:0 ssthresh:0
ESTAB 0 0 172.20.0.2:5001 172.20.0.1:32785 ino:629 sk:c13409a0
mem:(r0,w0,f0,t0) ts rto:1000 rtt:0.004/0 cwnd:0 ssthresh:0 rcv_rtt:61.377
This, for instance, shows that we're not congestion controlling ACKs,
as the above output is in the ttcp receiving host, and ttcp is a one
way app, i.e. the received never calls sendmsg, so
ccid_hc_tx_send_packet is never called, so the TX half connection
stays in TFRC_SSTATE_NO_SENT state and hctx_rtt is never calculated,
stays with the value set in ccid3_hc_tx_init, 4us, as show above in
milliseconds (0.004ms), upcoming patches will fix this.
rcv_rtt seems sane tho, matching ping results :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-08-23 21:52:35 -07:00
static void ccid3_hc_rx_get_info ( struct sock * sk , struct tcp_info * info )
{
2005-09-09 02:40:58 -03:00
const struct ccid3_hc_rx_sock * hcrx = ccid3_hc_rx_sk ( sk ) ;
[DCCP]: Introduce dccp_get_info
And also hc_tx and hc_rx get_info functions for the CCIDs to fill in
information that is specific to them.
For now reusing struct tcp_info, later I'll try to figure out a better
solution, for now its really nice to get this kind of info:
[root@qemu ~]# ./ss -danemi
State Recv-Q Send-Q Local Addr:Port Peer Addr:Port
LISTEN 0 0 *:5001 *:* ino:628 sk:c1340040
mem:(r0,w0,f0,t0) cwnd:0 ssthresh:0
ESTAB 0 0 172.20.0.2:5001 172.20.0.1:32785 ino:629 sk:c13409a0
mem:(r0,w0,f0,t0) ts rto:1000 rtt:0.004/0 cwnd:0 ssthresh:0 rcv_rtt:61.377
This, for instance, shows that we're not congestion controlling ACKs,
as the above output is in the ttcp receiving host, and ttcp is a one
way app, i.e. the received never calls sendmsg, so
ccid_hc_tx_send_packet is never called, so the TX half connection
stays in TFRC_SSTATE_NO_SENT state and hctx_rtt is never calculated,
stays with the value set in ccid3_hc_tx_init, 4us, as show above in
milliseconds (0.004ms), upcoming patches will fix this.
rcv_rtt seems sane tho, matching ping results :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-08-23 21:52:35 -07:00
2005-09-12 14:16:58 -07:00
/* Listen socks doesn't have a private CCID block */
if ( sk - > sk_state = = DCCP_LISTEN )
return ;
2005-09-09 20:01:25 -03:00
BUG_ON ( hcrx = = NULL ) ;
[DCCP]: Introduce dccp_get_info
And also hc_tx and hc_rx get_info functions for the CCIDs to fill in
information that is specific to them.
For now reusing struct tcp_info, later I'll try to figure out a better
solution, for now its really nice to get this kind of info:
[root@qemu ~]# ./ss -danemi
State Recv-Q Send-Q Local Addr:Port Peer Addr:Port
LISTEN 0 0 *:5001 *:* ino:628 sk:c1340040
mem:(r0,w0,f0,t0) cwnd:0 ssthresh:0
ESTAB 0 0 172.20.0.2:5001 172.20.0.1:32785 ino:629 sk:c13409a0
mem:(r0,w0,f0,t0) ts rto:1000 rtt:0.004/0 cwnd:0 ssthresh:0 rcv_rtt:61.377
This, for instance, shows that we're not congestion controlling ACKs,
as the above output is in the ttcp receiving host, and ttcp is a one
way app, i.e. the received never calls sendmsg, so
ccid_hc_tx_send_packet is never called, so the TX half connection
stays in TFRC_SSTATE_NO_SENT state and hctx_rtt is never calculated,
stays with the value set in ccid3_hc_tx_init, 4us, as show above in
milliseconds (0.004ms), upcoming patches will fix this.
rcv_rtt seems sane tho, matching ping results :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-08-23 21:52:35 -07:00
info - > tcpi_ca_state = hcrx - > ccid3hcrx_state ;
info - > tcpi_options | = TCPI_OPT_TIMESTAMPS ;
info - > tcpi_rcv_rtt = hcrx - > ccid3hcrx_rtt ;
}
static void ccid3_hc_tx_get_info ( struct sock * sk , struct tcp_info * info )
{
2005-09-09 02:40:58 -03:00
const struct ccid3_hc_tx_sock * hctx = ccid3_hc_tx_sk ( sk ) ;
[DCCP]: Introduce dccp_get_info
And also hc_tx and hc_rx get_info functions for the CCIDs to fill in
information that is specific to them.
For now reusing struct tcp_info, later I'll try to figure out a better
solution, for now its really nice to get this kind of info:
[root@qemu ~]# ./ss -danemi
State Recv-Q Send-Q Local Addr:Port Peer Addr:Port
LISTEN 0 0 *:5001 *:* ino:628 sk:c1340040
mem:(r0,w0,f0,t0) cwnd:0 ssthresh:0
ESTAB 0 0 172.20.0.2:5001 172.20.0.1:32785 ino:629 sk:c13409a0
mem:(r0,w0,f0,t0) ts rto:1000 rtt:0.004/0 cwnd:0 ssthresh:0 rcv_rtt:61.377
This, for instance, shows that we're not congestion controlling ACKs,
as the above output is in the ttcp receiving host, and ttcp is a one
way app, i.e. the received never calls sendmsg, so
ccid_hc_tx_send_packet is never called, so the TX half connection
stays in TFRC_SSTATE_NO_SENT state and hctx_rtt is never calculated,
stays with the value set in ccid3_hc_tx_init, 4us, as show above in
milliseconds (0.004ms), upcoming patches will fix this.
rcv_rtt seems sane tho, matching ping results :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-08-23 21:52:35 -07:00
2005-09-12 14:16:58 -07:00
/* Listen socks doesn't have a private CCID block */
if ( sk - > sk_state = = DCCP_LISTEN )
return ;
2005-09-09 20:01:25 -03:00
BUG_ON ( hctx = = NULL ) ;
[DCCP]: Introduce dccp_get_info
And also hc_tx and hc_rx get_info functions for the CCIDs to fill in
information that is specific to them.
For now reusing struct tcp_info, later I'll try to figure out a better
solution, for now its really nice to get this kind of info:
[root@qemu ~]# ./ss -danemi
State Recv-Q Send-Q Local Addr:Port Peer Addr:Port
LISTEN 0 0 *:5001 *:* ino:628 sk:c1340040
mem:(r0,w0,f0,t0) cwnd:0 ssthresh:0
ESTAB 0 0 172.20.0.2:5001 172.20.0.1:32785 ino:629 sk:c13409a0
mem:(r0,w0,f0,t0) ts rto:1000 rtt:0.004/0 cwnd:0 ssthresh:0 rcv_rtt:61.377
This, for instance, shows that we're not congestion controlling ACKs,
as the above output is in the ttcp receiving host, and ttcp is a one
way app, i.e. the received never calls sendmsg, so
ccid_hc_tx_send_packet is never called, so the TX half connection
stays in TFRC_SSTATE_NO_SENT state and hctx_rtt is never calculated,
stays with the value set in ccid3_hc_tx_init, 4us, as show above in
milliseconds (0.004ms), upcoming patches will fix this.
rcv_rtt seems sane tho, matching ping results :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-08-23 21:52:35 -07:00
info - > tcpi_rto = hctx - > ccid3hctx_t_rto ;
info - > tcpi_rtt = hctx - > ccid3hctx_rtt ;
}
2005-09-18 00:19:32 -07:00
static int ccid3_hc_rx_getsockopt ( struct sock * sk , const int optname , int len ,
u32 __user * optval , int __user * optlen )
{
const struct ccid3_hc_rx_sock * hcrx = ccid3_hc_rx_sk ( sk ) ;
const void * val ;
/* Listen socks doesn't have a private CCID block */
if ( sk - > sk_state = = DCCP_LISTEN )
return - EINVAL ;
switch ( optname ) {
case DCCP_SOCKOPT_CCID_RX_INFO :
if ( len < sizeof ( hcrx - > ccid3hcrx_tfrc ) )
return - EINVAL ;
len = sizeof ( hcrx - > ccid3hcrx_tfrc ) ;
val = & hcrx - > ccid3hcrx_tfrc ;
break ;
default :
return - ENOPROTOOPT ;
}
if ( put_user ( len , optlen ) | | copy_to_user ( optval , val , len ) )
return - EFAULT ;
return 0 ;
}
static int ccid3_hc_tx_getsockopt ( struct sock * sk , const int optname , int len ,
u32 __user * optval , int __user * optlen )
{
const struct ccid3_hc_tx_sock * hctx = ccid3_hc_tx_sk ( sk ) ;
const void * val ;
/* Listen socks doesn't have a private CCID block */
if ( sk - > sk_state = = DCCP_LISTEN )
return - EINVAL ;
switch ( optname ) {
case DCCP_SOCKOPT_CCID_TX_INFO :
if ( len < sizeof ( hctx - > ccid3hctx_tfrc ) )
return - EINVAL ;
len = sizeof ( hctx - > ccid3hctx_tfrc ) ;
val = & hctx - > ccid3hctx_tfrc ;
break ;
default :
return - ENOPROTOOPT ;
}
if ( put_user ( len , optlen ) | | copy_to_user ( optval , val , len ) )
return - EFAULT ;
return 0 ;
}
2006-03-20 19:21:44 -08:00
static struct ccid_operations ccid3 = {
2006-09-22 14:26:44 +12:00
. ccid_id = DCCPC_CCID3 ,
2005-08-09 20:14:34 -07:00
. ccid_name = " ccid3 " ,
. ccid_owner = THIS_MODULE ,
2006-03-20 19:21:44 -08:00
. ccid_hc_tx_obj_size = sizeof ( struct ccid3_hc_tx_sock ) ,
2005-08-09 20:14:34 -07:00
. ccid_hc_tx_init = ccid3_hc_tx_init ,
. ccid_hc_tx_exit = ccid3_hc_tx_exit ,
. ccid_hc_tx_send_packet = ccid3_hc_tx_send_packet ,
. ccid_hc_tx_packet_sent = ccid3_hc_tx_packet_sent ,
. ccid_hc_tx_packet_recv = ccid3_hc_tx_packet_recv ,
. ccid_hc_tx_insert_options = ccid3_hc_tx_insert_options ,
. ccid_hc_tx_parse_options = ccid3_hc_tx_parse_options ,
2006-03-20 19:21:44 -08:00
. ccid_hc_rx_obj_size = sizeof ( struct ccid3_hc_rx_sock ) ,
2005-08-09 20:14:34 -07:00
. ccid_hc_rx_init = ccid3_hc_rx_init ,
. ccid_hc_rx_exit = ccid3_hc_rx_exit ,
. ccid_hc_rx_insert_options = ccid3_hc_rx_insert_options ,
. ccid_hc_rx_packet_recv = ccid3_hc_rx_packet_recv ,
[DCCP]: Introduce dccp_get_info
And also hc_tx and hc_rx get_info functions for the CCIDs to fill in
information that is specific to them.
For now reusing struct tcp_info, later I'll try to figure out a better
solution, for now its really nice to get this kind of info:
[root@qemu ~]# ./ss -danemi
State Recv-Q Send-Q Local Addr:Port Peer Addr:Port
LISTEN 0 0 *:5001 *:* ino:628 sk:c1340040
mem:(r0,w0,f0,t0) cwnd:0 ssthresh:0
ESTAB 0 0 172.20.0.2:5001 172.20.0.1:32785 ino:629 sk:c13409a0
mem:(r0,w0,f0,t0) ts rto:1000 rtt:0.004/0 cwnd:0 ssthresh:0 rcv_rtt:61.377
This, for instance, shows that we're not congestion controlling ACKs,
as the above output is in the ttcp receiving host, and ttcp is a one
way app, i.e. the received never calls sendmsg, so
ccid_hc_tx_send_packet is never called, so the TX half connection
stays in TFRC_SSTATE_NO_SENT state and hctx_rtt is never calculated,
stays with the value set in ccid3_hc_tx_init, 4us, as show above in
milliseconds (0.004ms), upcoming patches will fix this.
rcv_rtt seems sane tho, matching ping results :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-08-23 21:52:35 -07:00
. ccid_hc_rx_get_info = ccid3_hc_rx_get_info ,
. ccid_hc_tx_get_info = ccid3_hc_tx_get_info ,
2005-09-18 00:19:32 -07:00
. ccid_hc_rx_getsockopt = ccid3_hc_rx_getsockopt ,
. ccid_hc_tx_getsockopt = ccid3_hc_tx_getsockopt ,
2005-08-09 20:14:34 -07:00
} ;
module_param ( ccid3_debug , int , 0444 ) ;
MODULE_PARM_DESC ( ccid3_debug , " Enable debug messages " ) ;
static __init int ccid3_module_init ( void )
{
2005-08-10 12:59:38 -03:00
int rc = - ENOBUFS ;
2005-08-09 20:14:34 -07:00
2005-08-10 12:59:38 -03:00
ccid3_rx_hist = dccp_rx_hist_new ( " ccid3 " ) ;
if ( ccid3_rx_hist = = NULL )
2005-08-09 20:14:34 -07:00
goto out ;
2005-08-10 12:59:38 -03:00
ccid3_tx_hist = dccp_tx_hist_new ( " ccid3 " ) ;
if ( ccid3_tx_hist = = NULL )
goto out_free_rx ;
2005-08-09 20:14:34 -07:00
2005-08-27 23:03:09 -03:00
ccid3_li_hist = dccp_li_hist_new ( " ccid3 " ) ;
if ( ccid3_li_hist = = NULL )
2005-08-10 12:59:38 -03:00
goto out_free_tx ;
2005-08-09 20:14:34 -07:00
rc = ccid_register ( & ccid3 ) ;
if ( rc ! = 0 )
goto out_free_loss_interval_history ;
out :
return rc ;
2005-08-10 12:59:38 -03:00
2005-08-09 20:14:34 -07:00
out_free_loss_interval_history :
2005-08-27 23:03:09 -03:00
dccp_li_hist_delete ( ccid3_li_hist ) ;
ccid3_li_hist = NULL ;
2005-08-10 12:59:38 -03:00
out_free_tx :
dccp_tx_hist_delete ( ccid3_tx_hist ) ;
ccid3_tx_hist = NULL ;
out_free_rx :
dccp_rx_hist_delete ( ccid3_rx_hist ) ;
ccid3_rx_hist = NULL ;
2005-08-09 20:14:34 -07:00
goto out ;
}
module_init ( ccid3_module_init ) ;
static __exit void ccid3_module_exit ( void )
{
ccid_unregister ( & ccid3 ) ;
2005-08-10 12:59:38 -03:00
if ( ccid3_tx_hist ! = NULL ) {
dccp_tx_hist_delete ( ccid3_tx_hist ) ;
ccid3_tx_hist = NULL ;
2005-08-09 20:14:34 -07:00
}
2005-08-10 12:59:38 -03:00
if ( ccid3_rx_hist ! = NULL ) {
dccp_rx_hist_delete ( ccid3_rx_hist ) ;
ccid3_rx_hist = NULL ;
2005-08-09 20:14:34 -07:00
}
2005-08-27 23:03:09 -03:00
if ( ccid3_li_hist ! = NULL ) {
dccp_li_hist_delete ( ccid3_li_hist ) ;
ccid3_li_hist = NULL ;
2005-08-09 20:14:34 -07:00
}
}
module_exit ( ccid3_module_exit ) ;
2006-08-26 19:01:30 -07:00
MODULE_AUTHOR ( " Ian McDonald <ian.mcdonald@jandi.co.nz>, "
2005-08-27 03:51:58 -03:00
" Arnaldo Carvalho de Melo <acme@ghostprotocols.net> " ) ;
2005-08-09 20:14:34 -07:00
MODULE_DESCRIPTION ( " DCCP TFRC CCID3 CCID " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " net-dccp-ccid-3 " ) ;