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 /net | |
| 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>
Diffstat (limited to '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; |
