ops->fdb_clear_offload(nve_dev, vni);
 }
 
+struct mlxsw_sp_nve_ipv6_ht_key {
+       u8 mac[ETH_ALEN];
+       u16 fid_index;
+};
+
+struct mlxsw_sp_nve_ipv6_ht_node {
+       struct rhash_head ht_node;
+       struct list_head list;
+       struct mlxsw_sp_nve_ipv6_ht_key key;
+       struct in6_addr addr6;
+};
+
+static const struct rhashtable_params mlxsw_sp_nve_ipv6_ht_params = {
+       .key_len = sizeof(struct mlxsw_sp_nve_ipv6_ht_key),
+       .key_offset = offsetof(struct mlxsw_sp_nve_ipv6_ht_node, key),
+       .head_offset = offsetof(struct mlxsw_sp_nve_ipv6_ht_node, ht_node),
+};
+
+int mlxsw_sp_nve_ipv6_addr_kvdl_set(struct mlxsw_sp *mlxsw_sp,
+                                   const struct in6_addr *addr6,
+                                   u32 *p_kvdl_index)
+{
+       return mlxsw_sp_ipv6_addr_kvdl_index_get(mlxsw_sp, addr6, p_kvdl_index);
+}
+
+void mlxsw_sp_nve_ipv6_addr_kvdl_unset(struct mlxsw_sp *mlxsw_sp,
+                                      const struct in6_addr *addr6)
+{
+       mlxsw_sp_ipv6_addr_put(mlxsw_sp, addr6);
+}
+
+static struct mlxsw_sp_nve_ipv6_ht_node *
+mlxsw_sp_nve_ipv6_ht_node_lookup(struct mlxsw_sp *mlxsw_sp, const char *mac,
+                                u16 fid_index)
+{
+       struct mlxsw_sp_nve_ipv6_ht_key key = {};
+
+       ether_addr_copy(key.mac, mac);
+       key.fid_index = fid_index;
+       return rhashtable_lookup_fast(&mlxsw_sp->nve->ipv6_ht, &key,
+                                     mlxsw_sp_nve_ipv6_ht_params);
+}
+
+static int mlxsw_sp_nve_ipv6_ht_insert(struct mlxsw_sp *mlxsw_sp,
+                                      const char *mac, u16 fid_index,
+                                      const struct in6_addr *addr6)
+{
+       struct mlxsw_sp_nve_ipv6_ht_node *ipv6_ht_node;
+       struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
+       int err;
+
+       ipv6_ht_node = kzalloc(sizeof(*ipv6_ht_node), GFP_KERNEL);
+       if (!ipv6_ht_node)
+               return -ENOMEM;
+
+       ether_addr_copy(ipv6_ht_node->key.mac, mac);
+       ipv6_ht_node->key.fid_index = fid_index;
+       ipv6_ht_node->addr6 = *addr6;
+
+       err = rhashtable_insert_fast(&nve->ipv6_ht, &ipv6_ht_node->ht_node,
+                                    mlxsw_sp_nve_ipv6_ht_params);
+       if (err)
+               goto err_rhashtable_insert;
+
+       list_add(&ipv6_ht_node->list, &nve->ipv6_addr_list);
+
+       return 0;
+
+err_rhashtable_insert:
+       kfree(ipv6_ht_node);
+       return err;
+}
+
+static void
+mlxsw_sp_nve_ipv6_ht_remove(struct mlxsw_sp *mlxsw_sp,
+                           struct mlxsw_sp_nve_ipv6_ht_node *ipv6_ht_node)
+{
+       struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
+
+       list_del(&ipv6_ht_node->list);
+       rhashtable_remove_fast(&nve->ipv6_ht, &ipv6_ht_node->ht_node,
+                              mlxsw_sp_nve_ipv6_ht_params);
+       kfree(ipv6_ht_node);
+}
+
+int
+mlxsw_sp_nve_ipv6_addr_map_replace(struct mlxsw_sp *mlxsw_sp, const char *mac,
+                                  u16 fid_index,
+                                  const struct in6_addr *new_addr6)
+{
+       struct mlxsw_sp_nve_ipv6_ht_node *ipv6_ht_node;
+
+       ASSERT_RTNL();
+
+       ipv6_ht_node = mlxsw_sp_nve_ipv6_ht_node_lookup(mlxsw_sp, mac,
+                                                       fid_index);
+       if (!ipv6_ht_node)
+               return mlxsw_sp_nve_ipv6_ht_insert(mlxsw_sp, mac, fid_index,
+                                                  new_addr6);
+
+       mlxsw_sp_ipv6_addr_put(mlxsw_sp, &ipv6_ht_node->addr6);
+       ipv6_ht_node->addr6 = *new_addr6;
+       return 0;
+}
+
+void mlxsw_sp_nve_ipv6_addr_map_del(struct mlxsw_sp *mlxsw_sp, const char *mac,
+                                   u16 fid_index)
+{
+       struct mlxsw_sp_nve_ipv6_ht_node *ipv6_ht_node;
+
+       ASSERT_RTNL();
+
+       ipv6_ht_node = mlxsw_sp_nve_ipv6_ht_node_lookup(mlxsw_sp, mac,
+                                                       fid_index);
+       if (WARN_ON(!ipv6_ht_node))
+               return;
+
+       mlxsw_sp_nve_ipv6_ht_remove(mlxsw_sp, ipv6_ht_node);
+}
+
+static void mlxsw_sp_nve_ipv6_addr_flush_by_fid(struct mlxsw_sp *mlxsw_sp,
+                                               u16 fid_index)
+{
+       struct mlxsw_sp_nve_ipv6_ht_node *ipv6_ht_node, *tmp;
+       struct mlxsw_sp_nve *nve = mlxsw_sp->nve;
+
+       list_for_each_entry_safe(ipv6_ht_node, tmp, &nve->ipv6_addr_list,
+                                list) {
+               if (ipv6_ht_node->key.fid_index != fid_index)
+                       continue;
+
+               mlxsw_sp_ipv6_addr_put(mlxsw_sp, &ipv6_ht_node->addr6);
+               mlxsw_sp_nve_ipv6_ht_remove(mlxsw_sp, ipv6_ht_node);
+       }
+}
+
 int mlxsw_sp_nve_fid_enable(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *fid,
                            struct mlxsw_sp_nve_params *params,
                            struct netlink_ext_ack *extack)
 
        mlxsw_sp_nve_flood_ip_flush(mlxsw_sp, fid);
        mlxsw_sp_nve_fdb_flush_by_fid(mlxsw_sp, fid_index);
