diff -Nurp linux-2.4.20.orig/include/linux/sysctl.h linux-2.4.20abc/include/linux/sysctl.h --- linux-2.4.20.orig/include/linux/sysctl.h Fri Nov 29 00:53:15 2002 +++ linux-2.4.20abc/include/linux/sysctl.h Tue Mar 4 11:22:00 2003 @@ -292,7 +292,9 @@ enum NET_IPV4_NONLOCAL_BIND=88, NET_IPV4_ICMP_RATELIMIT=89, NET_IPV4_ICMP_RATEMASK=90, - NET_TCP_TW_REUSE=91 + NET_TCP_TW_REUSE=91, + NET_TCP_ABC=92, + NET_TCP_ABC_L=93 }; enum { diff -Nurp linux-2.4.20.orig/include/net/sock.h linux-2.4.20abc/include/net/sock.h --- linux-2.4.20.orig/include/net/sock.h Sat Aug 3 02:39:46 2002 +++ linux-2.4.20abc/include/net/sock.h Tue Mar 4 11:23:17 2003 @@ -394,6 +394,9 @@ struct tcp_opt { __u8 urg_mode; /* In urgent mode */ __u32 snd_up; /* Urgent pointer */ + /* Appropriate Byte Counting (RFC3465) */ + __u32 bytes_acked; + /* The syn_wait_lock is necessary only to avoid tcp_get_info having * to grab the main lock sock while browsing the listening hash * (otherwise it's deadlock prone). diff -Nurp linux-2.4.20.orig/include/net/tcp.h linux-2.4.20abc/include/net/tcp.h --- linux-2.4.20.orig/include/net/tcp.h Fri Nov 29 00:53:15 2002 +++ linux-2.4.20abc/include/net/tcp.h Tue Mar 4 11:25:18 2003 @@ -460,6 +460,8 @@ extern int sysctl_tcp_rmem[3]; extern int sysctl_tcp_app_win; extern int sysctl_tcp_adv_win_scale; extern int sysctl_tcp_tw_reuse; +extern int sysctl_tcp_abc; +extern int sysctl_tcp_abc_L; extern atomic_t tcp_memory_allocated; extern atomic_t tcp_sockets_allocated; @@ -1138,6 +1140,7 @@ static inline void __tcp_enter_cwr(struc static inline void tcp_enter_cwr(struct tcp_opt *tp) { tp->prior_ssthresh = 0; + tp->bytes_acked = 0; if (tp->ca_state < TCP_CA_CWR) { __tcp_enter_cwr(tp); tp->ca_state = TCP_CA_CWR; diff -Nurp linux-2.4.20.orig/net/ipv4/sysctl_net_ipv4.c linux-2.4.20abc/net/ipv4/sysctl_net_ipv4.c --- linux-2.4.20.orig/net/ipv4/sysctl_net_ipv4.c Sat Aug 3 02:39:46 2002 +++ linux-2.4.20abc/net/ipv4/sysctl_net_ipv4.c Mon Mar 3 11:45:43 2003 @@ -221,6 +221,10 @@ ctl_table ipv4_table[] = { &sysctl_icmp_ratemask, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_TCP_TW_REUSE, "tcp_tw_reuse", &sysctl_tcp_tw_reuse, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_TCP_ABC, "tcp_abc", + &sysctl_tcp_abc, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_TCP_ABC_L, "tcp_abc_L", + &sysctl_tcp_abc_L, sizeof(int), 0644, NULL, &proc_dointvec}, {0} }; diff -Nurp linux-2.4.20.orig/net/ipv4/tcp.c linux-2.4.20abc/net/ipv4/tcp.c --- linux-2.4.20.orig/net/ipv4/tcp.c Fri Nov 29 00:53:15 2002 +++ linux-2.4.20abc/net/ipv4/tcp.c Mon Mar 3 15:47:14 2003 @@ -2123,6 +2123,7 @@ int tcp_disconnect(struct sock *sk, int tp->packets_out = 0; tp->snd_ssthresh = 0x7fffffff; tp->snd_cwnd_cnt = 0; + tp->bytes_acked = 0; tp->ca_state = TCP_CA_Open; tcp_clear_retrans(tp); tcp_delack_init(tp); diff -Nurp linux-2.4.20.orig/net/ipv4/tcp_input.c linux-2.4.20abc/net/ipv4/tcp_input.c --- linux-2.4.20.orig/net/ipv4/tcp_input.c Fri Nov 29 00:53:15 2002 +++ linux-2.4.20abc/net/ipv4/tcp_input.c Tue Mar 4 14:14:32 2003 @@ -87,6 +87,9 @@ int sysctl_tcp_stdurg = 0; int sysctl_tcp_rfc1337 = 0; int sysctl_tcp_max_orphans = NR_FILE; +int sysctl_tcp_abc = 1; +int sysctl_tcp_abc_L = 2; + #define FLAG_DATA 0x01 /* Incoming frame contained data. */ #define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */ #define FLAG_DATA_ACKED 0x04 /* This ACK acknowledged new data. */ @@ -987,6 +990,7 @@ void tcp_enter_loss(struct sock *sk, int } tp->snd_cwnd = 1; tp->snd_cwnd_cnt = 0; + tp->bytes_acked = 0; tp->snd_cwnd_stamp = tcp_time_stamp; tcp_clear_retrans(tp); @@ -1625,6 +1629,7 @@ tcp_fastretrans_alert(struct sock *sk, u } tp->snd_cwnd_cnt = 0; + tp->bytes_acked = 0; tp->ca_state = TCP_CA_Recovery; } @@ -1696,24 +1701,57 @@ tcp_ack_update_rtt(struct tcp_opt *tp, i /* This is Jacobson's slow start and congestion avoidance. * SIGCOMM '88, p. 328. */ -static __inline__ void tcp_cong_avoid(struct tcp_opt *tp) +static __inline__ void tcp_cong_avoid(struct tcp_opt *tp, unsigned int mss_now) { - if (tp->snd_cwnd <= tp->snd_ssthresh) { - /* In "safe" area, increase. */ - if (tp->snd_cwnd < tp->snd_cwnd_clamp) - tp->snd_cwnd++; + int incrs_applied = 0; + + if (sysctl_tcp_abc && !tp->nonagle) { + while (tp->bytes_acked > mss_now && incrs_applied < sysctl_tcp_abc_L) { + tp->bytes_acked -= mss_now; + if (tp->snd_cwnd <= tp->snd_ssthresh) { + /* In "safe" area, increase. */ + if (tp->snd_cwnd < tp->snd_cwnd_clamp) + tp->snd_cwnd++; + incrs_applied++; + } else { + /* In dangerous area, increase slowly. + * In theory this is tp->snd_cwnd += 1 / tp->snd_cwnd + */ + if (tp->snd_cwnd_cnt >= tp->snd_cwnd) { + if (tp->snd_cwnd < tp->snd_cwnd_clamp) + tp->snd_cwnd++; + tp->snd_cwnd_cnt=0; + incrs_applied++; + } else + tp->snd_cwnd_cnt++; + } + tp->snd_cwnd_stamp = tcp_time_stamp; + } + + if (tp->snd_cwnd <= tp->snd_ssthresh) { + while(tp->bytes_acked > mss_now){ + /* only apply per ack in slow start */ + tp->bytes_acked -= mss_now; + } + } } else { - /* In dangerous area, increase slowly. - * In theory this is tp->snd_cwnd += 1 / tp->snd_cwnd - */ - if (tp->snd_cwnd_cnt >= tp->snd_cwnd) { + if (tp->snd_cwnd <= tp->snd_ssthresh) { + /* In "safe" area, increase. */ if (tp->snd_cwnd < tp->snd_cwnd_clamp) tp->snd_cwnd++; - tp->snd_cwnd_cnt=0; - } else - tp->snd_cwnd_cnt++; - } - tp->snd_cwnd_stamp = tcp_time_stamp; + } else { + /* In dangerous area, increase slowly. + * In theory this is tp->snd_cwnd += 1 / tp->snd_cwnd + */ + if (tp->snd_cwnd_cnt >= tp->snd_cwnd) { + if (tp->snd_cwnd < tp->snd_cwnd_clamp) + tp->snd_cwnd++; + tp->snd_cwnd_cnt=0; + } else + tp->snd_cwnd_cnt++; + } + tp->snd_cwnd_stamp = tcp_time_stamp; + } } /* Restart timer after forward progress on connection. @@ -1901,6 +1939,7 @@ static int tcp_ack(struct sock *sk, stru u32 ack = TCP_SKB_CB(skb)->ack_seq; u32 prior_in_flight; int prior_packets; + int mss_now = tcp_current_mss(sk); /* Need mss for ABC in tcp_cong_avoid */ /* If the ack is newer than sent or older than previous acks * then we can probably ignore it. @@ -1911,6 +1950,10 @@ static int tcp_ack(struct sock *sk, stru if (before(ack, prior_snd_una)) goto old_ack; + if (sysctl_tcp_abc && tp->ca_state < TCP_CA_CWR) { + tp->bytes_acked += ack - prior_snd_una; + } + if (!(flag&FLAG_SLOWPATH) && after(ack, prior_snd_una)) { /* Window is constant, pure forward advance. * No more checks are required. @@ -1948,16 +1991,17 @@ static int tcp_ack(struct sock *sk, stru /* See if we can take anything off of the retransmit queue. */ flag |= tcp_clean_rtx_queue(sk); - + + if (tcp_ack_is_dubious(tp, flag)) { /* Advanve CWND, if state allows this. */ if ((flag&FLAG_DATA_ACKED) && prior_in_flight >= tp->snd_cwnd && tcp_may_raise_cwnd(tp, flag)) - tcp_cong_avoid(tp); + tcp_cong_avoid(tp, mss_now); tcp_fastretrans_alert(sk, prior_snd_una, prior_packets, flag); } else { if ((flag&FLAG_DATA_ACKED) && prior_in_flight >= tp->snd_cwnd) - tcp_cong_avoid(tp); + tcp_cong_avoid(tp, mss_now); } if ((flag & FLAG_FORWARD_PROGRESS) || !(flag&FLAG_NOT_DUP)) diff -Nurp linux-2.4.20.orig/net/ipv4/tcp_minisocks.c linux-2.4.20abc/net/ipv4/tcp_minisocks.c --- linux-2.4.20.orig/net/ipv4/tcp_minisocks.c Fri Nov 29 00:53:15 2002 +++ linux-2.4.20abc/net/ipv4/tcp_minisocks.c Mon Mar 3 15:49:25 2003 @@ -714,6 +714,7 @@ struct sock *tcp_create_openreq_child(st */ newtp->snd_cwnd = 2; newtp->snd_cwnd_cnt = 0; + newtp->bytes_acked = 0; newtp->ca_state = TCP_CA_Open; tcp_init_xmit_timers(newsk);