1e3118e83SDaniel Borkmann /* DataCenter TCP (DCTCP) congestion control. 2e3118e83SDaniel Borkmann * 3e3118e83SDaniel Borkmann * http://simula.stanford.edu/~alizade/Site/DCTCP.html 4e3118e83SDaniel Borkmann * 5e3118e83SDaniel Borkmann * This is an implementation of DCTCP over Reno, an enhancement to the 6e3118e83SDaniel Borkmann * TCP congestion control algorithm designed for data centers. DCTCP 7e3118e83SDaniel Borkmann * leverages Explicit Congestion Notification (ECN) in the network to 8e3118e83SDaniel Borkmann * provide multi-bit feedback to the end hosts. DCTCP's goal is to meet 9e3118e83SDaniel Borkmann * the following three data center transport requirements: 10e3118e83SDaniel Borkmann * 11e3118e83SDaniel Borkmann * - High burst tolerance (incast due to partition/aggregate) 12e3118e83SDaniel Borkmann * - Low latency (short flows, queries) 13e3118e83SDaniel Borkmann * - High throughput (continuous data updates, large file transfers) 14e3118e83SDaniel Borkmann * with commodity shallow buffered switches 15e3118e83SDaniel Borkmann * 16e3118e83SDaniel Borkmann * The algorithm is described in detail in the following two papers: 17e3118e83SDaniel Borkmann * 18e3118e83SDaniel Borkmann * 1) Mohammad Alizadeh, Albert Greenberg, David A. Maltz, Jitendra Padhye, 19e3118e83SDaniel Borkmann * Parveen Patel, Balaji Prabhakar, Sudipta Sengupta, and Murari Sridharan: 20e3118e83SDaniel Borkmann * "Data Center TCP (DCTCP)", Data Center Networks session 21e3118e83SDaniel Borkmann * Proc. ACM SIGCOMM, New Delhi, 2010. 22e3118e83SDaniel Borkmann * http://simula.stanford.edu/~alizade/Site/DCTCP_files/dctcp-final.pdf 23e3118e83SDaniel Borkmann * 24e3118e83SDaniel Borkmann * 2) Mohammad Alizadeh, Adel Javanmard, and Balaji Prabhakar: 25e3118e83SDaniel Borkmann * "Analysis of DCTCP: Stability, Convergence, and Fairness" 26e3118e83SDaniel Borkmann * Proc. ACM SIGMETRICS, San Jose, 2011. 27e3118e83SDaniel Borkmann * http://simula.stanford.edu/~alizade/Site/DCTCP_files/dctcp_analysis-full.pdf 28e3118e83SDaniel Borkmann * 29e3118e83SDaniel Borkmann * Initial prototype from Abdul Kabbani, Masato Yasuda and Mohammad Alizadeh. 30e3118e83SDaniel Borkmann * 31e3118e83SDaniel Borkmann * Authors: 32e3118e83SDaniel Borkmann * 33e3118e83SDaniel Borkmann * Daniel Borkmann <dborkman@redhat.com> 34e3118e83SDaniel Borkmann * Florian Westphal <fw@strlen.de> 35e3118e83SDaniel Borkmann * Glenn Judd <glenn.judd@morganstanley.com> 36e3118e83SDaniel Borkmann * 37e3118e83SDaniel Borkmann * This program is free software; you can redistribute it and/or modify 38e3118e83SDaniel Borkmann * it under the terms of the GNU General Public License as published by 39e3118e83SDaniel Borkmann * the Free Software Foundation; either version 2 of the License, or (at 40e3118e83SDaniel Borkmann * your option) any later version. 41e3118e83SDaniel Borkmann */ 42e3118e83SDaniel Borkmann 43e3118e83SDaniel Borkmann #include <linux/module.h> 44e3118e83SDaniel Borkmann #include <linux/mm.h> 45e3118e83SDaniel Borkmann #include <net/tcp.h> 46e3118e83SDaniel Borkmann #include <linux/inet_diag.h> 47e3118e83SDaniel Borkmann 48e3118e83SDaniel Borkmann #define DCTCP_MAX_ALPHA 1024U 49e3118e83SDaniel Borkmann 50e3118e83SDaniel Borkmann struct dctcp { 51e3118e83SDaniel Borkmann u32 acked_bytes_ecn; 52e3118e83SDaniel Borkmann u32 acked_bytes_total; 53e3118e83SDaniel Borkmann u32 prior_snd_una; 54e3118e83SDaniel Borkmann u32 prior_rcv_nxt; 55e3118e83SDaniel Borkmann u32 dctcp_alpha; 56e3118e83SDaniel Borkmann u32 next_seq; 57e3118e83SDaniel Borkmann u32 ce_state; 58e3118e83SDaniel Borkmann u32 delayed_ack_reserved; 59ce6dd233SFlorian Westphal u32 loss_cwnd; 60e3118e83SDaniel Borkmann }; 61e3118e83SDaniel Borkmann 62e3118e83SDaniel Borkmann static unsigned int dctcp_shift_g __read_mostly = 4; /* g = 1/2^4 */ 63e3118e83SDaniel Borkmann module_param(dctcp_shift_g, uint, 0644); 64e3118e83SDaniel Borkmann MODULE_PARM_DESC(dctcp_shift_g, "parameter g for updating dctcp_alpha"); 65e3118e83SDaniel Borkmann 66e3118e83SDaniel Borkmann static unsigned int dctcp_alpha_on_init __read_mostly = DCTCP_MAX_ALPHA; 67e3118e83SDaniel Borkmann module_param(dctcp_alpha_on_init, uint, 0644); 68e3118e83SDaniel Borkmann MODULE_PARM_DESC(dctcp_alpha_on_init, "parameter for initial alpha value"); 69e3118e83SDaniel Borkmann 70e3118e83SDaniel Borkmann static unsigned int dctcp_clamp_alpha_on_loss __read_mostly; 71e3118e83SDaniel Borkmann module_param(dctcp_clamp_alpha_on_loss, uint, 0644); 72e3118e83SDaniel Borkmann MODULE_PARM_DESC(dctcp_clamp_alpha_on_loss, 73e3118e83SDaniel Borkmann "parameter for clamping alpha on loss"); 74e3118e83SDaniel Borkmann 75e3118e83SDaniel Borkmann static struct tcp_congestion_ops dctcp_reno; 76e3118e83SDaniel Borkmann 77e3118e83SDaniel Borkmann static void dctcp_reset(const struct tcp_sock *tp, struct dctcp *ca) 78e3118e83SDaniel Borkmann { 79e3118e83SDaniel Borkmann ca->next_seq = tp->snd_nxt; 80e3118e83SDaniel Borkmann 81e3118e83SDaniel Borkmann ca->acked_bytes_ecn = 0; 82e3118e83SDaniel Borkmann ca->acked_bytes_total = 0; 83e3118e83SDaniel Borkmann } 84e3118e83SDaniel Borkmann 85e3118e83SDaniel Borkmann static void dctcp_init(struct sock *sk) 86e3118e83SDaniel Borkmann { 87e3118e83SDaniel Borkmann const struct tcp_sock *tp = tcp_sk(sk); 88e3118e83SDaniel Borkmann 89e3118e83SDaniel Borkmann if ((tp->ecn_flags & TCP_ECN_OK) || 90e3118e83SDaniel Borkmann (sk->sk_state == TCP_LISTEN || 91e3118e83SDaniel Borkmann sk->sk_state == TCP_CLOSE)) { 92e3118e83SDaniel Borkmann struct dctcp *ca = inet_csk_ca(sk); 93e3118e83SDaniel Borkmann 94e3118e83SDaniel Borkmann ca->prior_snd_una = tp->snd_una; 95e3118e83SDaniel Borkmann ca->prior_rcv_nxt = tp->rcv_nxt; 96e3118e83SDaniel Borkmann 97e3118e83SDaniel Borkmann ca->dctcp_alpha = min(dctcp_alpha_on_init, DCTCP_MAX_ALPHA); 98e3118e83SDaniel Borkmann 99e3118e83SDaniel Borkmann ca->delayed_ack_reserved = 0; 100ce6dd233SFlorian Westphal ca->loss_cwnd = 0; 101e3118e83SDaniel Borkmann ca->ce_state = 0; 102e3118e83SDaniel Borkmann 103e3118e83SDaniel Borkmann dctcp_reset(tp, ca); 104e3118e83SDaniel Borkmann return; 105e3118e83SDaniel Borkmann } 106e3118e83SDaniel Borkmann 107e3118e83SDaniel Borkmann /* No ECN support? Fall back to Reno. Also need to clear 108e3118e83SDaniel Borkmann * ECT from sk since it is set during 3WHS for DCTCP. 109e3118e83SDaniel Borkmann */ 110e3118e83SDaniel Borkmann inet_csk(sk)->icsk_ca_ops = &dctcp_reno; 111e3118e83SDaniel Borkmann INET_ECN_dontxmit(sk); 112e3118e83SDaniel Borkmann } 113e3118e83SDaniel Borkmann 114e3118e83SDaniel Borkmann static u32 dctcp_ssthresh(struct sock *sk) 115e3118e83SDaniel Borkmann { 116ce6dd233SFlorian Westphal struct dctcp *ca = inet_csk_ca(sk); 117e3118e83SDaniel Borkmann struct tcp_sock *tp = tcp_sk(sk); 118e3118e83SDaniel Borkmann 119ce6dd233SFlorian Westphal ca->loss_cwnd = tp->snd_cwnd; 120e3118e83SDaniel Borkmann return max(tp->snd_cwnd - ((tp->snd_cwnd * ca->dctcp_alpha) >> 11U), 2U); 121e3118e83SDaniel Borkmann } 122e3118e83SDaniel Borkmann 123e3118e83SDaniel Borkmann /* Minimal DCTP CE state machine: 124e3118e83SDaniel Borkmann * 125e3118e83SDaniel Borkmann * S: 0 <- last pkt was non-CE 126e3118e83SDaniel Borkmann * 1 <- last pkt was CE 127e3118e83SDaniel Borkmann */ 128e3118e83SDaniel Borkmann 129e3118e83SDaniel Borkmann static void dctcp_ce_state_0_to_1(struct sock *sk) 130e3118e83SDaniel Borkmann { 131e3118e83SDaniel Borkmann struct dctcp *ca = inet_csk_ca(sk); 132e3118e83SDaniel Borkmann struct tcp_sock *tp = tcp_sk(sk); 133e3118e83SDaniel Borkmann 134e3118e83SDaniel Borkmann /* State has changed from CE=0 to CE=1 and delayed 135e3118e83SDaniel Borkmann * ACK has not sent yet. 136e3118e83SDaniel Borkmann */ 137e3118e83SDaniel Borkmann if (!ca->ce_state && ca->delayed_ack_reserved) { 138e3118e83SDaniel Borkmann u32 tmp_rcv_nxt; 139e3118e83SDaniel Borkmann 140e3118e83SDaniel Borkmann /* Save current rcv_nxt. */ 141e3118e83SDaniel Borkmann tmp_rcv_nxt = tp->rcv_nxt; 142e3118e83SDaniel Borkmann 143e3118e83SDaniel Borkmann /* Generate previous ack with CE=0. */ 144e3118e83SDaniel Borkmann tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR; 145e3118e83SDaniel Borkmann tp->rcv_nxt = ca->prior_rcv_nxt; 146e3118e83SDaniel Borkmann 147e3118e83SDaniel Borkmann tcp_send_ack(sk); 148e3118e83SDaniel Borkmann 149e3118e83SDaniel Borkmann /* Recover current rcv_nxt. */ 150e3118e83SDaniel Borkmann tp->rcv_nxt = tmp_rcv_nxt; 151e3118e83SDaniel Borkmann } 152e3118e83SDaniel Borkmann 153e3118e83SDaniel Borkmann ca->prior_rcv_nxt = tp->rcv_nxt; 154e3118e83SDaniel Borkmann ca->ce_state = 1; 155e3118e83SDaniel Borkmann 156e3118e83SDaniel Borkmann tp->ecn_flags |= TCP_ECN_DEMAND_CWR; 157e3118e83SDaniel Borkmann } 158e3118e83SDaniel Borkmann 159e3118e83SDaniel Borkmann static void dctcp_ce_state_1_to_0(struct sock *sk) 160e3118e83SDaniel Borkmann { 161e3118e83SDaniel Borkmann struct dctcp *ca = inet_csk_ca(sk); 162e3118e83SDaniel Borkmann struct tcp_sock *tp = tcp_sk(sk); 163e3118e83SDaniel Borkmann 164e3118e83SDaniel Borkmann /* State has changed from CE=1 to CE=0 and delayed 165e3118e83SDaniel Borkmann * ACK has not sent yet. 166e3118e83SDaniel Borkmann */ 167e3118e83SDaniel Borkmann if (ca->ce_state && ca->delayed_ack_reserved) { 168e3118e83SDaniel Borkmann u32 tmp_rcv_nxt; 169e3118e83SDaniel Borkmann 170e3118e83SDaniel Borkmann /* Save current rcv_nxt. */ 171e3118e83SDaniel Borkmann tmp_rcv_nxt = tp->rcv_nxt; 172e3118e83SDaniel Borkmann 173e3118e83SDaniel Borkmann /* Generate previous ack with CE=1. */ 174e3118e83SDaniel Borkmann tp->ecn_flags |= TCP_ECN_DEMAND_CWR; 175e3118e83SDaniel Borkmann tp->rcv_nxt = ca->prior_rcv_nxt; 176e3118e83SDaniel Borkmann 177e3118e83SDaniel Borkmann tcp_send_ack(sk); 178e3118e83SDaniel Borkmann 179e3118e83SDaniel Borkmann /* Recover current rcv_nxt. */ 180e3118e83SDaniel Borkmann tp->rcv_nxt = tmp_rcv_nxt; 181e3118e83SDaniel Borkmann } 182e3118e83SDaniel Borkmann 183e3118e83SDaniel Borkmann ca->prior_rcv_nxt = tp->rcv_nxt; 184e3118e83SDaniel Borkmann ca->ce_state = 0; 185e3118e83SDaniel Borkmann 186e3118e83SDaniel Borkmann tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR; 187e3118e83SDaniel Borkmann } 188e3118e83SDaniel Borkmann 189e3118e83SDaniel Borkmann static void dctcp_update_alpha(struct sock *sk, u32 flags) 190e3118e83SDaniel Borkmann { 191e3118e83SDaniel Borkmann struct dctcp *ca = inet_csk_ca(sk); 19247805667SFlorian Westphal struct tcp_sock *tp = tcp_sk(sk); 193e3118e83SDaniel Borkmann u32 acked_bytes = tp->snd_una - ca->prior_snd_una; 194e3118e83SDaniel Borkmann 195e3118e83SDaniel Borkmann /* If ack did not advance snd_una, count dupack as MSS size. 196e3118e83SDaniel Borkmann * If ack did update window, do not count it at all. 197e3118e83SDaniel Borkmann */ 198e3118e83SDaniel Borkmann if (acked_bytes == 0 && !(flags & CA_ACK_WIN_UPDATE)) 199e3118e83SDaniel Borkmann acked_bytes = inet_csk(sk)->icsk_ack.rcv_mss; 200e3118e83SDaniel Borkmann if (acked_bytes) { 201e3118e83SDaniel Borkmann ca->acked_bytes_total += acked_bytes; 202e3118e83SDaniel Borkmann ca->prior_snd_una = tp->snd_una; 203e3118e83SDaniel Borkmann 204e3118e83SDaniel Borkmann if (flags & CA_ACK_ECE) 205e3118e83SDaniel Borkmann ca->acked_bytes_ecn += acked_bytes; 206e3118e83SDaniel Borkmann } 207e3118e83SDaniel Borkmann 208e3118e83SDaniel Borkmann /* Expired RTT */ 209e3118e83SDaniel Borkmann if (!before(tp->snd_una, ca->next_seq)) { 210f9c2ff22SEric Dumazet u64 bytes_ecn = ca->acked_bytes_ecn; 211f9c2ff22SEric Dumazet u32 alpha = ca->dctcp_alpha; 212e3118e83SDaniel Borkmann 213e3118e83SDaniel Borkmann /* alpha = (1 - g) * alpha + g * F */ 214e3118e83SDaniel Borkmann 215c80dbe04SAndrew Shewmaker alpha -= min_not_zero(alpha, alpha >> dctcp_shift_g); 216f9c2ff22SEric Dumazet if (bytes_ecn) { 217f9c2ff22SEric Dumazet /* If dctcp_shift_g == 1, a 32bit value would overflow 218f9c2ff22SEric Dumazet * after 8 Mbytes. 219f9c2ff22SEric Dumazet */ 220f9c2ff22SEric Dumazet bytes_ecn <<= (10 - dctcp_shift_g); 221f9c2ff22SEric Dumazet do_div(bytes_ecn, max(1U, ca->acked_bytes_total)); 222e3118e83SDaniel Borkmann 223f9c2ff22SEric Dumazet alpha = min(alpha + (u32)bytes_ecn, DCTCP_MAX_ALPHA); 224f9c2ff22SEric Dumazet } 225f9c2ff22SEric Dumazet /* dctcp_alpha can be read from dctcp_get_info() without 226f9c2ff22SEric Dumazet * synchro, so we ask compiler to not use dctcp_alpha 227f9c2ff22SEric Dumazet * as a temporary variable in prior operations. 228f9c2ff22SEric Dumazet */ 229f9c2ff22SEric Dumazet WRITE_ONCE(ca->dctcp_alpha, alpha); 230e3118e83SDaniel Borkmann dctcp_reset(tp, ca); 231e3118e83SDaniel Borkmann } 23247805667SFlorian Westphal 23347805667SFlorian Westphal if (flags & CA_ACK_ECE) { 23447805667SFlorian Westphal unsigned int cwnd = dctcp_ssthresh(sk); 23547805667SFlorian Westphal 23647805667SFlorian Westphal if (cwnd != tp->snd_cwnd) 23747805667SFlorian Westphal tp->snd_cwnd = cwnd; 23847805667SFlorian Westphal } 239e3118e83SDaniel Borkmann } 240e3118e83SDaniel Borkmann 241e3118e83SDaniel Borkmann static void dctcp_state(struct sock *sk, u8 new_state) 242e3118e83SDaniel Borkmann { 243e3118e83SDaniel Borkmann if (dctcp_clamp_alpha_on_loss && new_state == TCP_CA_Loss) { 244e3118e83SDaniel Borkmann struct dctcp *ca = inet_csk_ca(sk); 245e3118e83SDaniel Borkmann 246e3118e83SDaniel Borkmann /* If this extension is enabled, we clamp dctcp_alpha to 247e3118e83SDaniel Borkmann * max on packet loss; the motivation is that dctcp_alpha 248e3118e83SDaniel Borkmann * is an indicator to the extend of congestion and packet 249e3118e83SDaniel Borkmann * loss is an indicator of extreme congestion; setting 250e3118e83SDaniel Borkmann * this in practice turned out to be beneficial, and 251e3118e83SDaniel Borkmann * effectively assumes total congestion which reduces the 252e3118e83SDaniel Borkmann * window by half. 253e3118e83SDaniel Borkmann */ 254e3118e83SDaniel Borkmann ca->dctcp_alpha = DCTCP_MAX_ALPHA; 255e3118e83SDaniel Borkmann } 256e3118e83SDaniel Borkmann } 257e3118e83SDaniel Borkmann 258e3118e83SDaniel Borkmann static void dctcp_update_ack_reserved(struct sock *sk, enum tcp_ca_event ev) 259e3118e83SDaniel Borkmann { 260e3118e83SDaniel Borkmann struct dctcp *ca = inet_csk_ca(sk); 261e3118e83SDaniel Borkmann 262e3118e83SDaniel Borkmann switch (ev) { 263e3118e83SDaniel Borkmann case CA_EVENT_DELAYED_ACK: 264e3118e83SDaniel Borkmann if (!ca->delayed_ack_reserved) 265e3118e83SDaniel Borkmann ca->delayed_ack_reserved = 1; 266e3118e83SDaniel Borkmann break; 267e3118e83SDaniel Borkmann case CA_EVENT_NON_DELAYED_ACK: 268e3118e83SDaniel Borkmann if (ca->delayed_ack_reserved) 269e3118e83SDaniel Borkmann ca->delayed_ack_reserved = 0; 270e3118e83SDaniel Borkmann break; 271e3118e83SDaniel Borkmann default: 272e3118e83SDaniel Borkmann /* Don't care for the rest. */ 273e3118e83SDaniel Borkmann break; 274e3118e83SDaniel Borkmann } 275e3118e83SDaniel Borkmann } 276e3118e83SDaniel Borkmann 277e3118e83SDaniel Borkmann static void dctcp_cwnd_event(struct sock *sk, enum tcp_ca_event ev) 278e3118e83SDaniel Borkmann { 279e3118e83SDaniel Borkmann switch (ev) { 280e3118e83SDaniel Borkmann case CA_EVENT_ECN_IS_CE: 281e3118e83SDaniel Borkmann dctcp_ce_state_0_to_1(sk); 282e3118e83SDaniel Borkmann break; 283e3118e83SDaniel Borkmann case CA_EVENT_ECN_NO_CE: 284e3118e83SDaniel Borkmann dctcp_ce_state_1_to_0(sk); 285e3118e83SDaniel Borkmann break; 286e3118e83SDaniel Borkmann case CA_EVENT_DELAYED_ACK: 287e3118e83SDaniel Borkmann case CA_EVENT_NON_DELAYED_ACK: 288e3118e83SDaniel Borkmann dctcp_update_ack_reserved(sk, ev); 289e3118e83SDaniel Borkmann break; 290e3118e83SDaniel Borkmann default: 291e3118e83SDaniel Borkmann /* Don't care for the rest. */ 292e3118e83SDaniel Borkmann break; 293e3118e83SDaniel Borkmann } 294e3118e83SDaniel Borkmann } 295e3118e83SDaniel Borkmann 29664f40ff5SEric Dumazet static size_t dctcp_get_info(struct sock *sk, u32 ext, int *attr, 29764f40ff5SEric Dumazet union tcp_cc_info *info) 298e3118e83SDaniel Borkmann { 299e3118e83SDaniel Borkmann const struct dctcp *ca = inet_csk_ca(sk); 300e3118e83SDaniel Borkmann 301e3118e83SDaniel Borkmann /* Fill it also in case of VEGASINFO due to req struct limits. 302e3118e83SDaniel Borkmann * We can still correctly retrieve it later. 303e3118e83SDaniel Borkmann */ 304e3118e83SDaniel Borkmann if (ext & (1 << (INET_DIAG_DCTCPINFO - 1)) || 305e3118e83SDaniel Borkmann ext & (1 << (INET_DIAG_VEGASINFO - 1))) { 306dcf1158bSNeal Cardwell memset(&info->dctcp, 0, sizeof(info->dctcp)); 307e3118e83SDaniel Borkmann if (inet_csk(sk)->icsk_ca_ops != &dctcp_reno) { 30864f40ff5SEric Dumazet info->dctcp.dctcp_enabled = 1; 30964f40ff5SEric Dumazet info->dctcp.dctcp_ce_state = (u16) ca->ce_state; 31064f40ff5SEric Dumazet info->dctcp.dctcp_alpha = ca->dctcp_alpha; 31164f40ff5SEric Dumazet info->dctcp.dctcp_ab_ecn = ca->acked_bytes_ecn; 31264f40ff5SEric Dumazet info->dctcp.dctcp_ab_tot = ca->acked_bytes_total; 313e3118e83SDaniel Borkmann } 314e3118e83SDaniel Borkmann 31564f40ff5SEric Dumazet *attr = INET_DIAG_DCTCPINFO; 316dcf1158bSNeal Cardwell return sizeof(info->dctcp); 317e3118e83SDaniel Borkmann } 318521f1cf1SEric Dumazet return 0; 319e3118e83SDaniel Borkmann } 320e3118e83SDaniel Borkmann 321ce6dd233SFlorian Westphal static u32 dctcp_cwnd_undo(struct sock *sk) 322ce6dd233SFlorian Westphal { 323ce6dd233SFlorian Westphal const struct dctcp *ca = inet_csk_ca(sk); 324ce6dd233SFlorian Westphal 325ce6dd233SFlorian Westphal return max(tcp_sk(sk)->snd_cwnd, ca->loss_cwnd); 326ce6dd233SFlorian Westphal } 327ce6dd233SFlorian Westphal 328e3118e83SDaniel Borkmann static struct tcp_congestion_ops dctcp __read_mostly = { 329e3118e83SDaniel Borkmann .init = dctcp_init, 330e3118e83SDaniel Borkmann .in_ack_event = dctcp_update_alpha, 331e3118e83SDaniel Borkmann .cwnd_event = dctcp_cwnd_event, 332e3118e83SDaniel Borkmann .ssthresh = dctcp_ssthresh, 333e3118e83SDaniel Borkmann .cong_avoid = tcp_reno_cong_avoid, 334ce6dd233SFlorian Westphal .undo_cwnd = dctcp_cwnd_undo, 335e3118e83SDaniel Borkmann .set_state = dctcp_state, 336e3118e83SDaniel Borkmann .get_info = dctcp_get_info, 337e3118e83SDaniel Borkmann .flags = TCP_CONG_NEEDS_ECN, 338e3118e83SDaniel Borkmann .owner = THIS_MODULE, 339e3118e83SDaniel Borkmann .name = "dctcp", 340e3118e83SDaniel Borkmann }; 341e3118e83SDaniel Borkmann 342e3118e83SDaniel Borkmann static struct tcp_congestion_ops dctcp_reno __read_mostly = { 343e3118e83SDaniel Borkmann .ssthresh = tcp_reno_ssthresh, 344e3118e83SDaniel Borkmann .cong_avoid = tcp_reno_cong_avoid, 345*e9799183SFlorian Westphal .undo_cwnd = tcp_reno_undo_cwnd, 346e3118e83SDaniel Borkmann .get_info = dctcp_get_info, 347e3118e83SDaniel Borkmann .owner = THIS_MODULE, 348e3118e83SDaniel Borkmann .name = "dctcp-reno", 349e3118e83SDaniel Borkmann }; 350e3118e83SDaniel Borkmann 351e3118e83SDaniel Borkmann static int __init dctcp_register(void) 352e3118e83SDaniel Borkmann { 353e3118e83SDaniel Borkmann BUILD_BUG_ON(sizeof(struct dctcp) > ICSK_CA_PRIV_SIZE); 354e3118e83SDaniel Borkmann return tcp_register_congestion_control(&dctcp); 355e3118e83SDaniel Borkmann } 356e3118e83SDaniel Borkmann 357e3118e83SDaniel Borkmann static void __exit dctcp_unregister(void) 358e3118e83SDaniel Borkmann { 359e3118e83SDaniel Borkmann tcp_unregister_congestion_control(&dctcp); 360e3118e83SDaniel Borkmann } 361e3118e83SDaniel Borkmann 362e3118e83SDaniel Borkmann module_init(dctcp_register); 363e3118e83SDaniel Borkmann module_exit(dctcp_unregister); 364e3118e83SDaniel Borkmann 365e3118e83SDaniel Borkmann MODULE_AUTHOR("Daniel Borkmann <dborkman@redhat.com>"); 366e3118e83SDaniel Borkmann MODULE_AUTHOR("Florian Westphal <fw@strlen.de>"); 367e3118e83SDaniel Borkmann MODULE_AUTHOR("Glenn Judd <glenn.judd@morganstanley.com>"); 368e3118e83SDaniel Borkmann 369e3118e83SDaniel Borkmann MODULE_LICENSE("GPL v2"); 370e3118e83SDaniel Borkmann MODULE_DESCRIPTION("DataCenter TCP (DCTCP)"); 371