flow_hash_symmetric_l3(const struct flow *flow, uint32_t basis)
{
    struct {
        union {
            ovs_be32 ipv4_addr;
            struct in6_addr ipv6_addr;
        };
        ovs_be16 eth_type;
    } fields;

    int i;

    memset(&fields, 0, sizeof fields);
    fields.eth_type = flow->dl_type;

    if (fields.eth_type == htons(ETH_TYPE_IP)) {
        fields.ipv4_addr = flow->nw_src ^ flow->nw_dst;
    } else if (fields.eth_type == htons(ETH_TYPE_IPV6)) {
        const uint8_t *a = &flow->ipv6_src.s6_addr[0];
        const uint8_t *b = &flow->ipv6_dst.s6_addr[0];
        uint8_t *ipv6_addr = &fields.ipv6_addr.s6_addr[0];

        for (i = 0; i < 16; i++) {
            ipv6_addr[i] = a[i] ^ b[i];
        }
    }
    return jhash_bytes(&fields, sizeof fields, basis);
}
flow_hash_symmetric_l3(const struct flow *flow, uint32_t basis)
{
    struct {
        union {
            ovs_be32 ipv4_addr;
            struct in6_addr ipv6_addr;
        };
        ovs_be16 eth_type;
    } fields;

    int i;

    memset(&fields, 0, sizeof fields);
    fields.eth_type = flow->dl_type;

    if (fields.eth_type == htons(ETH_TYPE_IP)) {
        fields.ipv4_addr = flow->nw_src ^ flow->nw_dst;
    } else if (fields.eth_type == htons(ETH_TYPE_IPV6)) {
        const uint8_t *a = &flow->ipv6_src.s6_addr[0];
        const uint8_t *b = &flow->ipv6_dst.s6_addr[0];
        uint8_t *ipv6_addr = &fields.ipv6_addr.s6_addr[0];

        for (i = 0; i < 16; i++) {
            ipv6_addr[i] = a[i] ^ b[i];
        }
    }
    return jhash_bytes(&fields, sizeof fields, basis);
}