^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 Veno congestion control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * This is based on the congestion detection/avoidance scheme described in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * C. P. Fu, S. C. Liew.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * "TCP Veno: TCP Enhancement for Transmission over Wireless Access Networks."
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * IEEE Journal on Selected Areas in Communication,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Feb. 2003.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * See https://www.ie.cuhk.edu.hk/fileadmin/staff_upload/soung/Journal/J3.pdf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/skbuff.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/inet_diag.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <net/tcp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) /* Default values of the Veno variables, in fixed-point representation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * with V_PARAM_SHIFT bits to the right of the binary point.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define V_PARAM_SHIFT 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) static const int beta = 3 << V_PARAM_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) /* Veno variables */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct veno {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) u8 doing_veno_now; /* if true, do veno for this rtt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) u16 cntrtt; /* # of rtts measured within last rtt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) u32 minrtt; /* min of rtts measured within last rtt (in usec) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) u32 basertt; /* the min of all Veno rtt measurements seen (in usec) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) u32 inc; /* decide whether to increase cwnd */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) u32 diff; /* calculate the diff rate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) /* There are several situations when we must "re-start" Veno:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * o when a connection is established
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * o after an RTO
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * o after fast recovery
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * o when we send a packet and there is no outstanding
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * unacknowledged data (restarting an idle connection)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) static inline void veno_enable(struct sock *sk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) struct veno *veno = inet_csk_ca(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) /* turn on Veno */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) veno->doing_veno_now = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) veno->minrtt = 0x7fffffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) static inline void veno_disable(struct sock *sk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) struct veno *veno = inet_csk_ca(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) /* turn off Veno */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) veno->doing_veno_now = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static void tcp_veno_init(struct sock *sk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) struct veno *veno = inet_csk_ca(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) veno->basertt = 0x7fffffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) veno->inc = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) veno_enable(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) /* Do rtt sampling needed for Veno. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static void tcp_veno_pkts_acked(struct sock *sk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) const struct ack_sample *sample)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) struct veno *veno = inet_csk_ca(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) u32 vrtt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (sample->rtt_us < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) /* Never allow zero rtt or baseRTT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) vrtt = sample->rtt_us + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) /* Filter to find propagation delay: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (vrtt < veno->basertt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) veno->basertt = vrtt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) /* Find the min rtt during the last rtt to find
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * the current prop. delay + queuing delay:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) veno->minrtt = min(veno->minrtt, vrtt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) veno->cntrtt++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static void tcp_veno_state(struct sock *sk, u8 ca_state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if (ca_state == TCP_CA_Open)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) veno_enable(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) veno_disable(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * If the connection is idle and we are restarting,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) * then we don't want to do any Veno calculations
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * until we get fresh rtt samples. So when we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) * restart, we reset our Veno state to a clean
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * state. After we get acks for this flight of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * packets, _then_ we can make Veno calculations
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * again.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) static void tcp_veno_cwnd_event(struct sock *sk, enum tcp_ca_event event)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (event == CA_EVENT_CWND_RESTART || event == CA_EVENT_TX_START)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) tcp_veno_init(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) static void tcp_veno_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 tcp_sock *tp = tcp_sk(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) struct veno *veno = inet_csk_ca(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (!veno->doing_veno_now) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) tcp_reno_cong_avoid(sk, ack, acked);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) /* limited by applications */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if (!tcp_is_cwnd_limited(sk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) /* We do the Veno calculations only if we got enough rtt samples */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) if (veno->cntrtt <= 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) /* We don't have enough rtt samples to do the Veno
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) * calculation, so we'll behave like Reno.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) tcp_reno_cong_avoid(sk, ack, acked);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) u64 target_cwnd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) u32 rtt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) /* We have enough rtt samples, so, using the Veno
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) * algorithm, we determine the state of the network.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) rtt = veno->minrtt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) target_cwnd = (u64)tp->snd_cwnd * veno->basertt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) target_cwnd <<= V_PARAM_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) do_div(target_cwnd, rtt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) veno->diff = (tp->snd_cwnd << V_PARAM_SHIFT) - target_cwnd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (tcp_in_slow_start(tp)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) /* Slow start. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) acked = tcp_slow_start(tp, acked);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) if (!acked)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) /* Congestion avoidance. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if (veno->diff < beta) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) /* In the "non-congestive state", increase cwnd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) * every rtt.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) tcp_cong_avoid_ai(tp, tp->snd_cwnd, acked);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) /* In the "congestive state", increase cwnd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) * every other rtt.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) if (tp->snd_cwnd_cnt >= tp->snd_cwnd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) if (veno->inc &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) tp->snd_cwnd < tp->snd_cwnd_clamp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) tp->snd_cwnd++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) veno->inc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) veno->inc = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) tp->snd_cwnd_cnt = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) tp->snd_cwnd_cnt += acked;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) done:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) if (tp->snd_cwnd < 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) tp->snd_cwnd = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) else if (tp->snd_cwnd > tp->snd_cwnd_clamp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) tp->snd_cwnd = tp->snd_cwnd_clamp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) /* Wipe the slate clean for the next rtt. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) /* veno->cntrtt = 0; */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) veno->minrtt = 0x7fffffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) /* Veno MD phase */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) static u32 tcp_veno_ssthresh(struct sock *sk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) const struct tcp_sock *tp = tcp_sk(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) struct veno *veno = inet_csk_ca(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) if (veno->diff < beta)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) /* in "non-congestive state", cut cwnd by 1/5 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) return max(tp->snd_cwnd * 4 / 5, 2U);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) /* in "congestive state", cut cwnd by 1/2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) return max(tp->snd_cwnd >> 1U, 2U);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) static struct tcp_congestion_ops tcp_veno __read_mostly = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) .init = tcp_veno_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) .ssthresh = tcp_veno_ssthresh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) .undo_cwnd = tcp_reno_undo_cwnd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) .cong_avoid = tcp_veno_cong_avoid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) .pkts_acked = tcp_veno_pkts_acked,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) .set_state = tcp_veno_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) .cwnd_event = tcp_veno_cwnd_event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) .name = "veno",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) static int __init tcp_veno_register(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) BUILD_BUG_ON(sizeof(struct veno) > ICSK_CA_PRIV_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) tcp_register_congestion_control(&tcp_veno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) static void __exit tcp_veno_unregister(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) tcp_unregister_congestion_control(&tcp_veno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) module_init(tcp_veno_register);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) module_exit(tcp_veno_unregister);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) MODULE_AUTHOR("Bin Zhou, Cheng Peng Fu");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) MODULE_DESCRIPTION("TCP Veno");