* All rights reserved.
*
* DataCenter TCP with CAQM (Confined Active Queue Management).
* enable needs specific switch support
*
* Authors:
* Chengjun Jia <jiachengjun2@huawei.com>
* Shurui Ding <dongshurui@huawei.com>
*/
#include <linux/module.h>
#include <linux/mm.h>
#include <net/tcp.h>
#include <linux/inet_diag.h>
#include "tcp_caqm.h"
static struct tcp_congestion_ops caqm_reno;
static size_t caqm_get_info(struct sock *sk, u32 ext, int *attr, union tcp_cc_info *info)
{
return 0;
}
static void caqm_init(struct sock *sk)
{
struct tcp_sock *tp = tcp_sk(sk);
struct caqm_ca *ca = inet_csk_ca(sk);
if ((tp->ecn_flags & TCP_CAQM_OK) == TCP_CAQM_OK) {
init_caqm_ca(ca);
return;
}
* checkout clear work, see tcp_dctcp.c:95
*/
inet_csk(sk)->icsk_ca_ops = &caqm_reno;
}
static u32 tcp_caqm_ssthresh(struct sock *sk)
{
struct caqm_ca *ca = inet_csk_ca(sk);
struct tcp_sock *tp = tcp_sk(sk);
if (!ca->caqm_ca_enable)
return tcp_reno_ssthresh(sk);
ca->loss_cwnd = tp->snd_cwnd;
return max(tp->snd_cwnd, caqm_para_min_cwnd);
}
static void tcp_caqm_cong_avoid(struct sock *sk, u32 ack, u32 acked)
{
struct caqm_ca *ca = inet_csk_ca(sk);
if (!ca->caqm_ca_enable) {
tcp_reno_cong_avoid(sk, ack, acked);
return;
}
}
static void tcp_caqm_react_to_loss(struct sock *sk)
{
struct caqm_ca *ca = inet_csk_ca(sk);
struct tcp_sock *tp = tcp_sk(sk);
ca->loss_cwnd = tp->snd_cwnd;
tp->snd_ssthresh = max(tp->snd_cwnd >> 1U, 2U);
}
static void tcp_caqm_state(struct sock *sk, u8 new_state)
{
if (new_state == TCP_CA_Recovery &&
new_state != inet_csk(sk)->icsk_ca_state)
tcp_caqm_react_to_loss(sk);
* one loss-adjustment per RTT.
*/
}
static u32 tcp_caqm_undo_cwnd(struct sock *sk)
{
struct caqm_ca *ca = inet_csk_ca(sk);
if (!ca->caqm_ca_enable)
return tcp_reno_undo_cwnd(sk);
return max(tcp_sk(sk)->snd_cwnd, ca->loss_cwnd);
}
* Only after syn--syn-ack to enable, the alg changes to caqm.*/
static struct tcp_congestion_ops caqm __read_mostly = {
.init = caqm_init,
.ssthresh = tcp_caqm_ssthresh,
.cong_avoid = tcp_caqm_cong_avoid,
.undo_cwnd = tcp_caqm_undo_cwnd,
.set_state = tcp_caqm_state,
.get_info = caqm_get_info,
.flags = TCP_CONG_NEEDS_CAQM,
.owner = THIS_MODULE,
.name = "caqm",
};
static struct tcp_congestion_ops caqm_reno __read_mostly = {
.ssthresh = tcp_reno_ssthresh,
.cong_avoid = tcp_reno_cong_avoid,
.undo_cwnd = tcp_reno_undo_cwnd,
.get_info = caqm_get_info,
.owner = THIS_MODULE,
.name = "caqm_reno",
};
static int __init caqm_register(void)
{
BUILD_BUG_ON(sizeof(struct caqm_ca) > ICSK_CA_PRIV_SIZE);
return tcp_register_congestion_control(&caqm);
}
static void __exit caqm_unregister(void)
{
tcp_unregister_congestion_control(&caqm);
}
module_init(caqm_register);
module_exit(caqm_unregister);
MODULE_AUTHOR("Chengjun Jia <jiachengjun2@huawei.com>");
MODULE_AUTHOR("Shurui Dong <dongshurui@huawei.com>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("TCP w Confined Active Queue Management(CAQM)");