Commit 0dec879f authored by Julian Anastasov's avatar Julian Anastasov Committed by David S. Miller

net: use dst_confirm_neigh for UDP, RAW, ICMP, L2TP

When same struct dst_entry can be used for many different
neighbours we can not use it for pending confirmations.

The datagram protocols can use MSG_CONFIRM to confirm the
neighbour. When used with MSG_PROBE we do not reach the
code where neighbour is confirmed, so we have to do the
same slow lookup by using the dst_confirm_neigh() helper.
When MSG_PROBE is not used, ip_append_data/ip6_append_data
will set the skb flag dst_pending_confirm.
Reported-by: default avatarYueHaibing <yuehaibing@huawei.com>
Fixes: 5110effe ("net: Do delayed neigh confirmation.")
Fixes: f2bb4bed ("ipv4: Cache output routes in fib_info nexthops.")
Signed-off-by: default avatarJulian Anastasov <ja@ssi.bg>
Acked-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 63fca65d
...@@ -889,6 +889,9 @@ static inline int ip_ufo_append_data(struct sock *sk, ...@@ -889,6 +889,9 @@ static inline int ip_ufo_append_data(struct sock *sk,
skb->csum = 0; skb->csum = 0;
if (flags & MSG_CONFIRM)
skb_set_dst_pending_confirm(skb, 1);
__skb_queue_tail(queue, skb); __skb_queue_tail(queue, skb);
} else if (skb_is_gso(skb)) { } else if (skb_is_gso(skb)) {
goto append; goto append;
...@@ -1089,6 +1092,9 @@ static int __ip_append_data(struct sock *sk, ...@@ -1089,6 +1092,9 @@ static int __ip_append_data(struct sock *sk,
exthdrlen = 0; exthdrlen = 0;
csummode = CHECKSUM_NONE; csummode = CHECKSUM_NONE;
if ((flags & MSG_CONFIRM) && !skb_prev)
skb_set_dst_pending_confirm(skb, 1);
/* /*
* Put the packet on the pending queue. * Put the packet on the pending queue.
*/ */
......
...@@ -848,7 +848,8 @@ static int ping_v4_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -848,7 +848,8 @@ static int ping_v4_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
return err; return err;
do_confirm: do_confirm:
dst_confirm(&rt->dst); if (msg->msg_flags & MSG_PROBE)
dst_confirm_neigh(&rt->dst, &fl4.daddr);
if (!(msg->msg_flags & MSG_PROBE) || len) if (!(msg->msg_flags & MSG_PROBE) || len)
goto back_from_confirm; goto back_from_confirm;
err = 0; err = 0;
......
...@@ -383,6 +383,9 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, ...@@ -383,6 +383,9 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4,
sock_tx_timestamp(sk, sockc->tsflags, &skb_shinfo(skb)->tx_flags); sock_tx_timestamp(sk, sockc->tsflags, &skb_shinfo(skb)->tx_flags);
if (flags & MSG_CONFIRM)
skb_set_dst_pending_confirm(skb, 1);
skb->transport_header = skb->network_header; skb->transport_header = skb->network_header;
err = -EFAULT; err = -EFAULT;
if (memcpy_from_msg(iph, msg, length)) if (memcpy_from_msg(iph, msg, length))
...@@ -666,7 +669,8 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -666,7 +669,8 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
return len; return len;
do_confirm: do_confirm:
dst_confirm(&rt->dst); if (msg->msg_flags & MSG_PROBE)
dst_confirm_neigh(&rt->dst, &fl4.daddr);
if (!(msg->msg_flags & MSG_PROBE) || len) if (!(msg->msg_flags & MSG_PROBE) || len)
goto back_from_confirm; goto back_from_confirm;
err = 0; err = 0;
......
...@@ -1101,7 +1101,8 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -1101,7 +1101,8 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
return err; return err;
do_confirm: do_confirm:
dst_confirm(&rt->dst); if (msg->msg_flags & MSG_PROBE)
dst_confirm_neigh(&rt->dst, &fl4->daddr);
if (!(msg->msg_flags&MSG_PROBE) || len) if (!(msg->msg_flags&MSG_PROBE) || len)
goto back_from_confirm; goto back_from_confirm;
err = 0; err = 0;
......
...@@ -1145,6 +1145,9 @@ static inline int ip6_ufo_append_data(struct sock *sk, ...@@ -1145,6 +1145,9 @@ static inline int ip6_ufo_append_data(struct sock *sk,
skb->protocol = htons(ETH_P_IPV6); skb->protocol = htons(ETH_P_IPV6);
skb->csum = 0; skb->csum = 0;
if (flags & MSG_CONFIRM)
skb_set_dst_pending_confirm(skb, 1);
__skb_queue_tail(queue, skb); __skb_queue_tail(queue, skb);
} else if (skb_is_gso(skb)) { } else if (skb_is_gso(skb)) {
goto append; goto append;
...@@ -1517,6 +1520,9 @@ static int __ip6_append_data(struct sock *sk, ...@@ -1517,6 +1520,9 @@ static int __ip6_append_data(struct sock *sk,
exthdrlen = 0; exthdrlen = 0;
dst_exthdrlen = 0; dst_exthdrlen = 0;
if ((flags & MSG_CONFIRM) && !skb_prev)
skb_set_dst_pending_confirm(skb, 1);
/* /*
* Put the packet on the pending queue * Put the packet on the pending queue
*/ */
......
...@@ -654,6 +654,9 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, ...@@ -654,6 +654,9 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length,
skb->ip_summed = CHECKSUM_NONE; skb->ip_summed = CHECKSUM_NONE;
if (flags & MSG_CONFIRM)
skb_set_dst_pending_confirm(skb, 1);
skb->transport_header = skb->network_header; skb->transport_header = skb->network_header;
err = memcpy_from_msg(iph, msg, length); err = memcpy_from_msg(iph, msg, length);
if (err) if (err)
...@@ -934,7 +937,8 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -934,7 +937,8 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
txopt_put(opt_to_free); txopt_put(opt_to_free);
return err < 0 ? err : len; return err < 0 ? err : len;
do_confirm: do_confirm:
dst_confirm(dst); if (msg->msg_flags & MSG_PROBE)
dst_confirm_neigh(dst, &fl6.daddr);
if (!(msg->msg_flags & MSG_PROBE) || len) if (!(msg->msg_flags & MSG_PROBE) || len)
goto back_from_confirm; goto back_from_confirm;
err = 0; err = 0;
......
...@@ -1381,6 +1381,7 @@ static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt) ...@@ -1381,6 +1381,7 @@ 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, 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)
{ {
const struct in6_addr *daddr, *saddr;
struct rt6_info *rt6 = (struct rt6_info *)dst; struct rt6_info *rt6 = (struct rt6_info *)dst;
if (rt6->rt6i_flags & RTF_LOCAL) if (rt6->rt6i_flags & RTF_LOCAL)
...@@ -1389,26 +1390,26 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk, ...@@ -1389,26 +1390,26 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
if (dst_metric_locked(dst, RTAX_MTU)) if (dst_metric_locked(dst, RTAX_MTU))
return; return;
dst_confirm(dst); if (iph) {
daddr = &iph->daddr;
saddr = &iph->saddr;
} else if (sk) {
daddr = &sk->sk_v6_daddr;
saddr = &inet6_sk(sk)->saddr;
} else {
daddr = NULL;
saddr = NULL;
}
dst_confirm_neigh(dst, daddr);
mtu = max_t(u32, mtu, IPV6_MIN_MTU); mtu = max_t(u32, mtu, IPV6_MIN_MTU);
if (mtu >= dst_mtu(dst)) if (mtu >= dst_mtu(dst))
return; return;
if (!rt6_cache_allowed_for_pmtu(rt6)) { if (!rt6_cache_allowed_for_pmtu(rt6)) {
rt6_do_update_pmtu(rt6, mtu); rt6_do_update_pmtu(rt6, mtu);
} else { } else if (daddr) {
const struct in6_addr *daddr, *saddr;
struct rt6_info *nrt6; struct rt6_info *nrt6;
if (iph) {
daddr = &iph->daddr;
saddr = &iph->saddr;
} else if (sk) {
daddr = &sk->sk_v6_daddr;
saddr = &inet6_sk(sk)->saddr;
} else {
return;
}
nrt6 = ip6_rt_cache_alloc(rt6, daddr, saddr); nrt6 = ip6_rt_cache_alloc(rt6, daddr, saddr);
if (nrt6) { if (nrt6) {
rt6_do_update_pmtu(nrt6, mtu); rt6_do_update_pmtu(nrt6, mtu);
...@@ -2332,7 +2333,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu ...@@ -2332,7 +2333,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
* Look, redirects are sent only in response to data packets, * Look, redirects are sent only in response to data packets,
* so that this nexthop apparently is reachable. --ANK * so that this nexthop apparently is reachable. --ANK
*/ */
dst_confirm(&rt->dst); dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr);
neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1); neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
if (!neigh) if (!neigh)
......
...@@ -1308,7 +1308,8 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -1308,7 +1308,8 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
return err; return err;
do_confirm: do_confirm:
dst_confirm(dst); if (msg->msg_flags & MSG_PROBE)
dst_confirm_neigh(dst, &fl6.daddr);
if (!(msg->msg_flags&MSG_PROBE) || len) if (!(msg->msg_flags&MSG_PROBE) || len)
goto back_from_confirm; goto back_from_confirm;
err = 0; err = 0;
......
...@@ -658,7 +658,8 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -658,7 +658,8 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
return err < 0 ? err : len; return err < 0 ? err : len;
do_confirm: do_confirm:
dst_confirm(dst); if (msg->msg_flags & MSG_PROBE)
dst_confirm_neigh(dst, &fl6.daddr);
if (!(msg->msg_flags & MSG_PROBE) || len) if (!(msg->msg_flags & MSG_PROBE) || len)
goto back_from_confirm; goto back_from_confirm;
err = 0; err = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment