__be32            gaddr;        /* multicast group */
        __be32            saddr;        /* source address */
        unsigned int      link;         /* link to multicast over */
+       __u16             port_min;     /* source port range */
+       __u16             port_max;
        __u8              tos;          /* TOS override */
        __u8              ttl;
        bool              learn;
        skb->destructor = vxlan_sock_free;
 }
 
+/* Compute source port for outgoing packet
+ *   first choice to use L4 flow hash since it will spread
+ *     better and maybe available from hardware
+ *   secondary choice is to use jhash on the Ethernet header
+ */
+static u16 vxlan_src_port(const struct vxlan_dev *vxlan, struct sk_buff *skb)
+{
+       unsigned int range = (vxlan->port_max - vxlan->port_min) + 1;
+       u32 hash;
+
+       hash = skb_get_rxhash(skb);
+       if (!hash)
+               hash = jhash(skb->data, 2 * ETH_ALEN,
+                            (__force u32) skb->protocol);
+
+       return (((u64) hash * range) >> 32) + vxlan->port_min;
+}
+
 /* Transmit local packets over Vxlan
  *
  * Outer IP header inherits ECN and DF from inner header.
  * Outer UDP destination is the VXLAN assigned port.
- *           source port is based on hash of flow if available
- *                       otherwise use a random value
+ *           source port is based on hash of flow
  */
 static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct udphdr *uh;
        struct flowi4 fl4;
        unsigned int pkt_len = skb->len;
-       u32 hash;
        __be32 dst;
+       __u16 src_port;
        __be16 df = 0;
        __u8 tos, ttl;
        int err;
        if (tos == 1)
                tos = vxlan_get_dsfield(old_iph, skb);
 
-       hash = skb_get_rxhash(skb);
+       src_port = vxlan_src_port(vxlan, skb);
 
        memset(&fl4, 0, sizeof(fl4));
        fl4.flowi4_oif = vxlan->link;
        uh = udp_hdr(skb);
 
        uh->dest = htons(vxlan_port);
-       uh->source = hash ? :random32();
+       uh->source = htons(src_port);
 
        uh->len = htons(skb->len);
        uh->check = 0;
 {
        struct vxlan_dev *vxlan = netdev_priv(dev);
        unsigned h;
+       int low, high;
 
        eth_hw_addr_random(dev);
        ether_setup(dev);
        vxlan->age_timer.function = vxlan_cleanup;
        vxlan->age_timer.data = (unsigned long) vxlan;
 
+       inet_get_local_port_range(&low, &high);
+       vxlan->port_min = low;
+       vxlan->port_max = high;
+
        vxlan->dev = dev;
 
        for (h = 0; h < FDB_HASH_SIZE; ++h)
        [IFLA_VXLAN_LEARNING]   = { .type = NLA_U8 },
        [IFLA_VXLAN_AGEING]     = { .type = NLA_U32 },
        [IFLA_VXLAN_LIMIT]      = { .type = NLA_U32 },
+       [IFLA_VXLAN_PORT_RANGE] = { .len  = sizeof(struct ifla_vxlan_port_range) },
 };
 
 static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[])
                        return -EADDRNOTAVAIL;
                }
        }
+
+       if (data[IFLA_VXLAN_PORT_RANGE]) {
+               const struct ifla_vxlan_port_range *p
+                       = nla_data(data[IFLA_VXLAN_PORT_RANGE]);
+
+               if (ntohs(p->high) < ntohs(p->low)) {
+                       pr_debug("port range %u .. %u not valid\n",
+                                ntohs(p->low), ntohs(p->high));
+                       return -EINVAL;
+               }
+       }
+
        return 0;
 }
 
        if (data[IFLA_VXLAN_LIMIT])
                vxlan->addrmax = nla_get_u32(data[IFLA_VXLAN_LIMIT]);
 
+       if (data[IFLA_VXLAN_PORT_RANGE]) {
+               const struct ifla_vxlan_port_range *p
+                       = nla_data(data[IFLA_VXLAN_PORT_RANGE]);
+               vxlan->port_min = ntohs(p->low);
+               vxlan->port_max = ntohs(p->high);
+       }
+
        err = register_netdevice(dev);
        if (!err)
                hlist_add_head_rcu(&vxlan->hlist, vni_head(net, vxlan->vni));
                nla_total_size(sizeof(__u8)) +  /* IFLA_VXLAN_LEARNING */
                nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_AGEING */
                nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_LIMIT */
+               nla_total_size(sizeof(struct ifla_vxlan_port_range)) +
                0;
 }
 
 static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
 {
        const struct vxlan_dev *vxlan = netdev_priv(dev);
+       struct ifla_vxlan_port_range ports = {
+               .low =  htons(vxlan->port_min),
+               .high = htons(vxlan->port_max),
+       };
 
        if (nla_put_u32(skb, IFLA_VXLAN_ID, vxlan->vni))
                goto nla_put_failure;
            nla_put_u32(skb, IFLA_VXLAN_LIMIT, vxlan->addrmax))
                goto nla_put_failure;
 
+       if (nla_put(skb, IFLA_VXLAN_PORT_RANGE, sizeof(ports), &ports))
+               goto nla_put_failure;
+
        return 0;
 
 nla_put_failure: