Index: linux-4.19.118/drivers/net/vxlan.c
===================================================================
--- linux-4.19.118.orig/drivers/net/vxlan.c
+++ linux-4.19.118/drivers/net/vxlan.c
@@ -69,6 +69,10 @@ static bool vxlan_clear_df __read_mostly
 module_param_named(clear_df, vxlan_clear_df, bool, 0664);
 MODULE_PARM_DESC(clear_df, "Clear DF bit for all packets, otherwise only packets larger then physical device MTU will be cleared");
 
+static bool vxlan_vlan_aware __read_mostly = false;
+module_param_named(vlan_aware, vxlan_vlan_aware, bool, 0644);
+MODULE_PARM_DESC(vlan_aware, "Enable vlan fdb processing for classic vxlan, within single VNI");
+
 static unsigned int vxlan_net_id;
 static struct rtnl_link_ops vxlan_link_ops;
 
@@ -95,6 +99,7 @@ struct vxlan_fdb {
 	u8		  eth_addr[ETH_ALEN];
 	u16		  state;	/* see ndm_state */
 	__be32		  vni;
+	__be16		  vlan;
 	u8		  flags;	/* see ndm_flags */
 };
 
@@ -337,6 +342,9 @@ static int vxlan_fdb_info(struct sk_buff
 	    nla_put_u32(skb, NDA_SRC_VNI,
 			be32_to_cpu(fdb->vni)))
 		goto nla_put_failure;
+	if ((vxlan->cfg.flags & VXLAN_F_VLAN_AWARE) && fdb->vlan &&
+	    nla_put_u16(skb, NDA_VLAN, fdb->vlan))
+		goto nla_put_failure;
 	if (rdst->remote_ifindex &&
 	    nla_put_u32(skb, NDA_IFINDEX, rdst->remote_ifindex))
 		goto nla_put_failure;