+       mlxsw_sp_nve_ipv6_addr_flush_by_fid(mlxsw_sp, fid_index);
 
        if (WARN_ON(mlxsw_sp_fid_nve_ifindex(fid, &nve_ifindex) ||
                    mlxsw_sp_fid_vni(fid, &vni)))
        err = rhashtable_init(&nve->mc_list_ht,
                              &mlxsw_sp_nve_mc_list_ht_params);
        if (err)
-               goto err_rhashtable_init;
+               goto err_mc_rhashtable_init;
+
+       err = rhashtable_init(&nve->ipv6_ht, &mlxsw_sp_nve_ipv6_ht_params);
+       if (err)
+               goto err_ipv6_rhashtable_init;
+
+       INIT_LIST_HEAD(&nve->ipv6_addr_list);
 
        err = mlxsw_sp_nve_qos_init(mlxsw_sp);
        if (err)
 err_nve_resources_query:
 err_nve_ecn_init:
 err_nve_qos_init:
+       rhashtable_destroy(&nve->ipv6_ht);
+err_ipv6_rhashtable_init:
        rhashtable_destroy(&nve->mc_list_ht);
-err_rhashtable_init:
+err_mc_rhashtable_init:
        mlxsw_sp->nve = NULL;
        kfree(nve);
        return err;
 void mlxsw_sp_nve_fini(struct mlxsw_sp *mlxsw_sp)
 {
        WARN_ON(mlxsw_sp->nve->num_nve_tunnels);
+       WARN_ON(!list_empty(&mlxsw_sp->nve->ipv6_addr_list));
+       rhashtable_destroy(&mlxsw_sp->nve->ipv6_ht);
        rhashtable_destroy(&mlxsw_sp->nve->mc_list_ht);
        kfree(mlxsw_sp->nve);
        mlxsw_sp->nve = NULL;