diff options
author | Eric Dumazet <edumazet@google.com> | 2019-10-16 21:00:56 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-10-18 13:02:37 -0400 |
commit | 9669fffc1415bb0c30e5d2ec98a8e1c3a418cb9c (patch) | |
tree | 3abe73fdf43b7a670cc69b6930d07c2683ade0d4 | |
parent | 63158ac0ba5d5a279999387c86791a09930610aa (diff) |
net: ensure correct skb->tstamp in various fragmenters
Thomas found that some forwarded packets would be stuck
in FQ packet scheduler because their skb->tstamp contained
timestamps far in the future.
We thought we addressed this point in commit 8203e2d844d3
("net: clear skb->tstamp in forwarding paths") but there
is still an issue when/if a packet needs to be fragmented.
In order to meet EDT requirements, we have to make sure all
fragments get the original skb->tstamp.
Note that this original skb->tstamp should be zero in
forwarding path, but might have a non zero value in
output path if user decided so.
Fixes: fb420d5d91c1 ("tcp/fq: move back to CLOCK_MONOTONIC")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: Thomas Bartschies <Thomas.Bartschies@cvk.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/bridge/netfilter/nf_conntrack_bridge.c | 3 | ||||
-rw-r--r-- | net/ipv4/ip_output.c | 3 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 3 | ||||
-rw-r--r-- | net/ipv6/netfilter.c | 3 |
4 files changed, 12 insertions, 0 deletions
diff --git a/net/bridge/netfilter/nf_conntrack_bridge.c b/net/bridge/netfilter/nf_conntrack_bridge.c index 8842798c29e6..506d6141e44e 100644 --- a/net/bridge/netfilter/nf_conntrack_bridge.c +++ b/net/bridge/netfilter/nf_conntrack_bridge.c | |||
@@ -33,6 +33,7 @@ static int nf_br_ip_fragment(struct net *net, struct sock *sk, | |||
33 | { | 33 | { |
34 | int frag_max_size = BR_INPUT_SKB_CB(skb)->frag_max_size; | 34 | int frag_max_size = BR_INPUT_SKB_CB(skb)->frag_max_size; |
35 | unsigned int hlen, ll_rs, mtu; | 35 | unsigned int hlen, ll_rs, mtu; |
36 | ktime_t tstamp = skb->tstamp; | ||
36 | struct ip_frag_state state; | 37 | struct ip_frag_state state; |
37 | struct iphdr *iph; | 38 | struct iphdr *iph; |
38 | int err; | 39 | int err; |
@@ -80,6 +81,7 @@ static int nf_br_ip_fragment(struct net *net, struct sock *sk, | |||
80 | if (iter.frag) | 81 | if (iter.frag) |
81 | ip_fraglist_prepare(skb, &iter); | 82 | ip_fraglist_prepare(skb, &iter); |
82 | 83 | ||
84 | skb->tstamp = tstamp; | ||
83 | err = output(net, sk, data, skb); | 85 | err = output(net, sk, data, skb); |
84 | if (err || !iter.frag) | 86 | if (err || !iter.frag) |
85 | break; | 87 | break; |
@@ -104,6 +106,7 @@ slow_path: | |||
104 | goto blackhole; | 106 | goto blackhole; |
105 | } | 107 | } |
106 | 108 | ||
109 | skb2->tstamp = tstamp; | ||
107 | err = output(net, sk, data, skb2); | 110 | err = output(net, sk, data, skb2); |
108 | if (err) | 111 | if (err) |
109 | goto blackhole; | 112 | goto blackhole; |
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 28fca408812c..814b9b8882a0 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c | |||
@@ -771,6 +771,7 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, | |||
771 | struct rtable *rt = skb_rtable(skb); | 771 | struct rtable *rt = skb_rtable(skb); |
772 | unsigned int mtu, hlen, ll_rs; | 772 | unsigned int mtu, hlen, ll_rs; |
773 | struct ip_fraglist_iter iter; | 773 | struct ip_fraglist_iter iter; |
774 | ktime_t tstamp = skb->tstamp; | ||
774 | struct ip_frag_state state; | 775 | struct ip_frag_state state; |
775 | int err = 0; | 776 | int err = 0; |
776 | 777 | ||
@@ -846,6 +847,7 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, | |||
846 | ip_fraglist_prepare(skb, &iter); | 847 | ip_fraglist_prepare(skb, &iter); |
847 | } | 848 | } |
848 | 849 | ||
850 | skb->tstamp = tstamp; | ||
849 | err = output(net, sk, skb); | 851 | err = output(net, sk, skb); |
850 | 852 | ||
851 | if (!err) | 853 | if (!err) |
@@ -900,6 +902,7 @@ slow_path: | |||
900 | /* | 902 | /* |
901 | * Put this fragment into the sending queue. | 903 | * Put this fragment into the sending queue. |
902 | */ | 904 | */ |
905 | skb2->tstamp = tstamp; | ||
903 | err = output(net, sk, skb2); | 906 | err = output(net, sk, skb2); |
904 | if (err) | 907 | if (err) |
905 | goto fail; | 908 | goto fail; |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index edadee4a7e76..71827b56c006 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -768,6 +768,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, | |||
768 | inet6_sk(skb->sk) : NULL; | 768 | inet6_sk(skb->sk) : NULL; |
769 | struct ip6_frag_state state; | 769 | struct ip6_frag_state state; |
770 | unsigned int mtu, hlen, nexthdr_offset; | 770 | unsigned int mtu, hlen, nexthdr_offset; |
771 | ktime_t tstamp = skb->tstamp; | ||
771 | int hroom, err = 0; | 772 | int hroom, err = 0; |
772 | __be32 frag_id; | 773 | __be32 frag_id; |
773 | u8 *prevhdr, nexthdr = 0; | 774 | u8 *prevhdr, nexthdr = 0; |
@@ -855,6 +856,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, | |||
855 | if (iter.frag) | 856 | if (iter.frag) |
856 | ip6_fraglist_prepare(skb, &iter); | 857 | ip6_fraglist_prepare(skb, &iter); |
857 | 858 | ||
859 | skb->tstamp = tstamp; | ||
858 | err = output(net, sk, skb); | 860 | err = output(net, sk, skb); |
859 | if (!err) | 861 | if (!err) |
860 | IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), | 862 | IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), |
@@ -913,6 +915,7 @@ slow_path: | |||
913 | /* | 915 | /* |
914 | * Put this fragment into the sending queue. | 916 | * Put this fragment into the sending queue. |
915 | */ | 917 | */ |
918 | frag->tstamp = tstamp; | ||
916 | err = output(net, sk, frag); | 919 | err = output(net, sk, frag); |
917 | if (err) | 920 | if (err) |
918 | goto fail; | 921 | goto fail; |
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index a9bff556d3b2..409e79b84a83 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c | |||
@@ -119,6 +119,7 @@ int br_ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, | |||
119 | struct sk_buff *)) | 119 | struct sk_buff *)) |
120 | { | 120 | { |
121 | int frag_max_size = BR_INPUT_SKB_CB(skb)->frag_max_size; | 121 | int frag_max_size = BR_INPUT_SKB_CB(skb)->frag_max_size; |
122 | ktime_t tstamp = skb->tstamp; | ||
122 | struct ip6_frag_state state; | 123 | struct ip6_frag_state state; |
123 | u8 *prevhdr, nexthdr = 0; | 124 | u8 *prevhdr, nexthdr = 0; |
124 | unsigned int mtu, hlen; | 125 | unsigned int mtu, hlen; |
@@ -183,6 +184,7 @@ int br_ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, | |||
183 | if (iter.frag) | 184 | if (iter.frag) |
184 | ip6_fraglist_prepare(skb, &iter); | 185 | ip6_fraglist_prepare(skb, &iter); |
185 | 186 | ||
187 | skb->tstamp = tstamp; | ||
186 | err = output(net, sk, data, skb); | 188 | err = output(net, sk, data, skb); |
187 | if (err || !iter.frag) | 189 | if (err || !iter.frag) |
188 | break; | 190 | break; |
@@ -215,6 +217,7 @@ slow_path: | |||
215 | goto blackhole; | 217 | goto blackhole; |
216 | } | 218 | } |
217 | 219 | ||
220 | skb2->tstamp = tstamp; | ||
218 | err = output(net, sk, data, skb2); | 221 | err = output(net, sk, data, skb2); |
219 | if (err) | 222 | if (err) |
220 | goto blackhole; | 223 | goto blackhole; |