@@ -403,6 +403,7 @@ struct tcp_sock {
u32 snd_cwnd_used;
u32 snd_cwnd_stamp;
u32 prior_cwnd; /* cwnd right before starting loss recovery */
+ u32 init_cwnd; /* init cwnd controlled by setsockopt */
u32 prr_delivered; /* Number of newly delivered packets to
* receiver in Recovery. */
u32 last_oow_ack_time; /* timestamp of last out-of-window ACK */
@@ -142,6 +142,7 @@ enum {
#define TCP_RTO_MAX_MS 44 /* max rto time in ms */
#define TCP_RTO_MIN_US 45 /* min rto time in us */
#define TCP_DELACK_MAX_US 46 /* max delayed ack time in us */
+#define TCP_IW 47 /* initial congestion window */
#define TCP_REPAIR_ON 1
#define TCP_REPAIR_OFF 0
@@ -3863,6 +3863,11 @@ int do_tcp_setsockopt(struct sock *sk, int level, int optname,
WRITE_ONCE(inet_csk(sk)->icsk_delack_max, delack_max);
return 0;
}
+ case TCP_IW:
+ if (val <= 0 || tp->data_segs_out > tp->syn_data)
+ return -EINVAL;
+ tp->init_cwnd = val;
+ return 0;
}
sockopt_lock_sock(sk);
@@ -4708,6 +4713,9 @@ int do_tcp_getsockopt(struct sock *sk, int level,
case TCP_DELACK_MAX_US:
val = jiffies_to_usecs(READ_ONCE(inet_csk(sk)->icsk_delack_max));
break;
+ case TCP_IW:
+ val = tp->init_cwnd;
+ break;
default:
return -ENOPROTOOPT;
}
@@ -1019,7 +1019,7 @@ static void tcp_set_rto(struct sock *sk)
__u32 tcp_init_cwnd(const struct tcp_sock *tp, const struct dst_entry *dst)
{
- __u32 cwnd = (dst ? dst_metric(dst, RTAX_INITCWND) : 0);
+ __u32 cwnd = tp->init_cwnd ? : (dst ? dst_metric(dst, RTAX_INITCWND) : 0);
if (!cwnd)
cwnd = TCP_INIT_CWND;