TP_PROTO(const struct mlx5e_neigh_hash_entry *nhe, const u8 *ha,
                     bool neigh_connected),
            TP_ARGS(nhe, ha, neigh_connected),
-           TP_STRUCT__entry(__string(devname, nhe->m_neigh.dev->name)
+           TP_STRUCT__entry(__string(devname, nhe->neigh_dev->name)
                             __array(u8, ha, ETH_ALEN)
                             __array(u8, v4, 4)
                             __array(u8, v6, 16)
                        struct in6_addr *pin6;
                        __be32 *p32;
 
-                       __assign_str(devname, mn->dev->name);
+                       __assign_str(devname, nhe->neigh_dev->name);
                        __entry->neigh_connected = neigh_connected;
                        memcpy(__entry->ha, ha, ETH_ALEN);
 
 
 TRACE_EVENT(mlx5e_tc_update_neigh_used_value,
            TP_PROTO(const struct mlx5e_neigh_hash_entry *nhe, bool neigh_used),
            TP_ARGS(nhe, neigh_used),
-           TP_STRUCT__entry(__string(devname, nhe->m_neigh.dev->name)
+           TP_STRUCT__entry(__string(devname, nhe->neigh_dev->name)
                             __array(u8, v4, 4)
                             __array(u8, v6, 16)
                             __field(bool, neigh_used)
                        struct in6_addr *pin6;
                        __be32 *p32;
 
-                       __assign_str(devname, mn->dev->name);
+                       __assign_str(devname, nhe->neigh_dev->name);
                        __entry->neigh_used = neigh_used;
 
                        p32 = (__be32 *)__entry->v4;
 
                                                             work);
        struct mlx5e_neigh_hash_entry *nhe = update_work->nhe;
        struct neighbour *n = update_work->n;
+       bool neigh_connected, same_dev;
        struct mlx5e_encap_entry *e;
        unsigned char ha[ETH_ALEN];
        struct mlx5e_priv *priv;
-       bool neigh_connected;
        u8 nud_state, dead;
 
        rtnl_lock();
        memcpy(ha, n->ha, ETH_ALEN);
        nud_state = n->nud_state;
        dead = n->dead;
+       same_dev = READ_ONCE(nhe->neigh_dev) == n->dev;
        read_unlock_bh(&n->lock);
 
        neigh_connected = (nud_state & NUD_VALID) && !dead;
 
        trace_mlx5e_rep_neigh_update(nhe, ha, neigh_connected);
 
+       if (!same_dev)
+               goto out;
+
        list_for_each_entry(e, &nhe->encap_list, encap_list) {
                if (!mlx5e_encap_take(e))
                        continue;
                mlx5e_rep_update_flows(priv, e, neigh_connected, ha);
                mlx5e_encap_put(priv, e);
        }
+out:
        rtnl_unlock();
        mlx5e_release_neigh_update_work(update_work);
 }
        if (WARN_ON(!update_work))
                return NULL;
 
-       m_neigh.dev = n->dev;
        m_neigh.family = n->ops->family;
        memcpy(&m_neigh.dst_ip, n->primary_key, n->tbl->key_len);
 
                rcu_read_lock();
                list_for_each_entry_rcu(nhe, &neigh_update->neigh_list,
                                        neigh_list) {
-                       if (p->dev == nhe->m_neigh.dev) {
+                       if (p->dev == READ_ONCE(nhe->neigh_dev)) {
                                found = true;
                                break;
                        }
 }
 
 int mlx5e_rep_neigh_entry_create(struct mlx5e_priv *priv,
-                                struct mlx5e_encap_entry *e,
+                                struct mlx5e_neigh *m_neigh,
+                                struct net_device *neigh_dev,
                                 struct mlx5e_neigh_hash_entry **nhe)
 {
        int err;
                return -ENOMEM;
 
        (*nhe)->priv = priv;
-       memcpy(&(*nhe)->m_neigh, &e->m_neigh, sizeof(e->m_neigh));
+       memcpy(&(*nhe)->m_neigh, m_neigh, sizeof(*m_neigh));
        spin_lock_init(&(*nhe)->encap_list_lock);
        INIT_LIST_HEAD(&(*nhe)->encap_list);
        refcount_set(&(*nhe)->refcnt, 1);
+       WRITE_ONCE((*nhe)->neigh_dev, neigh_dev);
 
        err = mlx5e_rep_neigh_entry_insert(priv, *nhe);
        if (err)
 
 mlx5e_rep_neigh_entry_lookup(struct mlx5e_priv *priv,
                             struct mlx5e_neigh *m_neigh);
 int mlx5e_rep_neigh_entry_create(struct mlx5e_priv *priv,
-                                struct mlx5e_encap_entry *e,
+                                struct mlx5e_neigh *m_neigh,
+                                struct net_device *neigh_dev,
                                 struct mlx5e_neigh_hash_entry **nhe);
 void mlx5e_rep_neigh_entry_release(struct mlx5e_neigh_hash_entry *nhe);
 
 
 };
 
 int mlx5e_rep_encap_entry_attach(struct mlx5e_priv *priv,
-                                struct mlx5e_encap_entry *e)
+                                struct mlx5e_encap_entry *e,
+                                struct mlx5e_neigh *m_neigh,
+                                struct net_device *neigh_dev)
 {
        struct mlx5e_rep_priv *rpriv = priv->ppriv;
        struct mlx5_rep_uplink_priv *uplink_priv = &rpriv->uplink_priv;
                return err;
 
        mutex_lock(&rpriv->neigh_update.encap_lock);
-       nhe = mlx5e_rep_neigh_entry_lookup(priv, &e->m_neigh);
+       nhe = mlx5e_rep_neigh_entry_lookup(priv, m_neigh);
        if (!nhe) {
-               err = mlx5e_rep_neigh_entry_create(priv, e, &nhe);
+               err = mlx5e_rep_neigh_entry_create(priv, m_neigh, neigh_dev, &nhe);
                if (err) {
                        mutex_unlock(&rpriv->neigh_update.encap_lock);
                        mlx5_tun_entropy_refcount_dec(tun_entropy,
 
                            unsigned char ha[ETH_ALEN]);
 
 int mlx5e_rep_encap_entry_attach(struct mlx5e_priv *priv,
-                                struct mlx5e_encap_entry *e);
+                                struct mlx5e_encap_entry *e,
+                                struct mlx5e_neigh *m_neigh,
+                                struct net_device *neigh_dev);
 void mlx5e_rep_encap_entry_detach(struct mlx5e_priv *priv,
                                  struct mlx5e_encap_entry *e);
 
 
 {
        int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size);
        const struct ip_tunnel_key *tun_key = &e->tun_info->key;
+       struct mlx5e_neigh m_neigh = {};
        TC_TUN_ROUTE_ATTR_INIT(attr);
        int ipv4_encap_size;
        char *encap_header;
                goto release_neigh;
        }
 
-       /* used by mlx5e_detach_encap to lookup a neigh hash table
-        * entry in the neigh hash table when a user deletes a rule
-        */
-       e->m_neigh.dev = attr.n->dev;
-       e->m_neigh.family = attr.n->ops->family;
-       memcpy(&e->m_neigh.dst_ip, attr.n->primary_key, attr.n->tbl->key_len);
+       m_neigh.family = attr.n->ops->family;
+       memcpy(&m_neigh.dst_ip, attr.n->primary_key, attr.n->tbl->key_len);
        e->out_dev = attr.out_dev;
        e->route_dev_ifindex = attr.route_dev->ifindex;
 
         * neigh changes it's validity state, we would find the relevant neigh
         * in the hash.
         */
-       err = mlx5e_rep_encap_entry_attach(netdev_priv(attr.out_dev), e);
+       err = mlx5e_rep_encap_entry_attach(netdev_priv(attr.out_dev), e, &m_neigh, attr.n->dev);
        if (err)
                goto free_encap;
 
 {
        int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size);
        const struct ip_tunnel_key *tun_key = &e->tun_info->key;
+       struct mlx5e_neigh m_neigh = {};
        TC_TUN_ROUTE_ATTR_INIT(attr);
        struct ipv6hdr *ip6h;
        int ipv6_encap_size;
                goto release_neigh;
        }
 
-       /* used by mlx5e_detach_encap to lookup a neigh hash table
-        * entry in the neigh hash table when a user deletes a rule
-        */
-       e->m_neigh.dev = attr.n->dev;
-       e->m_neigh.family = attr.n->ops->family;
-       memcpy(&e->m_neigh.dst_ip, attr.n->primary_key, attr.n->tbl->key_len);
+       m_neigh.family = attr.n->ops->family;
+       memcpy(&m_neigh.dst_ip, attr.n->primary_key, attr.n->tbl->key_len);
        e->out_dev = attr.out_dev;
        e->route_dev_ifindex = attr.route_dev->ifindex;
 
         * neigh changes it's validity state, we would find the relevant neigh
         * in the hash.
         */
-       err = mlx5e_rep_encap_entry_attach(netdev_priv(attr.out_dev), e);
+       err = mlx5e_rep_encap_entry_attach(netdev_priv(attr.out_dev), e, &m_neigh, attr.n->dev);
        if (err)
                goto free_encap;
 
 
                /* find the relevant neigh according to the cached device and
                 * dst ip pair
                 */
-               n = neigh_lookup(tbl, &m_neigh->dst_ip, m_neigh->dev);
+               n = neigh_lookup(tbl, &m_neigh->dst_ip, READ_ONCE(nhe->neigh_dev));
                if (!n)
                        return;
 
 
 }
 
 struct mlx5e_neigh {
-       struct net_device *dev;
        union {
                __be32  v4;
                struct in6_addr v6;
        struct rhash_head rhash_node;
        struct mlx5e_neigh m_neigh;
        struct mlx5e_priv *priv;
+       struct net_device *neigh_dev;
 
        /* Save the neigh hash entry in a list on the representor in
         * addition to the hash table. In order to iterate easily over the
        struct mlx5e_neigh_hash_entry *nhe;
        /* neigh hash entry list of encaps sharing the same neigh */
        struct list_head encap_list;
-       struct mlx5e_neigh m_neigh;
        /* a node of the eswitch encap hash table which keeping all the encap
         * entries
         */