Message ID | CAC15z3g-LDOdpcsZEs6XFFOOb92bXAbdOORdnd+MTvF62TgSiA@mail.gmail.com |
---|---|
State | RFC, archived |
Delegated to: | David Miller |
Headers | show |
On Wed, Mar 23, 2016 at 04:57:22PM -0700, Wei Wang wrote: > What about something like this: > > diff --git a/net/ipv6/route.c b/net/ipv6/route.c > index ed44663..21b4102 100644 > --- a/net/ipv6/route.c > +++ b/net/ipv6/route.c > @@ -1394,6 +1394,19 @@ static void ip6_rt_update_pmtu(struct dst_entry > *dst, struct sock *sk, > __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu); > } > > +static void ip6_fill_in_flow(struct flowi6 *fl6, struct net *net, > + struct sk_buff *skb, int oif, u32 mark) > +{ > + const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data; > + > + memset(fl6, 0, sizeof(fl6)); > + fl6->flowi6_oif = oif; > + fl6->flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark); > + fl6->daddr = iph->daddr; > + fl6->saddr = iph->saddr; > + fl6->flowlabel = ip6_flowinfo(iph); > +} > + > void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, > int oif, u32 mark) > { > @@ -1401,13 +1414,7 @@ void ip6_update_pmtu(struct sk_buff *skb, > struct net *net, __be32 mtu, > struct dst_entry *dst; > struct flowi6 fl6; > > - memset(&fl6, 0, sizeof(fl6)); > - fl6.flowi6_oif = oif; > - fl6.flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark); > - fl6.daddr = iph->daddr; > - fl6.saddr = iph->saddr; > - fl6.flowlabel = ip6_flowinfo(iph); > - > + ip6_fill_in_flow(&fl6, net, skb, oif, mark); > dst = ip6_route_output(net, NULL, &fl6); > if (!dst->error) > __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu)); > @@ -1417,8 +1424,22 @@ EXPORT_SYMBOL_GPL(ip6_update_pmtu); > > void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu) > { > - ip6_update_pmtu(skb, sock_net(sk), mtu, > + struct ipv6_pinfo *np = inet6_sk(sk); > + struct dst_entry *dst_new; > + struct flowi6 fl6; > + struct net *net = sock_net(sk); > + > + ip6_update_pmtu(skb, net, mtu, > + sk->sk_bound_dev_if, sk->sk_mark); > + > + if (sk->sk_state == TCP_ESTABLISHED && > + !sk_dst_check(sk, np->dst_cookie)) { sk_dst_check could hold a refcnt to the current sk->sk_dst_cache. It has to be released. > + ip6_fill_in_flow(&fl6, net, skb, > sk->sk_bound_dev_if, sk->sk_mark); > + dst_new = ip6_route_output(net, NULL, &fl6); > + if (!IS_ERR(dst_new)) > + ip6_dst_store(sk, dst_new, NULL, NULL); Has sk been locked before ip6_dst_store? Some fast path may do __sk_dst_get() which does not refcnt the sk->sk_dst_cache. However, after a quick look, it seems udpv6_sendmsg() is calling ip6_dst_store() after release_sock also. I could be missing something.
On Thu, Mar 24, 2016 at 11:32:28AM -0700, Martin KaFai Lau wrote:
> Some fast path may do __sk_dst_get() which does not refcnt the sk->sk_dst_cache.
Ignore this comment. This should have been protected by rcu grace period.
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index ed44663..21b4102 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1394,6 +1394,19 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu); } +static void ip6_fill_in_flow(struct flowi6 *fl6, struct net *net, + struct sk_buff *skb, int oif, u32 mark) +{ + const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data; + + memset(fl6, 0, sizeof(fl6)); + fl6->flowi6_oif = oif; + fl6->flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark); + fl6->daddr = iph->daddr; + fl6->saddr = iph->saddr; + fl6->flowlabel = ip6_flowinfo(iph); +} + void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, int oif, u32 mark)