| From foo@baz Mon Sep 17 13:33:56 CEST 2018 |
| From: Stephen Hemminger <stephen@networkplumber.org> |
| Date: Thu, 13 Sep 2018 07:58:43 -0700 |
| Subject: inet: frags: get rif of inet_frag_evicting() |
| To: davem@davemloft.net, gregkh@linuxfoundation.org |
| Cc: netdev@vger.kernel.org, stable@vger.kernel.org, edumazet@google.com |
| Message-ID: <20180913145902.17531-12-sthemmin@microsoft.com> |
| |
| From: Eric Dumazet <edumazet@google.com> |
| |
| This refactors ip_expire() since one indentation level is removed. |
| |
| Note: in the future, we should try hard to avoid the skb_clone() |
| since this is a serious performance cost. |
| Under DDOS, the ICMP message wont be sent because of rate limits. |
| |
| Fact that ip6_expire_frag_queue() does not use skb_clone() is |
| disturbing too. Presumably IPv6 should have the same |
| issue than the one we fixed in commit ec4fbd64751d |
| ("inet: frag: release spinlock before calling icmp_send()") |
| |
| Signed-off-by: Eric Dumazet <edumazet@google.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| (cherry picked from commit 399d1404be660d355192ff4df5ccc3f4159ec1e4) |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| include/net/inet_frag.h | 5 --- |
| net/ipv4/ip_fragment.c | 65 +++++++++++++++++++++++------------------------- |
| net/ipv6/reassembly.c | 4 -- |
| 3 files changed, 32 insertions(+), 42 deletions(-) |
| |
| --- a/include/net/inet_frag.h |
| +++ b/include/net/inet_frag.h |
| @@ -119,11 +119,6 @@ static inline void inet_frag_put(struct |
| inet_frag_destroy(q); |
| } |
| |
| -static inline bool inet_frag_evicting(struct inet_frag_queue *q) |
| -{ |
| - return false; |
| -} |
| - |
| /* Memory Tracking Functions. */ |
| |
| static inline int frag_mem_limit(struct netns_frags *nf) |
| --- a/net/ipv4/ip_fragment.c |
| +++ b/net/ipv4/ip_fragment.c |
| @@ -143,8 +143,11 @@ static bool frag_expire_skip_icmp(u32 us |
| static void ip_expire(struct timer_list *t) |
| { |
| struct inet_frag_queue *frag = from_timer(frag, t, timer); |
| - struct ipq *qp; |
| + struct sk_buff *clone, *head; |
| + const struct iphdr *iph; |
| struct net *net; |
| + struct ipq *qp; |
| + int err; |
| |
| qp = container_of(frag, struct ipq, q); |
| net = container_of(qp->q.net, struct net, ipv4.frags); |
| @@ -158,45 +161,41 @@ static void ip_expire(struct timer_list |
| ipq_kill(qp); |
| __IP_INC_STATS(net, IPSTATS_MIB_REASMFAILS); |
| |
| - if (!inet_frag_evicting(&qp->q)) { |
| - struct sk_buff *clone, *head = qp->q.fragments; |
| - const struct iphdr *iph; |
| - int err; |
| + head = qp->q.fragments; |
| |
| - __IP_INC_STATS(net, IPSTATS_MIB_REASMTIMEOUT); |
| + __IP_INC_STATS(net, IPSTATS_MIB_REASMTIMEOUT); |
| |
| - if (!(qp->q.flags & INET_FRAG_FIRST_IN) || !qp->q.fragments) |
| - goto out; |
| + if (!(qp->q.flags & INET_FRAG_FIRST_IN) || !head) |
| + goto out; |
| |
| - head->dev = dev_get_by_index_rcu(net, qp->iif); |
| - if (!head->dev) |
| - goto out; |
| + head->dev = dev_get_by_index_rcu(net, qp->iif); |
| + if (!head->dev) |
| + goto out; |
| |
| |
| - /* skb has no dst, perform route lookup again */ |
| - iph = ip_hdr(head); |
| - err = ip_route_input_noref(head, iph->daddr, iph->saddr, |
| + /* skb has no dst, perform route lookup again */ |
| + iph = ip_hdr(head); |
| + err = ip_route_input_noref(head, iph->daddr, iph->saddr, |
| iph->tos, head->dev); |
| - if (err) |
| - goto out; |
| + if (err) |
| + goto out; |
| + |
| + /* Only an end host needs to send an ICMP |
| + * "Fragment Reassembly Timeout" message, per RFC792. |
| + */ |
| + if (frag_expire_skip_icmp(qp->q.key.v4.user) && |
| + (skb_rtable(head)->rt_type != RTN_LOCAL)) |
| + goto out; |
| + |
| + clone = skb_clone(head, GFP_ATOMIC); |
| |
| - /* Only an end host needs to send an ICMP |
| - * "Fragment Reassembly Timeout" message, per RFC792. |
| - */ |
| - if (frag_expire_skip_icmp(qp->q.key.v4.user) && |
| - (skb_rtable(head)->rt_type != RTN_LOCAL)) |
| - goto out; |
| - |
| - clone = skb_clone(head, GFP_ATOMIC); |
| - |
| - /* Send an ICMP "Fragment Reassembly Timeout" message. */ |
| - if (clone) { |
| - spin_unlock(&qp->q.lock); |
| - icmp_send(clone, ICMP_TIME_EXCEEDED, |
| - ICMP_EXC_FRAGTIME, 0); |
| - consume_skb(clone); |
| - goto out_rcu_unlock; |
| - } |
| + /* Send an ICMP "Fragment Reassembly Timeout" message. */ |
| + if (clone) { |
| + spin_unlock(&qp->q.lock); |
| + icmp_send(clone, ICMP_TIME_EXCEEDED, |
| + ICMP_EXC_FRAGTIME, 0); |
| + consume_skb(clone); |
| + goto out_rcu_unlock; |
| } |
| out: |
| spin_unlock(&qp->q.lock); |
| --- a/net/ipv6/reassembly.c |
| +++ b/net/ipv6/reassembly.c |
| @@ -106,10 +106,6 @@ void ip6_expire_frag_queue(struct net *n |
| goto out_rcu_unlock; |
| |
| __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); |
| - |
| - if (inet_frag_evicting(&fq->q)) |
| - goto out_rcu_unlock; |
| - |
| __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT); |
| |
| /* Don't send error if the first segment did not arrive. */ |