}
 EXPORT_SYMBOL_GPL(ip6_route_input_lookup);
 
+static void ip6_multipath_l3_keys(const struct sk_buff *skb,
+                                 struct flow_keys *keys)
+{
+       const struct ipv6hdr *outer_iph = ipv6_hdr(skb);
+       const struct ipv6hdr *key_iph = outer_iph;
+       const struct ipv6hdr *inner_iph;
+       const struct icmp6hdr *icmph;
+       struct ipv6hdr _inner_iph;
+
+       if (likely(outer_iph->nexthdr != IPPROTO_ICMPV6))
+               goto out;
+
+       icmph = icmp6_hdr(skb);
+       if (icmph->icmp6_type != ICMPV6_DEST_UNREACH &&
+           icmph->icmp6_type != ICMPV6_PKT_TOOBIG &&
+           icmph->icmp6_type != ICMPV6_TIME_EXCEED &&
+           icmph->icmp6_type != ICMPV6_PARAMPROB)
+               goto out;
+
+       inner_iph = skb_header_pointer(skb,
+                                      skb_transport_offset(skb) + sizeof(*icmph),
+                                      sizeof(_inner_iph), &_inner_iph);
+       if (!inner_iph)
+               goto out;
+
+       key_iph = inner_iph;
+out:
+       memset(keys, 0, sizeof(*keys));
+       keys->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
+       keys->addrs.v6addrs.src = key_iph->saddr;
+       keys->addrs.v6addrs.dst = key_iph->daddr;
+       keys->tags.flow_label = ip6_flowinfo(key_iph);
+       keys->basic.ip_proto = key_iph->nexthdr;
+}
+
+/* if skb is set it will be used and fl6 can be NULL */
+u32 rt6_multipath_hash(const struct flowi6 *fl6, const struct sk_buff *skb)
+{
+       struct flow_keys hash_keys;
+
+       if (skb) {
+               ip6_multipath_l3_keys(skb, &hash_keys);
+               return flow_hash_from_keys(&hash_keys);
+       }
+
+       return get_hash_from_flowi6(fl6);
+}
+
 void ip6_route_input(struct sk_buff *skb)
 {
        const struct ipv6hdr *iph = ipv6_hdr(skb);
        tun_info = skb_tunnel_info(skb);
        if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX))
                fl6.flowi6_tun_key.tun_id = tun_info->key.tun_id;
+       if (unlikely(fl6.flowi6_proto == IPPROTO_ICMPV6))
+               fl6.mp_hash = rt6_multipath_hash(&fl6, skb);
        skb_dst_drop(skb);
        skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
 }