aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_output.c
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2018-10-15 12:37:54 -0400
committerDavid S. Miller <davem@davemloft.net>2018-10-16 01:56:42 -0400
commita7a2563064e963bc5e3f39f533974f2730c0ff56 (patch)
tree08c2706535d382c6b7d07e19698f8e55fee371be /net/ipv4/tcp_output.c
parent76a9ebe811fb3d0605cb084f1ae6be5610541865 (diff)
tcp: mitigate scheduling jitter in EDT pacing model
In commit fefa569a9d4b ("net_sched: sch_fq: account for schedule/timers drifts") we added a mitigation for scheduling jitter in fq packet scheduler. This patch does the same in TCP stack, now it is using EDT model. Note that this mitigation is valid for both external (fq packet scheduler) or internal TCP pacing. This uses the same strategy than the above commit, allowing a time credit of half the packet currently sent. Consider following case : An skb is sent, after an idle period of 300 usec. The air-time (skb->len/pacing_rate) is 500 usec Instead of setting the pacing timer to now+500 usec, it will use now+min(500/2, 300) -> now+250usec This is like having a token bucket with a depth of half an skb. Tested: tc qdisc replace dev eth0 root pfifo_fast Before netperf -P0 -H remote -- -q 1000000000 # 8000Mbit 540000 262144 262144 10.00 7710.43 After : netperf -P0 -H remote -- -q 1000000000 # 8000 Mbit 540000 262144 262144 10.00 7999.75 # Much closer to 8000Mbit target Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_output.c')
-rw-r--r--net/ipv4/tcp_output.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index f4aa4109334a..5474c9854f25 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -985,7 +985,8 @@ static void tcp_internal_pacing(struct sock *sk)
985 sock_hold(sk); 985 sock_hold(sk);
986} 986}
987 987
988static void tcp_update_skb_after_send(struct sock *sk, struct sk_buff *skb) 988static void tcp_update_skb_after_send(struct sock *sk, struct sk_buff *skb,
989 u64 prior_wstamp)
989{ 990{
990 struct tcp_sock *tp = tcp_sk(sk); 991 struct tcp_sock *tp = tcp_sk(sk);
991 992
@@ -998,7 +999,12 @@ static void tcp_update_skb_after_send(struct sock *sk, struct sk_buff *skb)
998 * this is a minor annoyance. 999 * this is a minor annoyance.
999 */ 1000 */
1000 if (rate != ~0UL && rate && tp->data_segs_out >= 10) { 1001 if (rate != ~0UL && rate && tp->data_segs_out >= 10) {
1001 tp->tcp_wstamp_ns += div64_ul((u64)skb->len * NSEC_PER_SEC, rate); 1002 u64 len_ns = div64_ul((u64)skb->len * NSEC_PER_SEC, rate);
1003 u64 credit = tp->tcp_wstamp_ns - prior_wstamp;
1004
1005 /* take into account OS jitter */
1006 len_ns -= min_t(u64, len_ns / 2, credit);
1007 tp->tcp_wstamp_ns += len_ns;
1002 1008
1003 tcp_internal_pacing(sk); 1009 tcp_internal_pacing(sk);
1004 } 1010 }
@@ -1029,6 +1035,7 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb,
1029 struct sk_buff *oskb = NULL; 1035 struct sk_buff *oskb = NULL;
1030 struct tcp_md5sig_key *md5; 1036 struct tcp_md5sig_key *md5;
1031 struct tcphdr *th; 1037 struct tcphdr *th;
1038 u64 prior_wstamp;
1032 int err; 1039 int err;
1033 1040
1034 BUG_ON(!skb || !tcp_skb_pcount(skb)); 1041 BUG_ON(!skb || !tcp_skb_pcount(skb));
@@ -1050,7 +1057,7 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb,
1050 return -ENOBUFS; 1057 return -ENOBUFS;
1051 } 1058 }
1052 1059
1053 /* TODO: might take care of jitter here */ 1060 prior_wstamp = tp->tcp_wstamp_ns;
1054 tp->tcp_wstamp_ns = max(tp->tcp_wstamp_ns, tp->tcp_clock_cache); 1061 tp->tcp_wstamp_ns = max(tp->tcp_wstamp_ns, tp->tcp_clock_cache);
1055 1062
1056 skb->skb_mstamp_ns = tp->tcp_wstamp_ns; 1063 skb->skb_mstamp_ns = tp->tcp_wstamp_ns;
@@ -1169,7 +1176,7 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb,
1169 err = net_xmit_eval(err); 1176 err = net_xmit_eval(err);
1170 } 1177 }
1171 if (!err && oskb) { 1178 if (!err && oskb) {
1172 tcp_update_skb_after_send(sk, oskb); 1179 tcp_update_skb_after_send(sk, oskb, prior_wstamp);
1173 tcp_rate_skb_sent(sk, oskb); 1180 tcp_rate_skb_sent(sk, oskb);
1174 } 1181 }
1175 return err; 1182 return err;
@@ -2321,7 +2328,7 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
2321 2328
2322 if (unlikely(tp->repair) && tp->repair_queue == TCP_SEND_QUEUE) { 2329 if (unlikely(tp->repair) && tp->repair_queue == TCP_SEND_QUEUE) {
2323 /* "skb_mstamp" is used as a start point for the retransmit timer */ 2330 /* "skb_mstamp" is used as a start point for the retransmit timer */
2324 tcp_update_skb_after_send(sk, skb); 2331 tcp_update_skb_after_send(sk, skb, tp->tcp_wstamp_ns);
2325 goto repair; /* Skip network transmission */ 2332 goto repair; /* Skip network transmission */
2326 } 2333 }
2327 2334
@@ -2896,7 +2903,7 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs)
2896 } tcp_skb_tsorted_restore(skb); 2903 } tcp_skb_tsorted_restore(skb);
2897 2904
2898 if (!err) { 2905 if (!err) {
2899 tcp_update_skb_after_send(sk, skb); 2906 tcp_update_skb_after_send(sk, skb, tp->tcp_wstamp_ns);
2900 tcp_rate_skb_sent(sk, skb); 2907 tcp_rate_skb_sent(sk, skb);
2901 } 2908 }
2902 } else { 2909 } else {