^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * TCP Low Priority (TCP-LP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * TCP Low Priority is a distributed algorithm whose goal is to utilize only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * the excess network bandwidth as compared to the ``fair share`` of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * bandwidth as targeted by TCP.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * As of 2.6.13, Linux supports pluggable congestion control algorithms.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Due to the limitation of the API, we take the following changes from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * the original TCP-LP implementation:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * o We use newReno in most core CA handling. Only add some checking
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * within cong_avoid.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * o Error correcting in remote HZ, therefore remote HZ will be keeped
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * on checking and updating.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * o Handling calculation of One-Way-Delay (OWD) within rtt_sample, since
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * OWD have a similar meaning as RTT. Also correct the buggy formular.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * o Handle reaction for Early Congestion Indication (ECI) within
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * pkts_acked, as mentioned within pseudo code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * o OWD is handled in relative format, where local time stamp will in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * tcp_time_stamp format.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * Original Author:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * Aleksandar Kuzmanovic <akuzma@northwestern.edu>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * Available from:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * http://www.ece.rice.edu/~akuzma/Doc/akuzma/TCP-LP.pdf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * Original implementation for 2.4.19:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * http://www-ece.rice.edu/networks/TCP-LP/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * 2.6.x module Authors:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * Wong Hoi Sing, Edison <hswong3i@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * Hung Hing Lun, Mike <hlhung3i@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * SourceForge project page:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * http://tcp-lp-mod.sourceforge.net/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <net/tcp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) /* resolution of owd */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define LP_RESOL TCP_TS_HZ
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * enum tcp_lp_state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * @LP_VALID_RHZ: is remote HZ valid?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * @LP_VALID_OWD: is OWD valid?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * @LP_WITHIN_THR: are we within threshold?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * @LP_WITHIN_INF: are we within inference?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * TCP-LP's state flags.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * We create this set of state flag mainly for debugging.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) enum tcp_lp_state {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) LP_VALID_RHZ = (1 << 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) LP_VALID_OWD = (1 << 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) LP_WITHIN_THR = (1 << 3),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) LP_WITHIN_INF = (1 << 4),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * struct lp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * @flag: TCP-LP state flag
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * @sowd: smoothed OWD << 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * @owd_min: min OWD
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * @owd_max: max OWD
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * @owd_max_rsv: resrved max owd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * @remote_hz: estimated remote HZ
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * @remote_ref_time: remote reference time
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * @local_ref_time: local reference time
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * @last_drop: time for last active drop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * @inference: current inference
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * TCP-LP's private struct.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * We get the idea from original TCP-LP implementation where only left those we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * found are really useful.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) struct lp {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) u32 flag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) u32 sowd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) u32 owd_min;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) u32 owd_max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) u32 owd_max_rsv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) u32 remote_hz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) u32 remote_ref_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) u32 local_ref_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) u32 last_drop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) u32 inference;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * tcp_lp_init
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * Init all required variables.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * Clone the handling from Vegas module implementation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static void tcp_lp_init(struct sock *sk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) struct lp *lp = inet_csk_ca(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) lp->flag = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) lp->sowd = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) lp->owd_min = 0xffffffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) lp->owd_max = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) lp->owd_max_rsv = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) lp->remote_hz = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) lp->remote_ref_time = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) lp->local_ref_time = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) lp->last_drop = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) lp->inference = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) * tcp_lp_cong_avoid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) * Implementation of cong_avoid.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) * Will only call newReno CA when away from inference.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * From TCP-LP's paper, this will be handled in additive increasement.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) static void tcp_lp_cong_avoid(struct sock *sk, u32 ack, u32 acked)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) struct lp *lp = inet_csk_ca(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (!(lp->flag & LP_WITHIN_INF))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) tcp_reno_cong_avoid(sk, ack, acked);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * tcp_lp_remote_hz_estimator
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * Estimate remote HZ.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * We keep on updating the estimated value, where original TCP-LP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * implementation only guest it for once and use forever.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) static u32 tcp_lp_remote_hz_estimator(struct sock *sk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) struct tcp_sock *tp = tcp_sk(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) struct lp *lp = inet_csk_ca(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) s64 rhz = lp->remote_hz << 6; /* remote HZ << 6 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) s64 m = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) /* not yet record reference time
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) * go away!! record it before come back!! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) if (lp->remote_ref_time == 0 || lp->local_ref_time == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) /* we can't calc remote HZ with no different!! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if (tp->rx_opt.rcv_tsval == lp->remote_ref_time ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) tp->rx_opt.rcv_tsecr == lp->local_ref_time)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) m = TCP_TS_HZ *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) (tp->rx_opt.rcv_tsval - lp->remote_ref_time) /
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) (tp->rx_opt.rcv_tsecr - lp->local_ref_time);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if (m < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) m = -m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (rhz > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) m -= rhz >> 6; /* m is now error in remote HZ est */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) rhz += m; /* 63/64 old + 1/64 new */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) rhz = m << 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) /* record time for successful remote HZ calc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) if ((rhz >> 6) > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) lp->flag |= LP_VALID_RHZ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) lp->flag &= ~LP_VALID_RHZ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) /* record reference time stamp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) lp->remote_ref_time = tp->rx_opt.rcv_tsval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) lp->local_ref_time = tp->rx_opt.rcv_tsecr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) return rhz >> 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) * tcp_lp_owd_calculator
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) * Calculate one way delay (in relative format).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) * Original implement OWD as minus of remote time difference to local time
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) * difference directly. As this time difference just simply equal to RTT, when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) * the network status is stable, remote RTT will equal to local RTT, and result
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) * OWD into zero.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) * It seems to be a bug and so we fixed it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) static u32 tcp_lp_owd_calculator(struct sock *sk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) struct tcp_sock *tp = tcp_sk(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) struct lp *lp = inet_csk_ca(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) s64 owd = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) lp->remote_hz = tcp_lp_remote_hz_estimator(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (lp->flag & LP_VALID_RHZ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) owd =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) tp->rx_opt.rcv_tsval * (LP_RESOL / lp->remote_hz) -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) tp->rx_opt.rcv_tsecr * (LP_RESOL / TCP_TS_HZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (owd < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) owd = -owd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (owd > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) lp->flag |= LP_VALID_OWD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) lp->flag &= ~LP_VALID_OWD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) return owd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) * tcp_lp_rtt_sample
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) * Implementation or rtt_sample.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) * Will take the following action,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) * 1. calc OWD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) * 2. record the min/max OWD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * 3. calc smoothed OWD (SOWD).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) * Most ideas come from the original TCP-LP implementation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) static void tcp_lp_rtt_sample(struct sock *sk, u32 rtt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) struct lp *lp = inet_csk_ca(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) s64 mowd = tcp_lp_owd_calculator(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) /* sorry that we don't have valid data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (!(lp->flag & LP_VALID_RHZ) || !(lp->flag & LP_VALID_OWD))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) /* record the next min owd */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) if (mowd < lp->owd_min)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) lp->owd_min = mowd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) /* always forget the max of the max
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) * we just set owd_max as one below it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) if (mowd > lp->owd_max) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) if (mowd > lp->owd_max_rsv) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) if (lp->owd_max_rsv == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) lp->owd_max = mowd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) lp->owd_max = lp->owd_max_rsv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) lp->owd_max_rsv = mowd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) lp->owd_max = mowd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) /* calc for smoothed owd */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (lp->sowd != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) mowd -= lp->sowd >> 3; /* m is now error in owd est */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) lp->sowd += mowd; /* owd = 7/8 owd + 1/8 new */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) lp->sowd = mowd << 3; /* take the measured time be owd */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) * tcp_lp_pkts_acked
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) * Implementation of pkts_acked.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) * Deal with active drop under Early Congestion Indication.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) * Only drop to half and 1 will be handle, because we hope to use back
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) * newReno in increase case.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) * We work it out by following the idea from TCP-LP's paper directly
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) static void tcp_lp_pkts_acked(struct sock *sk, const struct ack_sample *sample)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) struct tcp_sock *tp = tcp_sk(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) struct lp *lp = inet_csk_ca(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) u32 now = tcp_time_stamp(tp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) u32 delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) if (sample->rtt_us > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) tcp_lp_rtt_sample(sk, sample->rtt_us);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) /* calc inference */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) delta = now - tp->rx_opt.rcv_tsecr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) if ((s32)delta > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) lp->inference = 3 * delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) /* test if within inference */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) if (lp->last_drop && (now - lp->last_drop < lp->inference))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) lp->flag |= LP_WITHIN_INF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) lp->flag &= ~LP_WITHIN_INF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) /* test if within threshold */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) if (lp->sowd >> 3 <
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) lp->owd_min + 15 * (lp->owd_max - lp->owd_min) / 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) lp->flag |= LP_WITHIN_THR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) lp->flag &= ~LP_WITHIN_THR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) pr_debug("TCP-LP: %05o|%5u|%5u|%15u|%15u|%15u\n", lp->flag,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) tp->snd_cwnd, lp->remote_hz, lp->owd_min, lp->owd_max,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) lp->sowd >> 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) if (lp->flag & LP_WITHIN_THR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) /* FIXME: try to reset owd_min and owd_max here
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) * so decrease the chance the min/max is no longer suitable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) * and will usually within threshold when whithin inference */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) lp->owd_min = lp->sowd >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) lp->owd_max = lp->sowd >> 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) lp->owd_max_rsv = lp->sowd >> 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) /* happened within inference
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) * drop snd_cwnd into 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) if (lp->flag & LP_WITHIN_INF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) tp->snd_cwnd = 1U;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) /* happened after inference
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) * cut snd_cwnd into half */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) tp->snd_cwnd = max(tp->snd_cwnd >> 1U, 1U);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) /* record this drop time */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) lp->last_drop = now;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) static struct tcp_congestion_ops tcp_lp __read_mostly = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) .init = tcp_lp_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) .ssthresh = tcp_reno_ssthresh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) .undo_cwnd = tcp_reno_undo_cwnd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) .cong_avoid = tcp_lp_cong_avoid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) .pkts_acked = tcp_lp_pkts_acked,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) .name = "lp"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) static int __init tcp_lp_register(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) BUILD_BUG_ON(sizeof(struct lp) > ICSK_CA_PRIV_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) return tcp_register_congestion_control(&tcp_lp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) static void __exit tcp_lp_unregister(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) tcp_unregister_congestion_control(&tcp_lp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) module_init(tcp_lp_register);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) module_exit(tcp_lp_unregister);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) MODULE_AUTHOR("Wong Hoi Sing Edison, Hung Hing Lun Mike");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) MODULE_DESCRIPTION("TCP Low Priority");