@@ -364,6 +372,7 @@ static inline size_t vxlan_nlmsg_size(vo
 		+ nla_total_size(sizeof(struct in6_addr)) /* NDA_DST */
 		+ nla_total_size(sizeof(__be16)) /* NDA_PORT */
 		+ nla_total_size(sizeof(__be32)) /* NDA_VNI */
+		+ nla_total_size(sizeof(__be16)) /* NDA_VLAN */
 		+ nla_total_size(sizeof(__u32)) /* NDA_IFINDEX */
 		+ nla_total_size(sizeof(__s32)) /* NDA_LINK_NETNSID */
 		+ nla_total_size(sizeof(struct nda_cacheinfo));
@@ -445,7 +454,7 @@ static u32 eth_vni_hash(const unsigned c
 
 /* Hash chain to use given mac address */
 static inline struct hlist_head *vxlan_fdb_head(struct vxlan_dev *vxlan,
-						const u8 *mac, __be32 vni)
+						const u8 *mac, __be32 vni, __be16 vlan)
 {
 	if (vxlan->cfg.flags & VXLAN_F_COLLECT_METADATA)
 		return &vxlan->fdb_head[eth_vni_hash(mac, vni)];
@@ -455,15 +464,15 @@ static inline struct hlist_head *vxlan_f
 
 /* Look up Ethernet address in forwarding table */
 static struct vxlan_fdb *__vxlan_find_mac(struct vxlan_dev *vxlan,
-					  const u8 *mac, __be32 vni)
+					  const u8 *mac, __be32 vni, __be16 vlan)
 {
-	struct hlist_head *head = vxlan_fdb_head(vxlan, mac, vni);
+	struct hlist_head *head = vxlan_fdb_head(vxlan, mac, vni, vlan);
 	struct vxlan_fdb *f;
 
 	hlist_for_each_entry_rcu(f, head, hlist) {
 		if (ether_addr_equal(mac, f->eth_addr)) {
 			if (vxlan->cfg.flags & VXLAN_F_COLLECT_METADATA) {
-				if (vni == f->vni)
+				if (vni == f->vni && vlan == f->vlan)
 					return f;
 			} else {
 				return f;
@@ -475,11 +484,13 @@ static struct vxlan_fdb *__vxlan_find_ma
 }
 
 static struct vxlan_fdb *vxlan_find_mac(struct vxlan_dev *vxlan,
-					const u8 *mac, __be32 vni)
+					const u8 *mac, __be32 vni, __be16 vlan)
 {
 	struct vxlan_fdb *f;
 
-	f = __vxlan_find_mac(vxlan, mac, vni);
+	f = __vxlan_find_mac(vxlan, mac, vni, vlan);
+	if (!f && vlan)
+		f = __vxlan_find_mac(vxlan, mac, vni, 0);
 	if (f)
 		f->used = jiffies;
 
@@ -489,7 +500,7 @@ static struct vxlan_fdb *vxlan_find_mac(
 /* caller should hold vxlan->hash_lock */
 static struct vxlan_rdst *vxlan_fdb_find_rdst(struct vxlan_fdb *f,
 					      union vxlan_addr *ip, __be16 port,
-					      __be32 vni, __u32 ifindex)
+					      __be32 vni, __be16 vlan,  __u32 ifindex)
 {
 	struct vxlan_rdst *rd;
 
@@ -497,6 +508,7 @@ static struct vxlan_rdst *vxlan_fdb_find
 		if (vxlan_addr_equal(&rd->remote_ip, ip) &&
 		    rd->remote_port == port &&
 		    rd->remote_vni == vni &&
+		    rd->remote_vlan == vlan &&
 		    rd->remote_ifindex == ifindex)
 			return rd;
 	}
@@ -506,12 +518,12 @@ static struct vxlan_rdst *vxlan_fdb_find
 
 /* Replace destination of unicast mac */
 static int vxlan_fdb_replace(struct vxlan_fdb *f,
-			     union vxlan_addr *ip, __be16 port, __be32 vni,
+			     union vxlan_addr *ip, __be16 port, __be32 vni, __be16 vlan,
 			     __u32 ifindex)
 {
 	struct vxlan_rdst *rd;
 
-	rd = vxlan_fdb_find_rdst(f, ip, port, vni, ifindex);
+	rd = vxlan_fdb_find_rdst(f, ip, port, vni, vlan, ifindex);
 	if (rd)
 		return 0;
 
@@ -523,18 +535,19 @@ static int vxlan_fdb_replace(struct vxla
 	rd->remote_ip = *ip;
 	rd->remote_port = port;
 	rd->remote_vni = vni;
+	rd->remote_vlan = vlan;
 	rd->remote_ifindex = ifindex;
 	return 1;
 }
 
 /* Add/update destinations for multicast */
 static int vxlan_fdb_append(struct vxlan_fdb *f,
-			    union vxlan_addr *ip, __be16 port, __be32 vni,
+			    union vxlan_addr *ip, __be16 port, __be32 vni, __be16 vlan,
 			    __u32 ifindex, struct vxlan_rdst **rdp)
 {
 	struct vxlan_rdst *rd;
 
-	rd = vxlan_fdb_find_rdst(f, ip, port, vni, ifindex);
+	rd = vxlan_fdb_find_rdst(f, ip, port, vni, vlan, ifindex);
 	if (rd)
 		return 0;
 
@@ -550,6 +563,7 @@ static int vxlan_fdb_append(struct vxlan
 	rd->remote_ip = *ip;
 	rd->remote_port = port;
 	rd->remote_vni = vni;
+	rd->remote_vlan = vlan;
 	rd->remote_ifindex = ifindex;
 
 	list_add_tail_rcu(&rd->list, &f->remotes);
@@ -655,7 +669,7 @@ static int vxlan_gro_complete(struct soc
 
 static struct vxlan_fdb *vxlan_fdb_alloc(struct vxlan_dev *vxlan,
 					 const u8 *mac, __u16 state,
-					 __be32 src_vni, __u8 ndm_flags)
+					 __be32 src_vni, __be16 src_vlan,  __u8 ndm_flags)
 {
 	struct vxlan_fdb *f;
 
@@ -666,6 +680,7 @@ static struct vxlan_fdb *vxlan_fdb_alloc
 	f->flags = ndm_flags;
 	f->updated = f->used = jiffies;
 	f->vni = src_vni;
+	f->vlan = src_vlan;
 	INIT_LIST_HEAD(&f->remotes);
 	memcpy(f->eth_addr, mac, ETH_ALEN);
 
@@ -674,8 +689,8 @@ static struct vxlan_fdb *vxlan_fdb_alloc
 
 static int vxlan_fdb_create(struct vxlan_dev *vxlan,
 			    const u8 *mac, union vxlan_addr *ip,
-			    __u16 state, __be16 port, __be32 src_vni,
-			    __be32 vni, __u32 ifindex, __u8 ndm_flags,
+			    __u16 state, __be16 port, __be32 src_vni, __be16 vlan,
+			    __be32 vni,  __u32 ifindex, __u8 ndm_flags,
 			    struct vxlan_fdb **fdb)
 {
 	struct vxlan_rdst *rd = NULL;
@@ -687,11 +702,11 @@ static int vxlan_fdb_create(struct vxlan
 		return -ENOSPC;
 
 	netdev_dbg(vxlan->dev, "add %pM -> %pIS\n", mac, ip);
-	f = vxlan_fdb_alloc(vxlan, mac, state, src_vni, ndm_flags);
+	f = vxlan_fdb_alloc(vxlan, mac, state, src_vni, vlan, ndm_flags);
 	if (!f)
 		return -ENOMEM;
 
-	rc = vxlan_fdb_append(f, ip, port, vni, ifindex, &rd);
+	rc = vxlan_fdb_append(f, ip, port, vni, vlan, ifindex, &rd);
 	if (rc < 0) {
 		kfree(f);
 		return rc;
@@ -699,7 +714,7 @@ static int vxlan_fdb_create(struct vxlan
 
 	++vxlan->addrcnt;
 	hlist_add_head_rcu(&f->hlist,
-			   vxlan_fdb_head(vxlan, mac, src_vni));
+			   vxlan_fdb_head(vxlan, mac, src_vni, vlan));
 
 	*fdb = f;
 
@@ -710,7 +725,7 @@ static int vxlan_fdb_create(struct vxlan
 static int vxlan_fdb_update(struct vxlan_dev *vxlan,
 			    const u8 *mac, union vxlan_addr *ip,
 			    __u16 state, __u16 flags,
-			    __be16 port, __be32 src_vni, __be32 vni,
+			    __be16 port, __be32 src_vni, __be16 vlan,  __be32 vni,
 			    __u32 ifindex, __u8 ndm_flags)
 {
 	struct vxlan_rdst *rd = NULL;
@@ -718,7 +733,7 @@ static int vxlan_fdb_update(struct vxlan
 	int notify = 0;
 	int rc;
 
-	f = __vxlan_find_mac(vxlan, mac, src_vni);
+	f = __vxlan_find_mac(vxlan, mac, src_vni, vlan);
 	if (f) {
 		if (flags & NLM_F_EXCL) {
 			netdev_dbg(vxlan->dev,
@@ -739,7 +754,7 @@ static int vxlan_fdb_update(struct vxlan
 			/* Only change unicasts */
 			if (!(is_multicast_ether_addr(f->eth_addr) ||
 			     is_zero_ether_addr(f->eth_addr))) {
-				notify |= vxlan_fdb_replace(f, ip, port, vni,
+				notify |= vxlan_fdb_replace(f, ip, port, vni, vlan,
 							   ifindex);
 			} else
 				return -EOPNOTSUPP;
@@ -747,7 +762,7 @@ static int vxlan_fdb_update(struct vxlan
 		if ((flags & NLM_F_APPEND) &&
 		    (is_multicast_ether_addr(f->eth_addr) ||
 		     is_zero_ether_addr(f->eth_addr))) {
-			rc = vxlan_fdb_append(f, ip, port, vni, ifindex, &rd);
+			rc = vxlan_fdb_append(f, ip, port, vni, vlan, ifindex, &rd);
 
 			if (rc < 0)
 				return rc;
@@ -762,8 +777,8 @@ static int vxlan_fdb_update(struct vxlan
 		    (is_multicast_ether_addr(mac) || is_zero_ether_addr(mac)))
 			return -EOPNOTSUPP;
 
-		netdev_dbg(vxlan->dev, "add %pM -> %pIS\n", mac, ip);
-		rc = vxlan_fdb_create(vxlan, mac, ip, state, port, src_vni,
+		netdev_dbg(vxlan->dev, "add %pM -> %pIS (vid %d)\n", mac, ip, vlan);
+		rc = vxlan_fdb_create(vxlan, mac, ip, state, port, src_vni, vlan,
 				      vni, ifindex, ndm_flags, &f);
 		if (rc < 0)
 			return rc;
@@ -822,7 +837,7 @@ static void vxlan_fdb_dst_destroy(struct
 }
 
 static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan,
-			   union vxlan_addr *ip, __be16 *port, __be32 *src_vni,
+			   union vxlan_addr *ip, __be16 *port, __be32 *src_vni, __be16 *vlan,
 			   __be32 *vni, u32 *ifindex)
 {
 	struct net *net = dev_net(vxlan->dev);
@@ -869,6 +884,14 @@ static int vxlan_fdb_parse(struct nlattr
 		*src_vni = vxlan->default_dst.remote_vni;
 	}
 
+	if (tb[NDA_VLAN]) {
+		if(nla_len(tb[NDA_VLAN]) != sizeof(u16))
+			return -EINVAL;
+		*vlan = cpu_to_be16(nla_get_u16(tb[NDA_VLAN]));
+	} else {
+		*vlan = 0;
+	}
+
 	if (tb[NDA_IFINDEX]) {
 		struct net_device *tdev;
 
@@ -895,6 +918,7 @@ static int vxlan_fdb_add(struct ndmsg *n
 	union vxlan_addr ip;
 	__be16 port;
 	__be32 src_vni, vni;
+	__be16 vlan;
 	u32 ifindex;
 	int err;
 
@@ -907,7 +931,7 @@ static int vxlan_fdb_add(struct ndmsg *n
 	if (tb[NDA_DST] == NULL)
 		return -EINVAL;
 
-	err = vxlan_fdb_parse(tb, vxlan, &ip, &port, &src_vni, &vni, &ifindex);
+	err = vxlan_fdb_parse(tb, vxlan, &ip, &port, &src_vni, &vlan, &vni, &ifindex);
 	if (err)
 		return err;
 
@@ -916,7 +940,7 @@ static int vxlan_fdb_add(struct ndmsg *n
 
 	spin_lock_bh(&vxlan->hash_lock);
 	err = vxlan_fdb_update(vxlan, addr, &ip, ndm->ndm_state, flags,
-			       port, src_vni, vni, ifindex, ndm->ndm_flags);
+			       port, src_vni, vlan, vni, ifindex, ndm->ndm_flags);
 	spin_unlock_bh(&vxlan->hash_lock);
 
 	return err;
@@ -924,19 +948,19 @@ static int vxlan_fdb_add(struct ndmsg *n
 
 static int __vxlan_fdb_delete(struct vxlan_dev *vxlan,
 			      const unsigned char *addr, union vxlan_addr ip,
-			      __be16 port, __be32 src_vni, __be32 vni,
+			      __be16 port, __be32 src_vni, __be16 vlan, __be32 vni,
 			      u32 ifindex, u16 vid)
 {
 	struct vxlan_fdb *f;
 	struct vxlan_rdst *rd = NULL;
 	int err = -ENOENT;
 
-	f = vxlan_find_mac(vxlan, addr, src_vni);
+	f = vxlan_find_mac(vxlan, addr, src_vni, vlan);
 	if (!f)
 		return err;
 
 	if (!vxlan_addr_any(&ip)) {
-		rd = vxlan_fdb_find_rdst(f, &ip, port, vni, ifindex);
+		rd = vxlan_fdb_find_rdst(f, &ip, port, vni, vlan, ifindex);
 		if (!rd)
 			goto out;
 	}
@@ -963,16 +987,16 @@ static int vxlan_fdb_delete(struct ndmsg
 	struct vxlan_dev *vxlan = netdev_priv(dev);
 	union vxlan_addr ip;
 	__be32 src_vni, vni;
-	__be16 port;
+	__be16 port, vlan;
 	u32 ifindex;
 	int err;
 
-	err = vxlan_fdb_parse(tb, vxlan, &ip, &port, &src_vni, &vni, &ifindex);
+	err = vxlan_fdb_parse(tb, vxlan, &ip, &port, &src_vni, &vlan, &vni, &ifindex);
 	if (err)
 		return err;
 
 	spin_lock_bh(&vxlan->hash_lock);
-	err = __vxlan_fdb_delete(vxlan, addr, ip, port, src_vni, vni, ifindex,
+	err = __vxlan_fdb_delete(vxlan, addr, ip, port, src_vni, vlan, vni, ifindex,
 				 vid);
 	spin_unlock_bh(&vxlan->hash_lock);
 
@@ -1020,7 +1044,7 @@ out:
  */
 static bool vxlan_snoop(struct net_device *dev,
 			union vxlan_addr *src_ip, const u8 *src_mac,
-			u32 src_ifindex, __be32 vni)
+			u32 src_ifindex, __be32 vni, __be16 vlan)
 {
 	struct vxlan_dev *vxlan = netdev_priv(dev);
 	struct vxlan_fdb *f;
@@ -1032,7 +1056,7 @@ static bool vxlan_snoop(struct net_devic
 		ifindex = src_ifindex;
 #endif
 
-	f = vxlan_find_mac(vxlan, src_mac, vni);
+	f = vxlan_find_mac(vxlan, src_mac, vni, vlan);
 	if (likely(f)) {
 		struct vxlan_rdst *rdst = first_remote_rcu(f);
 
@@ -1062,7 +1086,7 @@ static bool vxlan_snoop(struct net_devic
 					 NUD_REACHABLE,
 					 NLM_F_EXCL|NLM_F_CREATE,
 					 vxlan->cfg.dst_port,
-					 vni,
+					 vni, vlan,
 					 vxlan->default_dst.remote_vni,
 					 ifindex, NTF_SELF);
 		spin_unlock(&vxlan->hash_lock);
@@ -1325,6 +1349,7 @@ static bool vxlan_set_mac(struct vxlan_d
 			  struct sk_buff *skb, __be32 vni)
 {
 	union vxlan_addr saddr;
+	__be16 vlan = 0;
 	u32 ifindex = skb->dev->ifindex;
 
 	skb_reset_mac_header(skb);
@@ -1346,9 +1371,20 @@ static bool vxlan_set_mac(struct vxlan_d
 #endif
 	}
 
-	if ((vxlan->cfg.flags & VXLAN_F_LEARN) &&
-	    vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source, ifindex, vni))
-		return false;
+
+	if (vxlan->cfg.flags & VXLAN_F_LEARN) {
+		if (vxlan->cfg.flags & VXLAN_F_VLAN_AWARE) {
+			if (eth_hdr(skb)->h_proto == cpu_to_be16(ETH_P_8021Q) ||
+			    eth_hdr(skb)->h_proto == cpu_to_be16(ETH_P_8021AD))  {
+				struct vlan_hdr *vhdr = (struct vlan_hdr *)skb->data;
+				vlan = ntohs(vhdr->h_vlan_TCI & VLAN_VID_MASK);
+				if (vlan > VLAN_N_VID) /* wtf? */
+					vlan = 0;
+			}
+		}
+	    	if (vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source, ifindex, vni, vlan))
+			return false;
+	}
 
 	return true;
 }
@@ -1430,6 +1466,7 @@ static int vxlan_rcv(struct sock *sk, st
 				   !net_eq(vxlan->net, dev_net(vxlan->dev))))
 			goto drop;
 
+
 	if (vxlan_collect_metadata(vs)) {
 		struct metadata_dst *tun_dst;
 
@@ -1511,7 +1548,7 @@ drop:
 	return 0;
 }
 
-static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni)
+static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni, __be16 vlan)
 {
 	struct vxlan_dev *vxlan = netdev_priv(dev);
 	struct arphdr *parp;
@@ -1558,7 +1595,7 @@ static int arp_reduce(struct net_device
 			goto out;
 		}
 
-		f = vxlan_find_mac(vxlan, n->ha, vni);
+		f = vxlan_find_mac(vxlan, n->ha, vni, vlan);
 		if (f && vxlan_addr_any(&(first_remote_rcu(f)->remote_ip))) {
 			/* bridge-local neighbor */
 			neigh_release(n);
@@ -1681,7 +1718,7 @@ static struct sk_buff *vxlan_na_create(s
 	return reply;
 }
 
-static int neigh_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni)
+static int neigh_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni, __be16 vlan)
 {
 	struct vxlan_dev *vxlan = netdev_priv(dev);
 	const struct in6_addr *daddr;
@@ -1713,7 +1750,7 @@ static int neigh_reduce(struct net_devic
 			goto out;
 		}
 
-		f = vxlan_find_mac(vxlan, n->ha, vni);
+		f = vxlan_find_mac(vxlan, n->ha, vni, vlan);
 		if (f && vxlan_addr_any(&(first_remote_rcu(f)->remote_ip))) {
 			/* bridge-local neighbor */
 			neigh_release(n);
@@ -2023,7 +2060,7 @@ static struct dst_entry *vxlan6_get_rout
 
 /* Bypass encapsulation if the destination is local */
 static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan,
-			       struct vxlan_dev *dst_vxlan, __be32 vni)
+			       struct vxlan_dev *dst_vxlan, __be32 vni, __be16 vlan)
 {
 	struct pcpu_sw_netstats *tx_stats, *rx_stats;
 	union vxlan_addr loopback;
@@ -2056,7 +2093,7 @@ static void vxlan_encap_bypass(struct sk
 	}
 
 	if (dst_vxlan->cfg.flags & VXLAN_F_LEARN)
-		vxlan_snoop(dev, &loopback, eth_hdr(skb)->h_source, 0, vni);
+		vxlan_snoop(dev, &loopback, eth_hdr(skb)->h_source, 0, vni, vlan);
 
 	u64_stats_update_begin(&tx_stats->syncp);
 	tx_stats->tx_packets++;
@@ -2078,7 +2115,7 @@ drop:
 static int encap_bypass_if_local(struct sk_buff *skb, struct net_device *dev,
 				 struct vxlan_dev *vxlan,
 				 union vxlan_addr *daddr,
-				 __be16 dst_port, int dst_ifindex, __be32 vni,
+				 __be16 dst_port, int dst_ifindex, __be32 vni, __be16 vlan,
 				 struct dst_entry *dst,
 				 u32 rt_flags)
 {
@@ -2104,7 +2141,7 @@ static int encap_bypass_if_local(struct
 
 			return -ENOENT;
 		}
-		vxlan_encap_bypass(skb, vxlan, dst_vxlan, vni);
+		vxlan_encap_bypass(skb, vxlan, dst_vxlan, vni, vlan);
 		return 1;
 	}
 
@@ -2112,7 +2149,7 @@ static int encap_bypass_if_local(struct
 }
 
 static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
-			   __be32 default_vni, struct vxlan_rdst *rdst,
+			   __be32 default_vni, __be16 vlan, struct vxlan_rdst *rdst,
 			   bool did_rsc)
 {
 	struct dst_cache *dst_cache;
@@ -2140,7 +2177,7 @@ static void vxlan_xmit_one(struct sk_buf
 		if (vxlan_addr_any(dst)) {
 			if (did_rsc) {
 				/* short-circuited back to local bridge */
-				vxlan_encap_bypass(skb, vxlan, vxlan, default_vni);
+				vxlan_encap_bypass(skb, vxlan, vxlan, default_vni, vlan);
 				return;
 			}
 			goto drop;
@@ -2148,6 +2185,7 @@ static void vxlan_xmit_one(struct sk_buf
 
 		dst_port = rdst->remote_port ? rdst->remote_port : vxlan->cfg.dst_port;
 		vni = (rdst->remote_vni) ? : default_vni;
+		vlan = rdst->remote_vlan;
 		ifindex = rdst->remote_ifindex;
 		local_ip = vxlan->cfg.saddr;
 		dst_cache = &rdst->dst_cache;
@@ -2220,7 +2258,7 @@ static void vxlan_xmit_one(struct sk_buf
 		/* Bypass encapsulation if the destination is local */
 		if (!info) {
 			err = encap_bypass_if_local(skb, dev, vxlan, dst,
-						    dst_port, ifindex, vni,
+						    dst_port, ifindex, vni, vlan,
 						    &rt->dst, rt->rt_flags);
 			if (err)
 				goto out_unlock;
@@ -2267,7 +2305,7 @@ static void vxlan_xmit_one(struct sk_buf
 			u32 rt6i_flags = ((struct rt6_info *)ndst)->rt6i_flags;
 
 			err = encap_bypass_if_local(skb, dev, vxlan, dst,
-						    dst_port, ifindex, vni,
+						    dst_port, ifindex, vni, vlan,
 						    ndst, rt6i_flags);
 			if (err)
 				goto out_unlock;
@@ -2324,18 +2362,32 @@ static netdev_tx_t vxlan_xmit(struct sk_
 	struct vxlan_fdb *f;
 	struct ethhdr *eth;
 	__be32 vni = 0;
+	__be16 vlan = 0;
 
 	info = skb_tunnel_info(skb);
 
 	skb_reset_mac_header(skb);
 
+	if (vxlan->cfg.flags & VXLAN_F_VLAN_AWARE) {
+		if (eth_hdr(skb)->h_proto == cpu_to_be16(ETH_P_8021Q) ||
+		    eth_hdr(skb)->h_proto == cpu_to_be16(ETH_P_8021AD))  {
+			struct vlan_hdr *vhdr = (struct vlan_hdr *)skb->data;
+			vlan = ntohs(vhdr->h_vlan_TCI & VLAN_VID_MASK);
+			if (vlan > VLAN_N_VID) /* wtf? */
+				vlan = 0;
+		}
+	}
+	eth = eth_hdr(skb);
+	netdev_dbg_ratelimited(vxlan->dev,"xmit frame src mac %pM dst mac %pM vlan %d proto %x\n",
+			       eth->h_source, eth->h_dest, vlan, eth->h_proto);
+
 	if (vxlan->cfg.flags & VXLAN_F_COLLECT_METADATA) {
 		if (info && info->mode & IP_TUNNEL_INFO_BRIDGE &&
 		    info->mode & IP_TUNNEL_INFO_TX) {
 			vni = tunnel_id_to_key32(info->key.tun_id);
 		} else {
 			if (info && info->mode & IP_TUNNEL_INFO_TX)
-				vxlan_xmit_one(skb, dev, vni, NULL, false);
+				vxlan_xmit_one(skb, dev, vni, vlan, NULL, false);
 			else
 				kfree_skb(skb);
 			return NETDEV_TX_OK;
@@ -2345,7 +2397,7 @@ static netdev_tx_t vxlan_xmit(struct sk_
 	if (vxlan->cfg.flags & VXLAN_F_PROXY) {
 		eth = eth_hdr(skb);
 		if (ntohs(eth->h_proto) == ETH_P_ARP)
-			return arp_reduce(dev, skb, vni);
+			return arp_reduce(dev, skb, vni, vlan);
 #if IS_ENABLED(CONFIG_IPV6)
 		else if (ntohs(eth->h_proto) == ETH_P_IPV6 &&
 			 pskb_may_pull(skb, sizeof(struct ipv6hdr) +
@@ -2355,13 +2407,13 @@ static netdev_tx_t vxlan_xmit(struct sk_
 
 			if (m->icmph.icmp6_code == 0 &&
 			    m->icmph.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION)
-				return neigh_reduce(dev, skb, vni);
+				return neigh_reduce(dev, skb, vni, vlan);
 		}
 #endif
 	}
 
 	eth = eth_hdr(skb);
-	f = vxlan_find_mac(vxlan, eth->h_dest, vni);
+	f = vxlan_find_mac(vxlan, eth->h_dest, vni, vlan);
 	did_rsc = false;
 
 	if (f && (f->flags & NTF_ROUTER) && (vxlan->cfg.flags & VXLAN_F_RSC) &&
@@ -2369,11 +2421,13 @@ static netdev_tx_t vxlan_xmit(struct sk_
 	     ntohs(eth->h_proto) == ETH_P_IPV6)) {
 		did_rsc = route_shortcircuit(dev, skb);
 		if (did_rsc)
-			f = vxlan_find_mac(vxlan, eth->h_dest, vni);
+			f = vxlan_find_mac(vxlan, eth->h_dest, vni, vlan);
 	}
 
 	if (f == NULL) {
-		f = vxlan_find_mac(vxlan, all_zeros_mac, vni);
+		f = vxlan_find_mac(vxlan, all_zeros_mac, vni, vlan);
+		if (f == NULL)
+			f = vxlan_find_mac(vxlan, all_zeros_mac, vni, 0);
 		if (f == NULL) {
 			if ((vxlan->cfg.flags & VXLAN_F_L2MISS) &&
 			    !is_multicast_ether_addr(eth->h_dest))
@@ -2394,11 +2448,11 @@ static netdev_tx_t vxlan_xmit(struct sk_
 		}
 		skb1 = skb_clone(skb, GFP_ATOMIC);
 		if (skb1)
-			vxlan_xmit_one(skb1, dev, vni, rdst, did_rsc);
+			vxlan_xmit_one(skb1, dev, vni, vlan, rdst, did_rsc);
 	}
 
 	if (fdst)
-		vxlan_xmit_one(skb, dev, vni, fdst, did_rsc);
+		vxlan_xmit_one(skb, dev, vni, vlan, fdst, did_rsc);
 	else
 		kfree_skb(skb);
 	return NETDEV_TX_OK;
@@ -2488,12 +2542,17 @@ static int vxlan_init(struct net_device
 	return 0;
 }
 
-static void vxlan_fdb_delete_default(struct vxlan_dev *vxlan, __be32 vni)
+static void vxlan_fdb_delete_default(struct vxlan_dev *vxlan, __be32 vni, __be16 vlan)
 {
 	struct vxlan_fdb *f;
 
 	spin_lock_bh(&vxlan->hash_lock);
-	f = __vxlan_find_mac(vxlan, all_zeros_mac, vni);
+	if (vlan) {
+		f = __vxlan_find_mac(vxlan, all_zeros_mac, vni, vlan);
+		if (f)
+			vxlan_fdb_destroy(vxlan, f, true);
+	}
+	f = __vxlan_find_mac(vxlan, all_zeros_mac, vni, 0);
 	if (f)
 		vxlan_fdb_destroy(vxlan, f, true);
 	spin_unlock_bh(&vxlan->hash_lock);
@@ -2505,7 +2564,7 @@ static void vxlan_uninit(struct net_devi
 
 	gro_cells_destroy(&vxlan->gro_cells);
 
-	vxlan_fdb_delete_default(vxlan, vxlan->cfg.vni);
+	vxlan_fdb_delete_default(vxlan, vxlan->cfg.vni, 0);
 
 	free_percpu(dev->tstats);
 }
@@ -2794,6 +2853,7 @@ static const struct nla_policy vxlan_pol
 	[IFLA_VXLAN_GPE]	= { .type = NLA_FLAG, },
 	[IFLA_VXLAN_REMCSUM_NOPARTIAL]	= { .type = NLA_FLAG },
 	[IFLA_VXLAN_TTL_INHERIT]	= { .type = NLA_FLAG },
+	[IFLA_VXLAN_VLAN_AWARE]	= { .type = NLA_FLAG },
 };
 
 static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[],
@@ -2850,6 +2910,11 @@ static int vxlan_validate(struct nlattr
 		}
 	}
 
+	if (data[IFLA_VXLAN_VLAN_AWARE] && !vxlan_vlan_aware) {
+			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_VLAN_AWARE],
+					    "Vxlan vlan aware is disabled");
+	}
+
 	return 0;
 }
 
@@ -3159,6 +3224,12 @@ static int vxlan_config_validate(struct
 		return -EEXIST;
 	}
 
+	if ((conf->flags & VXLAN_F_VLAN_AWARE) && !vxlan_vlan_aware) {
+		NL_SET_ERR_MSG(extack,
+			       "Vlan aware processing is disabled");
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -3270,7 +3341,7 @@ static int __vxlan_dev_create(struct net
 				       &vxlan->default_dst.remote_ip,
 				       NUD_REACHABLE | NUD_PERMANENT,
 				       vxlan->cfg.dst_port,
-				       vxlan->default_dst.remote_vni,
+				       vxlan->default_dst.remote_vni, 0,
 				       vxlan->default_dst.remote_vni,
 				       vxlan->default_dst.remote_ifindex,
 				       NTF_SELF, &f);
@@ -3530,6 +3601,15 @@ static int vxlan_nl2conf(struct nlattr *
 			return -EINVAL;
 	}
 
+	if (tb[IFLA_VXLAN_VLAN_AWARE]) {
+		if (nla_get_u8(tb[IFLA_VXLAN_VLAN_AWARE])) {
+			if (!vxlan_vlan_aware)
+				return -EOPNOTSUPP;
+			conf->flags |= VXLAN_F_VLAN_AWARE;
+		} else
+			conf->flags &= ~VXLAN_F_VLAN_AWARE;
+	}
+
 	return 0;
 }
 
@@ -3576,6 +3656,7 @@ static int vxlan_changelink(struct net_d
 					   old_dst.remote_ip,
 					   vxlan->cfg.dst_port,
 					   old_dst.remote_vni,
+					   old_dst.remote_vlan,
 					   old_dst.remote_vni,
 					   old_dst.remote_ifindex, 0);
 
@@ -3585,7 +3666,7 @@ static int vxlan_changelink(struct net_d
 					       NUD_REACHABLE | NUD_PERMANENT,
 					       NLM_F_APPEND | NLM_F_CREATE,
 					       vxlan->cfg.dst_port,
-					       dst->remote_vni,
+					       dst->remote_vni, dst->remote_vlan,
 					       dst->remote_vni,
 					       dst->remote_ifindex,
 					       NTF_SELF);
@@ -3638,6 +3719,7 @@ static size_t vxlan_get_size(const struc
 		nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_ZERO_CSUM6_RX */
 		nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_REMCSUM_TX */
 		nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_REMCSUM_RX */
+		nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_VLAN_AWARE */
 		0;
 }
 
@@ -3670,6 +3752,9 @@ static int vxlan_fill_info(struct sk_buf
 	if (dst->remote_ifindex && nla_put_u32(skb, IFLA_VXLAN_LINK, dst->remote_ifindex))
 		goto nla_put_failure;
 
+	if (dst->remote_vlan && nla_put_u16(skb, IFLA_VXLAN_VLAN_ID, dst->remote_vlan))
+		goto nla_put_failure;
+
 	if (!vxlan_addr_any(&vxlan->cfg.saddr)) {
 		if (vxlan->cfg.saddr.sa.sa_family == AF_INET) {
 			if (nla_put_in_addr(skb, IFLA_VXLAN_LOCAL,
@@ -3713,7 +3798,9 @@ static int vxlan_fill_info(struct sk_buf
 	    nla_put_u8(skb, IFLA_VXLAN_REMCSUM_TX,
 			!!(vxlan->cfg.flags & VXLAN_F_REMCSUM_TX)) ||
 	    nla_put_u8(skb, IFLA_VXLAN_REMCSUM_RX,
-			!!(vxlan->cfg.flags & VXLAN_F_REMCSUM_RX)))
+			!!(vxlan->cfg.flags & VXLAN_F_REMCSUM_RX)) ||
+	    nla_put_u8(skb, IFLA_VXLAN_VLAN_AWARE,
+			!!(vxlan->cfg.flags & VXLAN_F_VLAN_AWARE)))
 		goto nla_put_failure;
 
 	if (nla_put(skb, IFLA_VXLAN_PORT_RANGE, sizeof(ports), &ports))
@@ -3986,7 +4073,7 @@ static int store_flag(struct vxlan_dev *
 	if (flags != p->cfg.flags)
 		p->cfg.flags = flags;
 
-	return 1;
+	return 0;
 }
 
 VXLAN_ATTR_FLAG(learn, VXLAN_F_LEARN);
Index: linux-4.19.118/include/net/vxlan.h
===================================================================
--- linux-4.19.118.orig/include/net/vxlan.h
+++ linux-4.19.118/include/net/vxlan.h
@@ -192,6 +192,7 @@ struct vxlan_rdst {
 	union vxlan_addr	 remote_ip;
 	__be16			 remote_port;
 	__be32			 remote_vni;
+	__be16			 remote_vlan;
 	u32			 remote_ifindex;
 	struct list_head	 list;
 	struct rcu_head		 rcu;
@@ -266,6 +267,7 @@ struct vxlan_dev {
 #define VXLAN_F_TTL_INHERIT		0x10000
 #define VXLAN_F_CLEAR_DF		0x20000
 #define VXLAN_F_SLAVE_MTU		0x40000
+#define VXLAN_F_VLAN_AWARE		0x80000
 
 #define SYSFS_VXLAN_ATTR		"vxlan"
 #define SYSFS_VXLAN_FDB			"fdbread"
Index: linux-4.19.118/include/uapi/linux/if_link.h
===================================================================
--- linux-4.19.118.orig/include/uapi/linux/if_link.h
+++ linux-4.19.118/include/uapi/linux/if_link.h
@@ -531,6 +531,8 @@ enum {
 	IFLA_VXLAN_LABEL,
 	IFLA_VXLAN_GPE,
 	IFLA_VXLAN_TTL_INHERIT,
+	IFLA_VXLAN_VLAN_ID,
+	IFLA_VXLAN_VLAN_AWARE,
 	__IFLA_VXLAN_MAX
 };
 #define IFLA_VXLAN_MAX	(__IFLA_VXLAN_MAX - 1)
