On Mon, Feb 12, 2018 at 04:06:00PM -0800, David Ahern wrote:
> Some operators prefer IPv6 path selection to use a standard 5-tuple
> hash rather than just an L3 hash with the flow the label. To that end
> add support to IPv6 for multipath hash policy similar to bf4e0a3db97eb
> ("net: ipv4: add support for ECMP hash policy choice"). The default
> is still L3 which covers source and destination addresses along with
> flow label and IPv6 protocol.
> 
> Signed-off-by: David Ahern <dsah...@gmail.com>

[...]

> @@ -1819,20 +1820,53 @@ static void ip6_multipath_l3_keys(const struct 
> sk_buff *skb,
>  }
>  
>  /* 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)
> +u32 rt6_multipath_hash(const struct net *net, const struct flowi6 *fl6,
> +                    const struct sk_buff *skb)
>  {
>       struct flow_keys hash_keys;
>       u32 mhash;
>  
> -     memset(&hash_keys, 0, sizeof(hash_keys));
> -     hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
> -     if (skb) {
> -             ip6_multipath_l3_keys(skb, &hash_keys);
> -     } else {
> -             hash_keys.addrs.v6addrs.src = fl6->saddr;
> -             hash_keys.addrs.v6addrs.dst = fl6->daddr;
> -             hash_keys.tags.flow_label = (__force u32)fl6->flowlabel;
> -             hash_keys.basic.ip_proto = fl6->flowi6_proto;
> +     switch (net->ipv6.sysctl.multipath_hash_policy) {
> +     case 0:
> +             memset(&hash_keys, 0, sizeof(hash_keys));
> +             hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
> +             if (skb) {
> +                     ip6_multipath_l3_keys(skb, &hash_keys);
> +             } else {
> +                     hash_keys.addrs.v6addrs.src = fl6->saddr;
> +                     hash_keys.addrs.v6addrs.dst = fl6->daddr;
> +                     hash_keys.tags.flow_label = (__force u32)fl6->flowlabel;
> +                     hash_keys.basic.ip_proto = fl6->flowi6_proto;
> +             }
> +             break;
> +     case 1:
> +             if (skb) {
> +                     unsigned int flag = FLOW_DISSECTOR_F_STOP_AT_ENCAP;
> +                     struct flow_keys keys;
> +
> +                     /* short-circuit if we already have L4 hash present */
> +                     if (skb->l4_hash)
> +                             return skb_get_hash_raw(skb) >> 1;
> +
> +                     memset(&hash_keys, 0, sizeof(hash_keys));
> +
> +                     skb_flow_dissect_flow_keys(skb, &keys, flag);
> +
> +                     hash_keys.addrs.v6addrs.src = keys.addrs.v6addrs.src;
> +                     hash_keys.addrs.v6addrs.dst = keys.addrs.v6addrs.dst;

Shouldn't you add:

hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;

?

Otherwise flow_hash_from_keys() will not consistentify the ports and the
addresses and it will also not use the addresses for the hash
computation.

It's missing from fib_multipath_hash() as well, so I might be missing
something.

> +                     hash_keys.ports.src = keys.ports.src;
> +                     hash_keys.ports.dst = keys.ports.dst;
> +                     hash_keys.tags.flow_label = keys.tags.flow_label;

Why are you using the flow label?

> +                     hash_keys.basic.ip_proto = keys.basic.ip_proto;
> +             } else {
> +                     memset(&hash_keys, 0, sizeof(hash_keys));
> +                     hash_keys.control.addr_type = 
> FLOW_DISSECTOR_KEY_IPV6_ADDRS;
> +                     hash_keys.addrs.v6addrs.src = fl6->saddr;
> +                     hash_keys.addrs.v6addrs.dst = fl6->daddr;
> +                     hash_keys.ports.src = fl6->fl6_sport;
> +                     hash_keys.ports.dst = fl6->fl6_dport;
> +                     hash_keys.basic.ip_proto = fl6->flowi6_proto;
> +             }
>       }
>       mhash = flow_hash_from_keys(&hash_keys);
>  
> @@ -1858,7 +1892,7 @@ void ip6_route_input(struct sk_buff *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);
> +             fl6.mp_hash = rt6_multipath_hash(net, &fl6, skb);
>       skb_dst_drop(skb);
>       skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags));
>  }

Reply via email to