Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * TCP Westwood+: end-to-end bandwidth estimation for TCP
0004  *
0005  *      Angelo Dell'Aera: author of the first version of TCP Westwood+ in Linux 2.4
0006  *
0007  * Support at http://c3lab.poliba.it/index.php/Westwood
0008  * Main references in literature:
0009  *
0010  * - Mascolo S, Casetti, M. Gerla et al.
0011  *   "TCP Westwood: bandwidth estimation for TCP" Proc. ACM Mobicom 2001
0012  *
0013  * - A. Grieco, s. Mascolo
0014  *   "Performance evaluation of New Reno, Vegas, Westwood+ TCP" ACM Computer
0015  *     Comm. Review, 2004
0016  *
0017  * - A. Dell'Aera, L. Grieco, S. Mascolo.
0018  *   "Linux 2.4 Implementation of Westwood+ TCP with Rate-Halving :
0019  *    A Performance Evaluation Over the Internet" (ICC 2004), Paris, June 2004
0020  *
0021  * Westwood+ employs end-to-end bandwidth measurement to set cwnd and
0022  * ssthresh after packet loss. The probing phase is as the original Reno.
0023  */
0024 
0025 #include <linux/mm.h>
0026 #include <linux/module.h>
0027 #include <linux/skbuff.h>
0028 #include <linux/inet_diag.h>
0029 #include <net/tcp.h>
0030 
0031 /* TCP Westwood structure */
0032 struct westwood {
0033     u32    bw_ns_est;        /* first bandwidth estimation..not too smoothed 8) */
0034     u32    bw_est;           /* bandwidth estimate */
0035     u32    rtt_win_sx;       /* here starts a new evaluation... */
0036     u32    bk;
0037     u32    snd_una;          /* used for evaluating the number of acked bytes */
0038     u32    cumul_ack;
0039     u32    accounted;
0040     u32    rtt;
0041     u32    rtt_min;          /* minimum observed RTT */
0042     u8     first_ack;        /* flag which infers that this is the first ack */
0043     u8     reset_rtt_min;    /* Reset RTT min to next RTT sample*/
0044 };
0045 
0046 /* TCP Westwood functions and constants */
0047 #define TCP_WESTWOOD_RTT_MIN   (HZ/20)  /* 50ms */
0048 #define TCP_WESTWOOD_INIT_RTT  (20*HZ)  /* maybe too conservative?! */
0049 
0050 /*
0051  * @tcp_westwood_create
0052  * This function initializes fields used in TCP Westwood+,
0053  * it is called after the initial SYN, so the sequence numbers
0054  * are correct but new passive connections we have no
0055  * information about RTTmin at this time so we simply set it to
0056  * TCP_WESTWOOD_INIT_RTT. This value was chosen to be too conservative
0057  * since in this way we're sure it will be updated in a consistent
0058  * way as soon as possible. It will reasonably happen within the first
0059  * RTT period of the connection lifetime.
0060  */
0061 static void tcp_westwood_init(struct sock *sk)
0062 {
0063     struct westwood *w = inet_csk_ca(sk);
0064 
0065     w->bk = 0;
0066     w->bw_ns_est = 0;
0067     w->bw_est = 0;
0068     w->accounted = 0;
0069     w->cumul_ack = 0;
0070     w->reset_rtt_min = 1;
0071     w->rtt_min = w->rtt = TCP_WESTWOOD_INIT_RTT;
0072     w->rtt_win_sx = tcp_jiffies32;
0073     w->snd_una = tcp_sk(sk)->snd_una;
0074     w->first_ack = 1;
0075 }
0076 
0077 /*
0078  * @westwood_do_filter
0079  * Low-pass filter. Implemented using constant coefficients.
0080  */
0081 static inline u32 westwood_do_filter(u32 a, u32 b)
0082 {
0083     return ((7 * a) + b) >> 3;
0084 }
0085 
0086 static void westwood_filter(struct westwood *w, u32 delta)
0087 {
0088     /* If the filter is empty fill it with the first sample of bandwidth  */
0089     if (w->bw_ns_est == 0 && w->bw_est == 0) {
0090         w->bw_ns_est = w->bk / delta;
0091         w->bw_est = w->bw_ns_est;
0092     } else {
0093         w->bw_ns_est = westwood_do_filter(w->bw_ns_est, w->bk / delta);
0094         w->bw_est = westwood_do_filter(w->bw_est, w->bw_ns_est);
0095     }
0096 }
0097 
0098 /*
0099  * @westwood_pkts_acked
0100  * Called after processing group of packets.
0101  * but all westwood needs is the last sample of srtt.
0102  */
0103 static void tcp_westwood_pkts_acked(struct sock *sk,
0104                     const struct ack_sample *sample)
0105 {
0106     struct westwood *w = inet_csk_ca(sk);
0107 
0108     if (sample->rtt_us > 0)
0109         w->rtt = usecs_to_jiffies(sample->rtt_us);
0110 }
0111 
0112 /*
0113  * @westwood_update_window
0114  * It updates RTT evaluation window if it is the right moment to do
0115  * it. If so it calls filter for evaluating bandwidth.
0116  */
0117 static void westwood_update_window(struct sock *sk)
0118 {
0119     struct westwood *w = inet_csk_ca(sk);
0120     s32 delta = tcp_jiffies32 - w->rtt_win_sx;
0121 
0122     /* Initialize w->snd_una with the first acked sequence number in order
0123      * to fix mismatch between tp->snd_una and w->snd_una for the first
0124      * bandwidth sample
0125      */
0126     if (w->first_ack) {
0127         w->snd_una = tcp_sk(sk)->snd_una;
0128         w->first_ack = 0;
0129     }
0130 
0131     /*
0132      * See if a RTT-window has passed.
0133      * Be careful since if RTT is less than
0134      * 50ms we don't filter but we continue 'building the sample'.
0135      * This minimum limit was chosen since an estimation on small
0136      * time intervals is better to avoid...
0137      * Obviously on a LAN we reasonably will always have
0138      * right_bound = left_bound + WESTWOOD_RTT_MIN
0139      */
0140     if (w->rtt && delta > max_t(u32, w->rtt, TCP_WESTWOOD_RTT_MIN)) {
0141         westwood_filter(w, delta);
0142 
0143         w->bk = 0;
0144         w->rtt_win_sx = tcp_jiffies32;
0145     }
0146 }
0147 
0148 static inline void update_rtt_min(struct westwood *w)
0149 {
0150     if (w->reset_rtt_min) {
0151         w->rtt_min = w->rtt;
0152         w->reset_rtt_min = 0;
0153     } else
0154         w->rtt_min = min(w->rtt, w->rtt_min);
0155 }
0156 
0157 /*
0158  * @westwood_fast_bw
0159  * It is called when we are in fast path. In particular it is called when
0160  * header prediction is successful. In such case in fact update is
0161  * straight forward and doesn't need any particular care.
0162  */
0163 static inline void westwood_fast_bw(struct sock *sk)
0164 {
0165     const struct tcp_sock *tp = tcp_sk(sk);
0166     struct westwood *w = inet_csk_ca(sk);
0167 
0168     westwood_update_window(sk);
0169 
0170     w->bk += tp->snd_una - w->snd_una;
0171     w->snd_una = tp->snd_una;
0172     update_rtt_min(w);
0173 }
0174 
0175 /*
0176  * @westwood_acked_count
0177  * This function evaluates cumul_ack for evaluating bk in case of
0178  * delayed or partial acks.
0179  */
0180 static inline u32 westwood_acked_count(struct sock *sk)
0181 {
0182     const struct tcp_sock *tp = tcp_sk(sk);
0183     struct westwood *w = inet_csk_ca(sk);
0184 
0185     w->cumul_ack = tp->snd_una - w->snd_una;
0186 
0187     /* If cumul_ack is 0 this is a dupack since it's not moving
0188      * tp->snd_una.
0189      */
0190     if (!w->cumul_ack) {
0191         w->accounted += tp->mss_cache;
0192         w->cumul_ack = tp->mss_cache;
0193     }
0194 
0195     if (w->cumul_ack > tp->mss_cache) {
0196         /* Partial or delayed ack */
0197         if (w->accounted >= w->cumul_ack) {
0198             w->accounted -= w->cumul_ack;
0199             w->cumul_ack = tp->mss_cache;
0200         } else {
0201             w->cumul_ack -= w->accounted;
0202             w->accounted = 0;
0203         }
0204     }
0205 
0206     w->snd_una = tp->snd_una;
0207 
0208     return w->cumul_ack;
0209 }
0210 
0211 /*
0212  * TCP Westwood
0213  * Here limit is evaluated as Bw estimation*RTTmin (for obtaining it
0214  * in packets we use mss_cache). Rttmin is guaranteed to be >= 2
0215  * so avoids ever returning 0.
0216  */
0217 static u32 tcp_westwood_bw_rttmin(const struct sock *sk)
0218 {
0219     const struct tcp_sock *tp = tcp_sk(sk);
0220     const struct westwood *w = inet_csk_ca(sk);
0221 
0222     return max_t(u32, (w->bw_est * w->rtt_min) / tp->mss_cache, 2);
0223 }
0224 
0225 static void tcp_westwood_ack(struct sock *sk, u32 ack_flags)
0226 {
0227     if (ack_flags & CA_ACK_SLOWPATH) {
0228         struct westwood *w = inet_csk_ca(sk);
0229 
0230         westwood_update_window(sk);
0231         w->bk += westwood_acked_count(sk);
0232 
0233         update_rtt_min(w);
0234         return;
0235     }
0236 
0237     westwood_fast_bw(sk);
0238 }
0239 
0240 static void tcp_westwood_event(struct sock *sk, enum tcp_ca_event event)
0241 {
0242     struct tcp_sock *tp = tcp_sk(sk);
0243     struct westwood *w = inet_csk_ca(sk);
0244 
0245     switch (event) {
0246     case CA_EVENT_COMPLETE_CWR:
0247         tp->snd_ssthresh = tcp_westwood_bw_rttmin(sk);
0248         tcp_snd_cwnd_set(tp, tp->snd_ssthresh);
0249         break;
0250     case CA_EVENT_LOSS:
0251         tp->snd_ssthresh = tcp_westwood_bw_rttmin(sk);
0252         /* Update RTT_min when next ack arrives */
0253         w->reset_rtt_min = 1;
0254         break;
0255     default:
0256         /* don't care */
0257         break;
0258     }
0259 }
0260 
0261 /* Extract info for Tcp socket info provided via netlink. */
0262 static size_t tcp_westwood_info(struct sock *sk, u32 ext, int *attr,
0263                 union tcp_cc_info *info)
0264 {
0265     const struct westwood *ca = inet_csk_ca(sk);
0266 
0267     if (ext & (1 << (INET_DIAG_VEGASINFO - 1))) {
0268         info->vegas.tcpv_enabled = 1;
0269         info->vegas.tcpv_rttcnt = 0;
0270         info->vegas.tcpv_rtt    = jiffies_to_usecs(ca->rtt);
0271         info->vegas.tcpv_minrtt = jiffies_to_usecs(ca->rtt_min);
0272 
0273         *attr = INET_DIAG_VEGASINFO;
0274         return sizeof(struct tcpvegas_info);
0275     }
0276     return 0;
0277 }
0278 
0279 static struct tcp_congestion_ops tcp_westwood __read_mostly = {
0280     .init       = tcp_westwood_init,
0281     .ssthresh   = tcp_reno_ssthresh,
0282     .cong_avoid = tcp_reno_cong_avoid,
0283     .undo_cwnd      = tcp_reno_undo_cwnd,
0284     .cwnd_event = tcp_westwood_event,
0285     .in_ack_event   = tcp_westwood_ack,
0286     .get_info   = tcp_westwood_info,
0287     .pkts_acked = tcp_westwood_pkts_acked,
0288 
0289     .owner      = THIS_MODULE,
0290     .name       = "westwood"
0291 };
0292 
0293 static int __init tcp_westwood_register(void)
0294 {
0295     BUILD_BUG_ON(sizeof(struct westwood) > ICSK_CA_PRIV_SIZE);
0296     return tcp_register_congestion_control(&tcp_westwood);
0297 }
0298 
0299 static void __exit tcp_westwood_unregister(void)
0300 {
0301     tcp_unregister_congestion_control(&tcp_westwood);
0302 }
0303 
0304 module_init(tcp_westwood_register);
0305 module_exit(tcp_westwood_unregister);
0306 
0307 MODULE_AUTHOR("Stephen Hemminger, Angelo Dell'Aera");
0308 MODULE_LICENSE("GPL");
0309 MODULE_DESCRIPTION("TCP Westwood+");