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; 59e3118e83SDaniel Borkmann }; 60e3118e83SDaniel Borkmann 61e3118e83SDaniel Borkmann static unsigned int dctcp_shift_g __read_mostly = 4; /* g = 1/2^4 */ 62e3118e83SDaniel Borkmann module_param(dctcp_shift_g, uint, 0644); 63e3118e83SDaniel Borkmann MODULE_PARM_DESC(dctcp_shift_g, "parameter g for updating dctcp_alpha"); 64e3118e83SDaniel Borkmann 65e3118e83SDaniel Borkmann static unsigned int dctcp_alpha_on_init __read_mostly = DCTCP_MAX_ALPHA; 66e3118e83SDaniel Borkmann module_param(dctcp_alpha_on_init, uint, 0644); 67e3118e83SDaniel Borkmann MODULE_PARM_DESC(dctcp_alpha_on_init, "parameter for initial alpha value"); 68e3118e83SDaniel Borkmann 69e3118e83SDaniel Borkmann static unsigned int dctcp_clamp_alpha_on_loss __read_mostly; 70e3118e83SDaniel Borkmann module_param(dctcp_clamp_alpha_on_loss, uint, 0644); 71e3118e83SDaniel Borkmann MODULE_PARM_DESC(dctcp_clamp_alpha_on_loss, 72e3118e83SDaniel Borkmann "parameter for clamping alpha on loss"); 73e3118e83SDaniel Borkmann 74e3118e83SDaniel Borkmann static struct tcp_congestion_ops dctcp_reno; 75e3118e83SDaniel Borkmann 76e3118e83SDaniel Borkmann static void dctcp_reset(const struct tcp_sock *tp, struct dctcp *ca) 77e3118e83SDaniel Borkmann { 78e3118e83SDaniel Borkmann ca->next_seq = tp->snd_nxt; 79e3118e83SDaniel Borkmann 80e3118e83SDaniel Borkmann ca->acked_bytes_ecn = 0; 81e3118e83SDaniel Borkmann ca->acked_bytes_total = 0; 82e3118e83SDaniel Borkmann } 83e3118e83SDaniel Borkmann 84e3118e83SDaniel Borkmann static void dctcp_init(struct sock *sk) 85e3118e83SDaniel Borkmann { 86e3118e83SDaniel Borkmann const struct tcp_sock *tp = tcp_sk(sk); 87e3118e83SDaniel Borkmann 88e3118e83SDaniel Borkmann if ((tp->ecn_flags & TCP_ECN_OK) || 89e3118e83SDaniel Borkmann (sk->sk_state == TCP_LISTEN || 90e3118e83SDaniel Borkmann sk->sk_state == TCP_CLOSE)) { 91e3118e83SDaniel Borkmann struct dctcp *ca = inet_csk_ca(sk); 92e3118e83SDaniel Borkmann 93e3118e83SDaniel Borkmann ca->prior_snd_una = tp->snd_una; 94e3118e83SDaniel Borkmann ca->prior_rcv_nxt = tp->rcv_nxt; 95e3118e83SDaniel Borkmann 96e3118e83SDaniel Borkmann ca->dctcp_alpha = min(dctcp_alpha_on_init, DCTCP_MAX_ALPHA); 97e3118e83SDaniel Borkmann 98e3118e83SDaniel Borkmann ca->delayed_ack_reserved = 0; 99e3118e83SDaniel Borkmann ca->ce_state = 0; 100e3118e83SDaniel Borkmann 101e3118e83SDaniel Borkmann dctcp_reset(tp, ca); 102e3118e83SDaniel Borkmann return; 103e3118e83SDaniel Borkmann } 104e3118e83SDaniel Borkmann 105e3118e83SDaniel Borkmann /* No ECN support? Fall back to Reno. Also need to clear 106e3118e83SDaniel Borkmann * ECT from sk since it is set during 3WHS for DCTCP. 107e3118e83SDaniel Borkmann */ 108e3118e83SDaniel Borkmann inet_csk(sk)->icsk_ca_ops = &dctcp_reno; 109e3118e83SDaniel Borkmann INET_ECN_dontxmit(sk); 110e3118e83SDaniel Borkmann } 111e3118e83SDaniel Borkmann 112e3118e83SDaniel Borkmann static u32 dctcp_ssthresh(struct sock *sk) 113e3118e83SDaniel Borkmann { 114e3118e83SDaniel Borkmann const struct dctcp *ca = inet_csk_ca(sk); 115e3118e83SDaniel Borkmann struct tcp_sock *tp = tcp_sk(sk); 116e3118e83SDaniel Borkmann 117e3118e83SDaniel Borkmann return max(tp->snd_cwnd - ((tp->snd_cwnd * ca->dctcp_alpha) >> 11U), 2U); 118e3118e83SDaniel Borkmann } 119e3118e83SDaniel Borkmann 120e3118e83SDaniel Borkmann /* Minimal DCTP CE state machine: 121e3118e83SDaniel Borkmann * 122e3118e83SDaniel Borkmann * S: 0 <- last pkt was non-CE 123e3118e83SDaniel Borkmann * 1 <- last pkt was CE 124e3118e83SDaniel Borkmann */ 125e3118e83SDaniel Borkmann 126e3118e83SDaniel Borkmann static void dctcp_ce_state_0_to_1(struct sock *sk) 127e3118e83SDaniel Borkmann { 128e3118e83SDaniel Borkmann struct dctcp *ca = inet_csk_ca(sk); 129e3118e83SDaniel Borkmann struct tcp_sock *tp = tcp_sk(sk); 130e3118e83SDaniel Borkmann 131e3118e83SDaniel Borkmann /* State has changed from CE=0 to CE=1 and delayed 132e3118e83SDaniel Borkmann * ACK has not sent yet. 133e3118e83SDaniel Borkmann */ 134e3118e83SDaniel Borkmann if (!ca->ce_state && ca->delayed_ack_reserved) { 135e3118e83SDaniel Borkmann u32 tmp_rcv_nxt; 136e3118e83SDaniel Borkmann 137e3118e83SDaniel Borkmann /* Save current rcv_nxt. */ 138e3118e83SDaniel Borkmann tmp_rcv_nxt = tp->rcv_nxt; 139e3118e83SDaniel Borkmann 140e3118e83SDaniel Borkmann /* Generate previous ack with CE=0. */ 141e3118e83SDaniel Borkmann tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR; 142e3118e83SDaniel Borkmann tp->rcv_nxt = ca->prior_rcv_nxt; 143e3118e83SDaniel Borkmann 144e3118e83SDaniel Borkmann tcp_send_ack(sk); 145e3118e83SDaniel Borkmann 146e3118e83SDaniel Borkmann /* Recover current rcv_nxt. */ 147e3118e83SDaniel Borkmann tp->rcv_nxt = tmp_rcv_nxt; 148e3118e83SDaniel Borkmann } 149e3118e83SDaniel Borkmann 150e3118e83SDaniel Borkmann ca->prior_rcv_nxt = tp->rcv_nxt; 151e3118e83SDaniel Borkmann ca->ce_state = 1; 152e3118e83SDaniel Borkmann 153e3118e83SDaniel Borkmann tp->ecn_flags |= TCP_ECN_DEMAND_CWR; 154e3118e83SDaniel Borkmann } 155e3118e83SDaniel Borkmann 156e3118e83SDaniel Borkmann static void dctcp_ce_state_1_to_0(struct sock *sk) 157e3118e83SDaniel Borkmann { 158e3118e83SDaniel Borkmann struct dctcp *ca = inet_csk_ca(sk); 159e3118e83SDaniel Borkmann struct tcp_sock *tp = tcp_sk(sk); 160e3118e83SDaniel Borkmann 161e3118e83SDaniel Borkmann /* State has changed from CE=1 to CE=0 and delayed 162e3118e83SDaniel Borkmann * ACK has not sent yet. 163e3118e83SDaniel Borkmann */ 164e3118e83SDaniel Borkmann if (ca->ce_state && ca->delayed_ack_reserved) { 165e3118e83SDaniel Borkmann u32 tmp_rcv_nxt; 166e3118e83SDaniel Borkmann 167e3118e83SDaniel Borkmann /* Save current rcv_nxt. */ 168e3118e83SDaniel Borkmann tmp_rcv_nxt = tp->rcv_nxt; 169e3118e83SDaniel Borkmann 170e3118e83SDaniel Borkmann /* Generate previous ack with CE=1. */ 171e3118e83SDaniel Borkmann tp->ecn_flags |= TCP_ECN_DEMAND_CWR; 172e3118e83SDaniel Borkmann tp->rcv_nxt = ca->prior_rcv_nxt; 173e3118e83SDaniel Borkmann 174e3118e83SDaniel Borkmann tcp_send_ack(sk); 175e3118e83SDaniel Borkmann 176e3118e83SDaniel Borkmann /* Recover current rcv_nxt. */ 177e3118e83SDaniel Borkmann tp->rcv_nxt = tmp_rcv_nxt; 178e3118e83SDaniel Borkmann } 179e3118e83SDaniel Borkmann 180e3118e83SDaniel Borkmann ca->prior_rcv_nxt = tp->rcv_nxt; 181e3118e83SDaniel Borkmann ca->ce_state = 0; 182e3118e83SDaniel Borkmann 183e3118e83SDaniel Borkmann tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR; 184e3118e83SDaniel Borkmann } 185e3118e83SDaniel Borkmann 186e3118e83SDaniel Borkmann static void dctcp_update_alpha(struct sock *sk, u32 flags) 187e3118e83SDaniel Borkmann { 188e3118e83SDaniel Borkmann const struct tcp_sock *tp = tcp_sk(sk); 189e3118e83SDaniel Borkmann struct dctcp *ca = inet_csk_ca(sk); 190e3118e83SDaniel Borkmann u32 acked_bytes = tp->snd_una - ca->prior_snd_una; 191e3118e83SDaniel Borkmann 192e3118e83SDaniel Borkmann /* If ack did not advance snd_una, count dupack as MSS size. 193e3118e83SDaniel Borkmann * If ack did update window, do not count it at all. 194e3118e83SDaniel Borkmann */ 195e3118e83SDaniel Borkmann if (acked_bytes == 0 && !(flags & CA_ACK_WIN_UPDATE)) 196e3118e83SDaniel Borkmann acked_bytes = inet_csk(sk)->icsk_ack.rcv_mss; 197e3118e83SDaniel Borkmann if (acked_bytes) { 198e3118e83SDaniel Borkmann ca->acked_bytes_total += acked_bytes; 199e3118e83SDaniel Borkmann ca->prior_snd_una = tp->snd_una; 200e3118e83SDaniel Borkmann 201e3118e83SDaniel Borkmann if (flags & CA_ACK_ECE) 202e3118e83SDaniel Borkmann ca->acked_bytes_ecn += acked_bytes; 203e3118e83SDaniel Borkmann } 204e3118e83SDaniel Borkmann 205e3118e83SDaniel Borkmann /* Expired RTT */ 206e3118e83SDaniel Borkmann if (!before(tp->snd_una, ca->next_seq)) { 207f9c2ff22SEric Dumazet u64 bytes_ecn = ca->acked_bytes_ecn; 208f9c2ff22SEric Dumazet u32 alpha = ca->dctcp_alpha; 209e3118e83SDaniel Borkmann 210e3118e83SDaniel Borkmann /* alpha = (1 - g) * alpha + g * F */ 211e3118e83SDaniel Borkmann 212c80dbe04SAndrew Shewmaker alpha -= min_not_zero(alpha, alpha >> dctcp_shift_g); 213f9c2ff22SEric Dumazet if (bytes_ecn) { 214f9c2ff22SEric Dumazet /* If dctcp_shift_g == 1, a 32bit value would overflow 215f9c2ff22SEric Dumazet * after 8 Mbytes. 216f9c2ff22SEric Dumazet */ 217f9c2ff22SEric Dumazet bytes_ecn <<= (10 - dctcp_shift_g); 218f9c2ff22SEric Dumazet do_div(bytes_ecn, max(1U, ca->acked_bytes_total)); 219e3118e83SDaniel Borkmann 220f9c2ff22SEric Dumazet alpha = min(alpha + (u32)bytes_ecn, DCTCP_MAX_ALPHA); 221f9c2ff22SEric Dumazet } 222f9c2ff22SEric Dumazet /* dctcp_alpha can be read from dctcp_get_info() without 223f9c2ff22SEric Dumazet * synchro, so we ask compiler to not use dctcp_alpha 224f9c2ff22SEric Dumazet * as a temporary variable in prior operations. 225f9c2ff22SEric Dumazet */ 226f9c2ff22SEric Dumazet WRITE_ONCE(ca->dctcp_alpha, alpha); 227e3118e83SDaniel Borkmann dctcp_reset(tp, ca); 228e3118e83SDaniel Borkmann } 229e3118e83SDaniel Borkmann } 230e3118e83SDaniel Borkmann 231e3118e83SDaniel Borkmann static void dctcp_state(struct sock *sk, u8 new_state) 232e3118e83SDaniel Borkmann { 233e3118e83SDaniel Borkmann if (dctcp_clamp_alpha_on_loss && new_state == TCP_CA_Loss) { 234e3118e83SDaniel Borkmann struct dctcp *ca = inet_csk_ca(sk); 235e3118e83SDaniel Borkmann 236e3118e83SDaniel Borkmann /* If this extension is enabled, we clamp dctcp_alpha to 237e3118e83SDaniel Borkmann * max on packet loss; the motivation is that dctcp_alpha 238e3118e83SDaniel Borkmann * is an indicator to the extend of congestion and packet 239e3118e83SDaniel Borkmann * loss is an indicator of extreme congestion; setting 240e3118e83SDaniel Borkmann * this in practice turned out to be beneficial, and 241e3118e83SDaniel Borkmann * effectively assumes total congestion which reduces the 242e3118e83SDaniel Borkmann * window by half. 243e3118e83SDaniel Borkmann */ 244e3118e83SDaniel Borkmann ca->dctcp_alpha = DCTCP_MAX_ALPHA; 245e3118e83SDaniel Borkmann } 246e3118e83SDaniel Borkmann } 247e3118e83SDaniel Borkmann 248e3118e83SDaniel Borkmann static void dctcp_update_ack_reserved(struct sock *sk, enum tcp_ca_event ev) 249e3118e83SDaniel Borkmann { 250e3118e83SDaniel Borkmann struct dctcp *ca = inet_csk_ca(sk); 251e3118e83SDaniel Borkmann 252e3118e83SDaniel Borkmann switch (ev) { 253e3118e83SDaniel Borkmann case CA_EVENT_DELAYED_ACK: 254e3118e83SDaniel Borkmann if (!ca->delayed_ack_reserved) 255e3118e83SDaniel Borkmann ca->delayed_ack_reserved = 1; 256e3118e83SDaniel Borkmann break; 257e3118e83SDaniel Borkmann case CA_EVENT_NON_DELAYED_ACK: 258e3118e83SDaniel Borkmann if (ca->delayed_ack_reserved) 259e3118e83SDaniel Borkmann ca->delayed_ack_reserved = 0; 260e3118e83SDaniel Borkmann break; 261e3118e83SDaniel Borkmann default: 262e3118e83SDaniel Borkmann /* Don't care for the rest. */ 263e3118e83SDaniel Borkmann break; 264e3118e83SDaniel Borkmann } 265e3118e83SDaniel Borkmann } 266e3118e83SDaniel Borkmann 267e3118e83SDaniel Borkmann static void dctcp_cwnd_event(struct sock *sk, enum tcp_ca_event ev) 268e3118e83SDaniel Borkmann { 269e3118e83SDaniel Borkmann switch (ev) { 270e3118e83SDaniel Borkmann case CA_EVENT_ECN_IS_CE: 271e3118e83SDaniel Borkmann dctcp_ce_state_0_to_1(sk); 272e3118e83SDaniel Borkmann break; 273e3118e83SDaniel Borkmann case CA_EVENT_ECN_NO_CE: 274e3118e83SDaniel Borkmann dctcp_ce_state_1_to_0(sk); 275e3118e83SDaniel Borkmann break; 276e3118e83SDaniel Borkmann case CA_EVENT_DELAYED_ACK: 277e3118e83SDaniel Borkmann case CA_EVENT_NON_DELAYED_ACK: 278e3118e83SDaniel Borkmann dctcp_update_ack_reserved(sk, ev); 279e3118e83SDaniel Borkmann break; 280e3118e83SDaniel Borkmann default: 281e3118e83SDaniel Borkmann /* Don't care for the rest. */ 282e3118e83SDaniel Borkmann break; 283e3118e83SDaniel Borkmann } 284e3118e83SDaniel Borkmann } 285e3118e83SDaniel Borkmann 28664f40ff5SEric Dumazet static size_t dctcp_get_info(struct sock *sk, u32 ext, int *attr, 28764f40ff5SEric Dumazet union tcp_cc_info *info) 288e3118e83SDaniel Borkmann { 289e3118e83SDaniel Borkmann const struct dctcp *ca = inet_csk_ca(sk); 290e3118e83SDaniel Borkmann 291e3118e83SDaniel Borkmann /* Fill it also in case of VEGASINFO due to req struct limits. 292e3118e83SDaniel Borkmann * We can still correctly retrieve it later. 293e3118e83SDaniel Borkmann */ 294e3118e83SDaniel Borkmann if (ext & (1 << (INET_DIAG_DCTCPINFO - 1)) || 295e3118e83SDaniel Borkmann ext & (1 << (INET_DIAG_VEGASINFO - 1))) { 296*dcf1158bSNeal Cardwell memset(&info->dctcp, 0, sizeof(info->dctcp)); 297e3118e83SDaniel Borkmann if (inet_csk(sk)->icsk_ca_ops != &dctcp_reno) { 29864f40ff5SEric Dumazet info->dctcp.dctcp_enabled = 1; 29964f40ff5SEric Dumazet info->dctcp.dctcp_ce_state = (u16) ca->ce_state; 30064f40ff5SEric Dumazet info->dctcp.dctcp_alpha = ca->dctcp_alpha; 30164f40ff5SEric Dumazet info->dctcp.dctcp_ab_ecn = ca->acked_bytes_ecn; 30264f40ff5SEric Dumazet info->dctcp.dctcp_ab_tot = ca->acked_bytes_total; 303e3118e83SDaniel Borkmann } 304e3118e83SDaniel Borkmann 30564f40ff5SEric Dumazet *attr = INET_DIAG_DCTCPINFO; 306*dcf1158bSNeal Cardwell return sizeof(info->dctcp); 307e3118e83SDaniel Borkmann } 308521f1cf1SEric Dumazet return 0; 309e3118e83SDaniel Borkmann } 310e3118e83SDaniel Borkmann 311e3118e83SDaniel Borkmann static struct tcp_congestion_ops dctcp __read_mostly = { 312e3118e83SDaniel Borkmann .init = dctcp_init, 313e3118e83SDaniel Borkmann .in_ack_event = dctcp_update_alpha, 314e3118e83SDaniel Borkmann .cwnd_event = dctcp_cwnd_event, 315e3118e83SDaniel Borkmann .ssthresh = dctcp_ssthresh, 316e3118e83SDaniel Borkmann .cong_avoid = tcp_reno_cong_avoid, 317e3118e83SDaniel Borkmann .set_state = dctcp_state, 318e3118e83SDaniel Borkmann .get_info = dctcp_get_info, 319e3118e83SDaniel Borkmann .flags = TCP_CONG_NEEDS_ECN, 320e3118e83SDaniel Borkmann .owner = THIS_MODULE, 321e3118e83SDaniel Borkmann .name = "dctcp", 322e3118e83SDaniel Borkmann }; 323e3118e83SDaniel Borkmann 324e3118e83SDaniel Borkmann static struct tcp_congestion_ops dctcp_reno __read_mostly = { 325e3118e83SDaniel Borkmann .ssthresh = tcp_reno_ssthresh, 326e3118e83SDaniel Borkmann .cong_avoid = tcp_reno_cong_avoid, 327e3118e83SDaniel Borkmann .get_info = dctcp_get_info, 328e3118e83SDaniel Borkmann .owner = THIS_MODULE, 329e3118e83SDaniel Borkmann .name = "dctcp-reno", 330e3118e83SDaniel Borkmann }; 331e3118e83SDaniel Borkmann 332e3118e83SDaniel Borkmann static int __init dctcp_register(void) 333e3118e83SDaniel Borkmann { 334e3118e83SDaniel Borkmann BUILD_BUG_ON(sizeof(struct dctcp) > ICSK_CA_PRIV_SIZE); 335e3118e83SDaniel Borkmann return tcp_register_congestion_control(&dctcp); 336e3118e83SDaniel Borkmann } 337e3118e83SDaniel Borkmann 338e3118e83SDaniel Borkmann static void __exit dctcp_unregister(void) 339e3118e83SDaniel Borkmann { 340e3118e83SDaniel Borkmann tcp_unregister_congestion_control(&dctcp); 341e3118e83SDaniel Borkmann } 342e3118e83SDaniel Borkmann 343e3118e83SDaniel Borkmann module_init(dctcp_register); 344e3118e83SDaniel Borkmann module_exit(dctcp_unregister); 345e3118e83SDaniel Borkmann 346e3118e83SDaniel Borkmann MODULE_AUTHOR("Daniel Borkmann <dborkman@redhat.com>"); 347e3118e83SDaniel Borkmann MODULE_AUTHOR("Florian Westphal <fw@strlen.de>"); 348e3118e83SDaniel Borkmann MODULE_AUTHOR("Glenn Judd <glenn.judd@morganstanley.com>"); 349e3118e83SDaniel Borkmann 350e3118e83SDaniel Borkmann MODULE_LICENSE("GPL v2"); 351e3118e83SDaniel Borkmann MODULE_DESCRIPTION("DataCenter TCP (DCTCP)"); 352