| From 2d24213ecbbccf4e59b0c50098d95b0721e083ed Mon Sep 17 00:00:00 2001 |
| From: Hangbin Liu <liuhangbin@gmail.com> |
| Date: Sun, 22 Dec 2019 10:51:09 +0800 |
| Subject: [PATCH] net: add bool confirm_neigh parameter for dst_ops.update_pmtu |
| |
| commit bd085ef678b2cc8c38c105673dfe8ff8f5ec0c57 upstream. |
| |
| The MTU update code is supposed to be invoked in response to real |
| networking events that update the PMTU. In IPv6 PMTU update function |
| __ip6_rt_update_pmtu() we called dst_confirm_neigh() to update neighbor |
| confirmed time. |
| |
| But for tunnel code, it will call pmtu before xmit, like: |
| - tnl_update_pmtu() |
| - skb_dst_update_pmtu() |
| - ip6_rt_update_pmtu() |
| - __ip6_rt_update_pmtu() |
| - dst_confirm_neigh() |
| |
| If the tunnel remote dst mac address changed and we still do the neigh |
| confirm, we will not be able to update neigh cache and ping6 remote |
| will failed. |
| |
| So for this ip_tunnel_xmit() case, _EVEN_ if the MTU is changed, we |
| should not be invoking dst_confirm_neigh() as we have no evidence |
| of successful two-way communication at this point. |
| |
| On the other hand it is also important to keep the neigh reachability fresh |
| for TCP flows, so we cannot remove this dst_confirm_neigh() call. |
| |
| To fix the issue, we have to add a new bool parameter for dst_ops.update_pmtu |
| to choose whether we should do neigh update or not. I will add the parameter |
| in this patch and set all the callers to true to comply with the previous |
| way, and fix the tunnel code one by one on later patches. |
| |
| v5: No change. |
| v4: No change. |
| v3: Do not remove dst_confirm_neigh, but add a new bool parameter in |
| dst_ops.update_pmtu to control whether we should do neighbor confirm. |
| Also split the big patch to small ones for each area. |
| v2: Remove dst_confirm_neigh in __ip6_rt_update_pmtu. |
| |
| Suggested-by: David Miller <davem@davemloft.net> |
| Reviewed-by: Guillaume Nault <gnault@redhat.com> |
| Acked-by: David Ahern <dsahern@gmail.com> |
| Signed-off-by: Hangbin Liu <liuhangbin@gmail.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c |
| index 607f38712b4e..a4d1a408db59 100644 |
| --- a/drivers/net/gtp.c |
| +++ b/drivers/net/gtp.c |
| @@ -541,7 +541,7 @@ static int gtp_build_skb_ip4(struct sk_buff *skb, struct net_device *dev, |
| mtu = dst_mtu(&rt->dst); |
| } |
| |
| - rt->dst.ops->update_pmtu(&rt->dst, NULL, skb, mtu); |
| + rt->dst.ops->update_pmtu(&rt->dst, NULL, skb, mtu, true); |
| |
| if (!skb_is_gso(skb) && (iph->frag_off & htons(IP_DF)) && |
| mtu < ntohs(iph->tot_len)) { |
| diff --git a/include/net/dst.h b/include/net/dst.h |
| index e3129af8aa05..a01b194234bf 100644 |
| --- a/include/net/dst.h |
| +++ b/include/net/dst.h |
| @@ -516,7 +516,7 @@ static inline void skb_dst_update_pmtu(struct sk_buff *skb, u32 mtu) |
| struct dst_entry *dst = skb_dst(skb); |
| |
| if (dst && dst->ops->update_pmtu) |
| - dst->ops->update_pmtu(dst, NULL, skb, mtu); |
| + dst->ops->update_pmtu(dst, NULL, skb, mtu, true); |
| } |
| |
| static inline void skb_tunnel_check_pmtu(struct sk_buff *skb, |
| diff --git a/include/net/dst_ops.h b/include/net/dst_ops.h |
| index 5ec645f27ee3..443863c7b8da 100644 |
| --- a/include/net/dst_ops.h |
| +++ b/include/net/dst_ops.h |
| @@ -27,7 +27,8 @@ struct dst_ops { |
| struct dst_entry * (*negative_advice)(struct dst_entry *); |
| void (*link_failure)(struct sk_buff *); |
| void (*update_pmtu)(struct dst_entry *dst, struct sock *sk, |
| - struct sk_buff *skb, u32 mtu); |
| + struct sk_buff *skb, u32 mtu, |
| + bool confirm_neigh); |
| void (*redirect)(struct dst_entry *dst, struct sock *sk, |
| struct sk_buff *skb); |
| int (*local_out)(struct net *net, struct sock *sk, struct sk_buff *skb); |
| diff --git a/net/bridge/br_nf_core.c b/net/bridge/br_nf_core.c |
| index 2cdfc5d6c25d..8c69f0c95a8e 100644 |
| --- a/net/bridge/br_nf_core.c |
| +++ b/net/bridge/br_nf_core.c |
| @@ -22,7 +22,8 @@ |
| #endif |
| |
| static void fake_update_pmtu(struct dst_entry *dst, struct sock *sk, |
| - struct sk_buff *skb, u32 mtu) |
| + struct sk_buff *skb, u32 mtu, |
| + bool confirm_neigh) |
| { |
| } |
| |
| diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c |
| index aea918135ec3..08c3dc45f1a4 100644 |
| --- a/net/decnet/dn_route.c |
| +++ b/net/decnet/dn_route.c |
| @@ -110,7 +110,8 @@ static void dn_dst_ifdown(struct dst_entry *, struct net_device *dev, int how); |
| static struct dst_entry *dn_dst_negative_advice(struct dst_entry *); |
| static void dn_dst_link_failure(struct sk_buff *); |
| static void dn_dst_update_pmtu(struct dst_entry *dst, struct sock *sk, |
| - struct sk_buff *skb , u32 mtu); |
| + struct sk_buff *skb , u32 mtu, |
| + bool confirm_neigh); |
| static void dn_dst_redirect(struct dst_entry *dst, struct sock *sk, |
| struct sk_buff *skb); |
| static struct neighbour *dn_dst_neigh_lookup(const struct dst_entry *dst, |
| @@ -251,7 +252,8 @@ static int dn_dst_gc(struct dst_ops *ops) |
| * advertise to the other end). |
| */ |
| static void dn_dst_update_pmtu(struct dst_entry *dst, struct sock *sk, |
| - struct sk_buff *skb, u32 mtu) |
| + struct sk_buff *skb, u32 mtu, |
| + bool confirm_neigh) |
| { |
| struct dn_route *rt = (struct dn_route *) dst; |
| struct neighbour *n = rt->n; |
| diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c |
| index e4fa9e5833e4..2a16c83a866c 100644 |
| --- a/net/ipv4/inet_connection_sock.c |
| +++ b/net/ipv4/inet_connection_sock.c |
| @@ -1087,7 +1087,7 @@ struct dst_entry *inet_csk_update_pmtu(struct sock *sk, u32 mtu) |
| if (!dst) |
| goto out; |
| } |
| - dst->ops->update_pmtu(dst, sk, NULL, mtu); |
| + dst->ops->update_pmtu(dst, sk, NULL, mtu, true); |
| |
| dst = __sk_dst_check(sk, 0); |
| if (!dst) |
| diff --git a/net/ipv4/route.c b/net/ipv4/route.c |
| index 697744127a66..edd352538d69 100644 |
| --- a/net/ipv4/route.c |
| +++ b/net/ipv4/route.c |
| @@ -138,7 +138,8 @@ static unsigned int ipv4_mtu(const struct dst_entry *dst); |
| static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst); |
| static void ipv4_link_failure(struct sk_buff *skb); |
| static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, |
| - struct sk_buff *skb, u32 mtu); |
| + struct sk_buff *skb, u32 mtu, |
| + bool confirm_neigh); |
| static void ip_do_redirect(struct dst_entry *dst, struct sock *sk, |
| struct sk_buff *skb); |
| static void ipv4_dst_destroy(struct dst_entry *dst); |
| @@ -1042,7 +1043,8 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu) |
| } |
| |
| static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, |
| - struct sk_buff *skb, u32 mtu) |
| + struct sk_buff *skb, u32 mtu, |
| + bool confirm_neigh) |
| { |
| struct rtable *rt = (struct rtable *) dst; |
| struct flowi4 fl4; |
| @@ -2618,7 +2620,8 @@ static unsigned int ipv4_blackhole_mtu(const struct dst_entry *dst) |
| } |
| |
| static void ipv4_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk, |
| - struct sk_buff *skb, u32 mtu) |
| + struct sk_buff *skb, u32 mtu, |
| + bool confirm_neigh) |
| { |
| } |
| |
| diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c |
| index 35b84b52b702..9ebd54752e03 100644 |
| --- a/net/ipv4/xfrm4_policy.c |
| +++ b/net/ipv4/xfrm4_policy.c |
| @@ -100,12 +100,13 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, |
| } |
| |
| static void xfrm4_update_pmtu(struct dst_entry *dst, struct sock *sk, |
| - struct sk_buff *skb, u32 mtu) |
| + struct sk_buff *skb, u32 mtu, |
| + bool confirm_neigh) |
| { |
| struct xfrm_dst *xdst = (struct xfrm_dst *)dst; |
| struct dst_entry *path = xdst->route; |
| |
| - path->ops->update_pmtu(path, sk, skb, mtu); |
| + path->ops->update_pmtu(path, sk, skb, mtu, confirm_neigh); |
| } |
| |
| static void xfrm4_redirect(struct dst_entry *dst, struct sock *sk, |
| diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c |
| index 9f3ef6e02568..eb0ce481bf6e 100644 |
| --- a/net/ipv6/inet6_connection_sock.c |
| +++ b/net/ipv6/inet6_connection_sock.c |
| @@ -146,7 +146,7 @@ struct dst_entry *inet6_csk_update_pmtu(struct sock *sk, u32 mtu) |
| |
| if (IS_ERR(dst)) |
| return NULL; |
| - dst->ops->update_pmtu(dst, sk, NULL, mtu); |
| + dst->ops->update_pmtu(dst, sk, NULL, mtu, true); |
| |
| dst = inet6_csk_route_socket(sk, &fl6); |
| return IS_ERR(dst) ? NULL : dst; |
| diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c |
| index 4efc272c6027..5a4143d9ba27 100644 |
| --- a/net/ipv6/ip6_gre.c |
| +++ b/net/ipv6/ip6_gre.c |
| @@ -1040,7 +1040,7 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb, |
| |
| /* TooBig packet may have updated dst->dev's mtu */ |
| if (!t->parms.collect_md && dst && dst_mtu(dst) > dst->dev->mtu) |
| - dst->ops->update_pmtu(dst, NULL, skb, dst->dev->mtu); |
| + dst->ops->update_pmtu(dst, NULL, skb, dst->dev->mtu, true); |
| |
| err = ip6_tnl_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu, |
| NEXTHDR_GRE); |
| diff --git a/net/ipv6/route.c b/net/ipv6/route.c |
| index 1021c8d3c20b..32ea5042dd50 100644 |
| --- a/net/ipv6/route.c |
| +++ b/net/ipv6/route.c |
| @@ -95,7 +95,8 @@ static int ip6_pkt_prohibit(struct sk_buff *skb); |
| static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb); |
| static void ip6_link_failure(struct sk_buff *skb); |
| static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, |
| - struct sk_buff *skb, u32 mtu); |
| + struct sk_buff *skb, u32 mtu, |
| + bool confirm_neigh); |
| static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, |
| struct sk_buff *skb); |
| static int rt6_score_route(const struct fib6_nh *nh, u32 fib6_flags, int oif, |
| @@ -264,7 +265,8 @@ static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst) |
| } |
| |
| static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk, |
| - struct sk_buff *skb, u32 mtu) |
| + struct sk_buff *skb, u32 mtu, |
| + bool confirm_neigh) |
| { |
| } |
| |
| @@ -2347,7 +2349,8 @@ static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt) |
| } |
| |
| static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk, |
| - const struct ipv6hdr *iph, u32 mtu) |
| + const struct ipv6hdr *iph, u32 mtu, |
| + bool confirm_neigh) |
| { |
| const struct in6_addr *daddr, *saddr; |
| struct rt6_info *rt6 = (struct rt6_info *)dst; |
| @@ -2365,7 +2368,10 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk, |
| daddr = NULL; |
| saddr = NULL; |
| } |
| - dst_confirm_neigh(dst, daddr); |
| + |
| + if (confirm_neigh) |
| + dst_confirm_neigh(dst, daddr); |
| + |
| mtu = max_t(u32, mtu, IPV6_MIN_MTU); |
| if (mtu >= dst_mtu(dst)) |
| return; |
| @@ -2400,9 +2406,11 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk, |
| } |
| |
| static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, |
| - struct sk_buff *skb, u32 mtu) |
| + struct sk_buff *skb, u32 mtu, |
| + bool confirm_neigh) |
| { |
| - __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu); |
| + __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu, |
| + confirm_neigh); |
| } |
| |
| void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, |
| @@ -2421,7 +2429,7 @@ void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, |
| |
| dst = ip6_route_output(net, NULL, &fl6); |
| if (!dst->error) |
| - __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu)); |
| + __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu), true); |
| dst_release(dst); |
| } |
| EXPORT_SYMBOL_GPL(ip6_update_pmtu); |
| diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c |
| index 699e0730ce8e..af7a4b8b1e9c 100644 |
| --- a/net/ipv6/xfrm6_policy.c |
| +++ b/net/ipv6/xfrm6_policy.c |
| @@ -98,12 +98,13 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, |
| } |
| |
| static void xfrm6_update_pmtu(struct dst_entry *dst, struct sock *sk, |
| - struct sk_buff *skb, u32 mtu) |
| + struct sk_buff *skb, u32 mtu, |
| + bool confirm_neigh) |
| { |
| struct xfrm_dst *xdst = (struct xfrm_dst *)dst; |
| struct dst_entry *path = xdst->route; |
| |
| - path->ops->update_pmtu(path, sk, skb, mtu); |
| + path->ops->update_pmtu(path, sk, skb, mtu, confirm_neigh); |
| } |
| |
| static void xfrm6_redirect(struct dst_entry *dst, struct sock *sk, |
| diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c |
| index e101eda05d55..0ee2c15b049b 100644 |
| --- a/net/netfilter/ipvs/ip_vs_xmit.c |
| +++ b/net/netfilter/ipvs/ip_vs_xmit.c |
| @@ -206,7 +206,7 @@ static inline void maybe_update_pmtu(int skb_af, struct sk_buff *skb, int mtu) |
| struct rtable *ort = skb_rtable(skb); |
| |
| if (!skb->dev && sk && sk_fullsock(sk)) |
| - ort->dst.ops->update_pmtu(&ort->dst, sk, NULL, mtu); |
| + ort->dst.ops->update_pmtu(&ort->dst, sk, NULL, mtu, true); |
| } |
| |
| static inline bool ensure_mtu_is_adequate(struct netns_ipvs *ipvs, int skb_af, |
| diff --git a/net/sctp/transport.c b/net/sctp/transport.c |
| index e2f8e369cd08..515cef5e0dce 100644 |
| --- a/net/sctp/transport.c |
| +++ b/net/sctp/transport.c |
| @@ -263,7 +263,7 @@ bool sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu) |
| |
| pf->af->from_sk(&addr, sk); |
| pf->to_sk_daddr(&t->ipaddr, sk); |
| - dst->ops->update_pmtu(dst, sk, NULL, pmtu); |
| + dst->ops->update_pmtu(dst, sk, NULL, pmtu, true); |
| pf->to_sk_daddr(&addr, sk); |
| |
| dst = sctp_transport_dst_check(t); |
| -- |
| 2.7.4 |
| |