Repository: kiali/kiali

Issue:
Refactor out global variables from business package
### What do you want to improve?

This is a "tech debt" issue. The business package has a number of global variables that must be set in order to use the package: https://github.com/kiali/kiali/blob/9a11e24d993ef34be0de7fbad3d6df946a530bfa/business/layer.go#L38-L44

Most of the api handlers call `business.Get` which uses these globals and then calls `NewWithBackends` that also uses these globals:
https://github.com/kiali/kiali/blob/9a11e24d993ef34be0de7fbad3d6df946a530bfa/business/layer.go#L83-L115

The problems for this are apparent when writing unit tests for and with the business package. When you write a test that doesn't set all the right globals, your test will panic and fail. It's not always obvious what you need to set and how. This makes it much harder to write tests and discourages folks from writing tests. Another issue is that having global variables lends itself to having global locks alongside those variables to prevent race conditions with multiple different actors trying to use those global variables.

### What is the new behavior?

Instead of having global variables in the business package, those variables can be passed into the business package when creating a new layer. Create a new function to create a `business.Layer` and migrate to the new method over time. Something like
```
NewLayer(cf kubernetes.ClientFactory, cache cache.KialiCache, conf config.Config, prom prometheus.ClientInterface) *Layer {
  	temporaryLayer := &Layer{}

        userClients := cf.GetClients()
	temporaryLayer.App = AppService{prom: prom, userClients: userClients, businessLayer: temporaryLayer}
        ...

	return temporaryLayer
```

Notice that almost all the arguments are interfaces so the "fake" implementations can easily be passed in testing.

The http handlers would need to pass these into the `NewLayer` function when they access the business layer. Although the handlers need to conform to `http.HandlerFunc`, it is a common pattern to wrap handler methods in a closure to pass dependencies into them. So this:
```
func AppList(w http.ResponseWriter, r *http.Request) {
  // Uses globals
  business.Get()
}
```
would become:
```
func AppList(cf kubernetes.ClientFactory, cache cache.KialiCache, conf config.Config, prom prometheus.ClientInterface) http.HandlerFunc {
  return func(w http.ResponseWriter, r *http.Request) {
    // Does not use globals
    business.NewLayer(cf, cache, conf, prom)
  }
}
```

Adding the `AppList` handler to the route becomes:
```
		{
			"AppList",
			"GET",
			"/api/namespaces/{namespace}/apps",
			handlers.AppList(cf, cache, conf, prom),
			true,
		},
```

Using this approach we can also migrate each handler individually rather than all at once.

Hints from issue comments:

Solution patch:
diff --git a/business/checkers/authorization/no_host_checker.go b/business/checkers/authorization/no_host_checker.go
index 6bd822207..a51950aba 100644
--- a/business/checkers/authorization/no_host_checker.go
+++ b/business/checkers/authorization/no_host_checker.go
@@ -15,7 +15,7 @@ import (
 type NoHostChecker struct {
 	AuthorizationPolicy *security_v1.AuthorizationPolicy
 	Conf                *config.Config
-	Namespaces          models.Namespaces
+	Namespaces          []string
 	ServiceEntries      map[string][]string
 	VirtualServices     []*networking_v1.VirtualService
 	RegistryServices    []*kubernetes.RegistryService
@@ -51,6 +51,7 @@ func (n NoHostChecker) validateHost(ruleIdx int, to []*api_security_v1.Rule_To)
 		return nil, true
 	}
 	namespace := n.AuthorizationPolicy.Namespace
+
 	checks, valid := make([]*models.IstioCheck, 0, len(to)), true
 	for toIdx, t := range to {
 		if t == nil {
@@ -66,7 +67,7 @@ func (n NoHostChecker) validateHost(ruleIdx int, to []*api_security_v1.Rule_To)
 		}
 
 		for hostIdx, h := range t.Operation.Hosts {
-			fqdn := kubernetes.GetHost(h, namespace, n.Namespaces.GetNames(), n.Conf)
+			fqdn := kubernetes.GetHost(h, namespace, n.Namespaces, n.Conf)
 			if !n.hasMatchingService(fqdn, namespace) {
 				path := fmt.Sprintf("spec/rules[%d]/to[%d]/operation/hosts[%d]", ruleIdx, toIdx, hostIdx)
 				validation := models.Build("authorizationpolicy.nodest.matchingregistry", path)
diff --git a/business/checkers/authorization_policies_checker.go b/business/checkers/authorization_policies_checker.go
index 144f18e2a..8e7eba6c0 100644
--- a/business/checkers/authorization_policies_checker.go
+++ b/business/checkers/authorization_policies_checker.go
@@ -15,7 +15,7 @@ type AuthorizationPolicyChecker struct {
 	Cluster               string
 	Conf                  *config.Config
 	MtlsDetails           kubernetes.MTLSDetails
-	Namespaces            models.Namespaces
+	Namespaces            []string
 	PolicyAllowAny        bool
 	RegistryServices      []*kubernetes.RegistryService
 	ServiceAccounts       map[string][]string
@@ -57,7 +57,7 @@ func (a AuthorizationPolicyChecker) runChecks(authPolicy *security_v1.Authorizat
 
 	enabledCheckers := []Checker{
 		common.SelectorNoWorkloadFoundChecker(kubernetes.AuthorizationPolicies, matchLabels, a.WorkloadsPerNamespace),
-		authorization.NamespaceMethodChecker{AuthorizationPolicy: authPolicy, Namespaces: a.Namespaces.GetNames()},
+		authorization.NamespaceMethodChecker{AuthorizationPolicy: authPolicy, Namespaces: a.Namespaces},
 		authorization.NoHostChecker{Conf: a.Conf, AuthorizationPolicy: authPolicy, Namespaces: a.Namespaces,
 			ServiceEntries: serviceHosts, VirtualServices: a.VirtualServices, RegistryServices: a.RegistryServices, PolicyAllowAny: a.PolicyAllowAny},
 		authorization.PrincipalsChecker{Cluster: a.Cluster, AuthorizationPolicy: authPolicy, ServiceAccounts: a.ServiceAccounts},
diff --git a/business/checkers/common/export_to_namespace_checker.go b/business/checkers/common/export_to_namespace_checker.go
index add0939a1..89d202f3a 100644
--- a/business/checkers/common/export_to_namespace_checker.go
+++ b/business/checkers/common/export_to_namespace_checker.go
@@ -4,11 +4,12 @@ import (
 	"fmt"
 
 	"github.com/kiali/kiali/models"
+	"github.com/kiali/kiali/util/sliceutil"
 )
 
 type ExportToNamespaceChecker struct {
 	ExportTo   []string
-	Namespaces models.Namespaces
+	Namespaces []string
 }
 
 func (p ExportToNamespaceChecker) Check() ([]*models.IstioCheck, bool) {
@@ -16,7 +17,7 @@ func (p ExportToNamespaceChecker) Check() ([]*models.IstioCheck, bool) {
 
 	if len(p.ExportTo) > 0 {
 		for nsIndex, namespace := range p.ExportTo {
-			if namespace != "." && namespace != "*" && !p.Namespaces.Includes(namespace) {
+			if namespace != "." && namespace != "*" && !sliceutil.SomeString(p.Namespaces, namespace) {
 				validation := models.Build("generic.exportto.namespacenotfound",
 					fmt.Sprintf("spec/exportTo[%d]", nsIndex))
 				validations = append(validations, &validation)
diff --git a/business/checkers/destination_rules_checker.go b/business/checkers/destination_rules_checker.go
index 3678c6b80..f702828c4 100644
--- a/business/checkers/destination_rules_checker.go
+++ b/business/checkers/destination_rules_checker.go
@@ -34,7 +34,7 @@ func (in DestinationRulesChecker) runGroupChecks() models.IstioValidations {
 	seHosts := kubernetes.ServiceEntryHostnames(in.ServiceEntries)
 
 	enabledDRCheckers := []GroupChecker{
-		destinationrules.MultiMatchChecker{Conf: in.Conf, Namespaces: in.Namespaces, ServiceEntries: seHosts, DestinationRules: in.DestinationRules, Cluster: in.Cluster},
+		destinationrules.MultiMatchChecker{Conf: in.Conf, Namespaces: in.Namespaces.GetNames(), ServiceEntries: seHosts, DestinationRules: in.DestinationRules, Cluster: in.Cluster},
 	}
 
 	enabledDRCheckers = append(enabledDRCheckers, destinationrules.TrafficPolicyChecker{Conf: in.Conf, DestinationRules: in.DestinationRules, MTLSDetails: in.MTLSDetails, Cluster: in.Cluster})
@@ -49,14 +49,15 @@ func (in DestinationRulesChecker) runGroupChecks() models.IstioValidations {
 func (in DestinationRulesChecker) runIndividualChecks() models.IstioValidations {
 	validations := models.IstioValidations{}
 
+	nsNames := in.Namespaces.GetNames()
 	for _, destinationRule := range in.DestinationRules {
-		validations.MergeValidations(in.runChecks(destinationRule))
+		validations.MergeValidations(in.runChecks(destinationRule, nsNames))
 	}
 
 	return validations
 }
 
-func (in DestinationRulesChecker) runChecks(destinationRule *networking_v1.DestinationRule) models.IstioValidations {
+func (in DestinationRulesChecker) runChecks(destinationRule *networking_v1.DestinationRule, nsNames []string) models.IstioValidations {
 	destinationRuleName := destinationRule.Name
 	key, rrValidation := EmptyValidValidation(destinationRuleName, destinationRule.Namespace, kubernetes.DestinationRules, in.Cluster)
 
@@ -65,7 +66,7 @@ func (in DestinationRulesChecker) runChecks(destinationRule *networking_v1.Desti
 		destinationrules.DisabledMeshWideMTLSChecker{DestinationRule: destinationRule, MeshPeerAuthns: in.MTLSDetails.MeshPeerAuthentications},
 	}
 	if !in.Namespaces.IsNamespaceAmbient(destinationRule.Namespace, in.Cluster) {
-		enabledCheckers = append(enabledCheckers, common.ExportToNamespaceChecker{ExportTo: destinationRule.Spec.ExportTo, Namespaces: in.Namespaces})
+		enabledCheckers = append(enabledCheckers, common.ExportToNamespaceChecker{ExportTo: destinationRule.Spec.ExportTo, Namespaces: nsNames})
 	}
 
 	enabledCheckers = append(enabledCheckers, destinationrules.NamespaceWideMTLSChecker{Conf: in.Conf, DestinationRule: destinationRule, MTLSDetails: in.MTLSDetails})
diff --git a/business/checkers/destinationrules/multi_match_checker.go b/business/checkers/destinationrules/multi_match_checker.go
index 8cd4ff971..fb11d895c 100644
--- a/business/checkers/destinationrules/multi_match_checker.go
+++ b/business/checkers/destinationrules/multi_match_checker.go
@@ -15,7 +15,7 @@ type MultiMatchChecker struct {
 	Cluster          string
 	Conf             *config.Config
 	DestinationRules []*networking_v1.DestinationRule
-	Namespaces       models.Namespaces
+	Namespaces       []string
 	ServiceEntries   map[string][]string
 }
 
@@ -40,7 +40,7 @@ func (m MultiMatchChecker) Check() models.IstioValidations {
 	for _, dr := range m.DestinationRules {
 		destinationRulesName := dr.Name
 		destinationRulesNamespace := dr.Namespace
-		fqdn := kubernetes.GetHost(dr.Spec.Host, dr.Namespace, m.Namespaces.GetNames(), m.Conf)
+		fqdn := kubernetes.GetHost(dr.Spec.Host, dr.Namespace, m.Namespaces, m.Conf)
 
 		// Skip DR validation if it enables mTLS either namespace or mesh-wide
 		if isNonLocalmTLSForServiceEnabled(dr, fqdn.String()) {
diff --git a/business/checkers/destinationrules/no_dest_checker.go b/business/checkers/destinationrules/no_dest_checker.go
index efecfbb49..a145ee25b 100644
--- a/business/checkers/destinationrules/no_dest_checker.go
+++ b/business/checkers/destinationrules/no_dest_checker.go
@@ -14,7 +14,7 @@ import (
 type NoDestinationChecker struct {
 	Conf                  *config.Config
 	DestinationRule       *networking_v1.DestinationRule
-	Namespaces            models.Namespaces
+	Namespaces            []string
 	PolicyAllowAny        bool
 	RegistryServices      []*kubernetes.RegistryService
 	ServiceEntries        []*networking_v1.ServiceEntry
@@ -30,7 +30,7 @@ func (n NoDestinationChecker) Check() ([]*models.IstioCheck, bool) {
 
 	namespace := n.DestinationRule.Namespace
 
-	fqdn := kubernetes.GetHost(n.DestinationRule.Spec.Host, namespace, n.Namespaces.GetNames(), n.Conf)
+	fqdn := kubernetes.GetHost(n.DestinationRule.Spec.Host, namespace, n.Namespaces, n.Conf)
 	// Testing Kubernetes Services + Istio ServiceEntries + Istio Runtime Registry (cross namespace)
 	if !n.hasMatchingService(fqdn, namespace) {
 		validation := models.Build("destinationrules.nodest.matchingregistry", "spec/host")
@@ -176,8 +176,8 @@ func (n NoDestinationChecker) getVirtualServices(virtualServiceHost string, virt
 						}
 						host := dest.Destination.Host
 						subset := dest.Destination.Subset
-						drHost := kubernetes.GetHost(host, n.DestinationRule.Namespace, n.Namespaces.GetNames(), n.Conf)
-						vsHost := kubernetes.GetHost(virtualServiceHost, virtualService.Namespace, n.Namespaces.GetNames(), n.Conf)
+						drHost := kubernetes.GetHost(host, n.DestinationRule.Namespace, n.Namespaces, n.Conf)
+						vsHost := kubernetes.GetHost(virtualServiceHost, virtualService.Namespace, n.Namespaces, n.Conf)
 						// Host could be in another namespace (FQDN)
 						if kubernetes.FilterByHost(vsHost.String(), vsHost.Namespace, drHost.Service, drHost.Namespace, n.Conf) && subset == virtualServiceSubset {
 							vss = append(vss, virtualService)
@@ -199,8 +199,8 @@ func (n NoDestinationChecker) getVirtualServices(virtualServiceHost string, virt
 						}
 						host := dest.Destination.Host
 						subset := dest.Destination.Subset
-						drHost := kubernetes.GetHost(host, n.DestinationRule.Namespace, n.Namespaces.GetNames(), n.Conf)
-						vsHost := kubernetes.GetHost(virtualServiceHost, virtualService.Namespace, n.Namespaces.GetNames(), n.Conf)
+						drHost := kubernetes.GetHost(host, n.DestinationRule.Namespace, n.Namespaces, n.Conf)
+						vsHost := kubernetes.GetHost(virtualServiceHost, virtualService.Namespace, n.Namespaces, n.Conf)
 						// Host could be in another namespace (FQDN)
 						if kubernetes.FilterByHost(vsHost.String(), vsHost.Namespace, drHost.Service, drHost.Namespace, n.Conf) && subset == virtualServiceSubset {
 							vss = append(vss, virtualService)
@@ -222,8 +222,8 @@ func (n NoDestinationChecker) getVirtualServices(virtualServiceHost string, virt
 						}
 						host := dest.Destination.Host
 						subset := dest.Destination.Subset
-						drHost := kubernetes.GetHost(host, n.DestinationRule.Namespace, n.Namespaces.GetNames(), n.Conf)
-						vsHost := kubernetes.GetHost(virtualServiceHost, virtualService.Namespace, n.Namespaces.GetNames(), n.Conf)
+						drHost := kubernetes.GetHost(host, n.DestinationRule.Namespace, n.Namespaces, n.Conf)
+						vsHost := kubernetes.GetHost(virtualServiceHost, virtualService.Namespace, n.Namespaces, n.Conf)
 						// Host could be in another namespace (FQDN)
 						if kubernetes.FilterByHost(vsHost.String(), vsHost.Namespace, drHost.Service, drHost.Namespace, n.Conf) && subset == virtualServiceSubset {
 							vss = append(vss, virtualService)
diff --git a/business/checkers/k8sgrpcroute_checker.go b/business/checkers/k8sgrpcroute_checker.go
index 08a6c0eed..5097575e0 100644
--- a/business/checkers/k8sgrpcroute_checker.go
+++ b/business/checkers/k8sgrpcroute_checker.go
@@ -55,7 +55,7 @@ func (in K8sGRPCRouteChecker) runChecks(rt *k8s_networking_v1.GRPCRoute, gateway
 		},
 		k8sgrpcroutes.NoHostChecker{
 			Conf:               in.Conf,
-			Namespaces:         in.Namespaces,
+			Namespaces:         in.Namespaces.GetNames(),
 			K8sGRPCRoute:       rt,
 			K8sReferenceGrants: in.K8sReferenceGrants,
 			RegistryServices:   in.RegistryServices,
diff --git a/business/checkers/k8sgrpcroutes/no_host_checker.go b/business/checkers/k8sgrpcroutes/no_host_checker.go
index c8261d269..436afe09c 100644
--- a/business/checkers/k8sgrpcroutes/no_host_checker.go
+++ b/business/checkers/k8sgrpcroutes/no_host_checker.go
@@ -16,7 +16,7 @@ type NoHostChecker struct {
 	Conf               *config.Config
 	K8sGRPCRoute       *k8s_networking_v1.GRPCRoute
 	K8sReferenceGrants []*k8s_networking_v1beta1.ReferenceGrant
-	Namespaces         models.Namespaces
+	Namespaces         []string
 	RegistryServices   []*kubernetes.RegistryService
 }
 
@@ -48,7 +48,7 @@ func (n NoHostChecker) checkReference(refNamespace *k8s_networking_v1.Namespace,
 	if refNamespace != nil && string(*refNamespace) != "" {
 		namespace = string(*refNamespace)
 	}
-	fqdn := kubernetes.GetHost(string(refName), namespace, n.Namespaces.GetNames(), n.Conf)
+	fqdn := kubernetes.GetHost(string(refName), namespace, n.Namespaces, n.Conf)
 	//service name should not be set in fqdn format
 	// if the grpc route is referencing to a service from the same namespace, then service should exist there
 	// if the grpc route is referencing to a service from other namespace, then a ReferenceGrant should exist to cross namespace reference, and the service should exist in remote namespace
diff --git a/business/checkers/k8shttproute_checker.go b/business/checkers/k8shttproute_checker.go
index 52ad40513..c08ba3bea 100644
--- a/business/checkers/k8shttproute_checker.go
+++ b/business/checkers/k8shttproute_checker.go
@@ -55,7 +55,7 @@ func (in K8sHTTPRouteChecker) runChecks(rt *k8s_networking_v1.HTTPRoute, gateway
 		},
 		k8shttproutes.NoHostChecker{
 			Conf:               in.Conf,
-			Namespaces:         in.Namespaces,
+			Namespaces:         in.Namespaces.GetNames(),
 			K8sHTTPRoute:       rt,
 			K8sReferenceGrants: in.K8sReferenceGrants,
 			RegistryServices:   in.RegistryServices,
diff --git a/business/checkers/k8shttproutes/no_host_checker.go b/business/checkers/k8shttproutes/no_host_checker.go
index 6529bf74b..5a623a14c 100644
--- a/business/checkers/k8shttproutes/no_host_checker.go
+++ b/business/checkers/k8shttproutes/no_host_checker.go
@@ -16,7 +16,7 @@ type NoHostChecker struct {
 	Conf               *config.Config
 	K8sHTTPRoute       *k8s_networking_v1.HTTPRoute
 	K8sReferenceGrants []*k8s_networking_v1beta1.ReferenceGrant
-	Namespaces         models.Namespaces
+	Namespaces         []string
 	RegistryServices   []*kubernetes.RegistryService
 }
 
@@ -48,7 +48,7 @@ func (n NoHostChecker) checkReference(refNamespace *k8s_networking_v1.Namespace,
 	if refNamespace != nil && string(*refNamespace) != "" {
 		namespace = string(*refNamespace)
 	}
-	fqdn := kubernetes.GetHost(string(refName), namespace, n.Namespaces.GetNames(), n.Conf)
+	fqdn := kubernetes.GetHost(string(refName), namespace, n.Namespaces, n.Conf)
 	//service name should not be set in fqdn format
 	// if the http route is referencing to a service from the same namespace, then service should exist there
 	// if the http route is referencing to a service from other namespace, then a ReferenceGrant should exist to cross namespace reference, and the service should exist in remote namespace
diff --git a/business/checkers/no_service_checker.go b/business/checkers/no_service_checker.go
index 23dde8f2a..36fd432d1 100644
--- a/business/checkers/no_service_checker.go
+++ b/business/checkers/no_service_checker.go
@@ -47,7 +47,7 @@ func runVirtualServiceCheck(virtualService *networking_v1.VirtualService, servic
 
 	result, valid := virtualservices.NoHostChecker{
 		Conf:              conf,
-		Namespaces:        clusterNamespaces,
+		Namespaces:        clusterNamespaces.GetNames(),
 		VirtualService:    virtualService,
 		ServiceEntryHosts: serviceHosts,
 		RegistryServices:  registryStatus,
@@ -82,7 +82,7 @@ func runDestinationRuleCheck(destinationRule *networking_v1.DestinationRule, wor
 
 	result, valid := destinationrules.NoDestinationChecker{
 		Conf:                  conf,
-		Namespaces:            clusterNamespaces,
+		Namespaces:            clusterNamespaces.GetNames(),
 		WorkloadsPerNamespace: workloads,
 		DestinationRule:       destinationRule,
 		VirtualServices:       virtualServices,
diff --git a/business/checkers/service_entry_checker.go b/business/checkers/service_entry_checker.go
index 8ac87d958..e37760aaa 100644
--- a/business/checkers/service_entry_checker.go
+++ b/business/checkers/service_entry_checker.go
@@ -35,7 +35,7 @@ func (s ServiceEntryChecker) runSingleChecks(se *networking_v1.ServiceEntry, wor
 		serviceentries.HasMatchingWorkloadEntryAddress{ServiceEntry: se, WorkloadEntries: workloadEntriesMap},
 	}
 	if !s.Namespaces.IsNamespaceAmbient(se.Namespace, s.Cluster) {
-		enabledCheckers = append(enabledCheckers, common.ExportToNamespaceChecker{ExportTo: se.Spec.ExportTo, Namespaces: s.Namespaces})
+		enabledCheckers = append(enabledCheckers, common.ExportToNamespaceChecker{ExportTo: se.Spec.ExportTo, Namespaces: s.Namespaces.GetNames()})
 	}
 
 	for _, checker := range enabledCheckers {
diff --git a/business/checkers/virtual_service_checker.go b/business/checkers/virtual_service_checker.go
index 0f92955be..74d364211 100644
--- a/business/checkers/virtual_service_checker.go
+++ b/business/checkers/virtual_service_checker.go
@@ -35,8 +35,10 @@ func (in VirtualServiceChecker) Check() models.IstioValidations {
 func (in VirtualServiceChecker) runIndividualChecks() models.IstioValidations {
 	validations := models.IstioValidations{}
 
+	nsNames := in.Namespaces.GetNames()
+	drSubsets := in.prepareSubsetMap(nsNames)
 	for _, virtualService := range in.VirtualServices {
-		validations.MergeValidations(in.runChecks(virtualService))
+		validations.MergeValidations(in.runChecks(virtualService, nsNames, drSubsets))
 	}
 
 	return validations
@@ -47,7 +49,7 @@ func (in VirtualServiceChecker) runGroupChecks() models.IstioValidations {
 	validations := models.IstioValidations{}
 
 	enabledCheckers := []GroupChecker{
-		virtualservices.SingleHostChecker{Conf: in.Conf, Namespaces: in.Namespaces, VirtualServices: in.VirtualServices, Cluster: in.Cluster},
+		virtualservices.SingleHostChecker{Conf: in.Conf, Namespaces: in.Namespaces.GetNames(), VirtualServices: in.VirtualServices, Cluster: in.Cluster},
 	}
 
 	for _, checker := range enabledCheckers {
@@ -58,16 +60,16 @@ func (in VirtualServiceChecker) runGroupChecks() models.IstioValidations {
 }
 
 // runChecks runs all the individual checks for a single virtual service and appends the result into validations.
-func (in VirtualServiceChecker) runChecks(virtualService *networking_v1.VirtualService) models.IstioValidations {
+func (in VirtualServiceChecker) runChecks(virtualService *networking_v1.VirtualService, nsNames []string, drSubsets models.DestinationRuleSubsets) models.IstioValidations {
 	virtualServiceName := virtualService.Name
 	key, rrValidation := EmptyValidValidation(virtualServiceName, virtualService.Namespace, kubernetes.VirtualServices, in.Cluster)
 
 	enabledCheckers := []Checker{
-		virtualservices.RouteChecker{Conf: in.Conf, VirtualService: virtualService, Namespaces: in.Namespaces.GetNames()},
-		virtualservices.SubsetPresenceChecker{Conf: in.Conf, Namespaces: in.Namespaces.GetNames(), VirtualService: virtualService, DestinationRules: in.DestinationRules},
+		virtualservices.RouteChecker{Conf: in.Conf, VirtualService: virtualService, Namespaces: nsNames},
+		virtualservices.SubsetPresenceChecker{Conf: in.Conf, Namespaces: nsNames, VirtualService: virtualService, DRSubsets: drSubsets},
 	}
 	if !in.Namespaces.IsNamespaceAmbient(virtualService.Namespace, in.Cluster) {
-		enabledCheckers = append(enabledCheckers, common.ExportToNamespaceChecker{ExportTo: virtualService.Spec.ExportTo, Namespaces: in.Namespaces})
+		enabledCheckers = append(enabledCheckers, common.ExportToNamespaceChecker{ExportTo: virtualService.Spec.ExportTo, Namespaces: nsNames})
 	}
 
 	for _, checker := range enabledCheckers {
@@ -78,3 +80,24 @@ func (in VirtualServiceChecker) runChecks(virtualService *networking_v1.VirtualS
 
 	return models.IstioValidations{key: rrValidation}
 }
+
+func (in VirtualServiceChecker) prepareSubsetMap(namespaces []string) models.DestinationRuleSubsets {
+	subsetMap := make(models.DestinationRuleSubsets)
+
+	for _, dr := range in.DestinationRules {
+		host := dr.Spec.Host
+		drHost := kubernetes.GetHost(host, dr.Namespace, namespaces, in.Conf)
+
+		if _, exists := subsetMap[drHost.String()]; !exists {
+			subsetMap[drHost.String()] = make(map[string]kubernetes.Host)
+		}
+
+		for _, subset := range dr.Spec.Subsets {
+			if subset != nil {
+				subsetMap[drHost.String()][subset.Name] = drHost
+			}
+		}
+	}
+
+	return subsetMap
+}
diff --git a/business/checkers/virtualservices/no_host_checker.go b/business/checkers/virtualservices/no_host_checker.go
index e6e90ffa1..ce56c55ef 100644
--- a/business/checkers/virtualservices/no_host_checker.go
+++ b/business/checkers/virtualservices/no_host_checker.go
@@ -13,7 +13,7 @@ import (
 
 type NoHostChecker struct {
 	Conf              *config.Config
-	Namespaces        models.Namespaces
+	Namespaces        []string
 	PolicyAllowAny    bool
 	RegistryServices  []*kubernetes.RegistryService
 	ServiceEntryHosts map[string][]string
@@ -33,7 +33,7 @@ func (n NoHostChecker) Check() ([]*models.IstioCheck, bool) {
 					if host == "" {
 						continue
 					}
-					fqdn := kubernetes.GetHost(host, namespace, n.Namespaces.GetNames(), n.Conf)
+					fqdn := kubernetes.GetHost(host, namespace, n.Namespaces, n.Conf)
 					if !n.checkDestination(fqdn.String(), namespace) {
 						path := fmt.Sprintf("spec/http[%d]/route[%d]/destination/host", k, i)
 						validation := models.Build("virtualservices.nohost.hostnotfound", path)
@@ -56,7 +56,7 @@ func (n NoHostChecker) Check() ([]*models.IstioCheck, bool) {
 					if host == "" {
 						continue
 					}
-					fqdn := kubernetes.GetHost(host, namespace, n.Namespaces.GetNames(), n.Conf)
+					fqdn := kubernetes.GetHost(host, namespace, n.Namespaces, n.Conf)
 					if !n.checkDestination(fqdn.String(), namespace) {
 						path := fmt.Sprintf("spec/tcp[%d]/route[%d]/destination/host", k, i)
 						validation := models.Build("virtualservices.nohost.hostnotfound", path)
@@ -79,7 +79,7 @@ func (n NoHostChecker) Check() ([]*models.IstioCheck, bool) {
 					if host == "" {
 						continue
 					}
-					fqdn := kubernetes.GetHost(host, namespace, n.Namespaces.GetNames(), n.Conf)
+					fqdn := kubernetes.GetHost(host, namespace, n.Namespaces, n.Conf)
 					if !n.checkDestination(fqdn.String(), namespace) {
 						path := fmt.Sprintf("spec/tls[%d]/route[%d]/destination/host", k, i)
 						validation := models.Build("virtualservices.nohost.hostnotfound", path)
diff --git a/business/checkers/virtualservices/single_host_checker.go b/business/checkers/virtualservices/single_host_checker.go
index 9c031d7e1..8c0898492 100644
--- a/business/checkers/virtualservices/single_host_checker.go
+++ b/business/checkers/virtualservices/single_host_checker.go
@@ -11,7 +11,7 @@ import (
 type SingleHostChecker struct {
 	Cluster         string
 	Conf            *config.Config
-	Namespaces      models.Namespaces
+	Namespaces      []string
 	VirtualServices []*networking_v1.VirtualService
 }
 
@@ -150,7 +150,7 @@ func (s SingleHostChecker) getHosts(virtualService *networking_v1.VirtualService
 	targetHosts := make([]kubernetes.Host, 0, len(virtualService.Spec.Hosts))
 
 	for _, hostName := range virtualService.Spec.Hosts {
-		targetHosts = append(targetHosts, kubernetes.GetHost(hostName, namespace, s.Namespaces.GetNames(), s.Conf))
+		targetHosts = append(targetHosts, kubernetes.GetHost(hostName, namespace, s.Namespaces, s.Conf))
 	}
 	return targetHosts
 }
diff --git a/business/checkers/virtualservices/subset_presence_checker.go b/business/checkers/virtualservices/subset_presence_checker.go
index b63c5fad2..ec9b82a22 100644
--- a/business/checkers/virtualservices/subset_presence_checker.go
+++ b/business/checkers/virtualservices/subset_presence_checker.go
@@ -11,10 +11,10 @@ import (
 )
 
 type SubsetPresenceChecker struct {
-	Conf             *config.Config
-	DestinationRules []*networking_v1.DestinationRule
-	Namespaces       []string
-	VirtualService   *networking_v1.VirtualService
+	Conf           *config.Config
+	DRSubsets      models.DestinationRuleSubsets
+	Namespaces     []string
+	VirtualService *networking_v1.VirtualService
 }
 
 func (checker SubsetPresenceChecker) Check() ([]*models.IstioCheck, bool) {
@@ -97,45 +97,15 @@ func (checker SubsetPresenceChecker) Check() ([]*models.IstioCheck, bool) {
 }
 
 func (checker SubsetPresenceChecker) subsetPresent(host string, subset string) bool {
-	destinationRules, ok := checker.getDestinationRules(host)
-	if !ok || destinationRules == nil || len(destinationRules) == 0 {
-		return false
-	}
-
-	for _, dr := range destinationRules {
-		if hasSubsetDefined(dr, subset) {
-			return true
-		}
-	}
-	return false
-}
-
-func (checker SubsetPresenceChecker) getDestinationRules(virtualServiceHost string) ([]*networking_v1.DestinationRule, bool) {
-	drs := make([]*networking_v1.DestinationRule, 0, len(checker.DestinationRules))
-
-	for _, destinationRule := range checker.DestinationRules {
-		host := destinationRule.Spec.Host
+	vsHost := kubernetes.GetHost(host, checker.VirtualService.Namespace, checker.Namespaces, checker.Conf)
 
-		drHost := kubernetes.GetHost(host, destinationRule.Namespace, checker.Namespaces, checker.Conf)
-		vsHost := kubernetes.GetHost(virtualServiceHost, checker.VirtualService.Namespace, checker.Namespaces, checker.Conf)
-
-		// TODO Host could be in another namespace (FQDN)
-		if kubernetes.FilterByHost(vsHost.String(), vsHost.Namespace, drHost.Service, drHost.Namespace, checker.Conf) {
-			drs = append(drs, destinationRule)
+	if subsets, exists := checker.DRSubsets[vsHost.String()]; exists {
+		if drHost, hostExists := subsets[subset]; hostExists {
+			if kubernetes.FilterByHost(vsHost.String(), vsHost.Namespace, drHost.Service, drHost.Namespace, checker.Conf) {
+				return true
+			}
 		}
 	}
 
-	return drs, len(drs) > 0
-}
-
-func hasSubsetDefined(destinationRule *networking_v1.DestinationRule, subsetTarget string) bool {
-	for _, subset := range destinationRule.Spec.Subsets {
-		if subset == nil {
-			continue
-		}
-		if subset.Name == subsetTarget {
-			return true
-		}
-	}
 	return false
 }
diff --git a/business/istio_config.go b/business/istio_config.go
index 37b0a5c9a..eb019b763 100644
--- a/business/istio_config.go
+++ b/business/istio_config.go
@@ -983,16 +983,8 @@ func (in *IstioConfigService) CreateIstioConfigDetail(ctx context.Context, clust
 	return istioConfigDetail, nil
 }
 
-func (in *IstioConfigService) IsGatewayAPI(cluster string) bool {
-	return in.userClients[cluster].IsGatewayAPI()
-}
-
 func (in *IstioConfigService) GatewayAPIClasses(cluster string) []config.GatewayAPIClass {
-	return kubernetes.GatewayAPIClasses(in.IsAmbientEnabled(cluster), in.conf)
-}
-
-func (in *IstioConfigService) IsAmbientEnabled(cluster string) bool {
-	return in.kialiCache.IsAmbientEnabled(cluster)
+	return kubernetes.GatewayAPIClasses(in.kialiCache.IsAmbientEnabled(cluster), in.conf)
 }
 
 func (in *IstioConfigService) GetIstioConfigPermissions(ctx context.Context, namespaces []string, cluster string) models.IstioConfigPermissions {
diff --git a/business/istio_validations.go b/business/istio_validations.go
index b29383f2b..0527119c8 100644
--- a/business/istio_validations.go
+++ b/business/istio_validations.go
@@ -310,7 +310,7 @@ func (in *IstioValidationsService) Validate(ctx context.Context, cluster string,
 	}
 	vInfo.clusterInfo.istioConfig = istioConfigList
 
-	// if change detection is enabled then decide if we need to run the checkers
+	//if change detection is enabled then decide if we need to run the checkers
 	if vInfo.changeDetectionEnabled() {
 		changeDetected := detectClusterConfigChange(vInfo)
 		if !changeDetected && !vInfo.forceCheckers() {
@@ -456,6 +456,7 @@ func detectClusterConfigChange(vInfo *validationInfo) bool {
 func (in *IstioValidationsService) getAllObjectCheckers(vInfo *validationInfo) []checkers.ObjectChecker {
 	cluster := vInfo.clusterInfo.cluster
 	namespaces := vInfo.nsMap[cluster]
+	nsNames := getNsNames(namespaces)
 	istioConfigList := vInfo.nsInfo.istioConfig
 	workloadsPerNamespace := vInfo.wlMap[cluster]
 	mtlsDetails := vInfo.nsInfo.mtlsDetails
@@ -464,7 +465,7 @@ func (in *IstioValidationsService) getAllObjectCheckers(vInfo *validationInfo) [
 	conf := in.conf
 
 	return []checkers.ObjectChecker{
-		checkers.AuthorizationPolicyChecker{Conf: conf, AuthorizationPolicies: rbacDetails.AuthorizationPolicies, Namespaces: namespaces, ServiceEntries: istioConfigList.ServiceEntries, WorkloadsPerNamespace: workloadsPerNamespace, MtlsDetails: *mtlsDetails, VirtualServices: istioConfigList.VirtualServices, RegistryServices: registryServices, PolicyAllowAny: in.isPolicyAllowAny(vInfo.mesh), Cluster: cluster, ServiceAccounts: vInfo.saMap},
+		checkers.AuthorizationPolicyChecker{Conf: conf, AuthorizationPolicies: rbacDetails.AuthorizationPolicies, Namespaces: nsNames, ServiceEntries: istioConfigList.ServiceEntries, WorkloadsPerNamespace: workloadsPerNamespace, MtlsDetails: *mtlsDetails, VirtualServices: istioConfigList.VirtualServices, RegistryServices: registryServices, PolicyAllowAny: in.isPolicyAllowAny(vInfo.mesh), Cluster: cluster, ServiceAccounts: vInfo.saMap},
 		checkers.DestinationRulesChecker{Conf: conf, Namespaces: namespaces, DestinationRules: istioConfigList.DestinationRules, MTLSDetails: *mtlsDetails, ServiceEntries: istioConfigList.ServiceEntries, Cluster: cluster},
 		checkers.GatewayChecker{Conf: conf, Gateways: istioConfigList.Gateways, WorkloadsPerNamespace: workloadsPerNamespace, IsGatewayToNamespace: in.isGatewayToNamespace(vInfo.mesh), Cluster: cluster},
 		checkers.K8sGatewayChecker{K8sGateways: istioConfigList.K8sGateways, Cluster: cluster, GatewayClasses: in.istioConfig.GatewayAPIClasses(cluster)},
@@ -559,6 +560,7 @@ func (in *IstioValidationsService) ValidateIstioObject(ctx context.Context, clus
 	}
 
 	namespaces := vInfo.nsMap[cluster]
+	nsNames := getNsNames(namespaces)
 	istioConfigList := vInfo.nsInfo.istioConfig
 	workloadsPerNamespace := vInfo.wlMap[cluster]
 	mtlsDetails := vInfo.nsInfo.mtlsDetails
@@ -579,15 +581,15 @@ func (in *IstioValidationsService) ValidateIstioObject(ctx context.Context, clus
 	case kubernetes.VirtualServices:
 		virtualServiceChecker := checkers.VirtualServiceChecker{Conf: conf, Cluster: cluster, Namespaces: namespaces, VirtualServices: istioConfigList.VirtualServices, DestinationRules: istioConfigList.DestinationRules}
 		objectCheckers = []checkers.ObjectChecker{noServiceChecker, virtualServiceChecker}
-		referenceChecker = references.VirtualServiceReferences{Conf: conf, Namespace: namespace, Namespaces: namespaces, VirtualServices: istioConfigList.VirtualServices, DestinationRules: istioConfigList.DestinationRules, AuthorizationPolicies: rbacDetails.AuthorizationPolicies}
+		referenceChecker = references.VirtualServiceReferences{Conf: conf, Namespace: namespace, Namespaces: nsNames, VirtualServices: istioConfigList.VirtualServices, DestinationRules: istioConfigList.DestinationRules, AuthorizationPolicies: rbacDetails.AuthorizationPolicies}
 	case kubernetes.DestinationRules:
 		destinationRulesChecker := checkers.DestinationRulesChecker{Conf: conf, Cluster: cluster, Namespaces: namespaces, DestinationRules: istioConfigList.DestinationRules, MTLSDetails: *mtlsDetails, ServiceEntries: istioConfigList.ServiceEntries}
 		objectCheckers = []checkers.ObjectChecker{noServiceChecker, destinationRulesChecker}
-		referenceChecker = references.DestinationRuleReferences{Conf: conf, Namespace: namespace, Namespaces: namespaces, DestinationRules: istioConfigList.DestinationRules, VirtualServices: istioConfigList.VirtualServices, WorkloadsPerNamespace: workloadsPerNamespace, ServiceEntries: istioConfigList.ServiceEntries, RegistryServices: registryServices}
+		referenceChecker = references.DestinationRuleReferences{Conf: conf, Namespace: namespace, Namespaces: nsNames, DestinationRules: istioConfigList.DestinationRules, VirtualServices: istioConfigList.VirtualServices, WorkloadsPerNamespace: workloadsPerNamespace, ServiceEntries: istioConfigList.ServiceEntries, RegistryServices: registryServices}
 	case kubernetes.ServiceEntries:
 		serviceEntryChecker := checkers.ServiceEntryChecker{Cluster: cluster, ServiceEntries: istioConfigList.ServiceEntries, Namespaces: namespaces, WorkloadEntries: istioConfigList.WorkloadEntries}
 		objectCheckers = []checkers.ObjectChecker{serviceEntryChecker}
-		referenceChecker = references.ServiceEntryReferences{Conf: conf, AuthorizationPolicies: rbacDetails.AuthorizationPolicies, Namespace: namespace, Namespaces: namespaces, DestinationRules: istioConfigList.DestinationRules, ServiceEntries: istioConfigList.ServiceEntries, Sidecars: istioConfigList.Sidecars, RegistryServices: registryServices}
+		referenceChecker = references.ServiceEntryReferences{Conf: conf, AuthorizationPolicies: rbacDetails.AuthorizationPolicies, Namespace: namespace, Namespaces: nsNames, DestinationRules: istioConfigList.DestinationRules, ServiceEntries: istioConfigList.ServiceEntries, Sidecars: istioConfigList.Sidecars, RegistryServices: registryServices}
 	case kubernetes.Sidecars:
 		sidecarsChecker := checkers.SidecarChecker{Conf: conf,
 			Cluster: cluster, Sidecars: istioConfigList.Sidecars, Namespaces: namespaces,
@@ -599,11 +601,11 @@ func (in *IstioValidationsService) ValidateIstioObject(ctx context.Context, clus
 		authPoliciesChecker := checkers.AuthorizationPolicyChecker{
 			Conf:                  conf,
 			AuthorizationPolicies: rbacDetails.AuthorizationPolicies,
-			Cluster:               cluster, Namespaces: namespaces, ServiceEntries: istioConfigList.ServiceEntries, ServiceAccounts: vInfo.saMap,
+			Cluster:               cluster, Namespaces: nsNames, ServiceEntries: istioConfigList.ServiceEntries, ServiceAccounts: vInfo.saMap,
 			WorkloadsPerNamespace: workloadsPerNamespace, MtlsDetails: *mtlsDetails, VirtualServices: istioConfigList.VirtualServices, RegistryServices: registryServices, PolicyAllowAny: in.isPolicyAllowAny(vInfo.mesh),
 		}
 		objectCheckers = []checkers.ObjectChecker{authPoliciesChecker}
-		referenceChecker = references.AuthorizationPolicyReferences{Conf: conf, AuthorizationPolicies: rbacDetails.AuthorizationPolicies, Namespace: namespace, Namespaces: namespaces, VirtualServices: istioConfigList.VirtualServices, ServiceEntries: istioConfigList.ServiceEntries, RegistryServices: registryServices, WorkloadsPerNamespace: workloadsPerNamespace}
+		referenceChecker = references.AuthorizationPolicyReferences{Conf: conf, AuthorizationPolicies: rbacDetails.AuthorizationPolicies, Namespace: namespace, Namespaces: nsNames, VirtualServices: istioConfigList.VirtualServices, ServiceEntries: istioConfigList.ServiceEntries, RegistryServices: registryServices, WorkloadsPerNamespace: workloadsPerNamespace}
 	case kubernetes.PeerAuthentications:
 		// Validations on PeerAuthentications
 		peerAuthnChecker := checkers.PeerAuthenticationChecker{Conf: conf, Cluster: cluster, PeerAuthentications: mtlsDetails.PeerAuthentications, MTLSDetails: *mtlsDetails, WorkloadsPerNamespace: workloadsPerNamespace}
@@ -637,11 +639,11 @@ func (in *IstioValidationsService) ValidateIstioObject(ctx context.Context, clus
 	case kubernetes.K8sGRPCRoutes:
 		grpcRouteChecker := checkers.K8sGRPCRouteChecker{Conf: conf, Cluster: cluster, K8sGRPCRoutes: istioConfigList.K8sGRPCRoutes, K8sGateways: istioConfigList.K8sGateways, K8sReferenceGrants: istioConfigList.K8sReferenceGrants, Namespaces: namespaces, RegistryServices: registryServices}
 		objectCheckers = []checkers.ObjectChecker{noServiceChecker, grpcRouteChecker}
-		referenceChecker = references.K8sGRPCRouteReferences{Conf: conf, K8sGRPCRoutes: istioConfigList.K8sGRPCRoutes, Namespaces: namespaces, K8sReferenceGrants: istioConfigList.K8sReferenceGrants}
+		referenceChecker = references.K8sGRPCRouteReferences{Conf: conf, K8sGRPCRoutes: istioConfigList.K8sGRPCRoutes, Namespaces: nsNames, K8sReferenceGrants: istioConfigList.K8sReferenceGrants}
 	case kubernetes.K8sHTTPRoutes:
 		httpRouteChecker := checkers.K8sHTTPRouteChecker{Conf: conf, Cluster: cluster, K8sHTTPRoutes: istioConfigList.K8sHTTPRoutes, K8sGateways: istioConfigList.K8sGateways, K8sReferenceGrants: istioConfigList.K8sReferenceGrants, Namespaces: namespaces, RegistryServices: registryServices}
 		objectCheckers = []checkers.ObjectChecker{noServiceChecker, httpRouteChecker}
-		referenceChecker = references.K8sHTTPRouteReferences{Conf: conf, K8sHTTPRoutes: istioConfigList.K8sHTTPRoutes, Namespaces: namespaces, K8sReferenceGrants: istioConfigList.K8sReferenceGrants}
+		referenceChecker = references.K8sHTTPRouteReferences{Conf: conf, K8sHTTPRoutes: istioConfigList.K8sHTTPRoutes, Namespaces: nsNames, K8sReferenceGrants: istioConfigList.K8sReferenceGrants}
 	case kubernetes.K8sReferenceGrants:
 		objectCheckers = []checkers.ObjectChecker{
 			checkers.K8sReferenceGrantChecker{Cluster: cluster, K8sReferenceGrants: istioConfigList.K8sReferenceGrants, Namespaces: namespaces},
@@ -932,3 +934,11 @@ func isAmbient(namespaces []models.Namespace, namespace string) bool {
 	ns := sliceutil.Find(namespaces, func(ns models.Namespace) bool { return ns.Name == namespace })
 	return ns != nil && ns.IsAmbient
 }
+
+func getNsNames(nss []models.Namespace) []string {
+	names := make([]string, len(nss))
+	for _, ns := range nss {
+		names = append(names, ns.Name)
+	}
+	return names
+}
diff --git a/business/references/auth_policy_references.go b/business/references/auth_policy_references.go
index 83a100ada..ab707ade9 100644
--- a/business/references/auth_policy_references.go
+++ b/business/references/auth_policy_references.go
@@ -15,7 +15,7 @@ type AuthorizationPolicyReferences struct {
 	AuthorizationPolicies []*security_v1.AuthorizationPolicy
 	Conf                  *config.Config
 	Namespace             string
-	Namespaces            models.Namespaces
+	Namespaces            []string
 	ServiceEntries        []*networking_v1.ServiceEntry
 	VirtualServices       []*networking_v1.VirtualService
 	RegistryServices      []*kubernetes.RegistryService
@@ -39,7 +39,7 @@ func (n AuthorizationPolicyReferences) References() models.IstioReferencesMap {
 						continue
 					}
 					for _, h := range t.Operation.Hosts {
-						fqdn := kubernetes.GetHost(h, namespace, n.Namespaces.GetNames(), n.Conf)
+						fqdn := kubernetes.GetHost(h, namespace, n.Namespaces, n.Conf)
 						if !fqdn.IsWildcard() {
 							configRef := n.getConfigReferences(fqdn)
 							references.ObjectReferences = append(references.ObjectReferences, configRef...)
diff --git a/business/references/destination_rule_references.go b/business/references/destination_rule_references.go
index f68e9e33a..f4847c4fe 100644
--- a/business/references/destination_rule_references.go
+++ b/business/references/destination_rule_references.go
@@ -15,7 +15,7 @@ type DestinationRuleReferences struct {
 	Conf                  *config.Config
 	DestinationRules      []*networking_v1.DestinationRule
 	Namespace             string
-	Namespaces            models.Namespaces
+	Namespaces            []string
 	RegistryServices      []*kubernetes.RegistryService
 	ServiceEntries        []*networking_v1.ServiceEntry
 	VirtualServices       []*networking_v1.VirtualService
@@ -44,7 +44,7 @@ func (n DestinationRuleReferences) References() models.IstioReferencesMap {
 func (n DestinationRuleReferences) getServiceReferences(dr *networking_v1.DestinationRule) []models.ServiceReference {
 	result := make([]models.ServiceReference, 0)
 
-	fqdn := kubernetes.GetHost(dr.Spec.Host, dr.Namespace, n.Namespaces.GetNames(), n.Conf)
+	fqdn := kubernetes.GetHost(dr.Spec.Host, dr.Namespace, n.Namespaces, n.Conf)
 	if !fqdn.IsWildcard() && kubernetes.HasMatchingRegistryService(dr.Namespace, fqdn.String(), n.RegistryServices) {
 		result = append(result, models.ServiceReference{Name: fqdn.Service, Namespace: fqdn.Namespace})
 	}
@@ -56,7 +56,7 @@ func (n DestinationRuleReferences) getWorkloadReferences(dr *networking_v1.Desti
 	allWorkloads := make([]models.WorkloadReference, 0)
 	result := make([]models.WorkloadReference, 0)
 
-	host := kubernetes.GetHost(dr.Spec.Host, dr.Namespace, n.Namespaces.GetNames(), n.Conf)
+	host := kubernetes.GetHost(dr.Spec.Host, dr.Namespace, n.Namespaces, n.Conf)
 	if host.IsWildcard() {
 		return result
 	}
@@ -109,7 +109,7 @@ func (n DestinationRuleReferences) getWorkloadReferences(dr *networking_v1.Desti
 func (n DestinationRuleReferences) getSEReferences(dr *networking_v1.DestinationRule) []models.IstioReference {
 	result := make([]models.IstioReference, 0)
 
-	fqdn := kubernetes.GetHost(dr.Spec.Host, dr.Namespace, n.Namespaces.GetNames(), n.Conf)
+	fqdn := kubernetes.GetHost(dr.Spec.Host, dr.Namespace, n.Namespaces, n.Conf)
 	if !fqdn.IsWildcard() {
 		for _, se := range n.ServiceEntries {
 			for _, seHost := range se.Spec.Hosts {
@@ -143,8 +143,8 @@ func (n DestinationRuleReferences) getConfigReferences(dr *networking_v1.Destina
 									continue
 								}
 								host := dest.Destination.Host
-								drHost := kubernetes.GetHost(host, dr.Namespace, n.Namespaces.GetNames(), n.Conf)
-								vsHost := kubernetes.GetHost(dr.Spec.Host, virtualService.Namespace, n.Namespaces.GetNames(), n.Conf)
+								drHost := kubernetes.GetHost(host, dr.Namespace, n.Namespaces, n.Conf)
+								vsHost := kubernetes.GetHost(dr.Spec.Host, virtualService.Namespace, n.Namespaces, n.Conf)
 								if kubernetes.FilterByHost(vsHost.String(), vsHost.Namespace, drHost.Service, drHost.Namespace, n.Conf) {
 									allConfigs = append(allConfigs, models.IstioReference{Name: virtualService.Name, Namespace: virtualService.Namespace, ObjectGVK: kubernetes.VirtualServices})
 								}
@@ -164,8 +164,8 @@ func (n DestinationRuleReferences) getConfigReferences(dr *networking_v1.Destina
 									continue
 								}
 								host := dest.Destination.Host
-								drHost := kubernetes.GetHost(host, dr.Namespace, n.Namespaces.GetNames(), n.Conf)
-								vsHost := kubernetes.GetHost(dr.Spec.Host, virtualService.Namespace, n.Namespaces.GetNames(), n.Conf)
+								drHost := kubernetes.GetHost(host, dr.Namespace, n.Namespaces, n.Conf)
+								vsHost := kubernetes.GetHost(dr.Spec.Host, virtualService.Namespace, n.Namespaces, n.Conf)
 								if kubernetes.FilterByHost(vsHost.String(), vsHost.Namespace, drHost.Service, drHost.Namespace, n.Conf) {
 									allConfigs = append(allConfigs, models.IstioReference{Name: virtualService.Name, Namespace: virtualService.Namespace, ObjectGVK: kubernetes.VirtualServices})
 								}
@@ -185,8 +185,8 @@ func (n DestinationRuleReferences) getConfigReferences(dr *networking_v1.Destina
 									continue
 								}
 								host := dest.Destination.Host
-								drHost := kubernetes.GetHost(host, dr.Namespace, n.Namespaces.GetNames(), n.Conf)
-								vsHost := kubernetes.GetHost(dr.Spec.Host, virtualService.Namespace, n.Namespaces.GetNames(), n.Conf)
+								drHost := kubernetes.GetHost(host, dr.Namespace, n.Namespaces, n.Conf)
+								vsHost := kubernetes.GetHost(dr.Spec.Host, virtualService.Namespace, n.Namespaces, n.Conf)
 								if kubernetes.FilterByHost(vsHost.String(), vsHost.Namespace, drHost.Service, drHost.Namespace, n.Conf) {
 									allConfigs = append(allConfigs, models.IstioReference{Name: virtualService.Name, Namespace: virtualService.Namespace, ObjectGVK: kubernetes.VirtualServices})
 								}
diff --git a/business/references/k8sgrpcroute_references.go b/business/references/k8sgrpcroute_references.go
index 225d5bbb4..53166ab14 100644
--- a/business/references/k8sgrpcroute_references.go
+++ b/business/references/k8sgrpcroute_references.go
@@ -14,7 +14,7 @@ type K8sGRPCRouteReferences struct {
 	Conf               *config.Config
 	K8sGRPCRoutes      []*k8s_networking_v1.GRPCRoute
 	K8sReferenceGrants []*k8s_networking_v1beta1.ReferenceGrant
-	Namespaces         models.Namespaces
+	Namespaces         []string
 }
 
 func (n K8sGRPCRouteReferences) References() models.IstioReferencesMap {
@@ -45,7 +45,7 @@ func (n K8sGRPCRouteReferences) getServiceReferences(rt *k8s_networking_v1.GRPCR
 			if ref.Namespace != nil && string(*ref.Namespace) != "" {
 				namespace = string(*ref.Namespace)
 			}
-			fqdn := kubernetes.GetHost(string(ref.Name), namespace, n.Namespaces.GetNames(), n.Conf)
+			fqdn := kubernetes.GetHost(string(ref.Name), namespace, n.Namespaces, n.Conf)
 			if !fqdn.IsWildcard() {
 				allServices = append(allServices, models.ServiceReference{Name: fqdn.Service, Namespace: fqdn.Namespace})
 			}
diff --git a/business/references/k8shttproute_references.go b/business/references/k8shttproute_references.go
index 55000e16e..7e6ca423b 100644
--- a/business/references/k8shttproute_references.go
+++ b/business/references/k8shttproute_references.go
@@ -14,7 +14,7 @@ type K8sHTTPRouteReferences struct {
 	Conf               *config.Config
 	K8sHTTPRoutes      []*k8s_networking_v1.HTTPRoute
 	K8sReferenceGrants []*k8s_networking_v1beta1.ReferenceGrant
-	Namespaces         models.Namespaces
+	Namespaces         []string
 }
 
 func (n K8sHTTPRouteReferences) References() models.IstioReferencesMap {
@@ -45,7 +45,7 @@ func (n K8sHTTPRouteReferences) getServiceReferences(rt *k8s_networking_v1.HTTPR
 			if ref.Namespace != nil && string(*ref.Namespace) != "" {
 				namespace = string(*ref.Namespace)
 			}
-			fqdn := kubernetes.GetHost(string(ref.Name), namespace, n.Namespaces.GetNames(), n.Conf)
+			fqdn := kubernetes.GetHost(string(ref.Name), namespace, n.Namespaces, n.Conf)
 			if !fqdn.IsWildcard() {
 				allServices = append(allServices, models.ServiceReference{Name: fqdn.Service, Namespace: fqdn.Namespace})
 			}
diff --git a/business/references/service_entry_references.go b/business/references/service_entry_references.go
index 92ed3719c..87d3b55ae 100644
--- a/business/references/service_entry_references.go
+++ b/business/references/service_entry_references.go
@@ -13,7 +13,7 @@ import (
 type ServiceEntryReferences struct {
 	Conf                  *config.Config
 	Namespace             string
-	Namespaces            models.Namespaces
+	Namespaces            []string
 	ServiceEntries        []*networking_v1.ServiceEntry
 	Sidecars              []*networking_v1.Sidecar
 	AuthorizationPolicies []*security_v1.AuthorizationPolicy
@@ -39,7 +39,7 @@ func (n ServiceEntryReferences) References() models.IstioReferencesMap {
 func (n ServiceEntryReferences) getConfigReferences(se *networking_v1.ServiceEntry) []models.IstioReference {
 	result := make([]models.IstioReference, 0)
 	for _, dr := range n.DestinationRules {
-		fqdn := kubernetes.GetHost(dr.Spec.Host, dr.Namespace, n.Namespaces.GetNames(), n.Conf)
+		fqdn := kubernetes.GetHost(dr.Spec.Host, dr.Namespace, n.Namespaces, n.Conf)
 		if !fqdn.IsWildcard() {
 			for _, seHost := range se.Spec.Hosts {
 				if seHost == fqdn.String() {
@@ -93,7 +93,7 @@ func (n ServiceEntryReferences) getAuthPoliciesReferences(se *networking_v1.Serv
 						continue
 					}
 					for _, h := range t.Operation.Hosts {
-						fqdn := kubernetes.GetHost(h, namespace, n.Namespaces.GetNames(), n.Conf)
+						fqdn := kubernetes.GetHost(h, namespace, n.Namespaces, n.Conf)
 						if !fqdn.IsWildcard() {
 							for _, seHost := range se.Spec.Hosts {
 								if seHost == fqdn.String() {
diff --git a/business/references/virtual_service_references.go b/business/references/virtual_service_references.go
index 1a2cace0e..e9f11f823 100644
--- a/business/references/virtual_service_references.go
+++ b/business/references/virtual_service_references.go
@@ -15,7 +15,7 @@ type VirtualServiceReferences struct {
 	Conf                  *config.Config
 	DestinationRules      []*networking_v1.DestinationRule
 	Namespace             string
-	Namespaces            models.Namespaces
+	Namespaces            []string
 	VirtualServices       []*networking_v1.VirtualService
 }
 
@@ -47,7 +47,7 @@ func (n VirtualServiceReferences) getServiceReferences(vs *networking_v1.Virtual
 					if host == "" {
 						continue
 					}
-					fqdn := kubernetes.GetHost(host, namespace, n.Namespaces.GetNames(), n.Conf)
+					fqdn := kubernetes.GetHost(host, namespace, n.Namespaces, n.Conf)
 					if !fqdn.IsWildcard() {
 						allServices = append(allServices, models.ServiceReference{Name: fqdn.Service, Namespace: fqdn.Namespace})
 					}
@@ -64,7 +64,7 @@ func (n VirtualServiceReferences) getServiceReferences(vs *networking_v1.Virtual
 					if host == "" {
 						continue
 					}
-					fqdn := kubernetes.GetHost(host, namespace, n.Namespaces.GetNames(), n.Conf)
+					fqdn := kubernetes.GetHost(host, namespace, n.Namespaces, n.Conf)
 					if !fqdn.IsWildcard() {
 						allServices = append(allServices, models.ServiceReference{Name: fqdn.Service, Namespace: fqdn.Namespace})
 					}
@@ -81,7 +81,7 @@ func (n VirtualServiceReferences) getServiceReferences(vs *networking_v1.Virtual
 					if host == "" {
 						continue
 					}
-					fqdn := kubernetes.GetHost(host, namespace, n.Namespaces.GetNames(), n.Conf)
+					fqdn := kubernetes.GetHost(host, namespace, n.Namespaces, n.Conf)
 					if !fqdn.IsWildcard() {
 						allServices = append(allServices, models.ServiceReference{Name: fqdn.Service, Namespace: fqdn.Namespace})
 					}
@@ -147,8 +147,8 @@ func (n VirtualServiceReferences) getAllDestinationRules(virtualService *network
 							continue
 						}
 						host := dest.Destination.Host
-						drHost := kubernetes.GetHost(host, dr.Namespace, n.Namespaces.GetNames(), n.Conf)
-						vsHost := kubernetes.GetHost(dr.Spec.Host, virtualService.Namespace, n.Namespaces.GetNames(), n.Conf)
+						drHost := kubernetes.GetHost(host, dr.Namespace, n.Namespaces, n.Conf)
+						vsHost := kubernetes.GetHost(dr.Spec.Host, virtualService.Namespace, n.Namespaces, n.Conf)
 						if kubernetes.FilterByHost(vsHost.String(), vsHost.Namespace, drHost.Service, drHost.Namespace, n.Conf) {
 							allDRs = append(allDRs, models.IstioReference{Name: dr.Name, Namespace: dr.Namespace, ObjectGVK: kubernetes.DestinationRules})
 						}
@@ -168,8 +168,8 @@ func (n VirtualServiceReferences) getAllDestinationRules(virtualService *network
 							continue
 						}
 						host := dest.Destination.Host
-						drHost := kubernetes.GetHost(host, dr.Namespace, n.Namespaces.GetNames(), n.Conf)
-						vsHost := kubernetes.GetHost(dr.Spec.Host, virtualService.Namespace, n.Namespaces.GetNames(), n.Conf)
+						drHost := kubernetes.GetHost(host, dr.Namespace, n.Namespaces, n.Conf)
+						vsHost := kubernetes.GetHost(dr.Spec.Host, virtualService.Namespace, n.Namespaces, n.Conf)
 						if kubernetes.FilterByHost(vsHost.String(), vsHost.Namespace, drHost.Service, drHost.Namespace, n.Conf) {
 							allDRs = append(allDRs, models.IstioReference{Name: dr.Name, Namespace: dr.Namespace, ObjectGVK: kubernetes.DestinationRules})
 						}
@@ -189,8 +189,8 @@ func (n VirtualServiceReferences) getAllDestinationRules(virtualService *network
 							continue
 						}
 						host := dest.Destination.Host
-						drHost := kubernetes.GetHost(host, dr.Namespace, n.Namespaces.GetNames(), n.Conf)
-						vsHost := kubernetes.GetHost(dr.Spec.Host, virtualService.Namespace, n.Namespaces.GetNames(), n.Conf)
+						drHost := kubernetes.GetHost(host, dr.Namespace, n.Namespaces, n.Conf)
+						vsHost := kubernetes.GetHost(dr.Spec.Host, virtualService.Namespace, n.Namespaces, n.Conf)
 						if kubernetes.FilterByHost(vsHost.String(), vsHost.Namespace, drHost.Service, drHost.Namespace, n.Conf) {
 							allDRs = append(allDRs, models.IstioReference{Name: dr.Name, Namespace: dr.Namespace, ObjectGVK: kubernetes.DestinationRules})
 						}
@@ -263,7 +263,7 @@ func (n VirtualServiceReferences) getAuthPolicies(vs *networking_v1.VirtualServi
 						continue
 					}
 					for _, h := range t.Operation.Hosts {
-						fqdn := kubernetes.GetHost(h, namespace, n.Namespaces.GetNames(), n.Conf)
+						fqdn := kubernetes.GetHost(h, namespace, n.Namespaces, n.Conf)
 						if !fqdn.IsWildcard() {
 							for hostIdx := 0; hostIdx < len(vs.Spec.Hosts); hostIdx++ {
 								vHost := vs.Spec.Hosts[hostIdx]
diff --git a/business/workloads.go b/business/workloads.go
index 6376f67de..b79ba5a81 100644
--- a/business/workloads.go
+++ b/business/workloads.go
@@ -2167,9 +2167,7 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 }
 
 func (in *WorkloadService) GetZtunnelConfig(cluster, namespace, pod string) *kubernetes.ZtunnelConfigDump {
-
 	return in.cache.GetZtunnelDump(cluster, namespace, pod)
-
 }
 
 // GetWaypoints: Return the list of waypoint workloads.  This looks for all k8s gateways and then tests their labels
diff --git a/doc.go b/doc.go
index ce9294f65..d5041ea80 100644
--- a/doc.go
+++ b/doc.go
@@ -33,7 +33,7 @@ type AggregateValueParam struct {
 	Name string `json:"aggregateValue"`
 }
 
-// swagger:parameters appMetrics appDetails graphApp graphAppVersion appDashboard appSpans appTraces errorTraces
+// swagger:parameters appMetrics appDetails graphApp graphAppVersion appDashboard appSpans appTraces errorTraces usageMetrics
 type AppParam struct {
 	// The app name (label value).
 	//
@@ -69,6 +69,61 @@ type ContainerParam struct {
 	Name string `json:"container"`
 }
 
+// swagger:parameters controlPlaneMetrics
+type ControlPlaneParam struct {
+	// The control plane for metric collection, etc.
+	//
+	// in: path
+	// required: true
+	Name string `json:"controlplane"`
+}
+
+// swagger:parameters customDashboard
+type DashboardParam struct {
+	// The dashboard resource name.
+	//
+	// in: path
+	// required: true
+	Name string `json:"dashboard"`
+}
+
+// swagger:parameters podLogs
+type DurationLogParam struct {
+	// Query time-range duration (Golang string duration). Duration starts on
+	// `sinceTime` if set, or the time for the first log message if not set.
+	//
+	// in: query
+	// required: false
+	Name string `json:"duration"`
+}
+
+// swagger:parameters istioConfigCreate istioConfigDetails istioConfigDelete istioConfigUpdate
+type GVKGroupParam struct {
+	// The GVK group in a group/value/kind specification.
+	//
+	// in: path
+	// required: true
+	Name string `json:"group"`
+}
+
+// swagger:parameters istioConfigCreate istioConfigDetails istioConfigDelete istioConfigUpdate
+type GVKKindParam struct {
+	// The GVK kind in a group/value/kind specification.
+	//
+	// in: path
+	// required: true
+	Name string `json:"kind"`
+}
+
+// swagger:parameters istioConfigCreate istioConfigDetails istioConfigDelete istioConfigUpdate
+type GVKVersionParam struct {
+	// The GVK version in a group/value/kind specification.
+	//
+	// in: path
+	// required: true
+	Name string `json:"version"`
+}
+
 // swagger:parameters podProxyLogging
 type LoggingParam struct {
 	// The log level for the pod's proxy.
@@ -78,7 +133,7 @@ type LoggingParam struct {
 	Level ProxyLogLevel `json:"level"`
 }
 
-// swagger:parameters istioConfigList workloadDetails workloadUpdate serviceDetails serviceUpdate appSpans serviceSpans workloadSpans appTraces serviceTraces workloadTraces errorTraces workloadValidations serviceMetrics aggregateMetrics appMetrics workloadMetrics istioConfigDetails istioConfigDetailsSubtype istioConfigDelete istioConfigDeleteSubtype istioConfigUpdate istioConfigUpdateSubtype appDetails graphAggregate graphAggregateByService graphApp graphAppVersion graphNamespace graphService graphWorkload namespaceMetrics customDashboard appDashboard serviceDashboard workloadDashboard istioConfigCreate istioConfigCreateSubtype namespaceUpdate namespaceTls podDetails podLogs namespaceValidations podProxyDump podProxyResource podProxyLogging namespaceInfo
+// swagger:parameters istioConfigList workloadDetails workloadUpdate serviceDetails serviceUpdate appSpans serviceSpans workloadSpans appTraces serviceTraces workloadTraces errorTraces workloadValidations serviceMetrics aggregateMetrics appMetrics workloadMetrics istioConfigDetails istioConfigDetailsSubtype istioConfigDelete istioConfigDeleteSubtype istioConfigUpdate istioConfigUpdateSubtype appDetails graphAggregate graphAggregateByService graphApp graphAppVersion graphNamespace graphService graphWorkload namespaceMetrics customDashboard appDashboard serviceDashboard workloadDashboard istioConfigCreate istioConfigCreateSubtype namespaceUpdate namespaceTls podDetails podLogs namespaceValidations podProxyDump podProxyResource podProxyLogging namespaceInfo controlPlaneMetrics ztunnelDashboard ztunnelConfigDump usageMetrics
 type NamespacePathParam struct {
 	// The namespace name.
 	//
@@ -105,16 +160,6 @@ type ObjectNameParam struct {
 	Name string `json:"object"`
 }
 
-// swagger:parameters istioConfigDetails istioConfigDetailsSubtype istioConfigDelete istioConfigDeleteSubtype istioConfigUpdate istioConfigUpdateSubtype istioConfigCreate istioConfigCreateSubtype
-type ObjectTypeParam struct {
-	// The Istio object type.
-	//
-	// in: path
-	// required: true
-	// pattern: ^(gateways|virtualservices|destinationrules|serviceentries|rules|quotaspecs|quotaspecbindings)$
-	Name string `json:"object_type"`
-}
-
 // swagger:parameters istioConfigList istioConfigDetails serviceDetails serviceUpdate
 type ValidateParam struct {
 	// Enable validation or not
@@ -124,7 +169,7 @@ type ValidateParam struct {
 	Name string `json:"validate"`
 }
 
-// swagger:parameters podDetails podLogs podProxyDump podProxyResource podProxyLogging
+// swagger:parameters podDetails podLogs podProxyDump podProxyResource podProxyLogging ztunnelConfigDump
 type PodParam struct {
 	// The pod name.
 	//
@@ -160,16 +205,6 @@ type SinceTimeParam struct {
 	Name string `json:"sinceTime"`
 }
 
-// swagger:parameters podLogs
-type DurationLogParam struct {
-	// Query time-range duration (Golang string duration). Duration starts on
-	// `sinceTime` if set, or the time for the first log message if not set.
-	//
-	// in: query
-	// required: false
-	Name string `json:"duration"`
-}
-
 // swagger:parameters traceDetails
 type TraceIDParam struct {
 	// The trace ID.
@@ -179,16 +214,7 @@ type TraceIDParam struct {
 	Name string `json:"traceID"`
 }
 
-// swagger:parameters customDashboard
-type DashboardParam struct {
-	// The dashboard resource name.
-	//
-	// in: path
-	// required: true
-	Name string `json:"dashboard"`
-}
-
-// swagger:parameters workloadDetails workloadUpdate workloadValidations workloadMetrics graphWorkload workloadDashboard workloadSpans workloadTraces
+// swagger:parameters workloadDetails workloadUpdate workloadValidations workloadMetrics graphWorkload workloadDashboard workloadSpans workloadTraces ztunnelDashboard
 type WorkloadParam struct {
 	// The workload name.
 	//
@@ -241,15 +267,6 @@ type GraphTypeParam struct {
 	Name string `json:"graphType"`
 }
 
-// swagger:parameters graphApp graphAppVersion
-type AppGraphTypeParam struct {
-	// Graph type. Available graph types: [app, versionedApp].
-	//
-	// in: query
-	// required: true
-	Name string `json:"graphType"`
-}
-
 // swagger:parameters graphApp graphAppVersion graphNamespaces graphWorkload
 type IncludeIdleEdges struct {
 	// Flag for including edges that have no request traffic for the time period.
@@ -475,7 +492,7 @@ type StepParam struct {
 
 // swagger:parameters serviceMetrics aggregateMetrics appMetrics workloadMetrics
 type VersionParam struct {
-	// Filters metrics by the specified version.
+	// Filters metrics by the specified version
 	//
 	// in: query
 	// required: false
diff --git a/frontend/cypress/integration/common/app_details_multicluster-pf.ts b/frontend/cypress/integration/common/app_details_multicluster.ts
similarity index 93%
rename from frontend/cypress/integration/common/app_details_multicluster-pf.ts
rename to frontend/cypress/integration/common/app_details_multicluster.ts
index eea6055fb..cb84c4e3d 100644
--- a/frontend/cypress/integration/common/app_details_multicluster-pf.ts
+++ b/frontend/cypress/integration/common/app_details_multicluster.ts
@@ -2,9 +2,11 @@ import { Given, Then, When } from '@badeball/cypress-cucumber-preprocessor';
 import { openTab } from './transition';
 import { clusterParameterExists } from './navigation';
 import { ensureKialiFinishedLoading } from './transition';
-import { elems, nodeInfo } from './graph-pf';
 import { Visualization } from '@patternfly/react-topology';
 import { NodeType } from 'types/Graph';
+import { elems } from 'helpers/GraphHelpers';
+import { nodeInfo } from './graph';
+import { GraphDataSource } from 'services/GraphDataSource';
 
 Then('user sees details information for the remote {string} app', (name: string) => {
   cy.getBySel('app-description-card').within(() => {
@@ -61,7 +63,7 @@ Then(
 
 Then('user sees {string} from a remote {string} cluster in the minigraph', (type: string, cluster: string) => {
   cy.waitForReact();
-  cy.getReact('MiniGraphCardPFComponent', { state: { isReady: true } })
+  cy.getReact('MiniGraphCardComponent', { state: { isReady: true, isLoading: false } })
     .should('have.length', '1')
     .then($graph => {
       const { state } = $graph[0];
@@ -89,7 +91,7 @@ Given(
   'the {string} {string} from the {string} cluster is visible in the minigraph',
   (name: string, type: string, cluster: string) => {
     cy.waitForReact();
-    cy.getReact('MiniGraphCardPFComponent', { state: { isReady: true } })
+    cy.getReact('MiniGraphCardComponent', { state: { isReady: true, isLoading: false } })
       .should('have.length', '1')
       .then($graph => {
         const { props, state } = $graph[0];
@@ -131,7 +133,7 @@ When(
   'user clicks on the {string} {string} from the {string} cluster in the minigraph',
   (name: string, type: string, cluster: string) => {
     cy.waitForReact();
-    cy.getReact('MiniGraphCardPFComponent', { state: { isReady: true } })
+    cy.getReact('MiniGraphCardComponent', { state: { isReady: true, isLoading: false } })
       .should('have.length', '1')
       .then($graph => {
         const { props, state } = $graph[0];
diff --git a/frontend/cypress/integration/common/apps.ts b/frontend/cypress/integration/common/apps.ts
index 81f67ac51..f0c94ba41 100644
--- a/frontend/cypress/integration/common/apps.ts
+++ b/frontend/cypress/integration/common/apps.ts
@@ -54,6 +54,24 @@ When('user selects a trace', () => {
   cy.getBySel('tracing-scatterplot').find(`path${tracingDotQuery}`).first().should('be.visible').click({ force: true });
 });
 
+When('user selects a trace with at least {int} spans', (spans: number) => {
+  cy.getBySel('tracing-scatterplot').within(() => {
+    cy.waitForReact();
+    cy.getReact('Point')
+      .should('have.length.at.least', 1)
+      .then(($points: any) => {
+        // We want to find a point that has all of the specified number of spans loaded
+        // since some of the later assertions look for a certain number of spans.
+        // There doesn't seem to be a good way to inject a data-test attribute into individual points
+        // on the graph so here we are looking at the react state of the points and then finding one
+        // that matches the exact data path.
+        const pointWithTraceName = $points.filter(point => point.props?.datum?.trace?.spans.length >= spans)[0];
+        const dataPointInGraph = pointWithTraceName.children[0].props.d;
+        cy.get(`path[d="${dataPointInGraph}"]`).should('be.visible').click({ force: true });
+      });
+  });
+});
+
 Then('user sees span details', () => {
   cy.getBySel('trace-details-tabs').should('be.visible').contains('Span Details').click({ scrollBehavior: false });
 
diff --git a/frontend/cypress/integration/common/authorization-pf.ts b/frontend/cypress/integration/common/authorization.ts
similarity index 88%
rename from frontend/cypress/integration/common/authorization-pf.ts
rename to frontend/cypress/integration/common/authorization.ts
index 94e3e86b8..d6b51eaf1 100644
--- a/frontend/cypress/integration/common/authorization-pf.ts
+++ b/frontend/cypress/integration/common/authorization.ts
@@ -1,6 +1,7 @@
 import { Then } from '@badeball/cypress-cucumber-preprocessor';
-import { elems } from './graph-pf';
+import { elems } from './graph';
 import { Visualization } from '@patternfly/react-topology';
+import { GraphDataSource } from 'services/GraphDataSource';
 
 Then(`user does not see the {string} link`, link => {
   cy.get('div[role="dialog"]').find(`#${link}`).should('not.exist');
@@ -12,7 +13,7 @@ Then(`user see the {string} link`, link => {
 
 Then('the nodes located in the {string} cluster should be restricted', (cluster: string) => {
   cy.waitForReact();
-  cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+  cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
     .should('have.length', '1')
     .then($graph => {
       const { state } = $graph[0];
@@ -31,7 +32,7 @@ Then('the nodes located in the {string} cluster should be restricted', (cluster:
 
 Then('the nodes on the minigraph located in the {string} cluster should be restricted', (cluster: string) => {
   cy.waitForReact();
-  cy.getReact('MiniGraphCardPFComponent', { state: { isReady: true } })
+  cy.getReact('MiniGraphCardComponent', { state: { isReady: true, isLoading: false } })
     .should('have.length', '1')
     .then($graph => {
       const { state } = $graph[0];
diff --git a/frontend/cypress/integration/common/graph-pf.ts b/frontend/cypress/integration/common/graph.ts
similarity index 94%
rename from frontend/cypress/integration/common/graph-pf.ts
rename to frontend/cypress/integration/common/graph.ts
index df63fdfb4..9875580c7 100644
--- a/frontend/cypress/integration/common/graph-pf.ts
+++ b/frontend/cypress/integration/common/graph.ts
@@ -12,7 +12,7 @@ Then('user does not see a minigraph', () => {
 
 Then('user sees a minigraph', () => {
   cy.waitForReact();
-  cy.getReact('MiniGraphCardPFComponent', { state: { isReady: true } })
+  cy.getReact('MiniGraphCardComponent', { state: { isReady: true, isLoading: false } })
     .should('have.length', '1')
     .then($graph => {
       const { state } = $graph[0];
@@ -27,7 +27,7 @@ Then('user sees a minigraph', () => {
 
 Then('user sees the {string} namespace deployed across the east and west clusters', (namespace: string) => {
   cy.waitForReact();
-  cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+  cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
     .should('have.length', '1')
     .then($graph => {
       const { state } = $graph[0];
@@ -48,7 +48,7 @@ Then('user sees the {string} namespace deployed across the east and west cluster
 
 Then('nodes in the {string} cluster should contain the cluster name in their links', (cluster: string) => {
   cy.waitForReact();
-  cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+  cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
     .should('have.length', '1')
     .then($graph => {
       const { state } = $graph[0];
@@ -74,7 +74,7 @@ Then(
   'user clicks on the {string} workload in the {string} namespace in the {string} cluster',
   (workload: string, namespace: string, cluster: string) => {
     cy.waitForReact();
-    cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+    cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
       .should('have.length', '1')
       .then($graph => {
         const { state } = $graph[0];
diff --git a/frontend/cypress/integration/common/graph_context_menu-pf.ts b/frontend/cypress/integration/common/graph_context_menu.ts
similarity index 94%
rename from frontend/cypress/integration/common/graph_context_menu-pf.ts
rename to frontend/cypress/integration/common/graph_context_menu.ts
index 14cc51de5..21905ad67 100644
--- a/frontend/cypress/integration/common/graph_context_menu-pf.ts
+++ b/frontend/cypress/integration/common/graph_context_menu.ts
@@ -1,14 +1,13 @@
 import { Then, When } from '@badeball/cypress-cucumber-preprocessor';
 import { ensureKialiFinishedLoading } from './transition';
 import { Visualization } from '@patternfly/react-topology';
-import { elems, selectAnd } from './graph-pf';
+import { elems, selectAnd } from './graph';
 import { NodeAttr } from 'types/Graph';
 
 // Single cluster only.
 When('user opens the context menu of the {string} service node', (svcName: string) => {
-  ensureKialiFinishedLoading();
   cy.waitForReact();
-  cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+  cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
     .should('have.length', '1')
     .then($graph => {
       const { state } = $graph[0];
@@ -30,9 +29,8 @@ When('user opens the context menu of the {string} service node', (svcName: strin
 When(
   'user opens the context menu of the {string} service node on the {string} cluster',
   (svcName: string, cluster: string) => {
-    ensureKialiFinishedLoading();
     cy.waitForReact();
-    cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+    cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
       .should('have.length', '1')
       .then($graph => {
         const { state } = $graph[0];
diff --git a/frontend/cypress/integration/common/graph_display-pf.ts b/frontend/cypress/integration/common/graph_display.ts
similarity index 92%
rename from frontend/cypress/integration/common/graph_display-pf.ts
rename to frontend/cypress/integration/common/graph_display.ts
index 62f9dfc8f..13100ff6e 100644
--- a/frontend/cypress/integration/common/graph_display-pf.ts
+++ b/frontend/cypress/integration/common/graph_display.ts
@@ -1,14 +1,14 @@
 import { Given, Then, When } from '@badeball/cypress-cucumber-preprocessor';
 import { ensureKialiFinishedLoading } from './transition';
 import { Visualization } from '@patternfly/react-topology';
-import { elems, select, selectAnd, selectOr } from './graph-pf';
+import { elems, select, selectAnd, selectOr } from './graph';
 import { EdgeAttr, NodeAttr } from 'types/Graph';
 
 When('user graphs {string} namespaces', (namespaces: string) => {
   // Forcing "Pause" to not cause unhandled promises from the browser when cypress is testing
   cy.intercept(`**/api/namespaces/graph*`).as('graphNamespaces');
 
-  cy.visit({ url: `/console/graphpf/namespaces?refresh=0&namespaces=${namespaces}` });
+  cy.visit({ url: `/console/graph/namespaces?refresh=0&namespaces=${namespaces}` });
 
   if (namespaces !== '') {
     cy.wait('@graphNamespaces');
@@ -139,7 +139,7 @@ Then('the display menu has default settings', () => {
 
 Then('the graph reflects default settings', () => {
   cy.waitForReact();
-  cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+  cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
     .should('have.length', '1')
     .then($graph => {
       const { state } = $graph[0];
@@ -199,7 +199,7 @@ Then('user sees {string} edge labels', (el: string) => {
   }
 
   cy.waitForReact();
-  cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+  cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
     .should('have.length', '1')
     .then($graph => {
       const { state } = $graph[0];
@@ -221,7 +221,7 @@ Then('user does not see {string} boxing', (boxByType: string) => {
   validateInput(`boxBy${boxByType}`, 'does not appear');
 
   cy.waitForReact();
-  cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+  cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
     .should('have.length', '1')
     .then($graph => {
       const { state } = $graph[0];
@@ -246,8 +246,7 @@ Then('idle edges {string} in the graph', (action: string) => {
   validateInput('filterIdleEdges', action);
 
   cy.waitForReact();
-
-  cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+  cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
     .should('have.length', '1')
     .then($graph => {
       const { state } = $graph[0];
@@ -273,7 +272,7 @@ Then('idle nodes {string} in the graph', (action: string) => {
   validateInput('filterIdleNodes', action);
 
   cy.waitForReact();
-  cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+  cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
     .should('have.length', '1')
     .then($graph => {
       const { state } = $graph[0];
@@ -296,7 +295,7 @@ Then('ranks {string} in the graph', (action: string) => {
   validateInput('rank', action);
 
   cy.waitForReact();
-  cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+  cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
     .should('have.length', '1')
     .then($graph => {
       const { state } = $graph[0];
@@ -319,7 +318,7 @@ Then('user does not see service nodes', () => {
   validateInput('filterServiceNodes', 'do not appear');
 
   cy.waitForReact();
-  cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+  cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
     .should('have.length', '1')
     .then($graph => {
       const { state } = $graph[0];
@@ -341,7 +340,7 @@ Then('security {string} in the graph', (action: string) => {
   validateInput('filterSecurity', action);
 
   cy.waitForReact();
-  cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+  cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
     .should('have.length', '1')
     .then($graph => {
       const { state } = $graph[0];
@@ -398,7 +397,7 @@ Then('the {string} option should {string} and {string}', (option: string, option
 
 Then('only a single cluster box should be visible', () => {
   cy.waitForReact();
-  cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+  cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
     .should('have.length', '1')
     .then($graph => {
       const { state } = $graph[0];
@@ -492,9 +491,7 @@ When('user {string} {string} traffic option', (action: string, option: string) =
 
 Then('{int} edges appear in the graph', (graphEdges: number) => {
   cy.waitForReact();
-  ensureKialiFinishedLoading();
-
-  cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+  cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
     .should('have.length', '1')
     .then($graph => {
       const { state } = $graph[0];
@@ -511,7 +508,7 @@ Then('{int} edges appear in the graph', (graphEdges: number) => {
 
 Then('the {string} node {string} exists', (nodeName: string, action: string) => {
   cy.waitForReact();
-  cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+  cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
     .should('have.length', 1)
     .then($graph => {
       const { state } = $graph[0];
@@ -532,7 +529,7 @@ Then('the {string} node {string} exists', (nodeName: string, action: string) =>
 
 Then('the {string} service {string} exists', (serviceName: string, action: string) => {
   cy.waitForReact();
-  cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+  cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
     .should('have.length', 1)
     .then($graph => {
       const { state } = $graph[0];
diff --git a/frontend/cypress/integration/common/graph_find_hide-pf.ts b/frontend/cypress/integration/common/graph_find_hide.ts
similarity index 92%
rename from frontend/cypress/integration/common/graph_find_hide-pf.ts
rename to frontend/cypress/integration/common/graph_find_hide.ts
index ea2153f91..e365994af 100644
--- a/frontend/cypress/integration/common/graph_find_hide-pf.ts
+++ b/frontend/cypress/integration/common/graph_find_hide.ts
@@ -31,7 +31,7 @@ Then('user sees unhealthy workloads highlighted on the graph', () => {
     }
   ];
   cy.waitForReact();
-  cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+  cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
     .should('have.length', '1')
     .then($graph => {
       const { state } = $graph[0];
@@ -54,7 +54,7 @@ Then('user sees unhealthy workloads highlighted on the graph', () => {
 
 Then('user sees nothing highlighted on the graph', () => {
   cy.waitForReact();
-  cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+  cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
     .should('have.length', '1')
     .then($graph => {
       const { state } = $graph[0];
@@ -85,7 +85,7 @@ When('user hides unhealthy workloads', () => {
 
 Then('user sees no unhealthy workloads on the graph', () => {
   cy.waitForReact();
-  cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+  cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
     .should('have.length', '1')
     .then($graph => {
       const { state } = $graph[0];
@@ -123,7 +123,7 @@ When('user selects the preset hide option {string}', (option: string) => {
 
 Then('user sees no healthy workloads on the graph', () => {
   cy.waitForReact();
-  cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+  cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
     .should('have.length', '1')
     .then($graph => {
       const { state } = $graph[0];
diff --git a/frontend/cypress/integration/common/graph_side_panel-pf.ts b/frontend/cypress/integration/common/graph_side_panel.ts
similarity index 97%
rename from frontend/cypress/integration/common/graph_side_panel-pf.ts
rename to frontend/cypress/integration/common/graph_side_panel.ts
index ccc22f2d5..0f3b053a9 100644
--- a/frontend/cypress/integration/common/graph_side_panel-pf.ts
+++ b/frontend/cypress/integration/common/graph_side_panel.ts
@@ -1,11 +1,11 @@
 import { Then, When } from '@badeball/cypress-cucumber-preprocessor';
 import { Visualization } from '@patternfly/react-topology';
-import { elems, selectAnd } from './graph-pf';
+import { elems, selectAnd } from './graph';
 import { NodeAttr } from 'types/Graph';
 
 When('user clicks the {string} {string} node', (svcName: string, nodeType: string) => {
   cy.waitForReact();
-  cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+  cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
     .should('have.length', '1')
     .then($graph => {
       const { state } = $graph[0];
@@ -28,7 +28,7 @@ When(
   'user clicks the edge from {string} {string} to {string} {string}',
   (svcName: string, nodeType: string, destSvcName: string, destNodeType: string) => {
     cy.waitForReact();
-    cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+    cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
       .should('have.length', '1')
       .then($graph => {
         const { state } = $graph[0];
@@ -164,7 +164,7 @@ When(
   'user clicks the {string} service node in the {string} namespace in the {string} cluster',
   (service: string, namespace: string, cluster: string) => {
     cy.waitForReact();
-    cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+    cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
       .should('have.length', '1')
       .then($graph => {
         const { state } = $graph[0];
diff --git a/frontend/cypress/integration/common/graph_toolbar-pf.ts b/frontend/cypress/integration/common/graph_toolbar.ts
similarity index 95%
rename from frontend/cypress/integration/common/graph_toolbar-pf.ts
rename to frontend/cypress/integration/common/graph_toolbar.ts
index 35d2f7ddb..87762dc58 100644
--- a/frontend/cypress/integration/common/graph_toolbar-pf.ts
+++ b/frontend/cypress/integration/common/graph_toolbar.ts
@@ -1,13 +1,13 @@
 import { Then, When } from '@badeball/cypress-cucumber-preprocessor';
 import { EdgeAttr } from 'types/Graph';
-import { elems, select } from './graph-pf';
+import { elems, select } from './graph';
 import { Visualization } from '@patternfly/react-topology';
 
 When(
   'user graphs {string} namespaces with refresh {string} and duration {string}',
   (namespaces: string, refresh: string, duration: string) => {
     cy.visit({
-      url: `/console/graphpf/namespaces?refresh=${refresh}&duration=${duration}&namespaces=${namespaces}`
+      url: `/console/graph/namespaces?refresh=${refresh}&duration=${duration}&namespaces=${namespaces}`
     });
   }
 );
@@ -111,7 +111,7 @@ Then('user does not see graph traffic menu', () => {
 
 Then('user {string} {string} traffic', (action: string, protocol: string) => {
   cy.waitForReact();
-  cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+  cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
     .should('have.length', '1')
     .then($graph => {
       const { state } = $graph[0];
@@ -214,7 +214,7 @@ Then('user sees selected graph refresh {string}', (refresh: string) => {
 
 Then('user sees a {string} graph', graphType => {
   cy.waitForReact();
-  cy.getReact('GraphPagePFComponent', { state: { isReady: true } })
+  cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } })
     .should('have.length', '1')
     .then($graph => {
       const { state } = $graph[0];
diff --git a/frontend/cypress/integration/common/graph_toolbar_legend-pf.ts b/frontend/cypress/integration/common/graph_toolbar_legend.ts
similarity index 100%
rename from frontend/cypress/integration/common/graph_toolbar_legend-pf.ts
rename to frontend/cypress/integration/common/graph_toolbar_legend.ts
diff --git a/frontend/cypress/integration/common/mesh.ts b/frontend/cypress/integration/common/mesh.ts
index 366624dd1..c77b3d719 100644
--- a/frontend/cypress/integration/common/mesh.ts
+++ b/frontend/cypress/integration/common/mesh.ts
@@ -1,7 +1,7 @@
 import { Then, When } from '@badeball/cypress-cucumber-preprocessor';
 import { Visualization } from '@patternfly/react-topology';
 import { MeshInfraType, MeshNodeData } from 'types/Mesh';
-import { elems } from './graph-pf';
+import { elems } from './graph';
 
 When('user closes mesh tour', () => {
   cy.waitForReact();
diff --git a/frontend/cypress/integration/featureFiles/app_details.feature b/frontend/cypress/integration/featureFiles/app_details.feature
index f22e24d3c..fae5aae3b 100644
--- a/frontend/cypress/integration/featureFiles/app_details.feature
+++ b/frontend/cypress/integration/featureFiles/app_details.feature
@@ -43,7 +43,7 @@ Feature: Kiali App Details page
   @tracing
   Scenario: See span info after selecting app span
     And user sees trace information
-    When user selects a trace
+    When user selects a trace with at least 6 spans
     Then user sees span details
     And user can filter spans by app "productpage"
 
diff --git a/frontend/cypress/integration/featureFiles/app_details_graph-pf.feature b/frontend/cypress/integration/featureFiles/app_details_graph.feature
similarity index 100%
rename from frontend/cypress/integration/featureFiles/app_details_graph-pf.feature
rename to frontend/cypress/integration/featureFiles/app_details_graph.feature
diff --git a/frontend/cypress/integration/featureFiles/app_details_multicluster.feature b/frontend/cypress/integration/featureFiles/app_details_multicluster.feature
index 19285bc18..41c984ba1 100644
--- a/frontend/cypress/integration/featureFiles/app_details_multicluster.feature
+++ b/frontend/cypress/integration/featureFiles/app_details_multicluster.feature
@@ -38,7 +38,7 @@ Feature: Kiali App Details page for multicluster
   Scenario: See span info after selecting app span
     And user is at the details page for the "app" "bookinfo/reviews" located in the "west" cluster
     And user sees trace information
-    When user selects a trace
+    When user selects a trace with at least 6 spans
     Then user sees span details
     And user can filter spans by app "productpage"
 
diff --git a/frontend/cypress/integration/featureFiles/app_details_multicluster_graph-pf.feature b/frontend/cypress/integration/featureFiles/app_details_multicluster_graph.feature
similarity index 100%
rename from frontend/cypress/integration/featureFiles/app_details_multicluster_graph-pf.feature
rename to frontend/cypress/integration/featureFiles/app_details_multicluster_graph.feature
diff --git a/frontend/cypress/integration/featureFiles/graph_context_menu-pf.feature b/frontend/cypress/integration/featureFiles/graph_context_menu.feature
similarity index 100%
rename from frontend/cypress/integration/featureFiles/graph_context_menu-pf.feature
rename to frontend/cypress/integration/featureFiles/graph_context_menu.feature
diff --git a/frontend/cypress/integration/featureFiles/graph_display-pf.feature b/frontend/cypress/integration/featureFiles/graph_display.feature
similarity index 100%
rename from frontend/cypress/integration/featureFiles/graph_display-pf.feature
rename to frontend/cypress/integration/featureFiles/graph_display.feature
diff --git a/frontend/cypress/integration/featureFiles/graph_display_user-pf.feature b/frontend/cypress/integration/featureFiles/graph_display_user.feature
similarity index 100%
rename from frontend/cypress/integration/featureFiles/graph_display_user-pf.feature
rename to frontend/cypress/integration/featureFiles/graph_display_user.feature
diff --git a/frontend/cypress/integration/featureFiles/graph_find_hide-pf.feature b/frontend/cypress/integration/featureFiles/graph_find_hide.feature
similarity index 100%
rename from frontend/cypress/integration/featureFiles/graph_find_hide-pf.feature
rename to frontend/cypress/integration/featureFiles/graph_find_hide.feature
diff --git a/frontend/cypress/integration/featureFiles/graph_replay-pf.feature b/frontend/cypress/integration/featureFiles/graph_replay.feature
similarity index 100%
rename from frontend/cypress/integration/featureFiles/graph_replay-pf.feature
rename to frontend/cypress/integration/featureFiles/graph_replay.feature
diff --git a/frontend/cypress/integration/featureFiles/graph_side_panel-pf.feature b/frontend/cypress/integration/featureFiles/graph_side_panel.feature
similarity index 100%
rename from frontend/cypress/integration/featureFiles/graph_side_panel-pf.feature
rename to frontend/cypress/integration/featureFiles/graph_side_panel.feature
diff --git a/frontend/cypress/integration/featureFiles/graph_toolbar-pf.feature b/frontend/cypress/integration/featureFiles/graph_toolbar.feature
similarity index 100%
rename from frontend/cypress/integration/featureFiles/graph_toolbar-pf.feature
rename to frontend/cypress/integration/featureFiles/graph_toolbar.feature
diff --git a/frontend/cypress/integration/featureFiles/graph_toolbar_legend-pf.feature b/frontend/cypress/integration/featureFiles/graph_toolbar_legend.feature
similarity index 100%
rename from frontend/cypress/integration/featureFiles/graph_toolbar_legend-pf.feature
rename to frontend/cypress/integration/featureFiles/graph_toolbar_legend.feature
diff --git a/frontend/cypress/integration/featureFiles/service_details.feature b/frontend/cypress/integration/featureFiles/service_details.feature
index b16ba0023..8830414f5 100644
--- a/frontend/cypress/integration/featureFiles/service_details.feature
+++ b/frontend/cypress/integration/featureFiles/service_details.feature
@@ -63,5 +63,5 @@ Feature: Kiali Service Details page
   @waypoint-tracing
   Scenario: See span info after selecting service span
     And user sees trace information
-    When user selects a trace
+    When user selects a trace with at least 2 spans
     Then user sees span details
diff --git a/frontend/cypress/integration/featureFiles/service_details_graph-pf.feature b/frontend/cypress/integration/featureFiles/service_details_graph.feature
similarity index 100%
rename from frontend/cypress/integration/featureFiles/service_details_graph-pf.feature
rename to frontend/cypress/integration/featureFiles/service_details_graph.feature
diff --git a/frontend/cypress/integration/featureFiles/service_details_multicluster_graph-pf.feature b/frontend/cypress/integration/featureFiles/service_details_multicluster_graph.feature
similarity index 100%
rename from frontend/cypress/integration/featureFiles/service_details_multicluster_graph-pf.feature
rename to frontend/cypress/integration/featureFiles/service_details_multicluster_graph.feature
diff --git a/frontend/cypress/integration/featureFiles/waypoint.feature b/frontend/cypress/integration/featureFiles/waypoint.feature
index 0d4be8839..0aef0e19c 100644
--- a/frontend/cypress/integration/featureFiles/waypoint.feature
+++ b/frontend/cypress/integration/featureFiles/waypoint.feature
@@ -35,7 +35,7 @@ Feature: Kiali Waypoint related features
     And the user sees the L7 "waypoint" link
     And the link for the waypoint "waypoint" should redirect to a valid workload details
 
-    Scenario: [Workload details - waypoint] The workload details for a waypoint are valid
+  Scenario: [Workload details - waypoint] The workload details for a waypoint are valid
     Given user is at the details page for the "workload" "bookinfo/waypoint" located in the "" cluster
     Then the user sees the "L7" badge
     Then the user cannot see the "missing-sidecar" badge for "waypoint" workload in "bookinfo" namespace
@@ -52,14 +52,14 @@ Feature: Kiali Waypoint related features
     Then user goes to the waypoint "Info" subtab
     And validates waypoint Info data for "service"
 
-    Scenario: [Workload details - ztunnel] The workload details for a ztunnel are valid
+  Scenario: [Workload details - ztunnel] The workload details for a ztunnel are valid
     Given user is at the details page for the "workload" "istio-system/ztunnel" located in the "" cluster
     Then the user cannot see the "missing-sidecar" badge for "ztunnel" workload in "istio-system" namespace
     And the proxy status is "healthy"
     And the user validates the Ztunnel tab
 
   Scenario: [Traffic Graph] User sees ztunnel traffic
-    Given user is at the "graphpf" page
+    Given user is at the "graph" page
     When user graphs "bookinfo" namespaces
     Then user sees the "bookinfo" namespace
     Then user opens traffic menu
@@ -67,7 +67,7 @@ Feature: Kiali Waypoint related features
     Then 7 edges appear in the graph
 
   Scenario: [Traffic Graph] User sees no Ambient traffic
-    Given user is at the "graphpf" page
+    Given user is at the "graph" page
     When user graphs "bookinfo" namespaces
     Then user sees the "bookinfo" namespace
     Then user opens traffic menu
@@ -75,7 +75,7 @@ Feature: Kiali Waypoint related features
     Then 2 edges appear in the graph
 
   Scenario: [Traffic Graph] User sees all Ambient traffic
-    Given user is at the "graphpf" page
+    Given user is at the "graph" page
     When user graphs "bookinfo" namespaces
     Then user sees the "bookinfo" namespace
     Then user opens traffic menu
@@ -96,7 +96,7 @@ Feature: Kiali Waypoint related features
     And the "waypoint" node "does" exists
 
   Scenario: [Traffic Graph] User sees waypoint traffic
-    Given user is at the "graphpf" page
+    Given user is at the "graph" page
     When user graphs "bookinfo" namespaces
     Then user sees the "bookinfo" namespace
     Then user opens traffic menu
@@ -115,7 +115,7 @@ Feature: Kiali Waypoint related features
     And badge for "istio.io/use-waypoint=waypoint" is visible in the LIST view in the namespace "bookinfo"
 
   Scenario: [Traffic] Waypoint for different namespaces working as expected
-    Given user is at the "graphpf" page
+    Given user is at the "graph" page
     When user graphs "waypoint-differentns" namespaces
     Then user sees the "waypoint-differentns" namespace
     Then user opens traffic menu
@@ -128,7 +128,7 @@ Feature: Kiali Waypoint related features
     And the "curl-client" node "does" exists
 
   Scenario: [Traffic] Waypoint for different namespaces working as expected with waypoints
-    Given user is at the "graphpf" page
+    Given user is at the "graph" page
     When user graphs "waypoint-differentns" namespaces
     Then user sees the "waypoint-differentns" namespace
     Then user opens traffic menu
@@ -142,7 +142,7 @@ Feature: Kiali Waypoint related features
     Then 2 edges appear in the graph
 
   Scenario: [Traffic] Waypoint for all
-    Given user is at the "graphpf" page
+    Given user is at the "graph" page
     When user graphs "waypoint-forall" namespaces
     Then user sees the "waypoint-forall" namespace
     Then user opens traffic menu
@@ -155,7 +155,7 @@ Feature: Kiali Waypoint related features
     And the "curl-client" node "does" exists
 
   Scenario: [Traffic] Waypoint for all with waypoint
-    Given user is at the "graphpf" page
+    Given user is at the "graph" page
     When user graphs "waypoint-forall" namespaces
     Then user sees the "waypoint-forall" namespace
     Then user opens traffic menu
@@ -170,7 +170,7 @@ Feature: Kiali Waypoint related features
     Then 2 edges appear in the graph
 
   Scenario: [Traffic] Waypoint for none
-    Given user is at the "graphpf" page
+    Given user is at the "graph" page
     When user graphs "waypoint-fornone" namespaces
     Then user sees the "waypoint-fornone" namespace
     Then user opens traffic menu
@@ -183,7 +183,7 @@ Feature: Kiali Waypoint related features
     And the "curl-client" node "does" exists
 
   Scenario: [Traffic] Waypoint for none with waypoint proxies
-    Given user is at the "graphpf" page
+    Given user is at the "graph" page
     When user graphs "waypoint-fornone" namespaces
     Then user sees the "waypoint-fornone" namespace
     Then user opens traffic menu
@@ -197,7 +197,7 @@ Feature: Kiali Waypoint related features
     Then 0 edges appear in the graph
 
   Scenario: [Traffic] Waypoint for service
-    Given user is at the "graphpf" page
+    Given user is at the "graph" page
     When user graphs "waypoint-forservice" namespaces
     Then user sees the "waypoint-forservice" namespace
     Then user opens traffic menu
@@ -209,7 +209,7 @@ Feature: Kiali Waypoint related features
     And the "curl-client" node "does" exists
 
   Scenario: [Traffic] Waypoint for service with waypoints
-    Given user is at the "graphpf" page
+    Given user is at the "graph" page
     When user graphs "waypoint-forservice" namespaces
     Then user sees the "waypoint-forservice" namespace
     Then user opens traffic menu
@@ -224,7 +224,7 @@ Feature: Kiali Waypoint related features
 
   @skip-istio-1-23
   Scenario: [Traffic] Waypoint for workload
-    Given user is at the "graphpf" page
+    Given user is at the "graph" page
     When user graphs "waypoint-forworkload" namespaces
     Then user sees the "waypoint-forworkload" namespace
     Then user opens traffic menu
@@ -237,7 +237,7 @@ Feature: Kiali Waypoint related features
 
   @skip-istio-1-23
   Scenario: [Traffic] Waypoint for workload with waypoints
-    Given user is at the "graphpf" page
+    Given user is at the "graph" page
     When user graphs "waypoint-forworkload" namespaces
     Then user sees the "waypoint-forworkload" namespace
     Then user opens traffic menu
@@ -251,7 +251,7 @@ Feature: Kiali Waypoint related features
     Then 2 edges appear in the graph
 
   Scenario: [Traffic] Waypoint override
-    Given user is at the "graphpf" page
+    Given user is at the "graph" page
     When user graphs "waypoint-override" namespaces
     Then user sees the "waypoint-override" namespace
     Then user opens traffic menu
@@ -263,7 +263,7 @@ Feature: Kiali Waypoint related features
     And the "curl-client" node "does" exists
 
   Scenario: [Traffic] Waypoint override with waypoints
-    Given user is at the "graphpf" page
+    Given user is at the "graph" page
     When user graphs "waypoint-override" namespaces
     Then user sees the "waypoint-override" namespace
     Then user opens traffic menu
@@ -350,7 +350,7 @@ Feature: Kiali Waypoint related features
 
   @skip-istio-1-23
   Scenario: [Traffic] Sidecar Ambient traffic
-    Given user is at the "graphpf" page
+    Given user is at the "graph" page
     When user graphs "test-ambient,test-sidecar" namespaces
     Then user sees the "test-ambient" namespace
     Then user sees the "test-sidecar" namespace
diff --git a/frontend/cypress/integration/featureFiles/workloads_details _graph-pf.feature b/frontend/cypress/integration/featureFiles/workloads_details _graph.feature
similarity index 100%
rename from frontend/cypress/integration/featureFiles/workloads_details _graph-pf.feature
rename to frontend/cypress/integration/featureFiles/workloads_details _graph.feature
diff --git a/frontend/cypress/integration/featureFiles/workloads_details.feature b/frontend/cypress/integration/featureFiles/workloads_details.feature
index b1c0cd190..52e592cd2 100644
--- a/frontend/cypress/integration/featureFiles/workloads_details.feature
+++ b/frontend/cypress/integration/featureFiles/workloads_details.feature
@@ -42,7 +42,7 @@ Feature: Kiali Workload Details page
   @tracing
   Scenario: See workload span info after selecting a span
     And user sees trace information
-    When user selects a trace
+    When user selects a trace with at least 6 spans
     And user sees span details
     And user can filter spans by workload "details-v1"
 
@@ -58,7 +58,7 @@ Feature: Kiali Workload Details page
   Scenario: See tracing links
     And user sees trace information
     Then the user can see the "View in Tracing" link
-    When user selects a trace
+    When user selects a trace with at least 6 spans
     Then the user can see the "View in Tracing" trace link
     And user sees span details
     Then the user can see the "More span details" span link
diff --git a/frontend/cypress/integration/featureFiles/workloads_details_multicluster_graph-pf.feature b/frontend/cypress/integration/featureFiles/workloads_details_multicluster_graph.feature
similarity index 100%
rename from frontend/cypress/integration/featureFiles/workloads_details_multicluster_graph-pf.feature
rename to frontend/cypress/integration/featureFiles/workloads_details_multicluster_graph.feature
diff --git a/frontend/cypress/perf/common.ts b/frontend/cypress/perf/common.ts
index 78ca6ab34..460f846aa 100644
--- a/frontend/cypress/perf/common.ts
+++ b/frontend/cypress/perf/common.ts
@@ -42,7 +42,10 @@ const measureLoadTime = (
           });
           if (isGraph) {
             cy.waitForReact();
-            cy.getReact('GraphPagePFComponent', { state: { isReady: true } }).should('have.length', '1');
+            cy.getReact('GraphPageComponent', { state: { graphData: { isLoading: false }, isReady: true } }).should(
+              'have.length',
+              '1'
+            );
             // @TODO this check fails on jenkins with CPU/Memory error, to find a better solution
             // .getCurrentState().then(state => {const controller = state.graphRefs.getController() as Visualization; assert.isTrue(controller.hasGraph()); });
           } else {
diff --git a/frontend/cypress/perf/graphload.spec.ts b/frontend/cypress/perf/graphload.spec.ts
index 767be9fa7..b589e34f1 100644
--- a/frontend/cypress/perf/graphload.spec.ts
+++ b/frontend/cypress/perf/graphload.spec.ts
@@ -14,13 +14,13 @@ describe('Graph performance tests', () => {
       cy.fixture('commonParams')
         .then(data => {
           graphUrl = encodeURI(
-            `/console/graphpf/namespaces?traffic=${data.traffic}&graphType=${data.graphType}&namespaces=${data.namespaces}&duration=${data.duration}&refresh=${data.refresh}&layout=${data.layout}`
+            `/console/graph/namespaces?traffic=${data.traffic}&graphType=${data.graphType}&namespaces=${data.namespaces}&duration=${data.duration}&refresh=${data.refresh}&layout=${data.layout}`
           );
           graphUrlAllNamespaces = encodeURI(
-            `/console/graphpf/namespaces?traffic=${data.traffic}&graphType=${data.graphType}&namespaces=${data.allNamespaces}&duration=${data.duration}&refresh=${data.refresh}&layout=${data.layout}`
+            `/console/graph/namespaces?traffic=${data.traffic}&graphType=${data.graphType}&namespaces=${data.allNamespaces}&duration=${data.duration}&refresh=${data.refresh}&layout=${data.layout}`
           );
           graphUrlAllNamespacesIdle = encodeURI(
-            `/console/graphpf/namespaces?traffic=${data.traffic}&graphType=${data.graphType}&namespaces=${data.allNamespaces}&duration=${data.duration}&refresh=${data.refresh}&layout=${data.layout}&idleNodes=true`
+            `/console/graph/namespaces?traffic=${data.traffic}&graphType=${data.graphType}&namespaces=${data.allNamespaces}&duration=${data.duration}&refresh=${data.refresh}&layout=${data.layout}&idleNodes=true`
           );
         })
         .as('data');
diff --git a/frontend/package.json b/frontend/package.json
index ac61ca264..c6657eb72 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -82,7 +82,6 @@
     "@patternfly/react-topology": "^5.4.1",
     "axios": "^1.7.4",
     "bootstrap-slider-without-jquery": "10.0.0",
-    "dagre": "0.8.5",
     "deep-freeze": "0.0.1",
     "eventemitter3": "4.0.7",
     "i18next": "^23.10.1",
@@ -111,7 +110,6 @@
     "regression": "^2.0.1",
     "reselect": "4.0.0",
     "screenfull": "5.0.2",
-    "tippy.js": "3.4.1",
     "typesafe-actions": "^4.2.1",
     "typestyle": "^2.4.0",
     "visibilityjs": "2.0.2"
diff --git a/frontend/public/locales/zh/translation.json b/frontend/public/locales/zh/translation.json
index 87850143a..91048aef7 100644
--- a/frontend/public/locales/zh/translation.json
+++ b/frontend/public/locales/zh/translation.json
@@ -63,7 +63,6 @@
   "Circuit Breaker": "熔断",
   "Clear": "清除",
   "Click + Drag": "Click + Drag",
-  "Click kebab menu on a node label for links to details, traffic, inbound/outbound metrics and node graph.": "单击节点，可链接到详细信息、流量、入站/出站指标和节点图。",
   "Click kebab menu on a node label to see the contextual menu options for the node.": "Click kebab menu on a node label to see the contextual menu options for the node.",
   "Click on a node or edge to see its summary and emphasize its end-to-end paths.": "单击节点或边可查看其摘要并强调其端到端路径。",
   "Client Certificate": "客户端证书",
@@ -287,8 +286,6 @@
   "Node Shapes": "Node Shapes",
   "none": "无",
   "None": "None",
-  "Normal": "Normal",
-  "Normal Request": "Normal Request",
   "Not found": "Not found",
   "Not healthy": "Not healthy",
   "Not Present": "Not Present",
@@ -350,7 +347,7 @@
   "Return to last page": "Return to last page",
   "revision: {{revision}}": "revision: {{revision}}",
   "Right click": "Right click",
-  "Right-click a node or an edge to see the contextual menu with links to details, traffic and inbound/outbound metrics for the node or edge.": "右键单击节点或边缘可查看上下文菜单，其中包含指向节点或边缘的详细信息、流量和入站/出站指标的链接。",
+  "Right-click or click kebab menu on a node label for links to details, traffic, inbound/outbound metrics and node graph.": "Right-click or click kebab menu on a node label for links to details, traffic, inbound/outbound metrics and node graph.",
   "Route Rules": "路由规则表",
   "Route To": "路由流量配置",
   "Rule List": "Rule List",
diff --git a/frontend/src/actions/GraphActions.ts b/frontend/src/actions/GraphActions.ts
index fe5526db4..fb018ab58 100644
--- a/frontend/src/actions/GraphActions.ts
+++ b/frontend/src/actions/GraphActions.ts
@@ -2,7 +2,7 @@ import { ActionType, createAction, createStandardAction } from 'typesafe-actions
 import { GraphEvent, EdgeMode, GraphDefinition, NodeParamsType, RankResult } from '../types/Graph';
 import { ActionKeys } from './ActionKeys';
 import { TimeInMilliseconds } from 'types/Common';
-import { GraphLayout } from 'pages/Graph/GraphPF';
+import { GraphLayout } from 'pages/Graph/Graph';
 
 export const GraphActions = {
   onNamespaceChange: createAction(ActionKeys.GRAPH_ON_NAMESPACE_CHANGE),
diff --git a/frontend/src/actions/GraphThunkActions.ts b/frontend/src/actions/GraphThunkActions.ts
index 5939d4065..28e8efe06 100644
--- a/frontend/src/actions/GraphThunkActions.ts
+++ b/frontend/src/actions/GraphThunkActions.ts
@@ -3,7 +3,7 @@ import { KialiDispatch } from '../types/Redux';
 import { GraphActions } from './GraphActions';
 
 export const GraphThunkActions = {
-  graphPFReady: (controller: Controller) => {
+  graphReady: (controller: Controller) => {
     return (dispatch: KialiDispatch) => {
       dispatch(
         GraphActions.updateSummary({
diff --git a/frontend/src/actions/__tests__/GraphActions.test.ts b/frontend/src/actions/__tests__/GraphActions.test.ts
index 9214d3750..178611ca6 100644
--- a/frontend/src/actions/__tests__/GraphActions.test.ts
+++ b/frontend/src/actions/__tests__/GraphActions.test.ts
@@ -15,7 +15,7 @@ describe('GraphActions', () => {
 
   it('should dispatch "update summary" action on render', () => {
     const dispatch = jest.fn();
-    GraphThunkActions.graphPFReady({} as Controller)(dispatch);
+    GraphThunkActions.graphReady({} as Controller)(dispatch);
 
     expect(dispatch.mock.calls.length).toBe(1);
     expect(dispatch.mock.calls[0][0]).toEqual(
diff --git a/frontend/src/assets/img/graph/cy/edge-danger.svg b/frontend/src/assets/img/graph/cy/edge-danger.svg
deleted file mode 100644
index 013913b2d..000000000
--- a/frontend/src/assets/img/graph/cy/edge-danger.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="46" height="15"><g style="fill:none;fill-rule:evenodd;stroke:none;stroke-width:1"><path style="color:#000;font-style:normal;font-variant:normal;font-weight:400;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000;solid-opacity:1;vector-effect:none;fill:#c9190b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:.20034286;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:.60102858,.60102858000000003;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M566.224 35.833v2H599v-2z" transform="matrix(1.01938 0 0 .94853 -576.728 -27.444)"/><path style="fill:#c9190b;fill-opacity:1;fill-rule:evenodd;stroke:#c9190b;stroke-width:.88000005pt;stroke-opacity:1" d="m597.873 36.655-3.615 5.97 14.615-5.97-14.929-5.499z" transform="matrix(1.01938 0 0 .94853 -576.728 -27.444)"/></g></svg>
\ No newline at end of file
diff --git a/frontend/src/assets/img/graph/cy/edge-idle.svg b/frontend/src/assets/img/graph/cy/edge-idle.svg
deleted file mode 100644
index 7c35624d6..000000000
--- a/frontend/src/assets/img/graph/cy/edge-idle.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="46" height="15"><g style="fill:none;fill-rule:evenodd;stroke:none;stroke-width:1"><path d="M566.224 35.833v2H599v-2z" style="color:#000;font-style:normal;font-variant:normal;font-weight:400;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000;solid-opacity:1;vector-effect:none;fill:#8b8d8f;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:2.9000001;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" transform="matrix(1.01938 0 0 .94853 -576.665 -27.444)"/><path style="fill:#8b8d8f;fill-opacity:1;fill-rule:evenodd;stroke:#8b8d8f;stroke-width:.88000005pt;stroke-opacity:1" d="m597.873 36.655-3.615 5.97 14.615-5.97-14.929-5.499z" transform="matrix(1.01938 0 0 .94853 -576.665 -27.444)"/></g></svg>
\ No newline at end of file
diff --git a/frontend/src/assets/img/graph/cy/edge-success.svg b/frontend/src/assets/img/graph/cy/edge-success.svg
deleted file mode 100644
index e1467ec02..000000000
--- a/frontend/src/assets/img/graph/cy/edge-success.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="46" height="15"><g style="fill:none;fill-rule:evenodd;stroke:none;stroke-width:1"><path d="M566.224 35.833v2H599v-2z" style="color:#000;font-style:normal;font-variant:normal;font-weight:400;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000;solid-opacity:1;vector-effect:none;fill:#3e8635;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:2.9000001;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" transform="matrix(1.01938 0 0 .94853 -576.602 -27.823)"/><path style="fill:#3e8645;fill-opacity:1;fill-rule:evenodd;stroke:#3e8635;stroke-width:1.17358204;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" d="m597.873 36.655-3.615 5.97 14.615-5.97-14.929-5.499z" transform="matrix(1.01938 0 0 .94853 -576.602 -27.823)"/></g></svg>
\ No newline at end of file
diff --git a/frontend/src/assets/img/graph/cy/edge-tcp.svg b/frontend/src/assets/img/graph/cy/edge-tcp.svg
deleted file mode 100644
index ee5bc699c..000000000
--- a/frontend/src/assets/img/graph/cy/edge-tcp.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="46" height="15"><path style="fill:#004368;fill-rule:nonzero;stroke:none;stroke-width:.96316379" d="m615.253 97.12-14.002-6.493v12.986zm-44.006.928H603.251v-1.856H570.247v1.856z" transform="translate(-569.706 -89.839)"/><path d="M595.93 91.634v11.131" style="fill:none;fill-rule:evenodd;stroke:#004368;stroke-width:2.88949132;stroke-linecap:square" transform="translate(-569.706 -89.839)"/></svg>
\ No newline at end of file
diff --git a/frontend/src/assets/img/graph/cy/edge-warn.svg b/frontend/src/assets/img/graph/cy/edge-warn.svg
deleted file mode 100644
index f94a0b46c..000000000
--- a/frontend/src/assets/img/graph/cy/edge-warn.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="46" height="15"><g style="fill:none;fill-rule:evenodd;stroke:none;stroke-width:1"><path style="color:#000;font-style:normal;font-variant:normal;font-weight:400;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000;solid-opacity:1;vector-effect:none;fill:#f0ab00;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:2.9000001;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M566.224 35.833v2H599v-2z" transform="matrix(1.01938 0 0 .94853 -576.79 -27.634)"/><path style="fill:#f0ab00;fill-opacity:1;fill-rule:evenodd;stroke:#f0ab00;stroke-width:.88000005pt;stroke-opacity:1" d="m597.873 36.655-3.615 5.97 14.615-5.97-14.929-5.499z" transform="matrix(1.01938 0 0 .94853 -576.79 -27.634)"/></g></svg>
\ No newline at end of file
diff --git a/frontend/src/assets/img/graph/cy/node-color-idle.svg b/frontend/src/assets/img/graph/cy/node-color-idle.svg
deleted file mode 100644
index b276cdace..000000000
--- a/frontend/src/assets/img/graph/cy/node-color-idle.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="27" height="27"><path d="M13.658 26.21c6.904 0 12.5-5.596 12.5-12.5 0-6.903-5.596-12.5-12.5-12.5-6.903 0-12.5 5.597-12.5 12.5 0 6.904 5.597 12.5 12.5 12.5z" style="fill:none;fill-rule:evenodd;stroke:#8b8d8f;stroke-width:1;stroke-dasharray:6,5"/></svg>
\ No newline at end of file
diff --git a/frontend/src/assets/img/graph/cy/node-color-normal.svg b/frontend/src/assets/img/graph/cy/node-color-normal.svg
deleted file mode 100644
index 6ad4a0bae..000000000
--- a/frontend/src/assets/img/graph/cy/node-color-normal.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="27" height="27"><circle cx="13.499" cy="13.464" r="12.5" style="fill:none;fill-rule:evenodd;stroke:#8b8d8f;stroke-width:1"/></svg>
\ No newline at end of file
diff --git a/frontend/src/assets/img/graph/cy/operation.svg b/frontend/src/assets/img/graph/cy/operation.svg
deleted file mode 100644
index 7bf7199af..000000000
--- a/frontend/src/assets/img/graph/cy/operation.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="27" height="27"><path style="fill:none;fill-opacity:1;stroke:#8b8d8f;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="m13.611 2.394 10.966 8.426-4.626 13.033-13.824-.372-3.919-13.263Z" transform="rotate(-1.44 13.295 14.153)"/></svg>
\ No newline at end of file
diff --git a/frontend/src/assets/img/graph/cy/service-entry.svg b/frontend/src/assets/img/graph/cy/service-entry.svg
deleted file mode 100644
index cee2228f1..000000000
--- a/frontend/src/assets/img/graph/cy/service-entry.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="27" height="27"><path style="fill:none;stroke:#8b8d8f;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="m2.184-8.07-.299.528v20.053l.354.624.651.365h13.005l.847-.21.607-.409 7.686-10.247.077-1.079-.18-1.113-7.406-8.23-.85-.403-.803-.309H2.803Z" transform="translate(0 11)"/></svg>
\ No newline at end of file
diff --git a/frontend/src/assets/img/graph/cy/service.svg b/frontend/src/assets/img/graph/cy/service.svg
deleted file mode 100644
index 12dd4a177..000000000
--- a/frontend/src/assets/img/graph/cy/service.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="27" height="27"><path style="fill:none;fill-opacity:1;stroke:#8b8d8f;stroke-width:.88739789;stroke-opacity:1" d="m13.515 3.677.512.132 10.435 18.074-.052.717-.508.485H3.06l-.438-.56.115-.802L13.092 3.785Z"/></svg>
\ No newline at end of file
diff --git a/frontend/src/assets/img/graph/cy/traffic-failed-request.svg b/frontend/src/assets/img/graph/cy/traffic-failed-request.svg
deleted file mode 100644
index 1eed174bd..000000000
--- a/frontend/src/assets/img/graph/cy/traffic-failed-request.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="46" height="15"><path d="M747.346 57.883h43.775" style="fill:#000;fill-opacity:0;fill-rule:evenodd;stroke:#8b8d8f;stroke-width:2;stroke-linecap:square;stroke-opacity:1" fill="none" transform="translate(-746.258 -50.545)"/><path transform="translate(.864 -21.496)" style="fill:#fff;fill-opacity:1;fill-rule:evenodd;stroke:#c9190b;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="m23 23 6 6-6 6-6-6z"/><path transform="matrix(.56468 0 0 .56468 10.876 -8.871)" style="fill:#c9190b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="m23 23 6 6-6 6-6-6z"/></svg>
\ No newline at end of file
diff --git a/frontend/src/assets/img/graph/cy/traffic-normal-request.svg b/frontend/src/assets/img/graph/cy/traffic-normal-request.svg
deleted file mode 100644
index 631c85d12..000000000
--- a/frontend/src/assets/img/graph/cy/traffic-normal-request.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="48" height="15"><g transform="translate(-753.106 -31.962)"><path d="M754.957 39.134h43.776" style="fill:none;fill-rule:evenodd;stroke:#8b8d8f;stroke-width:2;stroke-linecap:square;stroke-opacity:1"/><circle cx="777.733" cy="39.134" r="5" style="fill:#fffffb;fill-opacity:1;fill-rule:evenodd;stroke:#8b8d8f;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"/></g></svg>
\ No newline at end of file
diff --git a/frontend/src/assets/img/graph/cy/traffic-tcp.svg b/frontend/src/assets/img/graph/cy/traffic-tcp.svg
deleted file mode 100644
index 0de0e373f..000000000
--- a/frontend/src/assets/img/graph/cy/traffic-tcp.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="46" height="15"><g transform="translate(-746.677 -70.49)"><path d="M747.897 78.16h43.775" style="fill:#004368;fill-opacity:1;fill-rule:evenodd;stroke:#004368;stroke-width:2;stroke-linecap:square;stroke-opacity:1"/><circle cx="752.553" cy="75.461" r="3.057" style="fill:#fff;fill-opacity:1;fill-rule:evenodd;stroke:#8b8d8f;stroke-width:.61144638;stroke-opacity:1"/><circle cx="764.029" cy="78.39" r="3.057" style="fill:#fff;fill-opacity:1;fill-rule:evenodd;stroke:#8b8d8f;stroke-width:.61144638;stroke-opacity:1"/><circle cx="776.377" cy="80.447" r="3.057" style="fill:#fff;fill-opacity:1;fill-rule:evenodd;stroke:#8b8d8f;stroke-width:.61144638;stroke-opacity:1"/><circle cx="786.508" cy="75.382" r="3.057" style="fill:#fff;fill-opacity:1;fill-rule:evenodd;stroke:#8b8d8f;stroke-width:.61144638;stroke-opacity:1"/></g></svg>
\ No newline at end of file
diff --git a/frontend/src/assets/img/graph/cy/app.svg b/frontend/src/assets/img/graph/legend/app.svg
similarity index 100%
rename from frontend/src/assets/img/graph/cy/app.svg
rename to frontend/src/assets/img/graph/legend/app.svg
diff --git a/frontend/src/assets/img/graph/pf/edge-danger.svg b/frontend/src/assets/img/graph/legend/edge-danger.svg
similarity index 100%
rename from frontend/src/assets/img/graph/pf/edge-danger.svg
rename to frontend/src/assets/img/graph/legend/edge-danger.svg
diff --git a/frontend/src/assets/img/graph/pf/edge-idle.svg b/frontend/src/assets/img/graph/legend/edge-idle.svg
similarity index 100%
rename from frontend/src/assets/img/graph/pf/edge-idle.svg
rename to frontend/src/assets/img/graph/legend/edge-idle.svg
diff --git a/frontend/src/assets/img/graph/pf/edge-success.svg b/frontend/src/assets/img/graph/legend/edge-success.svg
similarity index 100%
rename from frontend/src/assets/img/graph/pf/edge-success.svg
rename to frontend/src/assets/img/graph/legend/edge-success.svg
diff --git a/frontend/src/assets/img/graph/pf/edge-tcp.svg b/frontend/src/assets/img/graph/legend/edge-tcp.svg
similarity index 100%
rename from frontend/src/assets/img/graph/pf/edge-tcp.svg
rename to frontend/src/assets/img/graph/legend/edge-tcp.svg
diff --git a/frontend/src/assets/img/graph/pf/edge-warn.svg b/frontend/src/assets/img/graph/legend/edge-warn.svg
similarity index 100%
rename from frontend/src/assets/img/graph/pf/edge-warn.svg
rename to frontend/src/assets/img/graph/legend/edge-warn.svg
diff --git a/frontend/src/assets/img/graph/cy/node-color-danger.svg b/frontend/src/assets/img/graph/legend/node-color-danger.svg
similarity index 100%
rename from frontend/src/assets/img/graph/cy/node-color-danger.svg
rename to frontend/src/assets/img/graph/legend/node-color-danger.svg
diff --git a/frontend/src/assets/img/graph/pf/node-color-healthy.svg b/frontend/src/assets/img/graph/legend/node-color-healthy.svg
similarity index 100%
rename from frontend/src/assets/img/graph/pf/node-color-healthy.svg
rename to frontend/src/assets/img/graph/legend/node-color-healthy.svg
diff --git a/frontend/src/assets/img/graph/pf/node-color-idle.svg b/frontend/src/assets/img/graph/legend/node-color-idle.svg
similarity index 100%
rename from frontend/src/assets/img/graph/pf/node-color-idle.svg
rename to frontend/src/assets/img/graph/legend/node-color-idle.svg
diff --git a/frontend/src/assets/img/graph/cy/node-color-warning.svg b/frontend/src/assets/img/graph/legend/node-color-warning.svg
similarity index 100%
rename from frontend/src/assets/img/graph/cy/node-color-warning.svg
rename to frontend/src/assets/img/graph/legend/node-color-warning.svg
diff --git a/frontend/src/assets/img/graph/cy/node.svg b/frontend/src/assets/img/graph/legend/node.svg
similarity index 100%
rename from frontend/src/assets/img/graph/cy/node.svg
rename to frontend/src/assets/img/graph/legend/node.svg
diff --git a/frontend/src/assets/img/graph/pf/operation.svg b/frontend/src/assets/img/graph/legend/operation.svg
similarity index 100%
rename from frontend/src/assets/img/graph/pf/operation.svg
rename to frontend/src/assets/img/graph/legend/operation.svg
diff --git a/frontend/src/assets/img/graph/pf/service-entry.svg b/frontend/src/assets/img/graph/legend/service-entry.svg
similarity index 100%
rename from frontend/src/assets/img/graph/pf/service-entry.svg
rename to frontend/src/assets/img/graph/legend/service-entry.svg
diff --git a/frontend/src/assets/img/graph/pf/service.svg b/frontend/src/assets/img/graph/legend/service.svg
similarity index 100%
rename from frontend/src/assets/img/graph/pf/service.svg
rename to frontend/src/assets/img/graph/legend/service.svg
diff --git a/frontend/src/assets/img/graph/pf/traffic-failed-request.svg b/frontend/src/assets/img/graph/legend/traffic-failed-request.svg
similarity index 100%
rename from frontend/src/assets/img/graph/pf/traffic-failed-request.svg
rename to frontend/src/assets/img/graph/legend/traffic-failed-request.svg
diff --git a/frontend/src/assets/img/graph/pf/traffic-healthy-request.svg b/frontend/src/assets/img/graph/legend/traffic-healthy-request.svg
similarity index 100%
rename from frontend/src/assets/img/graph/pf/traffic-healthy-request.svg
rename to frontend/src/assets/img/graph/legend/traffic-healthy-request.svg
diff --git a/frontend/src/assets/img/graph/pf/traffic-tcp.svg b/frontend/src/assets/img/graph/legend/traffic-tcp.svg
similarity index 100%
rename from frontend/src/assets/img/graph/pf/traffic-tcp.svg
rename to frontend/src/assets/img/graph/legend/traffic-tcp.svg
diff --git a/frontend/src/assets/img/graph/pf/app.svg b/frontend/src/assets/img/graph/pf/app.svg
deleted file mode 100644
index f5ff9a691..000000000
--- a/frontend/src/assets/img/graph/pf/app.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="27" width="27"><rect style="fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#8b8d8f;stroke-width:.80000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" width="20.016" height="20.004" x="3.492" y="3.498" ry="3.908"/></svg>
\ No newline at end of file
diff --git a/frontend/src/assets/img/graph/pf/node-color-danger.svg b/frontend/src/assets/img/graph/pf/node-color-danger.svg
deleted file mode 100644
index 5da21fd0f..000000000
--- a/frontend/src/assets/img/graph/pf/node-color-danger.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="27" height="27"><circle style="fill:none;fill-rule:evenodd;stroke:#c9190b;stroke-width:1" r="12.5" cy="13.501" cx="13.424"/></svg>
\ No newline at end of file
diff --git a/frontend/src/assets/img/graph/pf/node-color-warning.svg b/frontend/src/assets/img/graph/pf/node-color-warning.svg
deleted file mode 100644
index d4fcbefa5..000000000
--- a/frontend/src/assets/img/graph/pf/node-color-warning.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="27" height="27"><circle cx="13.447" cy="13.605" r="12.5" style="fill:none;fill-rule:evenodd;stroke:#f0ab00;stroke-width:1"/></svg>
\ No newline at end of file
diff --git a/frontend/src/assets/img/graph/pf/node.svg b/frontend/src/assets/img/graph/pf/node.svg
deleted file mode 100644
index be7c352c8..000000000
--- a/frontend/src/assets/img/graph/pf/node.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="27" height="27"><circle cx="13.562" cy="13.605" r="12.5" style="fill:none;fill-rule:evenodd;stroke:#8b8d8f;stroke-width:1"/></svg>
\ No newline at end of file
diff --git a/frontend/src/components/Metrics/TraceLimit.tsx b/frontend/src/components/Metrics/TraceLimit.tsx
index a50d72762..220815022 100644
--- a/frontend/src/components/Metrics/TraceLimit.tsx
+++ b/frontend/src/components/Metrics/TraceLimit.tsx
@@ -75,6 +75,7 @@ export const TraceLimit: React.FC<TraceLimitProps> = (props: TraceLimitProps) =>
             <label key={`limit-${lim}`} className={itemStyleWithoutInfo}>
               <Radio
                 id={`limit-${lim}`}
+                data-test={`limit-${lim}`}
                 name={`limit-${lim}`}
                 isChecked={lim === limit}
                 label={lim}
diff --git a/frontend/src/components/Nav/NavUtils.tsx b/frontend/src/components/Nav/NavUtils.tsx
index 656ac5cea..d266df705 100644
--- a/frontend/src/components/Nav/NavUtils.tsx
+++ b/frontend/src/components/Nav/NavUtils.tsx
@@ -4,7 +4,7 @@ import { Namespace } from '../../types/Namespace';
 import { URLParam } from '../../app/History';
 import { getKioskMode, isKioskMode } from '../../utils/SearchParamUtils';
 import { isMultiCluster } from 'config';
-import { GraphLayout } from 'pages/Graph/GraphPF';
+import { GraphLayout } from 'pages/Graph/Graph';
 
 export type GraphUrlParams = {
   activeNamespaces: Namespace[];
@@ -46,7 +46,7 @@ const buildCommonQueryParams = (params: GraphUrlParams): string => {
 };
 
 export const makeNamespacesGraphUrlFromParams = (params: GraphUrlParams): string => {
-  const route = 'graphpf';
+  const route = 'graph';
   let queryParams = buildCommonQueryParams(params);
   if (params.activeNamespaces.length > 0) {
     const namespaces = params.activeNamespaces.map(namespace => namespace.name).join(',');
@@ -60,7 +60,7 @@ export const makeNamespacesGraphUrlFromParams = (params: GraphUrlParams): string
 };
 
 export const makeNodeGraphUrlFromParams = (params: GraphUrlParams): string => {
-  const route = 'graphpf';
+  const route = 'graph';
   const node = params.node;
   if (node) {
     switch (node.nodeType) {
diff --git a/frontend/src/components/Nav/Navigation.tsx b/frontend/src/components/Nav/Navigation.tsx
index 23eb285f3..3d6423600 100644
--- a/frontend/src/components/Nav/Navigation.tsx
+++ b/frontend/src/components/Nav/Navigation.tsx
@@ -63,7 +63,7 @@ export const NavigationComponent: React.FC<NavigationProps> = (props: Navigation
   }, []);
 
   const isGraph = (): boolean => {
-    return pathname.startsWith('/graph') || pathname.startsWith('/graphpf') || pathname.startsWith('/mesh');
+    return pathname.startsWith('/graph') || pathname.startsWith('/graph') || pathname.startsWith('/mesh');
   };
 
   const onNavToggleDesktop = (): void => {
diff --git a/frontend/src/components/Nav/__tests__/RenderPage.test.tsx b/frontend/src/components/Nav/__tests__/RenderPage.test.tsx
index 81242144d..b03d0808f 100644
--- a/frontend/src/components/Nav/__tests__/RenderPage.test.tsx
+++ b/frontend/src/components/Nav/__tests__/RenderPage.test.tsx
@@ -34,7 +34,7 @@ describe('RenderPage isGraph prop', () => {
     // we need a user session to render the navigation component
     store.dispatch(LoginActions.loginSuccess(session));
 
-    router.navigate('/graphpf/namespaces');
+    router.navigate('/graph/namespaces');
 
     const wrapper = mount(
       <Provider store={store}>
diff --git a/frontend/src/components/TracingIntegration/TracesDisplayOptions.tsx b/frontend/src/components/TracingIntegration/TracesDisplayOptions.tsx
index 7c9a7fe01..7c9df588a 100644
--- a/frontend/src/components/TracingIntegration/TracesDisplayOptions.tsx
+++ b/frontend/src/components/TracingIntegration/TracesDisplayOptions.tsx
@@ -108,6 +108,7 @@ export class TracesDisplayOptions extends React.Component<Props, State> {
           <MenuToggle
             ref={toggleRef}
             id={'traces-display-settings'}
+            data-test={'traces-display-settings'}
             onClick={() => this.onToggle(!isOpen)}
             isExpanded={isOpen}
           >
diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx
index dda6eb573..a306d3b21 100644
--- a/frontend/src/index.tsx
+++ b/frontend/src/index.tsx
@@ -10,8 +10,6 @@ import '@patternfly/patternfly/patternfly.css';
 import '@patternfly/patternfly/patternfly-charts.css';
 import '@patternfly/patternfly/patternfly-charts-theme-dark.css';
 import '@patternfly/patternfly/patternfly-addons.css';
-import 'tippy.js/dist/tippy.css';
-import 'tippy.js/dist/themes/light-border.css';
 
 // Enables ACE editor YAML themes
 import 'ace-builds/src-noconflict/mode-yaml';
diff --git a/frontend/src/pages/AppDetails/AppInfo.tsx b/frontend/src/pages/AppDetails/AppInfo.tsx
index 981a81b52..44fc2ddd7 100644
--- a/frontend/src/pages/AppDetails/AppInfo.tsx
+++ b/frontend/src/pages/AppDetails/AppInfo.tsx
@@ -7,7 +7,7 @@ import { DurationInSeconds } from 'types/Common';
 import { GraphDataSource } from 'services/GraphDataSource';
 import { AppHealth } from 'types/Health';
 import { kialiStyle } from 'styles/StyleUtils';
-import { MiniGraphCardPF } from 'pages/Graph/MiniGraphCardPF';
+import { MiniGraphCard } from 'pages/Graph/MiniGraphCard';
 
 type AppInfoProps = {
   app?: App;
@@ -68,7 +68,7 @@ export class AppInfo extends React.Component<AppInfoProps, AppInfoState> {
           </GridItem>
 
           <GridItem span={miniGraphSpan}>
-            <MiniGraphCardPF dataSource={this.graphDataSource} />
+            <MiniGraphCard dataSource={this.graphDataSource} />
           </GridItem>
         </Grid>
       </RenderComponentScroll>
diff --git a/frontend/src/pages/Graph/ContextMenu/NodeContextMenu.tsx b/frontend/src/pages/Graph/ContextMenu/NodeContextMenu.tsx
index 755ad00ce..4cb6c8e13 100644
--- a/frontend/src/pages/Graph/ContextMenu/NodeContextMenu.tsx
+++ b/frontend/src/pages/Graph/ContextMenu/NodeContextMenu.tsx
@@ -3,6 +3,7 @@ import { BoxByType, DecoratedGraphNodeData, NodeType } from 'types/Graph';
 import { TracingInfo } from 'types/TracingInfo';
 import { isMultiCluster, Paths } from 'config';
 import { isParentKiosk, kioskContextMenuAction } from '../../../components/Kiosk/KioskActions';
+import { GraphElement } from '@patternfly/react-topology';
 type LinkParams = { cluster?: string; name: string; namespace: string; type: string };
 
 const getLinkParamsForNode = (node: DecoratedGraphNodeData): LinkParams | undefined => {
@@ -47,7 +48,9 @@ const getTracingURL = (namespace: string, namespaceSelector: boolean, tracingURL
 };
 
 export type ContextMenuOption = {
+  altClickHandler?: (node: GraphElement, kiosk: string) => void;
   external?: boolean;
+  node?: GraphElement;
   target?: string;
   text: string;
   url: string;
diff --git a/frontend/src/pages/Graph/GraphPF.tsx b/frontend/src/pages/Graph/Graph.tsx
similarity index 98%
rename from frontend/src/pages/Graph/GraphPF.tsx
rename to frontend/src/pages/Graph/Graph.tsx
index 65fe9bb0e..caec24d50 100644
--- a/frontend/src/pages/Graph/GraphPF.tsx
+++ b/frontend/src/pages/Graph/Graph.tsx
@@ -47,29 +47,29 @@ import {
   EdgeData,
   getNodeShape,
   getNodeStatus,
-  GraphPFSettings,
+  GraphSettings,
   NodeData,
   setEdgeOptions,
   setNodeAttachments,
   setNodeLabel
-} from './GraphPFElems';
+} from './GraphElems';
 import { elems, selectAnd, SelectAnd, setObserved } from 'helpers/GraphHelpers';
 import { layoutFactory } from './layouts/layoutFactory';
-import { hideTrace, showTrace } from './TracePF';
-import { GraphHighlighterPF } from './GraphHighlighterPF';
+import { hideTrace, showTrace } from './Trace';
 import { TimeInMilliseconds } from 'types/Common';
 import { HistoryManager, URLParam } from 'app/History';
 import { TourStop } from 'components/Tour/TourStop';
 import { GraphTourStops } from 'pages/Graph/GraphHelpTour';
 import { supportsGroups } from 'utils/GraphUtils';
-import { GraphData, GraphRefs } from './GraphPagePF';
+import { GraphData, GraphRefs } from './GraphPage';
 import { WizardAction, WizardMode } from 'components/IstioWizards/WizardActions';
 import { ServiceDetailsInfo } from 'types/ServiceInfo';
 import { PeerAuthentication } from 'types/IstioObjects';
 import { KialiIcon } from 'config/KialiIcon';
 import { toolbarActiveStyle } from 'styles/GraphStyle';
 import { scoreNodes, ScoringCriteria } from 'pages/Graph/GraphScore';
-import { TrafficAnimation } from '../Graph/TrafficAnimation/TrafficRendererPF';
+import { TrafficAnimation } from '../Graph/TrafficAnimation/TrafficRenderer';
+import { GraphHighlighter } from './GraphHighlighter';
 
 const DEFAULT_NODE_SIZE = 40;
 const ZOOM_IN = 4 / 3;
@@ -140,7 +140,7 @@ const TopologyContent: React.FC<{
   edgeMode: EdgeMode;
   focusNode?: FocusNode;
   graphData: GraphData;
-  highlighter: GraphHighlighterPF;
+  highlighter: GraphHighlighter;
   isMiniGraph: boolean;
   layoutName: GraphLayout;
   onDeleteTrafficRouting: (key: string, serviceDetails: ServiceDetailsInfo) => void;
@@ -202,7 +202,7 @@ const TopologyContent: React.FC<{
 }) => {
   const [updateModelTime, setUpdateModelTime] = React.useState(0);
 
-  const graphSettings: GraphPFSettings = React.useMemo(() => {
+  const graphSettings: GraphSettings = React.useMemo(() => {
     return {
       activeNamespaces: graphData.fetchParams.namespaces,
       edgeLabels: edgeLabels,
@@ -211,7 +211,7 @@ const TopologyContent: React.FC<{
       showSecurity: showSecurity,
       showVirtualServices: showVirtualServices,
       trafficRates: graphData.fetchParams.trafficRates
-    } as GraphPFSettings;
+    } as GraphSettings;
   }, [graphData.fetchParams, edgeLabels, showOutOfMesh, showSecurity, showVirtualServices]);
 
   //
@@ -368,7 +368,7 @@ const TopologyContent: React.FC<{
       if (controller) {
         const defaultModel: Model = {
           graph: {
-            id: 'graphPF',
+            id: 'trafficgraph',
             layout: layoutName,
             type: 'graph'
           }
@@ -877,7 +877,7 @@ const TopologyContent: React.FC<{
   );
 };
 
-export const GraphPF: React.FC<{
+export const Graph: React.FC<{
   edgeLabels: EdgeLabelMode[];
   edgeMode: EdgeMode;
   focusNode?: FocusNode;
@@ -939,7 +939,7 @@ export const GraphPF: React.FC<{
 }) => {
   //create controller on startup and register factories
   const [controller, setController] = React.useState<Visualization>();
-  const [highlighter, setHighlighter] = React.useState<GraphHighlighterPF>();
+  const [highlighter, setHighlighter] = React.useState<GraphHighlighter>();
   const [trafficAnimation, setTrafficAnimation] = React.useState<TrafficAnimation>();
 
   // Set up the controller one time
@@ -951,7 +951,7 @@ export const GraphPF: React.FC<{
     c.registerLayoutFactory(layoutFactory);
     c.registerComponentFactory(stylesComponentFactory);
     setController(c);
-    setHighlighter(new GraphHighlighterPF(c));
+    setHighlighter(new GraphHighlighter(c));
     setTrafficAnimation(new TrafficAnimation(c));
   }, []);
 
diff --git a/frontend/src/pages/Graph/GraphPFElems.tsx b/frontend/src/pages/Graph/GraphElems.tsx
similarity index 98%
rename from frontend/src/pages/Graph/GraphPFElems.tsx
rename to frontend/src/pages/Graph/GraphElems.tsx
index 7f778679e..29841f5b2 100644
--- a/frontend/src/pages/Graph/GraphPFElems.tsx
+++ b/frontend/src/pages/Graph/GraphElems.tsx
@@ -35,10 +35,10 @@ import { getEdgeHealth } from 'types/ErrorRate/GraphEdgeStatus';
 import { Span } from 'types/TracingInfo';
 import { IconType } from 'config/Icons';
 import { NodeDecorator } from './NodeDecorator';
-import { GraphLayout } from './GraphPF';
+import { GraphLayout } from './Graph';
 import { supportsGroups } from 'utils/GraphUtils';
 import { kialiStyle } from 'styles/StyleUtils';
-import { TrafficPointGenerator } from '../Graph/TrafficAnimation/TrafficRendererPF';
+import { TrafficPointGenerator } from '../Graph/TrafficAnimation/TrafficRenderer';
 
 // Utilities for working with PF Topology
 
@@ -95,7 +95,7 @@ export type EdgeData = DecoratedGraphEdgeData & {
   tagStatus?: NodeStatus;
 };
 
-export type GraphPFSettings = {
+export type GraphSettings = {
   activeNamespaces: Namespace[];
   edgeLabels: EdgeLabelMode[];
   graphType: GraphType;
@@ -159,7 +159,7 @@ const getDecorator = (element: Node, quadrant: TopologyQuadrant, icon: IconType,
   return <NodeDecorator element={element} quadrant={quadrant} icon={icon} tooltip={tooltip} />;
 };
 
-export const setNodeAttachments = (node: Node<NodeModel>, settings: GraphPFSettings): void => {
+export const setNodeAttachments = (node: Node<NodeModel>, settings: GraphSettings): void => {
   // PFT provides the ability to add a single Icon (badge) on the label. And so we will use
   // attachments (up to 4) to display things that we'd prefer to have shown with more icons.
   const data = node.getData() as NodeData;
@@ -226,7 +226,7 @@ const waypointIconStyle = kialiStyle({
 export const setNodeLabel = (
   node: NodeModel,
   nodeMap: NodeMap,
-  settings: GraphPFSettings,
+  settings: GraphSettings,
   layoutName: GraphLayout
 ): void => {
   const data = node.data as NodeData;
@@ -389,7 +389,7 @@ export const setNodeLabel = (
   return;
 };
 
-const getEdgeLabel = (edge: EdgeModel, nodeMap: NodeMap, settings: GraphPFSettings): string => {
+const getEdgeLabel = (edge: EdgeModel, nodeMap: NodeMap, settings: GraphSettings): string => {
   const data = edge.data as EdgeData;
   const edgeLabels = settings.edgeLabels;
   const isVerbose = data.isSelected;
@@ -603,7 +603,7 @@ const getPathStyle = (data: EdgeData): React.CSSProperties => {
   } as React.CSSProperties;
 };
 
-export const setEdgeOptions = (edge: EdgeModel, nodeMap: NodeMap, settings: GraphPFSettings): void => {
+export const setEdgeOptions = (edge: EdgeModel, nodeMap: NodeMap, settings: GraphSettings): void => {
   const data = edge.data as EdgeData;
   if (data.waypoint?.fromEdge) {
     data.startTerminalType = EdgeTerminalType.directional;
@@ -617,7 +617,7 @@ export const setEdgeOptions = (edge: EdgeModel, nodeMap: NodeMap, settings: Grap
 export const assignEdgeHealth = (
   edges: DecoratedGraphEdgeWrapper[],
   nodeMap: NodeMap,
-  settings: GraphPFSettings
+  settings: GraphSettings
 ): void => {
   edges?.forEach(edge => {
     const edgeData = edge.data as EdgeData;
diff --git a/frontend/src/pages/Graph/GraphHelpTour.tsx b/frontend/src/pages/Graph/GraphHelpTour.tsx
index d9a4d2e34..802967f16 100644
--- a/frontend/src/pages/Graph/GraphHelpTour.tsx
+++ b/frontend/src/pages/Graph/GraphHelpTour.tsx
@@ -1,21 +1,13 @@
 import { PopoverPosition } from '@patternfly/react-core';
 import { TourStopInfo, TourInfo } from 'components/Tour/TourStop';
 import { t } from 'utils/I18nUtils';
-import { GraphShortcutsPF } from './GraphToolbar/GraphShortcutsPF';
+import { GraphShortcuts } from './GraphToolbar/GraphShortcuts';
 
 export const GraphTourStops: { [name: string]: TourStopInfo } = {
   ContextualMenu: {
     name: t('Contextual Menu'),
     description: t(
-      'Right-click a node or an edge to see the contextual menu with links to details, traffic and inbound/outbound metrics for the node or edge.'
-    ),
-    position: PopoverPosition.left,
-    distance: 250
-  },
-  ContextualMenuPF: {
-    name: t('Contextual Menu'),
-    description: t(
-      'Click kebab menu on a node label for links to details, traffic, inbound/outbound metrics and node graph.'
+      'Right-click or click kebab menu on a node label for links to details, traffic, inbound/outbound metrics and node graph.'
     ),
     position: PopoverPosition.left,
     distance: 250
@@ -35,13 +27,6 @@ export const GraphTourStops: { [name: string]: TourStopInfo } = {
     position: PopoverPosition.bottom
   },
   Graph: {
-    name: t('Graph'),
-    description:
-      "Click on a node or edge to see its summary and emphasize its end-to-end paths. Double-click a node to see a graph focused on that node.\nDouble-click an t('external namespace' node to navigate directly to the namespace in the node's text label. Shift-Drag to quickly zoom in.",
-    position: PopoverPosition.left,
-    distance: 250
-  },
-  GraphPF: {
     name: t('Graph'),
     description: t('Click on a node or edge to see its summary and emphasize its end-to-end paths.'),
     position: PopoverPosition.left,
@@ -78,9 +63,9 @@ export const GraphTourStops: { [name: string]: TourStopInfo } = {
     description: t('Select the namespaces you want to see in the graph.'),
     position: PopoverPosition.bottomStart
   },
-  ShortcutsPF: {
+  Shortcuts: {
     name: t('Shortcuts'),
-    htmlDescription: GraphShortcutsPF,
+    htmlDescription: GraphShortcuts,
     position: PopoverPosition.leftStart
   },
   SidePanel: {
@@ -99,18 +84,18 @@ export const GraphTourStops: { [name: string]: TourStopInfo } = {
   }
 };
 
-export const GraphTourPF: TourInfo = {
+export const GraphTour: TourInfo = {
   name: t('GraphTour'),
   stops: [
-    GraphTourStops.ShortcutsPF,
+    GraphTourStops.Shortcuts,
     GraphTourStops.Namespaces,
     GraphTourStops.GraphTraffic,
     GraphTourStops.GraphType,
     GraphTourStops.Display,
     GraphTourStops.Find,
     GraphTourStops.TimeRange,
-    GraphTourStops.GraphPF,
-    GraphTourStops.ContextualMenuPF,
+    GraphTourStops.Graph,
+    GraphTourStops.ContextualMenu,
     GraphTourStops.SidePanel,
     GraphTourStops.Layout,
     GraphTourStops.Legend
diff --git a/frontend/src/pages/Graph/GraphHighlighterPF.ts b/frontend/src/pages/Graph/GraphHighlighter.ts
similarity index 98%
rename from frontend/src/pages/Graph/GraphHighlighterPF.ts
rename to frontend/src/pages/Graph/GraphHighlighter.ts
index 01f5a72bb..c6133357e 100644
--- a/frontend/src/pages/Graph/GraphHighlighterPF.ts
+++ b/frontend/src/pages/Graph/GraphHighlighter.ts
@@ -23,10 +23,10 @@
 import { Edge, Node } from '@patternfly/react-topology';
 import { Controller, GraphElement } from '@patternfly/react-topology';
 import { BoxByType, NodeAttr } from 'types/Graph';
-import { NodeData } from './GraphPFElems';
+import { NodeData } from './GraphElems';
 import { ancestors, predecessors, setObserved, successors } from 'helpers/GraphHelpers';
 
-export class GraphHighlighterPF {
+export class GraphHighlighter {
   controller: Controller;
   hovered?: GraphElement;
   selectedId?: string;
diff --git a/frontend/src/pages/Graph/GraphLegend.tsx b/frontend/src/pages/Graph/GraphLegend.tsx
index 077153d41..1638733fa 100644
--- a/frontend/src/pages/Graph/GraphLegend.tsx
+++ b/frontend/src/pages/Graph/GraphLegend.tsx
@@ -7,7 +7,6 @@ import { KialiIcon } from 'config/KialiIcon';
 import { useKialiTranslation } from 'utils/I18nUtils';
 
 interface GraphLegendProps {
-  className?: string;
   closeLegend: () => void;
 }
 
@@ -55,7 +54,7 @@ const legendColumnHeadingStyle = kialiStyle({
 
 const legendBadgeStyle = kialiStyle({
   borderRadius: '0.25rem',
-  backgroundColor: '#703fec'
+  backgroundColor: '#6a6e73'
 });
 
 export const GraphLegend: React.FC<GraphLegendProps> = (props: GraphLegendProps) => {
diff --git a/frontend/src/pages/Graph/GraphLegendData.ts b/frontend/src/pages/Graph/GraphLegendData.ts
index 55bb61b22..d75650d43 100644
--- a/frontend/src/pages/Graph/GraphLegendData.ts
+++ b/frontend/src/pages/Graph/GraphLegendData.ts
@@ -1,28 +1,28 @@
 // Node Shapes
-import workloadImage from '../../assets/img/graph/cy/node.svg';
-import appImage from '../../assets/img/graph/cy/app.svg';
-import serviceImage from '../../assets/img/graph/cy/service.svg';
-import operationImage from '../../assets/img/graph/cy/operation.svg';
-import serviceEntryImage from '../../assets/img/graph/cy/service-entry.svg';
+import workloadImage from '../../assets/img/graph/legend/node.svg';
+import appImage from '../../assets/img/graph/legend/app.svg';
+import serviceImage from '../../assets/img/graph/legend/service.svg';
+import operationImage from '../../assets/img/graph/legend/operation.svg';
+import serviceEntryImage from '../../assets/img/graph/legend/service-entry.svg';
 // Node Colors
-import nodeColorNormalImage from '../../assets/img/graph/cy/node-color-normal.svg';
-import nodeColorWarningImage from '../../assets/img/graph/cy/node-color-warning.svg';
-import nodeColorDangerImage from '../../assets/img/graph/cy/node-color-danger.svg';
-import nodeColorIdleImage from '../../assets/img/graph/cy/node-color-idle.svg';
+import nodeColorHealthyImage from '../../assets/img/graph/legend/node-color-healthy.svg';
+import nodeColorWarningImage from '../../assets/img/graph/legend/node-color-warning.svg';
+import nodeColorDangerImage from '../../assets/img/graph/legend/node-color-danger.svg';
+import nodeColorIdleImage from '../../assets/img/graph/legend/node-color-idle.svg';
 // Node Background
 import externalNamespaceImage from '../../assets/img/graph/external-namespace.svg';
 import restrictedNamespaceImage from '../../assets/img/graph/restricted-namespace.svg';
 // Edges
-import edgeSuccessImage from '../../assets/img/graph/cy/edge-success.svg';
-import edgeDangerImage from '../../assets/img/graph/cy/edge-danger.svg';
-import edgeWarnImage from '../../assets/img/graph/cy/edge-warn.svg';
-import edgeIdlemage from '../../assets/img/graph/cy/edge-idle.svg';
-import edgeTcpImage from '../../assets/img/graph/cy/edge-tcp.svg';
+import edgeSuccessImage from '../../assets/img/graph/legend/edge-success.svg';
+import edgeDangerImage from '../../assets/img/graph/legend/edge-danger.svg';
+import edgeWarnImage from '../../assets/img/graph/legend/edge-warn.svg';
+import edgeIdlemage from '../../assets/img/graph/legend/edge-idle.svg';
+import edgeTcpImage from '../../assets/img/graph/legend/edge-tcp.svg';
 import edgeMtlsImage from '../../assets/img/graph/mtls-badge.svg';
 // Traffic Animation
-import trafficNormalImage from '../../assets/img/graph/cy/traffic-normal-request.svg';
-import trafficFailedImage from '../../assets/img/graph/cy/traffic-failed-request.svg';
-import trafficTcpImage from '../../assets/img/graph/cy/traffic-tcp.svg';
+import trafficHealthyImage from '../../assets/img/graph/legend/traffic-healthy-request.svg';
+import trafficFailedImage from '../../assets/img/graph/legend/traffic-failed-request.svg';
+import trafficTcpImage from '../../assets/img/graph/legend/traffic-tcp.svg';
 // Badges
 import badgeCircuitBreakerImage from '../../assets/img/graph/node-badge-circuit-breaker.svg';
 import badgeFaultInjectionImage from '../../assets/img/graph/node-badge-fault-injection.svg';
@@ -50,7 +50,7 @@ export interface GraphLegendItemRow {
 }
 
 export const legendData = (): GraphLegendItem[] => {
-  const nodesBadges = [
+  const nodeBadges = [
     { label: t('Circuit Breaker'), icon: badgeCircuitBreakerImage },
     { label: t('Fault Injection'), icon: badgeFaultInjectionImage },
     { label: t('Gateway'), icon: badgeGatewaysImage },
@@ -64,7 +64,7 @@ export const legendData = (): GraphLegendItem[] => {
   ];
 
   if (serverConfig.ambientEnabled) {
-    nodesBadges.push({ label: t('Waypoint'), icon: badgeWaypointImage });
+    nodeBadges.push({ label: t('Waypoint'), icon: badgeWaypointImage });
   }
 
   return [
@@ -81,7 +81,7 @@ export const legendData = (): GraphLegendItem[] => {
     {
       title: t('Node Colors'),
       data: [
-        { label: t('Normal'), icon: nodeColorNormalImage },
+        { label: t('Healthy'), icon: nodeColorHealthyImage },
         { label: t('Warn'), icon: nodeColorWarningImage },
         { label: t('Unhealthy'), icon: nodeColorDangerImage },
         { label: t('Idle'), icon: nodeColorIdleImage }
@@ -108,7 +108,7 @@ export const legendData = (): GraphLegendItem[] => {
     {
       title: t('Traffic Animation'),
       data: [
-        { label: t('Normal Request'), icon: trafficNormalImage },
+        { label: t('Healthy Request'), icon: trafficHealthyImage },
         { label: t('Failed Request'), icon: trafficFailedImage },
         { label: t('TCP Traffic'), icon: trafficTcpImage }
       ]
@@ -116,7 +116,7 @@ export const legendData = (): GraphLegendItem[] => {
     {
       title: t('Node Badges'),
       isBadge: true,
-      data: nodesBadges
+      data: nodeBadges
     }
   ];
 };
diff --git a/frontend/src/pages/Graph/GraphLegendDataPF.ts b/frontend/src/pages/Graph/GraphLegendDataPF.ts
deleted file mode 100644
index 5d93c8a2f..000000000
--- a/frontend/src/pages/Graph/GraphLegendDataPF.ts
+++ /dev/null
@@ -1,122 +0,0 @@
-// Node Shapes
-import workloadImage from '../../assets/img/graph/pf/node.svg';
-import appImage from '../../assets/img/graph/pf/app.svg';
-import serviceImage from '../../assets/img/graph/pf/service.svg';
-import operationImage from '../../assets/img/graph/pf/operation.svg';
-import serviceEntryImage from '../../assets/img/graph/pf/service-entry.svg';
-// Node Colors
-import nodeColorHealthyImage from '../../assets/img/graph/pf/node-color-healthy.svg';
-import nodeColorWarningImage from '../../assets/img/graph/pf/node-color-warning.svg';
-import nodeColorDangerImage from '../../assets/img/graph/pf/node-color-danger.svg';
-import nodeColorIdleImage from '../../assets/img/graph/pf/node-color-idle.svg';
-// Node Background
-import externalNamespaceImage from '../../assets/img/graph/external-namespace.svg';
-import restrictedNamespaceImage from '../../assets/img/graph/restricted-namespace.svg';
-// Edges
-import edgeSuccessImage from '../../assets/img/graph/pf/edge-success.svg';
-import edgeDangerImage from '../../assets/img/graph/pf/edge-danger.svg';
-import edgeWarnImage from '../../assets/img/graph/pf/edge-warn.svg';
-import edgeIdlemage from '../../assets/img/graph/pf/edge-idle.svg';
-import edgeTcpImage from '../../assets/img/graph/pf/edge-tcp.svg';
-import edgeMtlsImage from '../../assets/img/graph/mtls-badge.svg';
-// Traffic Animation
-import trafficHealthyImage from '../../assets/img/graph/pf/traffic-healthy-request.svg';
-import trafficFailedImage from '../../assets/img/graph/pf/traffic-failed-request.svg';
-import trafficTcpImage from '../../assets/img/graph/pf/traffic-tcp.svg';
-// Badges
-import badgeCircuitBreakerImage from '../../assets/img/graph/node-badge-circuit-breaker.svg';
-import badgeFaultInjectionImage from '../../assets/img/graph/node-badge-fault-injection.svg';
-import badgeGatewaysImage from '../../assets/img/graph/node-badge-gateways.svg';
-import badgeMirroringImage from '../../assets/img/graph/node-badge-mirroring.svg';
-import badgeMissingSidecarImage from '../../assets/img/graph/node-badge-missing-sidecar.svg';
-import badgeRequestTimeoutImage from '../../assets/img/graph/node-badge-request-timeout.svg';
-import badgeTrafficShiftingSourceImage from '../../assets/img/graph/node-badge-traffic-shifting.svg';
-import badgeTrafficSourceImage from '../../assets/img/graph/node-badge-traffic-source.svg';
-import badgeVirtualServicesImage from '../../assets/img/graph/node-badge-virtual-services.svg';
-import badgeWorkloadEntryImage from '../../assets/img/graph/node-badge-workload-entry.svg';
-import badgeWaypointImage from '../../assets/img/graph/node-badge-waypoint.svg';
-import { t } from 'utils/I18nUtils';
-import { serverConfig } from '../../config';
-
-export interface GraphLegendItem {
-  data: GraphLegendItemRow[];
-  isBadge?: boolean;
-  title: string;
-}
-
-export interface GraphLegendItemRow {
-  icon: string;
-  label: string;
-}
-
-export const legendData = (): GraphLegendItem[] => {
-  const nodeBadges = [
-    { label: t('Circuit Breaker'), icon: badgeCircuitBreakerImage },
-    { label: t('Fault Injection'), icon: badgeFaultInjectionImage },
-    { label: t('Gateway'), icon: badgeGatewaysImage },
-    { label: t('Mirroring'), icon: badgeMirroringImage },
-    { label: t('Missing Sidecar'), icon: badgeMissingSidecarImage },
-    { label: t('Request Timeout'), icon: badgeRequestTimeoutImage },
-    { label: t('Traffic Shifting / TCP Traffic Shifting'), icon: badgeTrafficShiftingSourceImage },
-    { label: t('Traffic Source'), icon: badgeTrafficSourceImage },
-    { label: t('Virtual Service / Request Routing'), icon: badgeVirtualServicesImage },
-    { label: t('Workload Entry'), icon: badgeWorkloadEntryImage }
-  ];
-
-  if (serverConfig.ambientEnabled) {
-    nodeBadges.push({ label: t('Waypoint'), icon: badgeWaypointImage });
-  }
-
-  return [
-    {
-      title: t('Node Shapes'),
-      data: [
-        { label: t('Workload'), icon: workloadImage },
-        { label: t('App'), icon: appImage },
-        { label: t('Operation'), icon: operationImage },
-        { label: t('Service'), icon: serviceImage },
-        { label: t('Service Entry'), icon: serviceEntryImage }
-      ]
-    },
-    {
-      title: t('Node Colors'),
-      data: [
-        { label: t('Healthy'), icon: nodeColorHealthyImage },
-        { label: t('Warn'), icon: nodeColorWarningImage },
-        { label: t('Unhealthy'), icon: nodeColorDangerImage },
-        { label: t('Idle'), icon: nodeColorIdleImage }
-      ]
-    },
-    {
-      title: t('Node Background'),
-      data: [
-        { label: t('Unselected Namespace'), icon: externalNamespaceImage },
-        { label: t('Restricted / External'), icon: restrictedNamespaceImage }
-      ]
-    },
-    {
-      title: t('Edges'),
-      data: [
-        { label: t('Failure'), icon: edgeDangerImage },
-        { label: t('Degraded'), icon: edgeWarnImage },
-        { label: t('Healthy'), icon: edgeSuccessImage },
-        { label: t('TCP Connection'), icon: edgeTcpImage },
-        { label: t('Idle'), icon: edgeIdlemage },
-        { label: t('mTLS (badge)'), icon: edgeMtlsImage }
-      ]
-    },
-    {
-      title: t('Traffic Animation'),
-      data: [
-        { label: t('Healthy Request'), icon: trafficHealthyImage },
-        { label: t('Failed Request'), icon: trafficFailedImage },
-        { label: t('TCP Traffic'), icon: trafficTcpImage }
-      ]
-    },
-    {
-      title: t('Node Badges'),
-      isBadge: true,
-      data: nodeBadges
-    }
-  ];
-};
diff --git a/frontend/src/pages/Graph/GraphLegendPF.tsx b/frontend/src/pages/Graph/GraphLegendPF.tsx
deleted file mode 100644
index fb2fe9552..000000000
--- a/frontend/src/pages/Graph/GraphLegendPF.tsx
+++ /dev/null
@@ -1,105 +0,0 @@
-import * as React from 'react';
-import { kialiStyle } from 'styles/StyleUtils';
-import { legendData, GraphLegendItem, GraphLegendItemRow } from './GraphLegendDataPF';
-import { Button, ButtonVariant, Tooltip } from '@patternfly/react-core';
-import { PFColors } from 'components/Pf/PfColors';
-import { KialiIcon } from 'config/KialiIcon';
-import { useKialiTranslation } from 'utils/I18nUtils';
-
-interface GraphLegendPFProps {
-  closeLegend: () => void;
-}
-
-const legendBoxStyle = kialiStyle({
-  width: '225px',
-  backgroundColor: PFColors.BackgroundColor100,
-  border: `1px solid ${PFColors.BorderColor100}`,
-  overflowY: 'auto',
-  zIndex: 3
-});
-
-const headerStyle = kialiStyle({
-  display: 'flex',
-  alignItems: 'center',
-  justifyContent: 'space-between',
-  borderBottom: `1px solid ${PFColors.BorderColor100}`,
-  padding: '0.5rem 0 0.5rem 1rem',
-  fontWeight: 'bold'
-});
-
-const bodyStyle = kialiStyle({
-  padding: '0 0.5rem 1rem 1rem'
-});
-
-const keyStyle = kialiStyle({
-  minWidth: '70px',
-  width: '70px'
-});
-
-const legendItemStyle = kialiStyle({
-  display: 'flex',
-  flexDirection: 'row',
-  alignItems: 'center',
-  padding: '0.25rem 0.25rem 0 0.25rem'
-});
-
-const legendItemLabelStyle = kialiStyle({
-  fontWeight: 'normal'
-});
-
-const legendColumnHeadingStyle = kialiStyle({
-  fontWeight: 'bold',
-  paddingTop: '1.25rem'
-});
-
-const legendBadgeStyle = kialiStyle({
-  borderRadius: '0.25rem',
-  backgroundColor: '#6a6e73'
-});
-
-export const GraphLegendPF: React.FC<GraphLegendPFProps> = (props: GraphLegendPFProps) => {
-  const { t } = useKialiTranslation();
-
-  const renderGraphLegendList = (legendData: GraphLegendItem[]): React.ReactNode => {
-    return (
-      <>
-        {legendData.map((legendItem: GraphLegendItem) => (
-          <div key={legendItem.title} className={legendColumnHeadingStyle}>
-            {t(legendItem.title)}
-
-            {legendItem.data.map((legendItemRow: GraphLegendItemRow) =>
-              renderLegendIconAndLabel(legendItemRow, legendItem.isBadge)
-            )}
-          </div>
-        ))}
-      </>
-    );
-  };
-
-  const renderLegendIconAndLabel = (legendItemRow: GraphLegendItemRow, isBadge?: boolean): React.ReactNode => {
-    return (
-      <div key={legendItemRow.icon} className={legendItemStyle}>
-        <span className={keyStyle}>
-          <img alt={legendItemRow.label} src={legendItemRow.icon} className={isBadge ? legendBadgeStyle : ''} />
-        </span>
-
-        <span className={legendItemLabelStyle}>{t(legendItemRow.label)}</span>
-      </div>
-    );
-  };
-
-  return (
-    <div className={legendBoxStyle} data-test="graph-legend">
-      <div className={headerStyle}>
-        <span>{t('Legend')}</span>
-        <Tooltip content={t('Close Legend')}>
-          <Button id="legend_close" variant={ButtonVariant.plain} onClick={props.closeLegend}>
-            <KialiIcon.Close />
-          </Button>
-        </Tooltip>
-      </div>
-
-      <div className={bodyStyle}>{renderGraphLegendList(legendData())}</div>
-    </div>
-  );
-};
diff --git a/frontend/src/pages/Graph/GraphPagePF.tsx b/frontend/src/pages/Graph/GraphPage.tsx
similarity index 96%
rename from frontend/src/pages/Graph/GraphPagePF.tsx
rename to frontend/src/pages/Graph/GraphPage.tsx
index b6a35149b..dec2872c5 100644
--- a/frontend/src/pages/Graph/GraphPagePF.tsx
+++ b/frontend/src/pages/Graph/GraphPage.tsx
@@ -56,7 +56,7 @@ import { GraphThunkActions } from '../../actions/GraphThunkActions';
 import { JaegerTrace } from 'types/TracingInfo';
 import { KialiDispatch } from 'types/Redux';
 import { TracingThunkActions } from 'actions/TracingThunkActions';
-import { GraphTourPF } from 'pages/Graph/GraphHelpTour';
+import { GraphTour } from 'pages/Graph/GraphHelpTour';
 import { getNextTourStop, TourInfo } from 'components/Tour/TourStop';
 import { ServiceWizard } from 'components/IstioWizards/ServiceWizard';
 import { ServiceDetailsInfo } from 'types/ServiceInfo';
@@ -67,9 +67,9 @@ import { deleteServiceTrafficRouting } from 'services/Api';
 import { canCreate, canUpdate } from '../../types/Permissions';
 import { connectRefresh } from '../../components/Refresh/connectRefresh';
 import { triggerRefresh } from '../../hooks/refresh';
-import { GraphPF, FocusNode, getValidGraphLayout, GraphLayout } from './GraphPF';
+import { Graph, FocusNode, getValidGraphLayout, GraphLayout } from './Graph';
 import { Controller } from '@patternfly/react-topology';
-import { GraphLegendPF } from './GraphLegendPF';
+import { GraphLegend } from './GraphLegend';
 import { HistoryManager, URLParam } from 'app/History';
 import { elementsChanged } from 'helpers/GraphHelpers';
 
@@ -140,7 +140,7 @@ type ReduxStateProps = {
 };
 type ReduxProps = ReduxStateProps & ReduxDispatchProps;
 
-export type GraphPagePropsPF = Partial<GraphURLPathProps> &
+export type GraphPageProps = Partial<GraphURLPathProps> &
   ReduxProps & {
     lastRefreshAt: TimeInMilliseconds; // redux by way of ConnectRefresh
   };
@@ -175,7 +175,7 @@ type WizardsData = {
   wizardType: string;
 };
 
-type GraphPageStatePF = {
+type GraphPageState = {
   graphData: GraphData;
   graphRefs?: GraphRefs;
   isReady: boolean;
@@ -229,7 +229,7 @@ const GraphErrorBoundaryFallback = (): React.ReactElement => {
   );
 };
 
-class GraphPagePFComponent extends React.Component<GraphPagePropsPF, GraphPageStatePF> {
+class GraphPageComponent extends React.Component<GraphPageProps, GraphPageState> {
   private readonly errorBoundaryRef: any;
   private focusNode?: FocusNode;
   private graphDataSource: GraphDataSource;
@@ -304,7 +304,7 @@ class GraphPagePFComponent extends React.Component<GraphPagePropsPF, GraphPageSt
     return false;
   }
 
-  constructor(props: GraphPagePropsPF) {
+  constructor(props: GraphPageProps) {
     super(props);
     this.errorBoundaryRef = React.createRef();
     const focusNodeId = getFocusSelector();
@@ -347,8 +347,8 @@ class GraphPagePFComponent extends React.Component<GraphPagePropsPF, GraphPageSt
     // the constructor but it seems to work better here when the initial URL
     // is for a node graph.  When setting the node here it is available for the
     // loadGraphFromBackend() call.
-    const urlNode = GraphPagePFComponent.getNodeParamsFromProps(this.props);
-    if (GraphPagePFComponent.isNodeChanged(urlNode, this.props.node)) {
+    const urlNode = GraphPageComponent.getNodeParamsFromProps(this.props);
+    if (GraphPageComponent.isNodeChanged(urlNode, this.props.node)) {
       // add the node namespace if necessary, but don't lose previously selected namespaces
       if (urlNode && !this.props.activeNamespaces.map(ns => ns.name).includes(urlNode.namespace.name)) {
         this.props.setActiveNamespaces([urlNode.namespace, ...this.props.activeNamespaces]);
@@ -380,7 +380,7 @@ class GraphPagePFComponent extends React.Component<GraphPagePropsPF, GraphPageSt
     setTimeout(() => this.loadGraphDataFromBackend(), 0);
   }
 
-  componentDidUpdate(prev: GraphPagePropsPF): void {
+  componentDidUpdate(prev: GraphPageProps): void {
     const curr = this.props;
 
     const activeNamespacesChanged = !arrayEquals(
@@ -415,7 +415,7 @@ class GraphPagePFComponent extends React.Component<GraphPagePropsPF, GraphPageSt
       prev.showIdleNodes !== curr.showIdleNodes ||
       prev.showWaypoints !== curr.showWaypoints ||
       prev.trafficRates !== curr.trafficRates ||
-      GraphPagePFComponent.isNodeChanged(prev.node, curr.node)
+      GraphPageComponent.isNodeChanged(prev.node, curr.node)
     ) {
       this.loadGraphDataFromBackend();
     }
@@ -465,7 +465,7 @@ class GraphPagePFComponent extends React.Component<GraphPagePropsPF, GraphPageSt
               onError={this.notifyError}
               fallBackComponent={<GraphErrorBoundaryFallback />}
             >
-              {this.props.showLegend && <GraphLegendPF closeLegend={this.props.toggleLegend} />}
+              {this.props.showLegend && <GraphLegend closeLegend={this.props.toggleLegend} />}
               {isReady && (
                 <Chip
                   className={`${graphTimeRange} ${this.props.replayActive ? replayBackground : graphBackground}`}
@@ -490,7 +490,7 @@ class GraphPagePFComponent extends React.Component<GraphPagePropsPF, GraphPageSt
                     showIdleNodes={this.props.showIdleNodes}
                     toggleIdleNodes={this.props.toggleIdleNodes}
                   >
-                    <GraphPF
+                    <Graph
                       {...this.props}
                       focusNode={this.focusNode}
                       graphData={this.state.graphData}
@@ -503,7 +503,7 @@ class GraphPagePFComponent extends React.Component<GraphPagePropsPF, GraphPageSt
                 </div>
               )}
             </ErrorBoundary>
-            {this.props.summaryData && (
+            {this.props.summaryData && (!this.props.replayActive || isReplayReady) && (
               <SummaryPanel
                 data={this.props.summaryData}
                 duration={this.state.graphData.fetchParams.duration}
@@ -708,8 +708,8 @@ class GraphPagePFComponent extends React.Component<GraphPagePropsPF, GraphPageSt
     if (this.props.activeTour) {
       this.props.endTour();
     } else {
-      const firstStop = getNextTourStop(GraphTourPF, -1, 'forward');
-      this.props.startTour({ info: GraphTourPF, stop: firstStop });
+      const firstStop = getNextTourStop(GraphTour, -1, 'forward');
+      this.props.startTour({ info: GraphTour, stop: firstStop });
     }
   };
 
@@ -792,7 +792,7 @@ const mapStateToProps = (state: KialiAppState): ReduxStateProps => ({
 const mapDispatchToProps = (dispatch: KialiDispatch): ReduxDispatchProps => ({
   endTour: bindActionCreators(TourActions.endTour, dispatch),
   onNamespaceChange: bindActionCreators(GraphActions.onNamespaceChange, dispatch),
-  onReady: (controller: Controller) => dispatch(GraphThunkActions.graphPFReady(controller)),
+  onReady: (controller: Controller) => dispatch(GraphThunkActions.graphReady(controller)),
   setActiveNamespaces: (namespaces: Namespace[]) => dispatch(NamespaceActions.setActiveNamespaces(namespaces)),
   setEdgeMode: bindActionCreators(GraphActions.setEdgeMode, dispatch),
   setGraphDefinition: bindActionCreators(GraphActions.setGraphDefinition, dispatch),
@@ -807,4 +807,4 @@ const mapDispatchToProps = (dispatch: KialiDispatch): ReduxDispatchProps => ({
   updateSummary: (event: GraphEvent) => dispatch(GraphActions.updateSummary(event))
 });
 
-export const GraphPagePF = connectRefresh(connect(mapStateToProps, mapDispatchToProps)(GraphPagePFComponent));
+export const GraphPage = connectRefresh(connect(mapStateToProps, mapDispatchToProps)(GraphPageComponent));
diff --git a/frontend/src/pages/Graph/GraphToolbar/GraphFindPF.tsx b/frontend/src/pages/Graph/GraphToolbar/GraphFind.tsx
similarity index 99%
rename from frontend/src/pages/Graph/GraphToolbar/GraphFindPF.tsx
rename to frontend/src/pages/Graph/GraphToolbar/GraphFind.tsx
index 4f3c4291a..94ff789ef 100644
--- a/frontend/src/pages/Graph/GraphToolbar/GraphFindPF.tsx
+++ b/frontend/src/pages/Graph/GraphToolbar/GraphFind.tsx
@@ -31,11 +31,11 @@ import { HEALTHY, NA, NOT_READY } from 'types/Health';
 import { GraphFindOptions } from './GraphFindOptions';
 import { location, HistoryManager, URLParam } from '../../../app/History';
 import { isValid } from 'utils/Common';
-import { EdgeData, NodeData } from 'pages/Graph/GraphPFElems';
+import { EdgeData, NodeData } from 'pages/Graph/GraphElems';
 import { elems, SelectAnd, SelectExp, selectOr, SelectOr, setObserved, toSafeFieldName } from 'helpers/GraphHelpers';
 import { descendents } from 'helpers/GraphHelpers';
 import { isArray } from 'lodash';
-import { graphLayout, LayoutType } from 'pages/Graph/GraphPF';
+import { graphLayout, LayoutType } from 'pages/Graph/Graph';
 import { infoStyle } from 'styles/IconStyle';
 
 type ReduxStateProps = {
@@ -162,7 +162,7 @@ const operands: string[] = [
   'workloadentry'
 ];
 
-export class GraphFindPFComponent extends React.Component<GraphFindProps, GraphFindState> {
+export class GraphFindComponent extends React.Component<GraphFindProps, GraphFindState> {
   static contextTypes = {
     router: (): null => null
   };
@@ -1219,4 +1219,4 @@ const mapDispatchToProps = (dispatch: KialiDispatch): ReduxDispatchProps => {
   };
 };
 
-export const GraphFindPF = connect(mapStateToProps, mapDispatchToProps)(GraphFindPFComponent);
+export const GraphFind = connect(mapStateToProps, mapDispatchToProps)(GraphFindComponent);
diff --git a/frontend/src/pages/Graph/GraphToolbar/GraphShortcutsPF.tsx b/frontend/src/pages/Graph/GraphToolbar/GraphShortcuts.tsx
similarity index 95%
rename from frontend/src/pages/Graph/GraphToolbar/GraphShortcutsPF.tsx
rename to frontend/src/pages/Graph/GraphToolbar/GraphShortcuts.tsx
index dfda048b5..9392068ce 100644
--- a/frontend/src/pages/Graph/GraphToolbar/GraphShortcutsPF.tsx
+++ b/frontend/src/pages/Graph/GraphToolbar/GraphShortcuts.tsx
@@ -30,7 +30,7 @@ const makeShortcut = (shortcut: Shortcut): React.ReactNode => {
   );
 };
 
-export const GraphShortcutsPF = (): React.ReactNode => (
+export const GraphShortcuts = (): React.ReactNode => (
   <>
     {shortcuts.map(
       (s: Shortcut): React.ReactNode => {
diff --git a/frontend/src/pages/Graph/GraphToolbar/GraphToolbar.tsx b/frontend/src/pages/Graph/GraphToolbar/GraphToolbar.tsx
index 50fbd7a0e..f8666af60 100644
--- a/frontend/src/pages/Graph/GraphToolbar/GraphToolbar.tsx
+++ b/frontend/src/pages/Graph/GraphToolbar/GraphToolbar.tsx
@@ -35,7 +35,7 @@ import { UserSettingsActions } from 'actions/UserSettingsActions';
 import { GraphSecondaryMasthead } from './GraphSecondaryMasthead';
 import { INITIAL_USER_SETTINGS_STATE } from 'reducers/UserSettingsState';
 import { GraphReset } from './GraphReset';
-import { GraphFindPF } from './GraphFindPF';
+import { GraphFind } from './GraphFind';
 import { kialiStyle } from 'styles/StyleUtils';
 import { isParentKiosk, kioskContextMenuAction } from 'components/Kiosk/KioskActions';
 
@@ -225,12 +225,12 @@ class GraphToolbarComponent extends React.PureComponent<GraphToolbarProps> {
             </ToolbarItem>
 
             <ToolbarItem>
-              <GraphFindPF controller={this.props.controller} elementsChanged={this.props.elementsChanged} />
+              <GraphFind controller={this.props.controller} elementsChanged={this.props.elementsChanged} />
             </ToolbarItem>
 
             <ToolbarItem style={{ marginLeft: 'auto', alignSelf: 'center' }}>
               <Tooltip key={'graph-tour-help-ot'} position={TooltipPosition.right} content="Shortcuts and tips...">
-                <TourStop info={GraphTourStops.ShortcutsPF}>
+                <TourStop info={GraphTourStops.Shortcuts}>
                   <Button
                     id="graph-tour"
                     variant={ButtonVariant.link}
@@ -253,7 +253,7 @@ class GraphToolbarComponent extends React.PureComponent<GraphToolbarProps> {
   }
 
   private handleNamespaceReturn = (): void => {
-    const route = 'graphpf';
+    const route = 'graph';
     if (
       !this.props.summaryData ||
       (this.props.summaryData.summaryType !== 'node' && this.props.summaryData.summaryType !== 'box')
diff --git a/frontend/src/pages/Graph/GraphToolbar/__tests__/GraphFind.test.tsx b/frontend/src/pages/Graph/GraphToolbar/__tests__/GraphFind.test.tsx
index 034d59048..7f2c5163e 100644
--- a/frontend/src/pages/Graph/GraphToolbar/__tests__/GraphFind.test.tsx
+++ b/frontend/src/pages/Graph/GraphToolbar/__tests__/GraphFind.test.tsx
@@ -1,6 +1,6 @@
 import * as React from 'react';
 import { shallow } from 'enzyme';
-import { GraphFindPFComponent } from '../GraphFindPF';
+import { GraphFindComponent } from '../GraphFind';
 import { EdgeLabelMode, EdgeMode } from 'types/Graph';
 import { Controller } from '@patternfly/react-topology';
 
@@ -11,7 +11,7 @@ const testSetter = _val => undefined;
 describe('Parse find value test', () => {
   it('should return the correct selector for raw find values', () => {
     const wrapper = shallow(
-      <GraphFindPFComponent
+      <GraphFindComponent
         controller={{} as Controller}
         edgeLabels={[] as EdgeLabelMode[]}
         edgeMode={EdgeMode.ALL}
@@ -32,7 +32,7 @@ describe('Parse find value test', () => {
       />
     );
 
-    const instance = wrapper.instance() as GraphFindPFComponent;
+    const instance = wrapper.instance() as GraphFindComponent;
 
     // check coverage of node operands
     // @ts-ignore
diff --git a/frontend/src/pages/Graph/GraphToolbar/__tests__/__snapshots__/GraphLegend.test.tsx.snap b/frontend/src/pages/Graph/GraphToolbar/__tests__/__snapshots__/GraphLegend.test.tsx.snap
index c8e332f4f..8ba5934ec 100644
--- a/frontend/src/pages/Graph/GraphToolbar/__tests__/__snapshots__/GraphLegend.test.tsx.snap
+++ b/frontend/src/pages/Graph/GraphToolbar/__tests__/__snapshots__/GraphLegend.test.tsx.snap
@@ -134,21 +134,21 @@ exports[`GraphLegend test should render correctly 1`] = `
       Node Colors
       <div
         className="kiali_fxx5dxr"
-        key="node-color-normal.svg"
+        key="node-color-healthy.svg"
       >
         <span
           className="kiali_fzoxfwf"
         >
           <img
-            alt="Normal"
+            alt="Healthy"
             className=""
-            src="node-color-normal.svg"
+            src="node-color-healthy.svg"
           />
         </span>
         <span
           className="kiali_f7pgfh0"
         >
-          Normal
+          Healthy
         </span>
       </div>
       <div
@@ -380,21 +380,21 @@ exports[`GraphLegend test should render correctly 1`] = `
       Traffic Animation
       <div
         className="kiali_fxx5dxr"
-        key="traffic-normal-request.svg"
+        key="traffic-healthy-request.svg"
       >
         <span
           className="kiali_fzoxfwf"
         >
           <img
-            alt="Normal Request"
+            alt="Healthy Request"
             className=""
-            src="traffic-normal-request.svg"
+            src="traffic-healthy-request.svg"
           />
         </span>
         <span
           className="kiali_f7pgfh0"
         >
-          Normal Request
+          Healthy Request
         </span>
       </div>
       <div
@@ -450,7 +450,7 @@ exports[`GraphLegend test should render correctly 1`] = `
         >
           <img
             alt="Circuit Breaker"
-            className="kiali_fc81d57"
+            className="kiali_f8j7sv3"
             src="node-badge-circuit-breaker.svg"
           />
         </span>
@@ -469,7 +469,7 @@ exports[`GraphLegend test should render correctly 1`] = `
         >
           <img
             alt="Fault Injection"
-            className="kiali_fc81d57"
+            className="kiali_f8j7sv3"
             src="node-badge-fault-injection.svg"
           />
         </span>
@@ -488,7 +488,7 @@ exports[`GraphLegend test should render correctly 1`] = `
         >
           <img
             alt="Gateway"
-            className="kiali_fc81d57"
+            className="kiali_f8j7sv3"
             src="node-badge-gateways.svg"
           />
         </span>
@@ -507,7 +507,7 @@ exports[`GraphLegend test should render correctly 1`] = `
         >
           <img
             alt="Mirroring"
-            className="kiali_fc81d57"
+            className="kiali_f8j7sv3"
             src="node-badge-mirroring.svg"
           />
         </span>
@@ -526,7 +526,7 @@ exports[`GraphLegend test should render correctly 1`] = `
         >
           <img
             alt="Missing Sidecar"
-            className="kiali_fc81d57"
+            className="kiali_f8j7sv3"
             src="node-badge-missing-sidecar.svg"
           />
         </span>
@@ -545,7 +545,7 @@ exports[`GraphLegend test should render correctly 1`] = `
         >
           <img
             alt="Request Timeout"
-            className="kiali_fc81d57"
+            className="kiali_f8j7sv3"
             src="node-badge-request-timeout.svg"
           />
         </span>
@@ -564,7 +564,7 @@ exports[`GraphLegend test should render correctly 1`] = `
         >
           <img
             alt="Traffic Shifting / TCP Traffic Shifting"
-            className="kiali_fc81d57"
+            className="kiali_f8j7sv3"
             src="node-badge-traffic-shifting.svg"
           />
         </span>
@@ -583,7 +583,7 @@ exports[`GraphLegend test should render correctly 1`] = `
         >
           <img
             alt="Traffic Source"
-            className="kiali_fc81d57"
+            className="kiali_f8j7sv3"
             src="node-badge-traffic-source.svg"
           />
         </span>
@@ -602,7 +602,7 @@ exports[`GraphLegend test should render correctly 1`] = `
         >
           <img
             alt="Virtual Service / Request Routing"
-            className="kiali_fc81d57"
+            className="kiali_f8j7sv3"
             src="node-badge-virtual-services.svg"
           />
         </span>
@@ -621,7 +621,7 @@ exports[`GraphLegend test should render correctly 1`] = `
         >
           <img
             alt="Workload Entry"
-            className="kiali_fc81d57"
+            className="kiali_f8j7sv3"
             src="node-badge-workload-entry.svg"
           />
         </span>
diff --git a/frontend/src/pages/Graph/MiniGraphCardPF.tsx b/frontend/src/pages/Graph/MiniGraphCard.tsx
similarity index 89%
rename from frontend/src/pages/Graph/MiniGraphCardPF.tsx
rename to frontend/src/pages/Graph/MiniGraphCard.tsx
index 334fe0d7f..8b9cdcebb 100644
--- a/frontend/src/pages/Graph/MiniGraphCardPF.tsx
+++ b/frontend/src/pages/Graph/MiniGraphCard.tsx
@@ -21,7 +21,7 @@ import { store } from 'store/ConfigStore';
 import { TimeInMilliseconds } from '../../types/Common';
 import { ServiceDetailsInfo } from '../../types/ServiceInfo';
 import { KialiAppState } from '../../store/Store';
-import { GraphLayout, GraphPF } from './GraphPF';
+import { GraphLayout, Graph } from './Graph';
 import { WizardAction, WizardMode } from 'components/IstioWizards/WizardActions';
 import { isKiosk, isParentKiosk, kioskContextMenuAction } from 'components/Kiosk/KioskActions';
 import { ServiceWizardActionsDropdownGroup } from 'components/IstioWizards/ServiceWizardActionsDropdownGroup';
@@ -32,14 +32,13 @@ import { TimeDurationModal } from 'components/Time/TimeDurationModal';
 import { KialiDispatch } from 'types/Redux';
 import { bindActionCreators } from 'redux';
 import { GraphActions } from 'actions/GraphActions';
-import { GraphSelectorBuilder } from 'pages/Graph/GraphSelector';
-import { NodeData } from './GraphPFElems';
+import { NodeData } from './GraphElems';
 import { elems, selectAnd } from 'helpers/GraphHelpers';
 import { KialiIcon } from 'config/KialiIcon';
 import { kebabToggleStyle } from 'styles/DropdownStyles';
 import { WorkloadWizardActionsDropdownGroup } from 'components/IstioWizards/WorkloadWizardActionsDropdownGroup';
 import { Workload } from 'types/Workload';
-import { GraphRefs } from './GraphPagePF';
+import { GraphRefs } from './GraphPage';
 import { EmptyGraphLayout } from 'pages/Graph/EmptyGraphLayout';
 
 type ReduxDispatchProps = {
@@ -53,7 +52,7 @@ type ReduxProps = ReduxDispatchProps & {
   kiosk: string;
 };
 
-type MiniGraphCardPropsPF = ReduxProps & {
+type MiniGraphCardProps = ReduxProps & {
   dataSource: GraphDataSource;
   namespace?: string;
   onDeleteTrafficRouting?: (key: string) => void;
@@ -67,16 +66,18 @@ type MiniGraphCardState = {
   graphData: DecoratedGraphElements;
   graphRefs?: GraphRefs;
   isKebabOpen: boolean;
+  isLoading: boolean;
   isReady: boolean;
   isTimeOptionsOpen: boolean;
 };
 
-class MiniGraphCardPFComponent extends React.Component<MiniGraphCardPropsPF, MiniGraphCardState> {
-  constructor(props: MiniGraphCardPropsPF) {
+class MiniGraphCardComponent extends React.Component<MiniGraphCardProps, MiniGraphCardState> {
+  constructor(props: MiniGraphCardProps) {
     super(props);
     this.state = {
-      isReady: false,
       isKebabOpen: false,
+      isLoading: props.dataSource.isLoading,
+      isReady: false,
       isTimeOptionsOpen: false,
       graphData: props.dataSource.graphData
     };
@@ -93,7 +94,7 @@ class MiniGraphCardPFComponent extends React.Component<MiniGraphCardPropsPF, Min
   }
 
   private refresh = (): void => {
-    this.setState({ graphData: this.props.dataSource.graphData });
+    this.setState({ graphData: this.props.dataSource.graphData, isLoading: this.props.dataSource.isLoading });
   };
 
   render(): React.ReactNode {
@@ -132,7 +133,7 @@ class MiniGraphCardPFComponent extends React.Component<MiniGraphCardPropsPF, Min
     }
 
     // The parent component supplies the datasource and the target element. Here we protect against a lifecycle issue where the two
-    // can be out of sync. If so, just assume the parent is currently loading until it things get synchronized.
+    // can be out of sync. If so, just assume the parent is currently loading until things get synchronized.
     const isLoading =
       (this.props.workload && this.props.workload?.name !== this.props.dataSource.fetchParameters.node?.workload) ||
       (this.props.serviceDetails &&
@@ -195,7 +196,7 @@ class MiniGraphCardPFComponent extends React.Component<MiniGraphCardPropsPF, Min
                 isError={this.props.dataSource.isError}
                 isMiniGraph={true}
               >
-                <GraphPF
+                <Graph
                   edgeLabels={this.props.dataSource.fetchParameters.edgeLabels}
                   edgeMode={EdgeMode.ALL}
                   graphData={{
@@ -203,7 +204,7 @@ class MiniGraphCardPFComponent extends React.Component<MiniGraphCardPropsPF, Min
                     elementsChanged: true,
                     errorMessage: !!this.props.dataSource.errorMessage ? this.props.dataSource.errorMessage : undefined,
                     isError: this.props.dataSource.isError,
-                    isLoading: this.props.dataSource.isLoading,
+                    isLoading: isLoading,
                     fetchParams: this.props.dataSource.fetchParameters,
                     timestamp: this.props.dataSource.graphTimestamp
                   }}
@@ -365,37 +366,14 @@ class MiniGraphCardPFComponent extends React.Component<MiniGraphCardPropsPF, Min
 
   private onViewFullGraph = (): void => {
     const namespace = this.props.dataSource.fetchParameters.namespaces[0].name;
-    let graphSelector = new GraphSelectorBuilder().namespace(namespace);
     let graphType: GraphType = GraphType.APP;
 
-    switch (this.props.dataSource.fetchParameters.node!.nodeType) {
-      case NodeType.AGGREGATE:
-        graphSelector = graphSelector
-          .aggregate(
-            this.props.dataSource.fetchParameters.node!.aggregate!,
-            this.props.dataSource.fetchParameters.node!.aggregateValue!
-          )
-          .nodeType(NodeType.AGGREGATE);
-        break;
-      case NodeType.APP:
-        graphSelector = graphSelector.app(this.props.dataSource.fetchParameters.node!.app).nodeType(NodeType.APP);
-        break;
-      case NodeType.SERVICE:
-        graphType = GraphType.SERVICE;
-        graphSelector = graphSelector.service(this.props.dataSource.fetchParameters.node!.service);
-        break;
-      case NodeType.WORKLOAD:
-        graphType = GraphType.WORKLOAD;
-        graphSelector = graphSelector.workload(this.props.dataSource.fetchParameters.node!.workload);
-        break;
-      default:
-        // NodeType.BOX is n/a
-        break;
-    }
+    const selected = selectAnd(elems(this.state.graphRefs!.getController()).nodes, [
+      { prop: 'isSelected', op: 'truthy' }
+    ]);
+    const focusSelector = selected.length > 0 ? `&focusSelector=${encodeURI(selected[0].getId())}` : '';
 
-    const graphUrl = `/graphpf/namespaces?graphType=${graphType}&injectServiceNodes=true&namespaces=${namespace}&focusSelector=${encodeURI(
-      graphSelector.build()
-    )}`;
+    const graphUrl = `/graph/namespaces?graphType=${graphType}&injectServiceNodes=true&namespaces=${namespace}${focusSelector}`;
 
     if (isParentKiosk(this.props.kiosk)) {
       kioskContextMenuAction(graphUrl);
@@ -461,4 +439,4 @@ const mapDispatchToProps = (dispatch: KialiDispatch): ReduxDispatchProps => ({
   updateSummary: (event: GraphEvent) => dispatch(GraphActions.updateSummary(event))
 });
 
-export const MiniGraphCardPF = connect(mapStateToProps, mapDispatchToProps)(MiniGraphCardPFComponent);
+export const MiniGraphCard = connect(mapStateToProps, mapDispatchToProps)(MiniGraphCardComponent);
diff --git a/frontend/src/pages/Graph/SummaryPanel.tsx b/frontend/src/pages/Graph/SummaryPanel.tsx
index 07abf1e5a..3667c639a 100644
--- a/frontend/src/pages/Graph/SummaryPanel.tsx
+++ b/frontend/src/pages/Graph/SummaryPanel.tsx
@@ -18,7 +18,7 @@ import { summaryPanelWidth } from './SummaryPanelCommon';
 import { WizardAction, WizardMode } from 'components/IstioWizards/WizardActions';
 import { ServiceDetailsInfo } from '../../types/ServiceInfo';
 import { PeerAuthentication } from '../../types/IstioObjects';
-import { FocusNode } from 'pages/Graph/GraphPF';
+import { FocusNode } from 'pages/Graph/Graph';
 import { classes } from 'typestyle';
 import { panelBodyStyle, panelStyle } from './SummaryPanelStyle';
 import { PFColors } from 'components/Pf/PfColors';
@@ -114,8 +114,8 @@ class SummaryPanelComponent extends React.Component<MainSummaryPanelPropType, Su
 
     let tourStops = [GraphTourStops.SidePanel];
 
-    tourStops.unshift(GraphTourStops.GraphPF);
-    tourStops.unshift(GraphTourStops.ContextualMenuPF);
+    tourStops.unshift(GraphTourStops.Graph);
+    tourStops.unshift(GraphTourStops.ContextualMenu);
 
     return (
       <TourStop info={tourStops}>
diff --git a/frontend/src/pages/Graph/SummaryPanelGraph.tsx b/frontend/src/pages/Graph/SummaryPanelGraph.tsx
index a0e6c9bd1..8ccf22eaf 100644
--- a/frontend/src/pages/Graph/SummaryPanelGraph.tsx
+++ b/frontend/src/pages/Graph/SummaryPanelGraph.tsx
@@ -34,7 +34,7 @@ import { ValidationStatus } from 'types/IstioObjects';
 import { ValidationSummary } from 'components/Validations/ValidationSummary';
 import { ValidationSummaryLink } from '../../components/Link/ValidationSummaryLink';
 import { PFBadge, PFBadges } from 'components/Pf/PfBadges';
-import { NodeData } from 'pages/Graph/GraphPFElems';
+import { NodeData } from 'pages/Graph/GraphElems';
 import { edgesIn, edgesOut, elems, leafNodes, select } from 'helpers/GraphHelpers';
 import { SimpleTabs } from 'components/Tab/SimpleTabs';
 import { panelHeadingStyle, panelStyle } from './SummaryPanelStyle';
diff --git a/frontend/src/pages/Graph/SummaryPanelTraceDetails.tsx b/frontend/src/pages/Graph/SummaryPanelTraceDetails.tsx
index a31404175..522570932 100644
--- a/frontend/src/pages/Graph/SummaryPanelTraceDetails.tsx
+++ b/frontend/src/pages/Graph/SummaryPanelTraceDetails.tsx
@@ -21,7 +21,7 @@ import { responseFlags } from 'utils/ResponseFlags';
 import { isParentKiosk, kioskContextMenuAction } from '../../components/Kiosk/KioskActions';
 import { Visualization, Node } from '@patternfly/react-topology';
 import { elems, selectAnd } from 'helpers/GraphHelpers';
-import { FocusNode } from 'pages/Graph/GraphPF';
+import { FocusNode } from 'pages/Graph/Graph';
 import { ExternalServiceInfo } from '../../types/StatusState';
 import { isMultiCluster } from '../../config';
 import { KialiIcon } from 'config/KialiIcon';
@@ -308,10 +308,6 @@ class SummaryPanelTraceDetailsComponent extends React.Component<Props, State> {
   }
 
   private linkToSpan(current: RichSpanData, target: RichSpanData, text: string): React.ReactNode {
-    return this.linkToSpanPF(current, target, text);
-  }
-
-  private linkToSpanPF(current: RichSpanData, target: RichSpanData, text: string): React.ReactNode {
     const useApp = this.props.graphType === GraphType.APP || this.props.graphType === GraphType.SERVICE;
     const currentElt = useApp ? current.app : current.workload;
     const targetElt = useApp ? target.app : target.workload;
@@ -319,7 +315,6 @@ class SummaryPanelTraceDetailsComponent extends React.Component<Props, State> {
     let tooltipContent = <>{text}</>;
 
     if (targetElt) {
-      // PF Graph
       const controller =
         this.props.data.summaryType === 'graph'
           ? (this.props.data.summaryTarget as Visualization)
diff --git a/frontend/src/pages/Graph/TracePF.ts b/frontend/src/pages/Graph/Trace.ts
similarity index 100%
rename from frontend/src/pages/Graph/TracePF.ts
rename to frontend/src/pages/Graph/Trace.ts
diff --git a/frontend/src/pages/Graph/TrafficAnimation/AnimationTimerConfig.ts b/frontend/src/pages/Graph/TrafficAnimation/AnimationTimerConfig.ts
index 0bb08bb96..63a824807 100644
--- a/frontend/src/pages/Graph/TrafficAnimation/AnimationTimerConfig.ts
+++ b/frontend/src/pages/Graph/TrafficAnimation/AnimationTimerConfig.ts
@@ -66,7 +66,7 @@ export class AnimationTimerConfig {
     return this.threshold / initialThreshold;
   }
 
-  computeAnimationSpeedPF(rate: number): EdgeAnimationSpeed {
+  computeAnimationSpeed(rate: number): EdgeAnimationSpeed {
     const range = maxDelay - minDelay;
     const chunk = range / 5; // there are 5 animation speeds for PFT
     const delay = this.computeDelay(rate);
diff --git a/frontend/src/pages/Graph/TrafficAnimation/TrafficPointRendererPF.tsx b/frontend/src/pages/Graph/TrafficAnimation/TrafficPointRenderer.tsx
similarity index 100%
rename from frontend/src/pages/Graph/TrafficAnimation/TrafficPointRendererPF.tsx
rename to frontend/src/pages/Graph/TrafficAnimation/TrafficPointRenderer.tsx
diff --git a/frontend/src/pages/Graph/TrafficAnimation/TrafficRendererPF.tsx b/frontend/src/pages/Graph/TrafficAnimation/TrafficRenderer.tsx
similarity index 96%
rename from frontend/src/pages/Graph/TrafficAnimation/TrafficRendererPF.tsx
rename to frontend/src/pages/Graph/TrafficAnimation/TrafficRenderer.tsx
index 76b96d0cc..217d0e83e 100644
--- a/frontend/src/pages/Graph/TrafficAnimation/TrafficRendererPF.tsx
+++ b/frontend/src/pages/Graph/TrafficAnimation/TrafficRenderer.tsx
@@ -1,13 +1,9 @@
 import { Point, clamp, distance } from '../../../utils/MathUtils';
-import {
-  TrafficPointCircleRenderer,
-  TrafficPointDiamondRenderer,
-  TrafficPointRenderer
-} from './TrafficPointRendererPF';
+import { TrafficPointCircleRenderer, TrafficPointDiamondRenderer, TrafficPointRenderer } from './TrafficPointRenderer';
 import { Protocol } from '../../../types/Graph';
 import { timerConfig, tcpTimerConfig } from './AnimationTimerConfig';
 import { Controller, Edge, EdgeAnimationSpeed, EdgeStyle } from '@patternfly/react-topology';
-import { EdgeData } from 'pages/Graph/GraphPFElems';
+import { EdgeData } from 'pages/Graph/GraphElems';
 import { PFColors } from 'components/Pf/PfColors';
 import { setObserved } from 'helpers/GraphHelpers';
 import { serverConfig } from 'config';
@@ -227,19 +223,19 @@ export class TrafficPointGenerator {
   //   2) look for a sizeable change in error rate
   // and combine the values.
   getHash(edgeData: EdgeData) {
-    let animationSpeedPF = EdgeAnimationSpeed.none;
+    let animationSpeed = EdgeAnimationSpeed.none;
     switch (edgeData.protocol) {
       case Protocol.GRPC:
-        animationSpeedPF = timerConfig.computeAnimationSpeedPF(edgeData.grpc);
+        animationSpeed = timerConfig.computeAnimationSpeed(edgeData.grpc);
         break;
       case Protocol.HTTP:
-        animationSpeedPF = timerConfig.computeAnimationSpeedPF(edgeData.http);
+        animationSpeed = timerConfig.computeAnimationSpeed(edgeData.http);
         break;
       case Protocol.TCP:
-        animationSpeedPF = tcpTimerConfig.computeAnimationSpeedPF(edgeData.tcp);
+        animationSpeed = tcpTimerConfig.computeAnimationSpeed(edgeData.tcp);
         break;
     }
-    return `${animationSpeedPF}:${(this.errorRate / 100).toFixed(1)}:${this.type}`;
+    return `${animationSpeed}:${(this.errorRate / 100).toFixed(1)}:${this.type}`;
   }
 }
 
@@ -359,13 +355,13 @@ export class TrafficAnimation {
         const edgeData = e.getData() as EdgeData;
         switch (edgeData.protocol) {
           case Protocol.GRPC:
-            e.setEdgeAnimationSpeed(timerConfig.computeAnimationSpeedPF(edgeData.grpc));
+            e.setEdgeAnimationSpeed(timerConfig.computeAnimationSpeed(edgeData.grpc));
             break;
           case Protocol.HTTP:
-            e.setEdgeAnimationSpeed(timerConfig.computeAnimationSpeedPF(edgeData.http));
+            e.setEdgeAnimationSpeed(timerConfig.computeAnimationSpeed(edgeData.http));
             break;
           case Protocol.TCP:
-            e.setEdgeAnimationSpeed(tcpTimerConfig.computeAnimationSpeedPF(edgeData.tcp));
+            e.setEdgeAnimationSpeed(tcpTimerConfig.computeAnimationSpeed(edgeData.tcp));
             break;
         }
         if (e.getEdgeAnimationSpeed() !== EdgeAnimationSpeed.none) {
diff --git a/frontend/src/pages/Graph/components/stylesComponentFactory.tsx b/frontend/src/pages/Graph/components/stylesComponentFactory.tsx
index 0e5a93146..985eea3e8 100644
--- a/frontend/src/pages/Graph/components/stylesComponentFactory.tsx
+++ b/frontend/src/pages/Graph/components/stylesComponentFactory.tsx
@@ -36,11 +36,6 @@ import { DropdownGroup, DropdownItem } from '@patternfly/react-core';
 import { getGVKTypeString } from '../../../utils/IstioConfigUtils';
 import { gvkType } from '../../../types/IstioConfigList';
 
-type ContextMenuOptionPF = ContextMenuOption & {
-  altClickHandler?: (node: GraphElement, kiosk: string) => void;
-  node?: GraphElement;
-};
-
 const graphNavHandler = (node: GraphElement, kiosk: string): void => {
   handleGraphNav(node, kiosk);
 };
@@ -56,10 +51,9 @@ const nodeContextMenu = (node: GraphElement, kiosk: string): Promise<React.React
   }
 
   const options = getOptions(nodeData);
-  const optionsPF = options.map(o => o as ContextMenuOptionPF);
 
   if (!(nodeData.isServiceEntry || (nodeData.nodeType === NodeType.BOX && nodeData.isBox !== BoxByType.APP))) {
-    optionsPF.unshift(
+    options.unshift(
       nodeData.isOutside
         ? ({
             text: 'Namespace Graph',
@@ -68,7 +62,7 @@ const nodeContextMenu = (node: GraphElement, kiosk: string): Promise<React.React
             node: node,
             target: '',
             url: ''
-          } as ContextMenuOptionPF)
+          } as ContextMenuOption)
         : ({
             text: 'Node Graph',
             altClickHandler: graphNavHandler,
@@ -76,7 +70,7 @@ const nodeContextMenu = (node: GraphElement, kiosk: string): Promise<React.React
             node: node,
             target: '',
             url: ''
-          } as ContextMenuOptionPF)
+          } as ContextMenuOption)
     );
   }
 
@@ -85,7 +79,7 @@ const nodeContextMenu = (node: GraphElement, kiosk: string): Promise<React.React
     paddingBottom: 0
   });
 
-  const menuOptions = optionsPF.map((o, i) => {
+  const menuOptions = options.map((o, i) => {
     return (
       // TODO: fix kiosk param
       !!o.altClickHandler ? (
diff --git a/frontend/src/pages/Graph/layouts/layoutFactory.ts b/frontend/src/pages/Graph/layouts/layoutFactory.ts
index 2ddf42c29..f76a128b9 100644
--- a/frontend/src/pages/Graph/layouts/layoutFactory.ts
+++ b/frontend/src/pages/Graph/layouts/layoutFactory.ts
@@ -6,7 +6,7 @@ import {
   LayoutFactory,
   BreadthFirstLayout
 } from '@patternfly/react-topology';
-import { GraphLayout } from '../GraphPF';
+import { GraphLayout } from '../Graph';
 import { ExtendedDagreLayout } from './ExtendedDagreLayout';
 
 /*
diff --git a/frontend/src/pages/Mesh/layouts/MeshDagreLayout.ts b/frontend/src/pages/Mesh/layouts/MeshDagreLayout.ts
index b9e4b9327..861c5b092 100644
--- a/frontend/src/pages/Mesh/layouts/MeshDagreLayout.ts
+++ b/frontend/src/pages/Mesh/layouts/MeshDagreLayout.ts
@@ -1,4 +1,4 @@
-import * as dagre from 'dagre';
+import { graphlib, layout as dagreLayout } from '@dagrejs/dagre';
 import {
   BaseLayout,
   DagreLayoutOptions,
@@ -127,7 +127,7 @@ export class MeshDagreLayout extends BaseLayout implements Layout {
   protected startLayout(graph: Graph, initialRun: boolean, addingNodes: boolean): void {
     if (initialRun || addingNodes) {
       const doLayout = (parentGroup?: LayoutGroup) => {
-        const dagreGraph = new dagre.graphlib.Graph({ compound: true });
+        const dagreGraph = new graphlib.Graph({ compound: true });
         const options = { ...this.dagreOptions };
 
         Object.keys(LAYOUT_DEFAULTS).forEach(key => delete options[key]);
@@ -168,7 +168,7 @@ export class MeshDagreLayout extends BaseLayout implements Layout {
             dagreGraph.setEdge(dagreEdge.source.id, dagreEdge.target.id, dagreEdge);
           });
 
-          dagre.layout(dagreGraph);
+          dagreLayout(dagreGraph);
 
           // Update the node element positions
           layerNodes.forEach(node => {
diff --git a/frontend/src/pages/ServiceDetails/ServiceInfo.tsx b/frontend/src/pages/ServiceDetails/ServiceInfo.tsx
index b7bca8c5d..bcf979397 100644
--- a/frontend/src/pages/ServiceDetails/ServiceInfo.tsx
+++ b/frontend/src/pages/ServiceDetails/ServiceInfo.tsx
@@ -41,7 +41,7 @@ import { deleteServiceTrafficRouting } from '../../services/Api';
 import * as AlertUtils from '../../utils/AlertUtils';
 import { triggerRefresh } from '../../hooks/refresh';
 import { serverConfig } from 'config';
-import { MiniGraphCardPF } from 'pages/Graph/MiniGraphCardPF';
+import { MiniGraphCard } from 'pages/Graph/MiniGraphCard';
 
 type ReduxProps = {
   duration: DurationInSeconds;
@@ -264,7 +264,7 @@ class ServiceInfoComponent extends React.Component<Props, ServiceInfoState> {
             </GridItem>
 
             <GridItem span={miniGraphSpan}>
-              <MiniGraphCardPF
+              <MiniGraphCard
                 dataSource={this.graphDataSource}
                 onDeleteTrafficRouting={this.handleDeleteTrafficRouting}
                 onLaunchWizard={this.handleLaunchWizard}
diff --git a/frontend/src/pages/WorkloadDetails/WorkloadInfo.tsx b/frontend/src/pages/WorkloadDetails/WorkloadInfo.tsx
index 20cd5232d..eb5126871 100644
--- a/frontend/src/pages/WorkloadDetails/WorkloadInfo.tsx
+++ b/frontend/src/pages/WorkloadDetails/WorkloadInfo.tsx
@@ -15,7 +15,7 @@ import { isIstioNamespace, serverConfig } from '../../config/ServerConfig';
 import { gvkType, IstioConfigList, skipUnrelatedK8sGateways, toIstioItems } from '../../types/IstioConfigList';
 import { WorkloadPods } from './WorkloadPods';
 import { IstioConfigCard } from '../../components/IstioConfigCard/IstioConfigCard';
-import { MiniGraphCardPF } from 'pages/Graph/MiniGraphCardPF';
+import { MiniGraphCard } from 'pages/Graph/MiniGraphCard';
 import { getGVKTypeString, stringToGVK } from '../../utils/IstioConfigUtils';
 import { WorkloadEntries } from './WorkloadEntries';
 
@@ -303,7 +303,7 @@ export class WorkloadInfo extends React.Component<WorkloadInfoProps, WorkloadInf
             </GridItem>
 
             <GridItem span={miniGraphSpan}>
-              <MiniGraphCardPF
+              <MiniGraphCard
                 dataSource={this.graphDataSource}
                 namespace={this.props.namespace}
                 workload={this.props.workload}
diff --git a/frontend/src/pages/WorkloadDetails/WorkloadPodLogs.tsx b/frontend/src/pages/WorkloadDetails/WorkloadPodLogs.tsx
index 47884af99..7e411fc83 100644
--- a/frontend/src/pages/WorkloadDetails/WorkloadPodLogs.tsx
+++ b/frontend/src/pages/WorkloadDetails/WorkloadPodLogs.tsx
@@ -433,7 +433,8 @@ export class WorkloadPodLogsComponent extends React.Component<WorkloadPodLogsPro
                                 </Button>
                               </Tooltip>
                             )}
-
+                          </ToolbarItem>
+                          <ToolbarItem style={{ alignSelf: 'center' }}>
                             <TextInput
                               id="log_hide"
                               name="log_hide"
diff --git a/frontend/src/reducers/GraphDataState.ts b/frontend/src/reducers/GraphDataState.ts
index cf742ffa6..cac1b72fa 100644
--- a/frontend/src/reducers/GraphDataState.ts
+++ b/frontend/src/reducers/GraphDataState.ts
@@ -5,7 +5,7 @@ import { GraphState } from '../store/Store';
 import { EdgeMode, GraphType, TrafficRate } from '../types/Graph';
 import { GraphToolbarActions } from '../actions/GraphToolbarActions';
 import { updateState } from '../utils/Reducer';
-import { GraphLayout } from 'pages/Graph/GraphPF';
+import { GraphLayout } from 'pages/Graph/Graph';
 
 export const INITIAL_GRAPH_STATE: GraphState = {
   edgeMode: EdgeMode.ALL,
diff --git a/frontend/src/reducers/__tests__/GraphDataState.test.ts b/frontend/src/reducers/__tests__/GraphDataState.test.ts
index 2e910bb80..8321780f6 100644
--- a/frontend/src/reducers/__tests__/GraphDataState.test.ts
+++ b/frontend/src/reducers/__tests__/GraphDataState.test.ts
@@ -4,7 +4,7 @@ import { GlobalActions } from '../../actions/GlobalActions';
 import { DefaultTrafficRates, EdgeMode, GraphType } from '../../types/Graph';
 import { GraphState } from 'store/Store';
 import { GraphElement } from '@patternfly/react-topology';
-import { GraphLayout } from 'pages/Graph/GraphPF';
+import { GraphLayout } from 'pages/Graph/Graph';
 
 describe('GraphDataState', () => {
   it('should return the initial state', () => {
diff --git a/frontend/src/routes.tsx b/frontend/src/routes.tsx
index 90a626ba1..33df34a14 100644
--- a/frontend/src/routes.tsx
+++ b/frontend/src/routes.tsx
@@ -12,8 +12,8 @@ import { WorkloadDetailsRoute } from 'routes/WorkloadDetailsRoute';
 import { AppDetailsRoute } from 'routes/AppDetailsRoute';
 import { IstioConfigDetailsRoute } from 'routes/IstioConfigDetailsRoute';
 import { IstioConfigNewRoute } from 'routes/IstioConfigNewRoute';
-import { GraphRoutePF } from 'routes/GraphRoutePF';
-import { GraphPagePF } from 'pages/Graph/GraphPagePF';
+import { GraphRoute } from 'routes/GraphRoute';
+import { GraphPage } from 'pages/Graph/GraphPage';
 import { t } from 'utils/I18nUtils';
 import { RouteObject } from 'react-router-dom-v5-compat';
 import { WildcardRoute } from 'routes/WildcardRoute';
@@ -32,8 +32,8 @@ const navMenuItems: MenuItem[] = [
   {
     id: 'traffic_graph',
     title: t('Traffic Graph'),
-    to: '/graphpf/namespaces/',
-    pathsActive: [/^\/graphpf\/(.*)/]
+    to: '/graph/namespaces/',
+    pathsActive: [/^\/graph\/(.*)/]
   },
   {
     id: 'applications',
@@ -77,28 +77,28 @@ const pathRoutes: RouteObject[] = [
     element: <OverviewPage />
   },
   {
-    path: `/graphpf/node/namespaces/:namespace/${Paths.AGGREGATES}/:aggregate/:aggregateValue`,
-    element: <GraphRoutePF />
+    path: `/graph/node/namespaces/:namespace/${Paths.AGGREGATES}/:aggregate/:aggregateValue`,
+    element: <GraphRoute />
   },
   {
-    path: `/graphpf/node/namespaces/:namespace/${Paths.APPLICATIONS}/:app/versions/:version`,
-    element: <GraphRoutePF />
+    path: `/graph/node/namespaces/:namespace/${Paths.APPLICATIONS}/:app/versions/:version`,
+    element: <GraphRoute />
   },
   {
-    path: `/graphpf/node/namespaces/:namespace/${Paths.APPLICATIONS}/:app`,
-    element: <GraphRoutePF />
+    path: `/graph/node/namespaces/:namespace/${Paths.APPLICATIONS}/:app`,
+    element: <GraphRoute />
   },
   {
-    path: `/graphpf/node/namespaces/:namespace/${Paths.SERVICES}/:service`,
-    element: <GraphRoutePF />
+    path: `/graph/node/namespaces/:namespace/${Paths.SERVICES}/:service`,
+    element: <GraphRoute />
   },
   {
-    path: `/graphpf/node/namespaces/:namespace/${Paths.WORKLOADS}/:workload`,
-    element: <GraphRoutePF />
+    path: `/graph/node/namespaces/:namespace/${Paths.WORKLOADS}/:workload`,
+    element: <GraphRoute />
   },
   {
-    path: '/graphpf/namespaces',
-    element: <GraphPagePF />
+    path: '/graph/namespaces',
+    element: <GraphPage />
   },
   {
     path: `/namespaces/:namespace/${Paths.SERVICES}/:service`,
diff --git a/frontend/src/routes/GraphRoutePF.tsx b/frontend/src/routes/GraphRoute.tsx
similarity index 72%
rename from frontend/src/routes/GraphRoutePF.tsx
rename to frontend/src/routes/GraphRoute.tsx
index c705a9354..ff9e889ee 100644
--- a/frontend/src/routes/GraphRoutePF.tsx
+++ b/frontend/src/routes/GraphRoute.tsx
@@ -1,12 +1,12 @@
 import * as React from 'react';
 import { useParams } from 'react-router-dom-v5-compat';
-import { GraphPagePF, GraphURLPathProps } from 'pages/Graph/GraphPagePF';
+import { GraphPage, GraphURLPathProps } from 'pages/Graph/GraphPage';
 
-export const GraphRoutePF: React.FC = () => {
+export const GraphRoute: React.FC = () => {
   const { aggregate, aggregateValue, app, namespace, service, version, workload } = useParams<GraphURLPathProps>();
 
   return (
-    <GraphPagePF
+    <GraphPage
       aggregate={aggregate}
       aggregateValue={aggregateValue}
       app={app}
@@ -14,6 +14,6 @@ export const GraphRoutePF: React.FC = () => {
       service={service}
       version={version}
       workload={workload}
-    ></GraphPagePF>
+    ></GraphPage>
   );
 };
diff --git a/frontend/src/store/Store.ts b/frontend/src/store/Store.ts
index 3455d1009..b101a354d 100644
--- a/frontend/src/store/Store.ts
+++ b/frontend/src/store/Store.ts
@@ -27,7 +27,7 @@ import { TracingState } from 'reducers/TracingState';
 import { MetricsStatsState } from 'reducers/MetricsStatsState';
 import { CertsInfo } from 'types/CertsInfo';
 import { MeshCluster, MeshDefinition, MeshTarget } from '../types/Mesh';
-import { GraphLayout } from 'pages/Graph/GraphPF';
+import { GraphLayout } from 'pages/Graph/Graph';
 import { MeshLayout } from 'pages/Mesh/layouts/layoutFactory';
 
 // Store is the Redux Data store
diff --git a/frontend/src/utils/GraphUtils.ts b/frontend/src/utils/GraphUtils.ts
index aa5106fbc..47b843cfc 100644
--- a/frontend/src/utils/GraphUtils.ts
+++ b/frontend/src/utils/GraphUtils.ts
@@ -1,4 +1,4 @@
-import { GraphLayout } from 'pages/Graph/GraphPF';
+import { GraphLayout } from 'pages/Graph/Graph';
 
 // check if the graph layout supports grouping
 export const supportsGroups = (layoutName: GraphLayout): boolean => {
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index 8023eec08..42fde3c5d 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -5441,14 +5441,6 @@ d3@^7.8.0:
     d3-transition "3"
     d3-zoom "3"
 
-dagre@0.8.5:
-  version "0.8.5"
-  resolved "https://registry.yarnpkg.com/dagre/-/dagre-0.8.5.tgz#ba30b0055dac12b6c1fcc247817442777d06afee"
-  integrity sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==
-  dependencies:
-    graphlib "^2.1.8"
-    lodash "^4.17.15"
-
 damerau-levenshtein@^1.0.8:
   version "1.0.8"
   resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7"
@@ -7243,13 +7235,6 @@ graphemer@^1.4.0:
   resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
   integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
 
-graphlib@^2.1.8:
-  version "2.1.8"
-  resolved "https://registry.yarnpkg.com/graphlib/-/graphlib-2.1.8.tgz#5761d414737870084c92ec7b5dbcb0592c9d35da"
-  integrity sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==
-  dependencies:
-    lodash "^4.17.15"
-
 gud@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0"
@@ -9852,7 +9837,7 @@ point-in-svg-path@^1.0.1:
   resolved "https://registry.yarnpkg.com/point-in-svg-path/-/point-in-svg-path-1.0.2.tgz#e7b25370e96f58a858c34882ffb57d41b7a574bf"
   integrity sha512-+Smsf7B9e7eRFHIwpN+4rE8inF2APbFWeywPfUgbeh02xdJSkbTz6Pqdt7A36wVCR+CnLbaNkRnBjgOpF5RMVQ==
 
-popper.js@^1.14.4, popper.js@^1.14.6, popper.js@^1.16.1:
+popper.js@^1.14.4, popper.js@^1.16.1:
   version "1.16.1"
   resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b"
   integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==
@@ -12292,13 +12277,6 @@ tiny-warning@^1.0.0:
   resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
   integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
 
-tippy.js@3.4.1:
-  version "3.4.1"
-  resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-3.4.1.tgz#f0eb3081824ad6c5d364336451ad77ae2f543da8"
-  integrity sha512-ZiyGP9WZyCCcjxKM4G88cm4U1r1ytjeMDGa5FSKPaPzwc/3yZJVZsb1ffcmqUMCpryRp5LNxRNGKLzbs11sb/Q==
-  dependencies:
-    popper.js "^1.14.6"
-
 tmp@0.2.3, tmp@~0.2.1:
   version "0.2.3"
   resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae"
diff --git a/handlers/config.go b/handlers/config.go
index b6043d7fe..6b852e82a 100644
--- a/handlers/config.go
+++ b/handlers/config.go
@@ -11,6 +11,8 @@ import (
 
 	"github.com/kiali/kiali/config"
 	"github.com/kiali/kiali/istio"
+	"github.com/kiali/kiali/kubernetes"
+	"github.com/kiali/kiali/kubernetes/cache"
 	"github.com/kiali/kiali/log"
 	"github.com/kiali/kiali/models"
 	"github.com/kiali/kiali/prometheus"
@@ -62,14 +64,13 @@ type PublicConfig struct {
 }
 
 // Config is a REST http.HandlerFunc serving up the Kiali configuration made public to clients.
-func Config(conf *config.Config, discovery *istio.Discovery) http.HandlerFunc {
+func Config(conf *config.Config, cache cache.KialiCache, discovery istio.MeshDiscovery, clientFactory kubernetes.ClientFactory, prom prometheus.ClientInterface) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		defer handlePanic(w)
 
 		// Note that we determine the Prometheus config at request time because it is not
 		// guaranteed to remain the same during the Kiali lifespan.
-		promConfig := getPrometheusConfig()
-		conf := config.Get()
+		promConfig := getPrometheusConfig(conf, prom)
 		publicConfig := PublicConfig{
 			AuthStrategy:      conf.Auth.Strategy,
 			Clusters:          make(map[string]models.KubeCluster),
@@ -97,35 +98,29 @@ func Config(conf *config.Config, discovery *istio.Discovery) http.HandlerFunc {
 			},
 		}
 
-		// The following code fetches the cluster info. Cluster info is not critical.
-		// It's even possible that it cannot be resolved (because of Istio not being with MC turned on).
-		// Because of these two reasons, let's simply ignore errors in the following code.
-		err := func() error {
-			layer, err := getBusiness(r)
-			if err != nil {
-				return err
-			}
-
-			// @TODO hardcoded home cluster
-			publicConfig.GatewayAPIEnabled = layer.IstioConfig.IsGatewayAPI(conf.KubernetesConfig.ClusterName)
-			publicConfig.AmbientEnabled = layer.IstioConfig.IsAmbientEnabled(conf.KubernetesConfig.ClusterName)
-			publicConfig.GatewayAPIClasses = layer.IstioConfig.GatewayAPIClasses(conf.KubernetesConfig.ClusterName)
-
-			// Fetch the list of all clusters in the mesh
-			// One usage of this data is to cross-link Kiali instances, when possible.
-			clusters, err := discovery.Clusters()
-			if err != nil {
-				return fmt.Errorf("failure while listing clusters in the mesh: %w", err)
-			}
+		userClients, err := getUserClients(r, clientFactory)
+		if err != nil {
+			RespondWithError(w, http.StatusInternalServerError, "Unable to convert session token into user client: "+err.Error())
+			return
+		}
 
-			for _, cluster := range clusters {
-				publicConfig.Clusters[cluster.Name] = cluster
-			}
+		// @TODO hardcoded home cluster
+		if client := userClients[conf.KubernetesConfig.ClusterName]; client != nil {
+			publicConfig.GatewayAPIEnabled = client.IsGatewayAPI()
+		}
+		publicConfig.AmbientEnabled = cache.IsAmbientEnabled(conf.KubernetesConfig.ClusterName)
+		publicConfig.GatewayAPIClasses = kubernetes.GatewayAPIClasses(publicConfig.AmbientEnabled, conf)
 
-			return nil
-		}()
+		// Fetch the list of all clusters in the mesh
+		// One usage of this data is to cross-link Kiali instances, when possible.
+		clusters, err := discovery.Clusters()
 		if err != nil {
-			log.Warningf("Unable to resolve cluster info: %s", err)
+			RespondWithError(w, http.StatusInternalServerError, "Failure while listing clusters in the mesh: "+err.Error())
+			return
+		}
+
+		for _, cluster := range clusters {
+			publicConfig.Clusters[cluster.Name] = cluster
 		}
 
 		RespondWithJSONIndent(w, http.StatusOK, publicConfig)
@@ -138,13 +133,13 @@ type PrometheusPartialConfig struct {
 	}
 }
 
-func getPrometheusConfig() PrometheusConfig {
+func getPrometheusConfig(conf *config.Config, client prometheus.ClientInterface) PrometheusConfig {
 	promConfig := PrometheusConfig{
 		GlobalScrapeInterval: defaultPrometheusGlobalScrapeInterval,
 		StorageTsdbRetention: defaultPrometheusGlobalStorageTSDBRetention,
 	}
 	// Check if thanosProxy
-	thanosConf := config.Get().ExternalServices.Prometheus.ThanosProxy
+	thanosConf := conf.ExternalServices.Prometheus.ThanosProxy
 	if thanosConf.Enabled {
 		scrapeInterval, err := model.ParseDuration(thanosConf.ScrapeInterval)
 		if checkErr(err, fmt.Sprintf("Invalid scrape interval in ThanosProxy configuration [%s]", scrapeInterval)) {
@@ -155,11 +150,6 @@ func getPrometheusConfig() PrometheusConfig {
 			promConfig.StorageTsdbRetention = int64(time.Duration(retention).Seconds())
 		}
 	} else {
-		client, err := prometheus.NewClient()
-		if !checkErr(err, "") {
-			log.Error(err)
-			return promConfig
-		}
 		configResult, err := client.GetConfiguration()
 		if checkErr(err, "Failed to fetch Prometheus configuration") {
 			var config PrometheusPartialConfig
@@ -210,61 +200,57 @@ type KialiCrippledFeatures struct {
 	ResponseTimePercentiles bool `json:"responseTimePercentiles"`
 }
 
-func CrippledFeatures(w http.ResponseWriter, r *http.Request) {
-	defer handlePanic(w)
-
-	requiredMetrics := []string{
-		"istio_request_bytes_bucket",
-		"istio_request_bytes_count",
-		"istio_request_bytes_sum",
-		"istio_request_duration_milliseconds_bucket",
-		"istio_request_duration_milliseconds_count",
-		"istio_request_duration_milliseconds_sum",
-		"istio_requests_total",
-		"istio_response_bytes_bucket",
-		"istio_response_bytes_count",
-		"istio_response_bytes_sum",
-	}
+func CrippledFeatures(client prometheus.ClientInterface) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		defer handlePanic(w)
 
-	// assume nothing crippled on error
-	crippledFeatures := KialiCrippledFeatures{}
+		requiredMetrics := []string{
+			"istio_request_bytes_bucket",
+			"istio_request_bytes_count",
+			"istio_request_bytes_sum",
+			"istio_request_duration_milliseconds_bucket",
+			"istio_request_duration_milliseconds_count",
+			"istio_request_duration_milliseconds_sum",
+			"istio_requests_total",
+			"istio_response_bytes_bucket",
+			"istio_response_bytes_count",
+			"istio_response_bytes_sum",
+		}
 
-	client, err := prometheus.NewClient()
-	if !checkErr(err, "") {
-		log.Error(err)
-		RespondWithJSONIndent(w, http.StatusOK, crippledFeatures)
-	}
+		// assume nothing crippled on error
+		crippledFeatures := KialiCrippledFeatures{}
 
-	existingMetrics, err := client.GetExistingMetricNames(requiredMetrics)
-	if !checkErr(err, "") {
-		log.Error(err)
-		RespondWithJSONIndent(w, http.StatusOK, crippledFeatures)
-	}
+		existingMetrics, err := client.GetExistingMetricNames(requiredMetrics)
+		if !checkErr(err, "") {
+			log.Error(err)
+			RespondWithJSONIndent(w, http.StatusOK, crippledFeatures)
+		}
 
-	// if we have all of the metrics then nothing is crippled, just return
-	// if we have no metrics then we have no requests (note that we check for istio_request_totals), nothing is known to be crippled
-	if len(existingMetrics) == len(requiredMetrics) || len(existingMetrics) == 0 {
-		RespondWithJSONIndent(w, http.StatusOK, crippledFeatures)
-	}
+		// if we have all of the metrics then nothing is crippled, just return
+		// if we have no metrics then we have no requests (note that we check for istio_request_totals), nothing is known to be crippled
+		if len(existingMetrics) == len(requiredMetrics) || len(existingMetrics) == 0 {
+			RespondWithJSONIndent(w, http.StatusOK, crippledFeatures)
+		}
 
-	exists := make(map[string]bool, len(existingMetrics))
-	for _, metric := range existingMetrics {
-		exists[metric] = true
-	}
+		exists := make(map[string]bool, len(existingMetrics))
+		for _, metric := range existingMetrics {
+			exists[metric] = true
+		}
 
-	crippledFeatures.RequestSize = !exists["istio_request_bytes_sum"]
-	crippledFeatures.RequestSizeAverage = crippledFeatures.RequestSize || !exists["istio_request_bytes_count"]
-	crippledFeatures.RequestSizePercentiles = crippledFeatures.RequestSizeAverage || !exists["istio_request_bytes_bucket"]
+		crippledFeatures.RequestSize = !exists["istio_request_bytes_sum"]
+		crippledFeatures.RequestSizeAverage = crippledFeatures.RequestSize || !exists["istio_request_bytes_count"]
+		crippledFeatures.RequestSizePercentiles = crippledFeatures.RequestSizeAverage || !exists["istio_request_bytes_bucket"]
 
-	crippledFeatures.ResponseSize = !exists["istio_response_bytes_sum"]
-	crippledFeatures.ResponseSizeAverage = crippledFeatures.ResponseSize || !exists["istio_response_bytes_count"]
-	crippledFeatures.ResponseSizePercentiles = crippledFeatures.ResponseSizeAverage || !exists["istio_response_bytes_bucket"]
+		crippledFeatures.ResponseSize = !exists["istio_response_bytes_sum"]
+		crippledFeatures.ResponseSizeAverage = crippledFeatures.ResponseSize || !exists["istio_response_bytes_count"]
+		crippledFeatures.ResponseSizePercentiles = crippledFeatures.ResponseSizeAverage || !exists["istio_response_bytes_bucket"]
 
-	crippledFeatures.ResponseTime = !exists["istio_request_duration_milliseconds_sum"]
-	crippledFeatures.ResponseTimeAverage = crippledFeatures.ResponseTime || !exists["istio_request_duration_milliseconds_count"]
-	crippledFeatures.ResponseTimePercentiles = crippledFeatures.ResponseTimeAverage || !exists["istio_request_duration_milliseconds_bucket"]
+		crippledFeatures.ResponseTime = !exists["istio_request_duration_milliseconds_sum"]
+		crippledFeatures.ResponseTimeAverage = crippledFeatures.ResponseTime || !exists["istio_request_duration_milliseconds_count"]
+		crippledFeatures.ResponseTimePercentiles = crippledFeatures.ResponseTimeAverage || !exists["istio_request_duration_milliseconds_bucket"]
 
-	RespondWithJSONIndent(w, http.StatusOK, crippledFeatures)
+		RespondWithJSONIndent(w, http.StatusOK, crippledFeatures)
+	}
 }
 
 func checkErr(err error, message string) bool {
diff --git a/handlers/istio_config.go b/handlers/istio_config.go
index 1172ebca9..7c2e75803 100644
--- a/handlers/istio_config.go
+++ b/handlers/istio_config.go
@@ -14,7 +14,7 @@ import (
 	"github.com/kiali/kiali/config"
 	"github.com/kiali/kiali/log"
 	"github.com/kiali/kiali/models"
-	"github.com/kiali/kiali/util"
+	"github.com/kiali/kiali/util/sliceutil"
 )
 
 func IstioConfigList(w http.ResponseWriter, r *http.Request) {
@@ -152,7 +152,7 @@ func IstioConfigDetails(w http.ResponseWriter, r *http.Request) {
 				// validations should be done per exported namespaces to apply exportTo configs
 				loadedNamespaces, _ := business.Namespace.GetClusterNamespaces(r.Context(), cluster)
 				for _, ns := range loadedNamespaces {
-					if util.InSlice(exportTo, ns.Name) && ns.Name != namespace {
+					if sliceutil.SomeString(exportTo, ns.Name) && ns.Name != namespace {
 						istioConfigValidationResults, istioConfigReferencesResults, err := business.Validations.ValidateIstioObject(r.Context(), cluster, ns.Name, gvk, object)
 						if err != nil {
 							validationsResult <- err
diff --git a/istio/discovery.go b/istio/discovery.go
index 3a78657b6..3247da55c 100644
--- a/istio/discovery.go
+++ b/istio/discovery.go
@@ -153,6 +153,7 @@ func sidecarInjectorConfigMapName(revision string) string {
 }
 
 type MeshDiscovery interface {
+	Clusters() ([]models.KubeCluster, error)
 	Mesh(ctx context.Context) (*models.Mesh, error)
 }
 
diff --git a/kiali_internal_api.md b/kiali_internal_api.md
index 0c89a5bb7..29b127faf 100644
--- a/kiali_internal_api.md
+++ b/kiali_internal_api.md
@@ -66,15 +66,6 @@ _
 | GET | /api/logout | [logout](#logout) |  |
 | GET | /api/auth/openid_redirect | [openid redirect](#openid-redirect) |  |
 | POST | /api/authenticate | [openshift check token](#openshift-check-token) |  |
-| GET | /api/auth/openshift_redirect | [openshift redirect](#openshift-redirect) |  |
-  
-
-
-###  certs
-
-| Method  | URI     | Name   | Summary |
-|---------|---------|--------|---------|
-| GET | /api/istio/certs | [istio certs](#istio-certs) |  |
   
 
 
@@ -99,12 +90,20 @@ _
 | Method  | URI     | Name   | Summary |
 |---------|---------|--------|---------|
 | GET | /api/istio/permissions | [get permissions](#get-permissions) |  |
-| POST | /api/namespaces/{namespace}/istio/{object_type} | [istio config create](#istio-config-create) |  |
-| DELETE | /api/namespaces/{namespace}/istio/{object_type}/{object} | [istio config delete](#istio-config-delete) |  |
-| GET | /api/namespaces/{namespace}/istio/{object_type}/{object} | [istio config details](#istio-config-details) |  |
+| POST | /api/namespaces/{namespace}/istio/{group}/{version}/{kind} | [istio config create](#istio-config-create) |  |
+| DELETE | /api/namespaces/{namespace}/istio/{group}/{version}/{kind}/{object} | [istio config delete](#istio-config-delete) |  |
+| GET | /api/namespaces/{namespace}/istio/{group}/{version}/{kind}/{object} | [istio config details](#istio-config-details) |  |
 | GET | /api/namespaces/{namespace}/istio | [istio config list](#istio-config-list) |  |
 | GET | /api/istio | [istio config list all](#istio-config-list-all) |  |
-| PATCH | /api/namespaces/{namespace}/istio/{object_type}/{object} | [istio config update](#istio-config-update) | Endpoint to update the Istio Config of an Istio object used for templates and adapters using Json Merge Patch strategy. |
+| PATCH | /api/namespaces/{namespace}/istio/{group}/{version}/{kind}/{object} | [istio config update](#istio-config-update) | Endpoint to update the Istio Config of an Istio object used for templates and adapters using Json Merge Patch strategy. |
+  
+
+
+###  controlplanes
+
+| Method  | URI     | Name   | Summary |
+|---------|---------|--------|---------|
+| GET | /api/namespaces/{namespace}/controlplanes/{controlplane}/metrics | [control plane metrics](#control-plane-metrics) |  |
   
 
 
@@ -150,14 +149,6 @@ _
   
 
 
-###  mesh
-
-| Method  | URI     | Name   | Summary |
-|---------|---------|--------|---------|
-| GET | /api/mesh | [configuration](#configuration) |  |
-  
-
-
 ###  namespaces
 
 | Method  | URI     | Name   | Summary |
@@ -175,6 +166,7 @@ _
 
 | Method  | URI     | Name   | Summary |
 |---------|---------|--------|---------|
+| GET | /api/mesh/controlplanes | [controlplanes](#controlplanes) |  |
 | GET | /api/mesh/graph | [mesh graph](#mesh-graph) |  |
   
 
@@ -191,6 +183,14 @@ _
   
 
 
+###  resource
+
+| Method  | URI     | Name   | Summary |
+|---------|---------|--------|---------|
+| GET | /api/namespaces/{namespace}/{app}/usage_metrics | [usage metrics](#usage-metrics) |  |
+  
+
+
 ###  services
 
 | Method  | URI     | Name   | Summary |
@@ -254,6 +254,7 @@ _
 | GET | /api/clusters/workloads | [workload list](#workload-list) |  |
 | GET | /api/namespaces/{namespace}/workloads/{workload}/metrics | [workload metrics](#workload-metrics) |  |
 | PATCH | /api/namespaces/{namespace}/workloads/{workload} | [workload update](#workload-update) | Endpoint to update the Workload configuration using Json Merge Patch strategy. |
+| GET | /api/namespaces/{namespace}/ztunnel/{workload}/dashboard | [ztunnel dashboard](#ztunnel-dashboard) |  |
   
 
 
@@ -464,7 +465,7 @@ Endpoint to fetch metrics to be displayed, related to a single aggregate
 | reporter | `query` | string | `string` |  |  | `"source"` | Istio telemetry reporter: 'source' or 'destination'. |
 | requestProtocol | `query` | string | `string` |  |  | `"all protocols"` | Desired request protocol for the telemetry: For example, 'http' or 'grpc'. |
 | step | `query` | int64 (formatted integer) | `int64` |  |  | `15` | Step between [graph] datapoints, in seconds. |
-| version | `query` | string | `string` |  |  |  | Filters metrics by the specified version. |
+| version | `query` | string | `string` |  |  |  | Filters metrics by the specified version |
 
 #### All responses
 | Code | Status | Description | Has headers | Schema |
@@ -837,7 +838,7 @@ Endpoint to fetch metrics to be displayed, related to a single app
 | reporter | `query` | string | `string` |  |  | `"source"` | Istio telemetry reporter: 'source' or 'destination'. |
 | requestProtocol | `query` | string | `string` |  |  | `"all protocols"` | Desired request protocol for the telemetry: For example, 'http' or 'grpc'. |
 | step | `query` | int64 (formatted integer) | `int64` |  |  | `15` | Step between [graph] datapoints, in seconds. |
-| version | `query` | string | `string` |  |  |  | Filters metrics by the specified version. |
+| version | `query` | string | `string` |  |  |  | Filters metrics by the specified version |
 
 #### All responses
 | Code | Status | Description | Has headers | Schema |
@@ -1286,13 +1287,106 @@ Status: Service Unavailable
 
 
 
-### <span id="configuration"></span> configuration (*configuration*)
+### <span id="control-plane-metrics"></span> control plane metrics (*controlPlaneMetrics*)
+
+```
+GET /api/namespaces/{namespace}/controlplanes/{controlplane}/metrics
+```
+
+Endpoint to fetch metrics to be displayed, related to a single control plane
+
+#### URI Schemes
+  * http
+  * https
+
+#### Produces
+  * application/json
+
+#### Parameters
+
+| Name | Source | Type | Go type | Separator | Required | Default | Description |
+|------|--------|------|---------|-----------| :------: |---------|-------------|
+| controlplane | `path` | string | `string` |  | ✓ |  | The control plane for metric collection, etc. |
+| namespace | `path` | string | `string` |  | ✓ |  | The namespace name. |
+
+#### All responses
+| Code | Status | Description | Has headers | Schema |
+|------|--------|-------------|:-----------:|--------|
+| [200](#control-plane-metrics-200) | OK | Metrics response model |  | [schema](#control-plane-metrics-200-schema) |
+| [400](#control-plane-metrics-400) | Bad Request | BadRequestError: the client request is incorrect |  | [schema](#control-plane-metrics-400-schema) |
+| [503](#control-plane-metrics-503) | Service Unavailable | A Internal is the error message that means something has gone wrong |  | [schema](#control-plane-metrics-503-schema) |
+
+#### Responses
+
+
+##### <span id="control-plane-metrics-200"></span> 200 - Metrics response model
+Status: OK
+
+###### <span id="control-plane-metrics-200-schema"></span> Schema
+   
+  
+
+map of [Metric](#metric)
+
+##### <span id="control-plane-metrics-400"></span> 400 - BadRequestError: the client request is incorrect
+Status: Bad Request
+
+###### <span id="control-plane-metrics-400-schema"></span> Schema
+   
+  
+
+[ControlPlaneMetricsBadRequestBody](#control-plane-metrics-bad-request-body)
+
+##### <span id="control-plane-metrics-503"></span> 503 - A Internal is the error message that means something has gone wrong
+Status: Service Unavailable
+
+###### <span id="control-plane-metrics-503-schema"></span> Schema
+   
+  
+
+[ControlPlaneMetricsServiceUnavailableBody](#control-plane-metrics-service-unavailable-body)
+
+###### Inlined models
+
+**<span id="control-plane-metrics-bad-request-body"></span> ControlPlaneMetricsBadRequestBody**
+
+
+  
+
+
+
+**Properties**
+
+| Name | Type | Go type | Required | Default | Description | Example |
+|------|------|---------|:--------:| ------- |-------------|---------|
+| Code | int32 (formatted integer)| `int32` |  | `400`| HTTP status code | `400` |
+| Message | string| `string` |  | |  |  |
+
+
+
+**<span id="control-plane-metrics-service-unavailable-body"></span> ControlPlaneMetricsServiceUnavailableBody**
+
+
+  
+
+
+
+**Properties**
+
+| Name | Type | Go type | Required | Default | Description | Example |
+|------|------|---------|:--------:| ------- |-------------|---------|
+| Code | int32 (formatted integer)| `int32` |  | `503`| HTTP status code | `503` |
+| Message | string| `string` |  | |  |  |
+
+
+
+### <span id="controlplanes"></span> controlplanes (*controlplanes*)
 
 ```
-GET /api/mesh
+GET /api/mesh/controlplanes
 ```
 
-Get Mesh status and configuration
+The backing JSON for mesh controlplanes
 
 #### URI Schemes
   * http
@@ -1304,43 +1398,43 @@ Get Mesh status and configuration
 #### All responses
 | Code | Status | Description | Has headers | Schema |
 |------|--------|-------------|:-----------:|--------|
-| [200](#configuration-200) | OK | Response of the mesh query |  | [schema](#configuration-200-schema) |
-| [400](#configuration-400) | Bad Request | BadRequestError: the client request is incorrect |  | [schema](#configuration-400-schema) |
-| [500](#configuration-500) | Internal Server Error | A Internal is the error message that means something has gone wrong |  | [schema](#configuration-500-schema) |
+| [200](#controlplanes-200) | OK | HTTP status code 200 and graph Config in data |  | [schema](#controlplanes-200-schema) |
+| [400](#controlplanes-400) | Bad Request | BadRequestError: the client request is incorrect |  | [schema](#controlplanes-400-schema) |
+| [500](#controlplanes-500) | Internal Server Error | A Internal is the error message that means something has gone wrong |  | [schema](#controlplanes-500-schema) |
 
 #### Responses
 
 
-##### <span id="configuration-200"></span> 200 - Response of the mesh query
+##### <span id="controlplanes-200"></span> 200 - HTTP status code 200 and graph Config in data
 Status: OK
 
-###### <span id="configuration-200-schema"></span> Schema
+###### <span id="controlplanes-200-schema"></span> Schema
    
   
 
-[Mesh](#mesh)
+[Config](#config)
 
-##### <span id="configuration-400"></span> 400 - BadRequestError: the client request is incorrect
+##### <span id="controlplanes-400"></span> 400 - BadRequestError: the client request is incorrect
 Status: Bad Request
 
-###### <span id="configuration-400-schema"></span> Schema
+###### <span id="controlplanes-400-schema"></span> Schema
    
   
 
-[ConfigurationBadRequestBody](#configuration-bad-request-body)
+[ControlplanesBadRequestBody](#controlplanes-bad-request-body)
 
-##### <span id="configuration-500"></span> 500 - A Internal is the error message that means something has gone wrong
+##### <span id="controlplanes-500"></span> 500 - A Internal is the error message that means something has gone wrong
 Status: Internal Server Error
 
-###### <span id="configuration-500-schema"></span> Schema
+###### <span id="controlplanes-500-schema"></span> Schema
    
   
 
-[ConfigurationInternalServerErrorBody](#configuration-internal-server-error-body)
+[ControlplanesInternalServerErrorBody](#controlplanes-internal-server-error-body)
 
 ###### Inlined models
 
-**<span id="configuration-bad-request-body"></span> ConfigurationBadRequestBody**
+**<span id="controlplanes-bad-request-body"></span> ControlplanesBadRequestBody**
 
 
   
@@ -1356,7 +1450,7 @@ Status: Internal Server Error
 
 
 
-**<span id="configuration-internal-server-error-body"></span> ConfigurationInternalServerErrorBody**
+**<span id="controlplanes-internal-server-error-body"></span> ControlplanesInternalServerErrorBody**
 
 
   
@@ -1942,14 +2036,14 @@ The backing JSON for an aggregate node detail graph. (supported graphTypes: app
 #### All responses
 | Code | Status | Description | Has headers | Schema |
 |------|--------|-------------|:-----------:|--------|
-| [200](#graph-aggregate-200) | OK | HTTP status code 200 and cytoscapejs Config in data |  | [schema](#graph-aggregate-200-schema) |
+| [200](#graph-aggregate-200) | OK | HTTP status code 200 and graph Config in data |  | [schema](#graph-aggregate-200-schema) |
 | [400](#graph-aggregate-400) | Bad Request | BadRequestError: the client request is incorrect |  | [schema](#graph-aggregate-400-schema) |
 | [500](#graph-aggregate-500) | Internal Server Error | A Internal is the error message that means something has gone wrong |  | [schema](#graph-aggregate-500-schema) |
 
 #### Responses
 
 
-##### <span id="graph-aggregate-200"></span> 200 - HTTP status code 200 and cytoscapejs Config in data
+##### <span id="graph-aggregate-200"></span> 200 - HTTP status code 200 and graph Config in data
 Status: OK
 
 ###### <span id="graph-aggregate-200-schema"></span> Schema
@@ -2038,14 +2132,14 @@ The backing JSON for an aggregate node detail graph, specific to a service. (sup
 #### All responses
 | Code | Status | Description | Has headers | Schema |
 |------|--------|-------------|:-----------:|--------|
-| [200](#graph-aggregate-by-service-200) | OK | HTTP status code 200 and cytoscapejs Config in data |  | [schema](#graph-aggregate-by-service-200-schema) |
+| [200](#graph-aggregate-by-service-200) | OK | HTTP status code 200 and graph Config in data |  | [schema](#graph-aggregate-by-service-200-schema) |
 | [400](#graph-aggregate-by-service-400) | Bad Request | BadRequestError: the client request is incorrect |  | [schema](#graph-aggregate-by-service-400-schema) |
 | [500](#graph-aggregate-by-service-500) | Internal Server Error | A Internal is the error message that means something has gone wrong |  | [schema](#graph-aggregate-by-service-500-schema) |
 
 #### Responses
 
 
-##### <span id="graph-aggregate-by-service-200"></span> 200 - HTTP status code 200 and cytoscapejs Config in data
+##### <span id="graph-aggregate-by-service-200"></span> 200 - HTTP status code 200 and graph Config in data
 Status: OK
 
 ###### <span id="graph-aggregate-by-service-200-schema"></span> Schema
@@ -2131,7 +2225,6 @@ The backing JSON for an app node detail graph. (supported graphTypes: app | vers
 | boxBy | `query` | string | `string` |  |  |  | Comma-separated list of desired node boxing. Available boxings: [app, cluster, namespace]. |
 | container | `query` | string | `string` |  |  |  | The cluster name. If not supplied queries/results will not be constrained by cluster. |
 | duration | `query` | string | `string` |  |  | `"10m"` | Query time-range duration (Golang string duration). |
-| graphType | `query` | string | `string` |  | ✓ |  | Graph type. Available graph types: [app, versionedApp]. |
 | includeIdleEdges | `query` | string | `string` |  |  | `"false"` | Flag for including edges that have no request traffic for the time period. |
 | injectServiceNodes | `query` | string | `string` |  |  | `"false"` | Flag for injecting the requested service node between source and destination nodes. |
 | queryTime | `query` | string | `string` |  |  | `"now"` | Unix time (seconds) for query such that time range is [queryTime-duration..queryTime]. Default is now. |
@@ -2144,14 +2237,14 @@ The backing JSON for an app node detail graph. (supported graphTypes: app | vers
 #### All responses
 | Code | Status | Description | Has headers | Schema |
 |------|--------|-------------|:-----------:|--------|
-| [200](#graph-app-200) | OK | HTTP status code 200 and cytoscapejs Config in data |  | [schema](#graph-app-200-schema) |
+| [200](#graph-app-200) | OK | HTTP status code 200 and graph Config in data |  | [schema](#graph-app-200-schema) |
 | [400](#graph-app-400) | Bad Request | BadRequestError: the client request is incorrect |  | [schema](#graph-app-400-schema) |
 | [500](#graph-app-500) | Internal Server Error | A Internal is the error message that means something has gone wrong |  | [schema](#graph-app-500-schema) |
 
 #### Responses
 
 
-##### <span id="graph-app-200"></span> 200 - HTTP status code 200 and cytoscapejs Config in data
+##### <span id="graph-app-200"></span> 200 - HTTP status code 200 and graph Config in data
 Status: OK
 
 ###### <span id="graph-app-200-schema"></span> Schema
@@ -2238,7 +2331,6 @@ The backing JSON for a versioned app node detail graph. (supported graphTypes: a
 | boxBy | `query` | string | `string` |  |  |  | Comma-separated list of desired node boxing. Available boxings: [app, cluster, namespace]. |
 | container | `query` | string | `string` |  |  |  | The cluster name. If not supplied queries/results will not be constrained by cluster. |
 | duration | `query` | string | `string` |  |  | `"10m"` | Query time-range duration (Golang string duration). |
-| graphType | `query` | string | `string` |  | ✓ |  | Graph type. Available graph types: [app, versionedApp]. |
 | includeIdleEdges | `query` | string | `string` |  |  | `"false"` | Flag for including edges that have no request traffic for the time period. |
 | injectServiceNodes | `query` | string | `string` |  |  | `"false"` | Flag for injecting the requested service node between source and destination nodes. |
 | queryTime | `query` | string | `string` |  |  | `"now"` | Unix time (seconds) for query such that time range is [queryTime-duration..queryTime]. Default is now. |
@@ -2251,14 +2343,14 @@ The backing JSON for a versioned app node detail graph. (supported graphTypes: a
 #### All responses
 | Code | Status | Description | Has headers | Schema |
 |------|--------|-------------|:-----------:|--------|
-| [200](#graph-app-version-200) | OK | HTTP status code 200 and cytoscapejs Config in data |  | [schema](#graph-app-version-200-schema) |
+| [200](#graph-app-version-200) | OK | HTTP status code 200 and graph Config in data |  | [schema](#graph-app-version-200-schema) |
 | [400](#graph-app-version-400) | Bad Request | BadRequestError: the client request is incorrect |  | [schema](#graph-app-version-400-schema) |
 | [500](#graph-app-version-500) | Internal Server Error | A Internal is the error message that means something has gone wrong |  | [schema](#graph-app-version-500-schema) |
 
 #### Responses
 
 
-##### <span id="graph-app-version-200"></span> 200 - HTTP status code 200 and cytoscapejs Config in data
+##### <span id="graph-app-version-200"></span> 200 - HTTP status code 200 and graph Config in data
 Status: OK
 
 ###### <span id="graph-app-version-200-schema"></span> Schema
@@ -2353,14 +2445,14 @@ GET /api/namespaces/graph
 #### All responses
 | Code | Status | Description | Has headers | Schema |
 |------|--------|-------------|:-----------:|--------|
-| [200](#graph-namespaces-200) | OK | HTTP status code 200 and cytoscapejs Config in data |  | [schema](#graph-namespaces-200-schema) |
+| [200](#graph-namespaces-200) | OK | HTTP status code 200 and graph Config in data |  | [schema](#graph-namespaces-200-schema) |
 | [400](#graph-namespaces-400) | Bad Request | BadRequestError: the client request is incorrect |  | [schema](#graph-namespaces-400-schema) |
 | [500](#graph-namespaces-500) | Internal Server Error | A Internal is the error message that means something has gone wrong |  | [schema](#graph-namespaces-500-schema) |
 
 #### Responses
 
 
-##### <span id="graph-namespaces-200"></span> 200 - HTTP status code 200 and cytoscapejs Config in data
+##### <span id="graph-namespaces-200"></span> 200 - HTTP status code 200 and graph Config in data
 Status: OK
 
 ###### <span id="graph-namespaces-200-schema"></span> Schema
@@ -2455,14 +2547,14 @@ GET /api/namespaces/{namespace}/services/{service}/graph
 #### All responses
 | Code | Status | Description | Has headers | Schema |
 |------|--------|-------------|:-----------:|--------|
-| [200](#graph-service-200) | OK | HTTP status code 200 and cytoscapejs Config in data |  | [schema](#graph-service-200-schema) |
+| [200](#graph-service-200) | OK | HTTP status code 200 and graph Config in data |  | [schema](#graph-service-200-schema) |
 | [400](#graph-service-400) | Bad Request | BadRequestError: the client request is incorrect |  | [schema](#graph-service-400-schema) |
 | [500](#graph-service-500) | Internal Server Error | A Internal is the error message that means something has gone wrong |  | [schema](#graph-service-500-schema) |
 
 #### Responses
 
 
-##### <span id="graph-service-200"></span> 200 - HTTP status code 200 and cytoscapejs Config in data
+##### <span id="graph-service-200"></span> 200 - HTTP status code 200 and graph Config in data
 Status: OK
 
 ###### <span id="graph-service-200-schema"></span> Schema
@@ -2559,14 +2651,14 @@ GET /api/namespaces/{namespace}/workloads/{workload}/graph
 #### All responses
 | Code | Status | Description | Has headers | Schema |
 |------|--------|-------------|:-----------:|--------|
-| [200](#graph-workload-200) | OK | HTTP status code 200 and cytoscapejs Config in data |  | [schema](#graph-workload-200-schema) |
+| [200](#graph-workload-200) | OK | HTTP status code 200 and graph Config in data |  | [schema](#graph-workload-200-schema) |
 | [400](#graph-workload-400) | Bad Request | BadRequestError: the client request is incorrect |  | [schema](#graph-workload-400-schema) |
 | [500](#graph-workload-500) | Internal Server Error | A Internal is the error message that means something has gone wrong |  | [schema](#graph-workload-500-schema) |
 
 #### Responses
 
 
-##### <span id="graph-workload-200"></span> 200 - HTTP status code 200 and cytoscapejs Config in data
+##### <span id="graph-workload-200"></span> 200 - HTTP status code 200 and graph Config in data
 Status: OK
 
 ###### <span id="graph-workload-200-schema"></span> Schema
@@ -2668,66 +2760,6 @@ Status: Internal Server Error
 
 
 
-**Properties**
-
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| Code | int32 (formatted integer)| `int32` |  | `500`| HTTP status code | `500` |
-| Message | string| `string` |  | |  |  |
-
-
-
-### <span id="istio-certs"></span> istio certs (*istioCerts*)
-
-```
-GET /api/istio/certs
-```
-
-Get certificates (internal) information used by Istio
-
-#### URI Schemes
-  * http
-  * https
-
-#### Produces
-  * application/json
-
-#### All responses
-| Code | Status | Description | Has headers | Schema |
-|------|--------|-------------|:-----------:|--------|
-| [200](#istio-certs-200) | OK | Return a list of certificates information |  | [schema](#istio-certs-200-schema) |
-| [500](#istio-certs-500) | Internal Server Error | A Internal is the error message that means something has gone wrong |  | [schema](#istio-certs-500-schema) |
-
-#### Responses
-
-
-##### <span id="istio-certs-200"></span> 200 - Return a list of certificates information
-Status: OK
-
-###### <span id="istio-certs-200-schema"></span> Schema
-   
-  
-
-[][CertInfo](#cert-info)
-
-##### <span id="istio-certs-500"></span> 500 - A Internal is the error message that means something has gone wrong
-Status: Internal Server Error
-
-###### <span id="istio-certs-500-schema"></span> Schema
-   
-  
-
-[IstioCertsInternalServerErrorBody](#istio-certs-internal-server-error-body)
-
-###### Inlined models
-
-**<span id="istio-certs-internal-server-error-body"></span> IstioCertsInternalServerErrorBody**
-
-
-  
-
-
-
 **Properties**
 
 | Name | Type | Go type | Required | Default | Description | Example |
@@ -2740,7 +2772,7 @@ Status: Internal Server Error
 ### <span id="istio-config-create"></span> istio config create (*istioConfigCreate*)
 
 ```
-POST /api/namespaces/{namespace}/istio/{object_type}
+POST /api/namespaces/{namespace}/istio/{group}/{version}/{kind}
 ```
 
 Endpoint to create an Istio object by using an Istio Config item
@@ -2756,8 +2788,10 @@ Endpoint to create an Istio object by using an Istio Config item
 
 | Name | Source | Type | Go type | Separator | Required | Default | Description |
 |------|--------|------|---------|-----------| :------: |---------|-------------|
+| group | `path` | string | `string` |  | ✓ |  | The GVK group in a group/value/kind specification. |
+| kind | `path` | string | `string` |  | ✓ |  | The GVK kind in a group/value/kind specification. |
 | namespace | `path` | string | `string` |  | ✓ |  | The namespace name. |
-| object_type | `path` | string | `string` |  | ✓ |  | The Istio object type. |
+| version | `path` | string | `string` |  | ✓ |  | The GVK version in a group/value/kind specification. |
 
 #### All responses
 | Code | Status | Description | Has headers | Schema |
@@ -2843,7 +2877,7 @@ Status: Internal Server Error
 ### <span id="istio-config-delete"></span> istio config delete (*istioConfigDelete*)
 
 ```
-DELETE /api/namespaces/{namespace}/istio/{object_type}/{object}
+DELETE /api/namespaces/{namespace}/istio/{group}/{version}/{kind}/{object}
 ```
 
 Endpoint to delete the Istio Config of an (arbitrary) Istio object
@@ -2859,9 +2893,11 @@ Endpoint to delete the Istio Config of an (arbitrary) Istio object
 
 | Name | Source | Type | Go type | Separator | Required | Default | Description |
 |------|--------|------|---------|-----------| :------: |---------|-------------|
+| group | `path` | string | `string` |  | ✓ |  | The GVK group in a group/value/kind specification. |
+| kind | `path` | string | `string` |  | ✓ |  | The GVK kind in a group/value/kind specification. |
 | namespace | `path` | string | `string` |  | ✓ |  | The namespace name. |
 | object | `path` | string | `string` |  | ✓ |  | The Istio object name. |
-| object_type | `path` | string | `string` |  | ✓ |  | The Istio object type. |
+| version | `path` | string | `string` |  | ✓ |  | The GVK version in a group/value/kind specification. |
 
 #### All responses
 | Code | Status | Description | Has headers | Schema |
@@ -2927,7 +2963,7 @@ Status: Internal Server Error
 ### <span id="istio-config-details"></span> istio config details (*istioConfigDetails*)
 
 ```
-GET /api/namespaces/{namespace}/istio/{object_type}/{object}
+GET /api/namespaces/{namespace}/istio/{group}/{version}/{kind}/{object}
 ```
 
 Endpoint to get the Istio Config of an Istio object
@@ -2943,9 +2979,11 @@ Endpoint to get the Istio Config of an Istio object
 
 | Name | Source | Type | Go type | Separator | Required | Default | Description |
 |------|--------|------|---------|-----------| :------: |---------|-------------|
+| group | `path` | string | `string` |  | ✓ |  | The GVK group in a group/value/kind specification. |
+| kind | `path` | string | `string` |  | ✓ |  | The GVK kind in a group/value/kind specification. |
 | namespace | `path` | string | `string` |  | ✓ |  | The namespace name. |
 | object | `path` | string | `string` |  | ✓ |  | The Istio object name. |
-| object_type | `path` | string | `string` |  | ✓ |  | The Istio object type. |
+| version | `path` | string | `string` |  | ✓ |  | The GVK version in a group/value/kind specification. |
 | validate | `query` | string | `string` |  |  |  | Enable validation or not |
 
 #### All responses
@@ -3175,7 +3213,7 @@ Status: Internal Server Error
 ### <span id="istio-config-update"></span> Endpoint to update the Istio Config of an Istio object used for templates and adapters using Json Merge Patch strategy. (*istioConfigUpdate*)
 
 ```
-PATCH /api/namespaces/{namespace}/istio/{object_type}/{object}
+PATCH /api/namespaces/{namespace}/istio/{group}/{version}/{kind}/{object}
 ```
 
 #### URI Schemes
@@ -3192,9 +3230,11 @@ PATCH /api/namespaces/{namespace}/istio/{object_type}/{object}
 
 | Name | Source | Type | Go type | Separator | Required | Default | Description |
 |------|--------|------|---------|-----------| :------: |---------|-------------|
+| group | `path` | string | `string` |  | ✓ |  | The GVK group in a group/value/kind specification. |
+| kind | `path` | string | `string` |  | ✓ |  | The GVK kind in a group/value/kind specification. |
 | namespace | `path` | string | `string` |  | ✓ |  | The namespace name. |
 | object | `path` | string | `string` |  | ✓ |  | The Istio object name. |
-| object_type | `path` | string | `string` |  | ✓ |  | The Istio object type. |
+| version | `path` | string | `string` |  | ✓ |  | The GVK version in a group/value/kind specification. |
 
 #### All responses
 | Code | Status | Description | Has headers | Schema |
@@ -3445,14 +3485,14 @@ The backing JSON for a mesh graph
 #### All responses
 | Code | Status | Description | Has headers | Schema |
 |------|--------|-------------|:-----------:|--------|
-| [200](#mesh-graph-200) | OK | HTTP status code 200 and cytoscapejs Config in data |  | [schema](#mesh-graph-200-schema) |
+| [200](#mesh-graph-200) | OK | HTTP status code 200 and graph Config in data |  | [schema](#mesh-graph-200-schema) |
 | [400](#mesh-graph-400) | Bad Request | BadRequestError: the client request is incorrect |  | [schema](#mesh-graph-400-schema) |
 | [500](#mesh-graph-500) | Internal Server Error | A Internal is the error message that means something has gone wrong |  | [schema](#mesh-graph-500-schema) |
 
 #### Responses
 
 
-##### <span id="mesh-graph-200"></span> 200 - HTTP status code 200 and cytoscapejs Config in data
+##### <span id="mesh-graph-200"></span> 200 - HTTP status code 200 and graph Config in data
 Status: OK
 
 ###### <span id="mesh-graph-200-schema"></span> Schema
@@ -4464,86 +4504,6 @@ Status: Internal Server Error
 
 
 
-### <span id="openshift-redirect"></span> openshift redirect (*openshiftRedirect*)
-
-```
-GET /api/auth/openshift_redirect
-```
-
-Endpoint to redirect the browser of the user to the authentication
-endpoint of the configured openshift provider.
-
-#### URI Schemes
-  * http
-  * https
-
-#### Consumes
-  * application/json
-
-#### Produces
-  * application/html
-
-#### All responses
-| Code | Status | Description | Has headers | Schema |
-|------|--------|-------------|:-----------:|--------|
-| [200](#openshift-redirect-200) | OK | NoContent: the response is empty |  | [schema](#openshift-redirect-200-schema) |
-| [500](#openshift-redirect-500) | Internal Server Error | A Internal is the error message that means something has gone wrong |  | [schema](#openshift-redirect-500-schema) |
-
-#### Responses
-
-
-##### <span id="openshift-redirect-200"></span> 200 - NoContent: the response is empty
-Status: OK
-
-###### <span id="openshift-redirect-200-schema"></span> Schema
-   
-  
-
-[OpenshiftRedirectOKBody](#openshift-redirect-o-k-body)
-
-##### <span id="openshift-redirect-500"></span> 500 - A Internal is the error message that means something has gone wrong
-Status: Internal Server Error
-
-###### <span id="openshift-redirect-500-schema"></span> Schema
-   
-  
-
-[OpenshiftRedirectInternalServerErrorBody](#openshift-redirect-internal-server-error-body)
-
-###### Inlined models
-
-**<span id="openshift-redirect-internal-server-error-body"></span> OpenshiftRedirectInternalServerErrorBody**
-
-
-  
-
-
-
-**Properties**
-
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| Code | int32 (formatted integer)| `int32` |  | `500`| HTTP status code | `500` |
-| Message | string| `string` |  | |  |  |
-
-
-
-**<span id="openshift-redirect-o-k-body"></span> OpenshiftRedirectOKBody**
-
-
-  
-
-
-
-**Properties**
-
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| Code | int32 (formatted integer)| `int32` |  | `204`| HTTP status code | `204` |
-| Message | string| `string` |  | |  |  |
-
-
-
 ### <span id="pod-details"></span> pod details (*podDetails*)
 
 ```
@@ -4659,7 +4619,8 @@ Endpoint to get pod logs
 | namespace | `path` | string | `string` |  | ✓ |  | The namespace name. |
 | pod | `path` | string | `string` |  | ✓ |  | The pod name. |
 | container | `query` | string | `string` |  |  |  | The pod container name. Optional for single-container pod. Otherwise required. |
-| duration | `query` | string | `string` |  |  |  | Query time-range duration (Golang string duration). Duration starts on</br>`sinceTime` if set, or the time for the first log message if not set. |
+| duration | `query` | string | `string` |  |  |  | Query time-range duration (Golang string duration). Duration starts on
+`sinceTime` if set, or the time for the first log message if not set. |
 | sinceTime | `query` | string | `string` |  |  |  | The start time for fetching logs. UNIX time in seconds. Default is all logs. |
 
 #### All responses
@@ -4847,7 +4808,7 @@ Endpoint to set pod proxy log level
 |------|--------|------|---------|-----------| :------: |---------|-------------|
 | namespace | `path` | string | `string` |  | ✓ |  | The namespace name. |
 | pod | `path` | string | `string` |  | ✓ |  | The pod name. |
-| level | `query` | string | `string` |  | ✓ |  | The log level for the pod's proxy.</br>off ProxyLogLevelOff</br>trace ProxyLogLevelTrace</br>debug ProxyLogLevelDebug</br>info ProxyLogLevelInfo</br>warning ProxyLogLevelWarning</br>error ProxyLogLevelError</br>critical ProxyLogLevelCritical |
+| level | `query` | string | `string` |  | ✓ |  | The log level for the pod's proxy. |
 
 #### All responses
 | Code | Status | Description | Has headers | Schema |
@@ -4968,7 +4929,7 @@ Status: Internal Server Error
 GET /api/namespaces/{namespace}/pods/{pod}/config_dump/{resource}
 ```
 
-Endpoint to get pod logs
+Endpoint to get pod resource entries
 
 #### URI Schemes
   * http
@@ -5417,7 +5378,7 @@ Endpoint to fetch metrics to be displayed, related to a single service
 | reporter | `query` | string | `string` |  |  | `"source"` | Istio telemetry reporter: 'source' or 'destination'. |
 | requestProtocol | `query` | string | `string` |  |  | `"all protocols"` | Desired request protocol for the telemetry: For example, 'http' or 'grpc'. |
 | step | `query` | int64 (formatted integer) | `int64` |  |  | `15` | Step between [graph] datapoints, in seconds. |
-| version | `query` | string | `string` |  |  |  | Filters metrics by the specified version. |
+| version | `query` | string | `string` |  |  |  | Filters metrics by the specified version |
 
 #### All responses
 | Code | Status | Description | Has headers | Schema |
@@ -5949,13 +5910,13 @@ Status: Not Acceptable
 
 
 
-### <span id="workload-dashboard"></span> workload dashboard (*workloadDashboard*)
+### <span id="usage-metrics"></span> usage metrics (*usageMetrics*)
 
 ```
-GET /api/namespaces/{namespace}/workloads/{workload}/dashboard
+GET /api/namespaces/{namespace}/{app}/usage_metrics
 ```
 
-Endpoint to fetch dashboard to be displayed, related to a single workload
+Endpoint to fetch metrics to be displayed, related to cpu and memory usage
 
 #### URI Schemes
   * http
@@ -5968,59 +5929,49 @@ Endpoint to fetch dashboard to be displayed, related to a single workload
 
 | Name | Source | Type | Go type | Separator | Required | Default | Description |
 |------|--------|------|---------|-----------| :------: |---------|-------------|
+| app | `path` | string | `string` |  | ✓ |  | The app name (label value). |
 | namespace | `path` | string | `string` |  | ✓ |  | The namespace name. |
-| workload | `path` | string | `string` |  | ✓ |  | The workload name. |
-| avg | `query` | boolean | `bool` |  |  | `true` | Flag for fetching histogram average. Default is true. |
-| byLabels[] | `query` | []string | `[]string` |  |  |  | List of labels to use for grouping metrics (via Prometheus 'by' clause). |
-| direction | `query` | string | `string` |  |  | `"outbound"` | Traffic direction: 'inbound' or 'outbound'. |
-| duration | `query` | int64 (formatted integer) | `int64` |  |  | `1800` | Duration of the query period, in seconds. |
-| quantiles[] | `query` | []string | `[]string` |  |  |  | List of quantiles to fetch. Fetch no quantiles when empty. Ex: [0.5, 0.95, 0.99]. |
-| rateFunc | `query` | string | `string` |  |  | `"rate"` | Prometheus function used to calculate rate: 'rate' or 'irate'. |
-| rateInterval | `query` | string | `string` |  |  | `"1m"` | Interval used for rate and histogram calculation. |
-| reporter | `query` | string | `string` |  |  | `"source"` | Istio telemetry reporter: 'source' or 'destination'. |
-| requestProtocol | `query` | string | `string` |  |  | `"all protocols"` | Desired request protocol for the telemetry: For example, 'http' or 'grpc'. |
-| step | `query` | int64 (formatted integer) | `int64` |  |  | `15` | Step between [graph] datapoints, in seconds. |
 
 #### All responses
 | Code | Status | Description | Has headers | Schema |
 |------|--------|-------------|:-----------:|--------|
-| [200](#workload-dashboard-200) | OK | Dashboard response model |  | [schema](#workload-dashboard-200-schema) |
-| [400](#workload-dashboard-400) | Bad Request | BadRequestError: the client request is incorrect |  | [schema](#workload-dashboard-400-schema) |
-| [503](#workload-dashboard-503) | Service Unavailable | A Internal is the error message that means something has gone wrong |  | [schema](#workload-dashboard-503-schema) |
+| [200](#usage-metrics-200) | OK | Metrics response model |  | [schema](#usage-metrics-200-schema) |
+| [400](#usage-metrics-400) | Bad Request | BadRequestError: the client request is incorrect |  | [schema](#usage-metrics-400-schema) |
+| [503](#usage-metrics-503) | Service Unavailable | A Internal is the error message that means something has gone wrong |  | [schema](#usage-metrics-503-schema) |
 
 #### Responses
 
 
-##### <span id="workload-dashboard-200"></span> 200 - Dashboard response model
+##### <span id="usage-metrics-200"></span> 200 - Metrics response model
 Status: OK
 
-###### <span id="workload-dashboard-200-schema"></span> Schema
+###### <span id="usage-metrics-200-schema"></span> Schema
    
   
 
-[MonitoringDashboard](#monitoring-dashboard)
+map of [Metric](#metric)
 
-##### <span id="workload-dashboard-400"></span> 400 - BadRequestError: the client request is incorrect
+##### <span id="usage-metrics-400"></span> 400 - BadRequestError: the client request is incorrect
 Status: Bad Request
 
-###### <span id="workload-dashboard-400-schema"></span> Schema
+###### <span id="usage-metrics-400-schema"></span> Schema
    
   
 
-[WorkloadDashboardBadRequestBody](#workload-dashboard-bad-request-body)
+[UsageMetricsBadRequestBody](#usage-metrics-bad-request-body)
 
-##### <span id="workload-dashboard-503"></span> 503 - A Internal is the error message that means something has gone wrong
+##### <span id="usage-metrics-503"></span> 503 - A Internal is the error message that means something has gone wrong
 Status: Service Unavailable
 
-###### <span id="workload-dashboard-503-schema"></span> Schema
+###### <span id="usage-metrics-503-schema"></span> Schema
    
   
 
-[WorkloadDashboardServiceUnavailableBody](#workload-dashboard-service-unavailable-body)
+[UsageMetricsServiceUnavailableBody](#usage-metrics-service-unavailable-body)
 
 ###### Inlined models
 
-**<span id="workload-dashboard-bad-request-body"></span> WorkloadDashboardBadRequestBody**
+**<span id="usage-metrics-bad-request-body"></span> UsageMetricsBadRequestBody**
 
 
   
@@ -6036,7 +5987,7 @@ Status: Service Unavailable
 
 
 
-**<span id="workload-dashboard-service-unavailable-body"></span> WorkloadDashboardServiceUnavailableBody**
+**<span id="usage-metrics-service-unavailable-body"></span> UsageMetricsServiceUnavailableBody**
 
 
   
@@ -6052,13 +6003,13 @@ Status: Service Unavailable
 
 
 
-### <span id="workload-details"></span> workload details (*workloadDetails*)
+### <span id="workload-dashboard"></span> workload dashboard (*workloadDashboard*)
 
 ```
-GET /api/namespaces/{namespace}/workloads/{workload}
+GET /api/namespaces/{namespace}/workloads/{workload}/dashboard
 ```
 
-Endpoint to get the workload details
+Endpoint to fetch dashboard to be displayed, related to a single workload
 
 #### URI Schemes
   * http
@@ -6073,9 +6024,112 @@ Endpoint to get the workload details
 |------|--------|------|---------|-----------| :------: |---------|-------------|
 | namespace | `path` | string | `string` |  | ✓ |  | The namespace name. |
 | workload | `path` | string | `string` |  | ✓ |  | The workload name. |
-
-#### All responses
-| Code | Status | Description | Has headers | Schema |
+| avg | `query` | boolean | `bool` |  |  | `true` | Flag for fetching histogram average. Default is true. |
+| byLabels[] | `query` | []string | `[]string` |  |  |  | List of labels to use for grouping metrics (via Prometheus 'by' clause). |
+| direction | `query` | string | `string` |  |  | `"outbound"` | Traffic direction: 'inbound' or 'outbound'. |
+| duration | `query` | int64 (formatted integer) | `int64` |  |  | `1800` | Duration of the query period, in seconds. |
+| quantiles[] | `query` | []string | `[]string` |  |  |  | List of quantiles to fetch. Fetch no quantiles when empty. Ex: [0.5, 0.95, 0.99]. |
+| rateFunc | `query` | string | `string` |  |  | `"rate"` | Prometheus function used to calculate rate: 'rate' or 'irate'. |
+| rateInterval | `query` | string | `string` |  |  | `"1m"` | Interval used for rate and histogram calculation. |
+| reporter | `query` | string | `string` |  |  | `"source"` | Istio telemetry reporter: 'source' or 'destination'. |
+| requestProtocol | `query` | string | `string` |  |  | `"all protocols"` | Desired request protocol for the telemetry: For example, 'http' or 'grpc'. |
+| step | `query` | int64 (formatted integer) | `int64` |  |  | `15` | Step between [graph] datapoints, in seconds. |
+
+#### All responses
+| Code | Status | Description | Has headers | Schema |
+|------|--------|-------------|:-----------:|--------|
+| [200](#workload-dashboard-200) | OK | Dashboard response model |  | [schema](#workload-dashboard-200-schema) |
+| [400](#workload-dashboard-400) | Bad Request | BadRequestError: the client request is incorrect |  | [schema](#workload-dashboard-400-schema) |
+| [503](#workload-dashboard-503) | Service Unavailable | A Internal is the error message that means something has gone wrong |  | [schema](#workload-dashboard-503-schema) |
+
+#### Responses
+
+
+##### <span id="workload-dashboard-200"></span> 200 - Dashboard response model
+Status: OK
+
+###### <span id="workload-dashboard-200-schema"></span> Schema
+   
+  
+
+[MonitoringDashboard](#monitoring-dashboard)
+
+##### <span id="workload-dashboard-400"></span> 400 - BadRequestError: the client request is incorrect
+Status: Bad Request
+
+###### <span id="workload-dashboard-400-schema"></span> Schema
+   
+  
+
+[WorkloadDashboardBadRequestBody](#workload-dashboard-bad-request-body)
+
+##### <span id="workload-dashboard-503"></span> 503 - A Internal is the error message that means something has gone wrong
+Status: Service Unavailable
+
+###### <span id="workload-dashboard-503-schema"></span> Schema
+   
+  
+
+[WorkloadDashboardServiceUnavailableBody](#workload-dashboard-service-unavailable-body)
+
+###### Inlined models
+
+**<span id="workload-dashboard-bad-request-body"></span> WorkloadDashboardBadRequestBody**
+
+
+  
+
+
+
+**Properties**
+
+| Name | Type | Go type | Required | Default | Description | Example |
+|------|------|---------|:--------:| ------- |-------------|---------|
+| Code | int32 (formatted integer)| `int32` |  | `400`| HTTP status code | `400` |
+| Message | string| `string` |  | |  |  |
+
+
+
+**<span id="workload-dashboard-service-unavailable-body"></span> WorkloadDashboardServiceUnavailableBody**
+
+
+  
+
+
+
+**Properties**
+
+| Name | Type | Go type | Required | Default | Description | Example |
+|------|------|---------|:--------:| ------- |-------------|---------|
+| Code | int32 (formatted integer)| `int32` |  | `503`| HTTP status code | `503` |
+| Message | string| `string` |  | |  |  |
+
+
+
+### <span id="workload-details"></span> workload details (*workloadDetails*)
+
+```
+GET /api/namespaces/{namespace}/workloads/{workload}
+```
+
+Endpoint to get the workload details
+
+#### URI Schemes
+  * http
+  * https
+
+#### Produces
+  * application/json
+
+#### Parameters
+
+| Name | Source | Type | Go type | Separator | Required | Default | Description |
+|------|--------|------|---------|-----------| :------: |---------|-------------|
+| namespace | `path` | string | `string` |  | ✓ |  | The namespace name. |
+| workload | `path` | string | `string` |  | ✓ |  | The workload name. |
+
+#### All responses
+| Code | Status | Description | Has headers | Schema |
 |------|--------|-------------|:-----------:|--------|
 | [200](#workload-details-200) | OK | Listing all the information related to a workload |  | [schema](#workload-details-200-schema) |
 | [404](#workload-details-404) | Not Found | A NotFoundError is the error message that is generated when server could not find what was requested. |  | [schema](#workload-details-404-schema) |
@@ -6243,7 +6297,7 @@ Endpoint to fetch metrics to be displayed, related to a single workload
 | reporter | `query` | string | `string` |  |  | `"source"` | Istio telemetry reporter: 'source' or 'destination'. |
 | requestProtocol | `query` | string | `string` |  |  | `"all protocols"` | Desired request protocol for the telemetry: For example, 'http' or 'grpc'. |
 | step | `query` | int64 (formatted integer) | `int64` |  |  | `15` | Step between [graph] datapoints, in seconds. |
-| version | `query` | string | `string` |  |  |  | Filters metrics by the specified version. |
+| version | `query` | string | `string` |  |  |  | Filters metrics by the specified version |
 
 #### All responses
 | Code | Status | Description | Has headers | Schema |
@@ -6596,9 +6650,68 @@ Status: Internal Server Error
 
 
 
-## Models
+### <span id="ztunnel-dashboard"></span> ztunnel dashboard (*ztunnelDashboard*)
 
-### <span id="additional-item"></span> AdditionalItem
+```
+GET /api/namespaces/{namespace}/ztunnel/{workload}/dashboard
+```
+
+Endpoint to fetch dashboard to be displayed, related to a ztunnel workload
+
+#### URI Schemes
+  * http
+  * https
+
+#### Produces
+  * application/json
+
+#### Parameters
+
+| Name | Source | Type | Go type | Separator | Required | Default | Description |
+|------|--------|------|---------|-----------| :------: |---------|-------------|
+| namespace | `path` | string | `string` |  | ✓ |  | The namespace name. |
+| workload | `path` | string | `string` |  | ✓ |  | The workload name. |
+
+#### All responses
+| Code | Status | Description | Has headers | Schema |
+|------|--------|-------------|:-----------:|--------|
+| [200](#ztunnel-dashboard-200) | OK | Dashboard response model |  | [schema](#ztunnel-dashboard-200-schema) |
+| [400](#ztunnel-dashboard-400) | Bad Request | BadRequestError: the client request is incorrect |  | [schema](#ztunnel-dashboard-400-schema) |
+| [503](#ztunnel-dashboard-503) | Service Unavailable | A Internal is the error message that means something has gone wrong |  | [schema](#ztunnel-dashboard-503-schema) |
+
+#### Responses
+
+
+##### <span id="ztunnel-dashboard-200"></span> 200 - Dashboard response model
+Status: OK
+
+###### <span id="ztunnel-dashboard-200-schema"></span> Schema
+   
+  
+
+[MonitoringDashboard](#monitoring-dashboard)
+
+##### <span id="ztunnel-dashboard-400"></span> 400 - BadRequestError: the client request is incorrect
+Status: Bad Request
+
+###### <span id="ztunnel-dashboard-400-schema"></span> Schema
+   
+  
+
+[ZtunnelDashboardBadRequestBody](#ztunnel-dashboard-bad-request-body)
+
+##### <span id="ztunnel-dashboard-503"></span> 503 - A Internal is the error message that means something has gone wrong
+Status: Service Unavailable
+
+###### <span id="ztunnel-dashboard-503-schema"></span> Schema
+   
+  
+
+[ZtunnelDashboardServiceUnavailableBody](#ztunnel-dashboard-service-unavailable-body)
+
+###### Inlined models
+
+**<span id="ztunnel-dashboard-bad-request-body"></span> ZtunnelDashboardBadRequestBody**
 
 
   
@@ -6609,13 +6722,12 @@ Status: Internal Server Error
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Icon | string| `string` |  | |  |  |
-| Title | string| `string` |  | |  |  |
-| Value | string| `string` |  | |  |  |
+| Code | int32 (formatted integer)| `int32` |  | `400`| HTTP status code | `400` |
+| Message | string| `string` |  | |  |  |
 
 
 
-### <span id="address"></span> Address
+**<span id="ztunnel-dashboard-service-unavailable-body"></span> ZtunnelDashboardServiceUnavailableBody**
 
 
   
@@ -6626,38 +6738,45 @@ Status: Internal Server Error
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| IP | string| `string` |  | |  |  |
-| Kind | string| `string` |  | |  |  |
-| Name | string| `string` |  | |  |  |
-| Port | uint32 (formatted integer)| `uint32` |  | |  |  |
+| Code | int32 (formatted integer)| `int32` |  | `503`| HTTP status code | `503` |
+| Message | string| `string` |  | |  |  |
 
 
 
-### <span id="address-type"></span> AddressType
+## Models
+
+### <span id="additional-item"></span> AdditionalItem
 
 
-> A predefined CamelCase string identifier (currently limited to `IPAddress` or `Hostname`)
-A domain-prefixed string identifier (like `acme.io/CustomAddressType`)
+  
 
-Values `IPAddress` and `Hostname` have Extended support.
 
-The `NamedAddress` value has been deprecated in favor of implementation
-specific domain-prefixed strings.
 
-All other values, including domain-prefixed values have Implementation-specific support,
-which are used in implementation-specific behaviors. Support for additional
-predefined CamelCase identifiers may be added in future releases.
+**Properties**
+
+| Name | Type | Go type | Required | Default | Description | Example |
+|------|------|---------|:--------:| ------- |-------------|---------|
+| Icon | string| `string` |  | |  |  |
+| Title | string| `string` |  | |  |  |
+| Value | string| `string` |  | |  |  |
+
+
+
+### <span id="address"></span> Address
+
 
-+kubebuilder:validation:MinLength=1
-+kubebuilder:validation:MaxLength=253
-+kubebuilder:validation:Pattern=`^Hostname|IPAddress|NamedAddress|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$`
   
 
 
 
-| Name | Type | Go type | Default | Description | Example |
-|------|------|---------| ------- |-------------|---------|
-| AddressType | string| string | | A predefined CamelCase string identifier (currently limited to `IPAddress` or `Hostname`)</br>A domain-prefixed string identifier (like `acme.io/CustomAddressType`)</br></br>Values `IPAddress` and `Hostname` have Extended support.</br></br>The `NamedAddress` value has been deprecated in favor of implementation</br>specific domain-prefixed strings.</br></br>All other values, including domain-prefixed values have Implementation-specific support,</br>which are used in implementation-specific behaviors. Support for additional</br>predefined CamelCase identifiers may be added in future releases.</br></br>+kubebuilder:validation:MinLength=1</br>+kubebuilder:validation:MaxLength=253</br>+kubebuilder:validation:Pattern=`^Hostname|IPAddress|NamedAddress|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$` |  |
+**Properties**
+
+| Name | Type | Go type | Required | Default | Description | Example |
+|------|------|---------|:--------:| ------- |-------------|---------|
+| IP | string| `string` |  | |  |  |
+| Kind | string| `string` |  | |  |  |
+| Name | string| `string` |  | |  |  |
+| Port | uint32 (formatted integer)| `uint32` |  | |  |  |
 
 
 
@@ -6703,7 +6822,10 @@ messages. All information should be static with respect to the error code.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| DocumentationUrl | string| `string` |  | | A url pointing to the Istio documentation for this specific error type.</br>Should be of the form</br>`^http(s)?://(preliminary\.)?istio.io/docs/reference/config/analysis/`</br>Required. |  |
+| DocumentationUrl | string| `string` |  | | A url pointing to the Istio documentation for this specific error type.
+Should be of the form
+`^http(s)?://(preliminary\.)?istio.io/docs/reference/config/analysis/`
+Required. |  |
 | level | [AnalysisMessageBaseLevel](#analysis-message-base-level)| `AnalysisMessageBaseLevel` |  | |  |  |
 | type | [AnalysisMessageBaseType](#analysis-message-base-type)| `AnalysisMessageBaseType` |  | |  |  |
 
@@ -6740,23 +6862,12 @@ codes between message types.)
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Code | string| `string` |  | | A 7 character code matching `^IST[0-9]{4}$` intended to uniquely identify</br>the message type. (e.g. "IST0001" is mapped to the "InternalError" message</br>type.) 0000-0100 are reserved. Required. |  |
-| Name | string| `string` |  | | A human-readable name for the message type. e.g. "InternalError",</br>"PodMissingProxy". This should be the same for all messages of the same type.</br>Required. |  |
-
-
-
-### <span id="annotation-value"></span> AnnotationValue
-
-
-> +kubebuilder:validation:MinLength=0
-+kubebuilder:validation:MaxLength=4096
-  
-
-
-
-| Name | Type | Go type | Default | Description | Example |
-|------|------|---------| ------- |-------------|---------|
-| AnnotationValue | string| string | | +kubebuilder:validation:MinLength=0</br>+kubebuilder:validation:MaxLength=4096 |  |
+| Code | string| `string` |  | | A 7 character code matching `^IST[0-9]{4}$` intended to uniquely identify
+the message type. (e.g. "IST0001" is mapped to the "InternalError" message
+type.) 0000-0100 are reserved. Required. |  |
+| Name | string| `string` |  | | A human-readable name for the message type. e.g. "InternalError",
+"PodMissingProxy". This should be the same for all messages of the same type.
+Required. |  |
 
 
 
@@ -6772,6 +6883,7 @@ codes between message types.)
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
 | Cluster | string| `string` |  | | Cluster of the application | `east` |
+| IsAmbient | boolean| `bool` | ✓ | | Define if all the workloads are ambient | `true` |
 | Name | string| `string` | ✓ | | Name of the application | `reviews` |
 | Runtimes | [][Runtime](#runtime)| `[]*Runtime` |  | | Runtimes and associated dashboards |  |
 | ServiceNames | []string| `[]string` | ✓ | | List of service names linked with an application |  |
@@ -6832,7 +6944,8 @@ codes between message types.)
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
 | Cluster | string| `string` |  | | The kube cluster where this application is located. |  |
-| IstioAmbient | boolean| `bool` | ✓ | | Define if any pod has the Ambient annotation | `true` |
+| IsAmbient | boolean| `bool` | ✓ | | Define if any pod has the Ambient annotation | `true` |
+| IsGateway | boolean| `bool` | ✓ | | Define if Labels related to this Workload contains any Gateway label | `true` |
 | IstioReferences | [][IstioValidationKey](#istio-validation-key)| `[]*IstioValidationKey` |  | | Istio References |  |
 | IstioSidecar | boolean| `bool` | ✓ | | Define if all Pods related to the Workloads of this app has an IstioSidecar deployed | `true` |
 | Labels | map of string| `map[string]string` |  | | Labels for App |  |
@@ -6842,66 +6955,6 @@ codes between message types.)
 
 
 
-### <span id="authorization-policy"></span> AuthorizationPolicy
-
-
-> <!-- crd generation tags
-+cue-gen:AuthorizationPolicy:groupName:security.istio.io
-+cue-gen:AuthorizationPolicy:version:v1
-+cue-gen:AuthorizationPolicy:annotations:helm.sh/resource-policy=keep
-+cue-gen:AuthorizationPolicy:labels:app=istio-pilot,chart=istio,istio=security,heritage=Tiller,release=istio
-+cue-gen:AuthorizationPolicy:subresource:status
-+cue-gen:AuthorizationPolicy:scope:Namespaced
-+cue-gen:AuthorizationPolicy:resource:categories=istio-io,security-istio-io,shortNames=ap,plural=authorizationpolicies
-+cue-gen:AuthorizationPolicy:preserveUnknownFields:false
-+cue-gen:AuthorizationPolicy:printerColumn:name=Action,type=string,JSONPath=.spec.action,description="The operation to take."
-+cue-gen:AuthorizationPolicy:printerColumn:name=Age,type=date,JSONPath=.metadata.creationTimestamp,description="CreationTimestamp is a timestamp
-representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations.
-Clients may not set this value. It is represented in RFC3339 form and is in UTC.
-Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata"
->
-
-<!-- go code generation tags
-+kubetype-gen
-+kubetype-gen:groupVersion=security.istio.io/v1
-+genclient
-+k8s:deepcopy-gen=true
->
-<!-- istio code generation tags
-+istio.io/sync-from:security/v1beta1/authorization_policy.proto
->
-  
-
-
-
-
-
-**Properties**
-
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| APIVersion | string| `string` |  | | APIVersion defines the versioned schema of this representation of an object.</br>Servers should convert recognized schemas to the latest internal value, and</br>may reject unrecognized values.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources</br>+optional |  |
-| Annotations | map of string| `map[string]string` |  | | Annotations is an unstructured key value map stored with a resource that may be</br>set by external tools to store and retrieve arbitrary metadata. They are not</br>queryable and should be preserved when modifying objects.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations</br>+optional |  |
-| CreationTimestamp | string| `string` |  | | CreationTimestamp is a timestamp representing the server time when this object was</br>created. It is not guaranteed to be set in happens-before order across separate operations.</br>Clients may not set this value. It is represented in RFC3339 form and is in UTC.</br></br>Populated by the system.</br>Read-only.</br>Null for lists.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| DeletionGracePeriodSeconds | int64 (formatted integer)| `int64` |  | | Number of seconds allowed for this object to gracefully terminate before</br>it will be removed from the system. Only set when deletionTimestamp is also set.</br>May only be shortened.</br>Read-only.</br>+optional |  |
-| DeletionTimestamp | string| `string` |  | | DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This</br>field is set by the server when a graceful deletion is requested by the user, and is not</br>directly settable by a client. The resource is expected to be deleted (no longer visible</br>from resource lists, and not reachable by name) after the time in this field, once the</br>finalizers list is empty. As long as the finalizers list contains items, deletion is blocked.</br>Once the deletionTimestamp is set, this value may not be unset or be set further into the</br>future, although it may be shortened or the resource may be deleted prior to this time.</br>For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react</br>by sending a graceful termination signal to the containers in the pod. After that 30 seconds,</br>the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,</br>remove the pod from the API. In the presence of network partitions, this object may still</br>exist after this timestamp, until an administrator or automated process can determine the</br>resource is fully terminated.</br>If not set, graceful deletion of the object has not been requested.</br></br>Populated by the system when a graceful deletion is requested.</br>Read-only.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| Finalizers | []string| `[]string` |  | | Must be empty before the object is deleted from the registry. Each entry</br>is an identifier for the responsible component that will remove the entry</br>from the list. If the deletionTimestamp of the object is non-nil, entries</br>in this list can only be removed.</br>Finalizers may be processed and removed in any order.  Order is NOT enforced</br>because it introduces significant risk of stuck finalizers.</br>finalizers is a shared field, any actor with permission can reorder it.</br>If the finalizer list is processed in order, then this can lead to a situation</br>in which the component responsible for the first finalizer in the list is</br>waiting for a signal (field value, external system, or other) produced by a</br>component responsible for a finalizer later in the list, resulting in a deadlock.</br>Without enforced ordering finalizers are free to order amongst themselves and</br>are not vulnerable to ordering changes in the list.</br>+optional</br>+patchStrategy=merge</br>+listType=set |  |
-| GenerateName | string| `string` |  | | GenerateName is an optional prefix, used by the server, to generate a unique</br>name ONLY IF the Name field has not been provided.</br>If this field is used, the name returned to the client will be different</br>than the name passed. This value will also be combined with a unique suffix.</br>The provided value has the same validation rules as the Name field,</br>and may be truncated by the length of the suffix required to make the value</br>unique on the server.</br></br>If this field is specified and the generated name exists, the server will return a 409.</br></br>Applied only if Name is not specified.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency</br>+optional |  |
-| Generation | int64 (formatted integer)| `int64` |  | | A sequence number representing a specific generation of the desired state.</br>Populated by the system. Read-only.</br>+optional |  |
-| Kind | string| `string` |  | | Kind is a string value representing the REST resource this object represents.</br>Servers may infer this from the endpoint the client submits requests to.</br>Cannot be updated.</br>In CamelCase.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds</br>+optional |  |
-| Labels | map of string| `map[string]string` |  | | Map of string keys and values that can be used to organize and categorize</br>(scope and select) objects. May match selectors of replication controllers</br>and services.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels</br>+optional |  |
-| ManagedFields | [][ManagedFieldsEntry](#managed-fields-entry)| `[]*ManagedFieldsEntry` |  | | ManagedFields maps workflow-id and version to the set of fields</br>that are managed by that workflow. This is mostly for internal</br>housekeeping, and users typically shouldn't need to set or</br>understand this field. A workflow can be the user's name, a</br>controller's name, or the name of a specific apply path like</br>"ci-cd". The set of fields is always in the version that the</br>workflow used when modifying the object.</br></br>+optional</br>+listType=atomic |  |
-| Name | string| `string` |  | | Name must be unique within a namespace. Is required when creating resources, although</br>some resources may allow a client to request the generation of an appropriate name</br>automatically. Name is primarily intended for creation idempotence and configuration</br>definition.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names</br>+optional |  |
-| Namespace | string| `string` |  | | Namespace defines the space within which each name must be unique. An empty namespace is</br>equivalent to the "default" namespace, but "default" is the canonical representation.</br>Not all objects are required to be scoped to a namespace - the value of this field for</br>those objects will be empty.</br></br>Must be a DNS_LABEL.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces</br>+optional |  |
-| OwnerReferences | [][OwnerReference](#owner-reference)| `[]*OwnerReference` |  | | List of objects depended by this object. If ALL objects in the list have</br>been deleted, this object will be garbage collected. If this object is managed by a controller,</br>then an entry in this list will point to this controller, with the controller field set to true.</br>There cannot be more than one managing controller.</br>+optional</br>+patchMergeKey=uid</br>+patchStrategy=merge</br>+listType=map</br>+listMapKey=uid |  |
-| ResourceVersion | string| `string` |  | | An opaque value that represents the internal version of this object that can</br>be used by clients to determine when objects have changed. May be used for optimistic</br>concurrency, change detection, and the watch operation on a resource or set of resources.</br>Clients must treat these values as opaque and passed unmodified back to the server.</br>They may only be valid for a particular resource or set of resources.</br></br>Populated by the system.</br>Read-only.</br>Value must be treated as opaque by clients and .</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency</br>+optional |  |
-| SelfLink | string| `string` |  | | Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.</br>+optional |  |
-| spec | [AuthorizationPolicy](#authorization-policy)| `AuthorizationPolicy` |  | |  |  |
-| status | [IstioStatus](#istio-status)| `IstioStatus` |  | |  |  |
-| uid | [UID](#uid)| `UID` |  | |  |  |
-
-
-
 ### <span id="backend-object-reference"></span> BackendObjectReference
 
 
@@ -6936,58 +6989,28 @@ on the containing object.
 
 
 
-### <span id="backend-ref"></span> BackendRef
+### <span id="bootstrap"></span> Bootstrap
 
 
-> Note that when a namespace different than the local namespace is specified, a
-ReferenceGrant object is required in the referent namespace to allow that
-namespace's owner to accept the reference. See the ReferenceGrant
-documentation for details.
+  
 
-<gateway:experimental:description>
 
-When the BackendRef points to a Kubernetes Service, implementations SHOULD
-honor the appProtocol field if it is set for the target Service Port.
 
-Implementations supporting appProtocol SHOULD recognize the Kubernetes
-Standard Application Protocols defined in KEP-3726.
+**Properties**
 
-If a Service appProtocol isn't specified, an implementation MAY infer the
-backend protocol through its own means. Implementations MAY infer the
-protocol from the Route type referring to the backend Service.
+| Name | Type | Go type | Required | Default | Description | Example |
+|------|------|---------|:--------:| ------- |-------------|---------|
+| Bootstrap | map of any | `map[string]interface{}` |  | |  |  |
 
-If a Route is not able to send traffic to the backend using the specified
-protocol then the backend is considered invalid. Implementations MUST set the
-"ResolvedRefs" condition to "False" with the "UnsupportedProtocol" reason.
 
-</gateway:experimental:description>
-
-Note that when the BackendTLSPolicy object is enabled by the implementation,
-there are some extra rules about validity to consider here. See the fields
-where this struct is used for more information about the exact behavior.
-  
-
-
-
-
-
-**Properties**
-
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| Weight | int32 (formatted integer)| `int32` |  | | Weight specifies the proportion of requests forwarded to the referenced</br>backend. This is computed as weight/(sum of all weights in this</br>BackendRefs list). For non-zero values, there may be some epsilon from</br>the exact proportion defined here depending on the precision an</br>implementation supports. Weight is not a percentage and the sum of</br>weights does not need to equal 100.</br></br>If only one backend is specified and it has a weight greater than 0, 100%</br>of the traffic is forwarded to that backend. If weight is set to 0, no</br>traffic should be forwarded for this entry. If unspecified, weight</br>defaults to 1.</br></br>Support for this field varies based on the context where used.</br></br>+optional</br>+kubebuilder:default=1</br>+kubebuilder:validation:Minimum=0</br>+kubebuilder:validation:Maximum=1000000 |  |
-| group | [Group](#group)| `Group` |  | |  |  |
-| kind | [Kind](#kind)| `Kind` |  | |  |  |
-| name | [ObjectName](#object-name)| `ObjectName` |  | |  |  |
-| namespace | [Namespace](#namespace)| `Namespace` |  | |  |  |
-| port | [PortNumber](#port-number)| `PortNumber` |  | |  |  |
 
+### <span id="cert-info"></span> CertInfo
 
 
-### <span id="bootstrap"></span> Bootstrap
+> CertInfo contains the information for a given certificate
+  
 
 
-  
 
 
 
@@ -6995,32 +7018,37 @@ where this struct is used for more information about the exact behavior.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Bootstrap | map of any | `map[string]interface{}` |  | |  |  |
+| Accessible | boolean| `bool` |  | |  |  |
+| ClusterName | string| `string` |  | |  |  |
+| ConfigMapName | string| `string` |  | |  |  |
+| ConfigMapNamespace | string| `string` |  | |  |  |
+| DNSNames | []string| `[]string` |  | |  |  |
+| Error | string| `string` |  | |  |  |
+| Issuer | string| `string` |  | |  |  |
+| NotAfter | date-time (formatted string)| `strfmt.DateTime` |  | |  |  |
+| NotBefore | date-time (formatted string)| `strfmt.DateTime` |  | |  |  |
 
 
 
-### <span id="cert-info"></span> CertInfo
+### <span id="certificate"></span> Certificate
 
 
-> CertInfo contains the information for a given certificate
   
 
 
 
-
-
 **Properties**
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
 | Accessible | boolean| `bool` |  | |  |  |
+| ClusterName | string| `string` |  | |  |  |
+| ConfigMapName | string| `string` |  | |  |  |
 | DNSNames | []string| `[]string` |  | |  |  |
 | Error | string| `string` |  | |  |  |
 | Issuer | string| `string` |  | |  |  |
 | NotAfter | date-time (formatted string)| `strfmt.DateTime` |  | |  |  |
 | NotBefore | date-time (formatted string)| `strfmt.DateTime` |  | |  |  |
-| SecretName | string| `string` |  | |  |  |
-| SecretNamespace | string| `string` |  | |  |  |
 
 
 
@@ -7054,25 +7082,20 @@ where this struct is used for more information about the exact behavior.
 ### <span id="cluster"></span> Cluster
 
 
-> Cluster holds some metadata about a cluster that is
-part of the mesh.
   
 
 
 
-
-
 **Properties**
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Accessible | boolean| `bool` |  | | Accessible specifies if the cluster is accessible or not. Clusters that are manually specified in the Kiali config</br>but do not have an associated remote cluster secret are considered not accessible. This is helpful when you have</br>two disconnected Kialis and want to link them without giving them access to each other. |  |
-| ApiEndpoint | string| `string` |  | | ApiEndpoint is the URL where the Kubernetes/Cluster API Server can be contacted |  |
-| IsKialiHome | boolean| `bool` |  | | IsKialiHome specifies if this cluster is hosting this Kiali instance (and the observed Mesh Control Plane) |  |
-| KialiInstances | [][KialiInstance](#kiali-instance)| `[]*KialiInstance` |  | | KialiInstances is the list of Kialis discovered in the cluster. |  |
-| Name | string| `string` |  | | Name specifies the CLUSTER_ID as known by the Control Plane |  |
-| Network | string| `string` |  | | Network specifies the logical NETWORK_ID as known by the Control Plane |  |
-| SecretName | string| `string` |  | | SecretName is the name of the kubernetes "remote cluster secret" that was mounted to the file system and where data of this cluster was resolved |  |
+| DestinationRule | string| `string` |  | |  |  |
+| Direction | string| `string` |  | |  |  |
+| Port | int64 (formatted integer)| `int64` |  | |  |  |
+| Subset | string| `string` |  | |  |  |
+| Type | string| `string` |  | |  |  |
+| service_fqdn | [Host](#host)| `Host` |  | |  |  |
 
 
 
@@ -7146,11 +7169,36 @@ other fields
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| LastTransitionTime | string| `string` |  | | lastTransitionTime is the last time the condition transitioned from one status to another.</br>This should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.</br>+required</br>+kubebuilder:validation:Required</br>+kubebuilder:validation:Type=string</br>+kubebuilder:validation:Format=date-time |  |
-| Message | string| `string` |  | | message is a human readable message indicating details about the transition.</br>This may be an empty string.</br>+required</br>+kubebuilder:validation:Required</br>+kubebuilder:validation:MaxLength=32768 |  |
-| ObservedGeneration | int64 (formatted integer)| `int64` |  | | observedGeneration represents the .metadata.generation that the condition was set based upon.</br>For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date</br>with respect to the current state of the instance.</br>+optional</br>+kubebuilder:validation:Minimum=0 |  |
-| Reason | string| `string` |  | | reason contains a programmatic identifier indicating the reason for the condition's last transition.</br>Producers of specific condition types may define expected values and meanings for this field,</br>and whether the values are considered a guaranteed API.</br>The value should be a CamelCase string.</br>This field may not be empty.</br>+required</br>+kubebuilder:validation:Required</br>+kubebuilder:validation:MaxLength=1024</br>+kubebuilder:validation:MinLength=1</br>+kubebuilder:validation:Pattern=`^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$` |  |
-| Type | string| `string` |  | | type of condition in CamelCase or in foo.example.com/CamelCase.</br></br>Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be</br>useful (see .node.status.conditions), the ability to deconflict is important.</br>The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)</br>+required</br>+kubebuilder:validation:Required</br>+kubebuilder:validation:Pattern=`^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$`</br>+kubebuilder:validation:MaxLength=316 |  |
+| Message | string| `string` |  | | message is a human readable message indicating details about the transition.
+This may be an empty string.
++required
++kubebuilder:validation:Required
++kubebuilder:validation:MaxLength=32768 |  |
+| ObservedGeneration | int64 (formatted integer)| `int64` |  | | observedGeneration represents the .metadata.generation that the condition was set based upon.
+For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
+with respect to the current state of the instance.
++optional
++kubebuilder:validation:Minimum=0 |  |
+| Reason | string| `string` |  | | reason contains a programmatic identifier indicating the reason for the condition's last transition.
+Producers of specific condition types may define expected values and meanings for this field,
+and whether the values are considered a guaranteed API.
+The value should be a CamelCase string.
+This field may not be empty.
++required
++kubebuilder:validation:Required
++kubebuilder:validation:MaxLength=1024
++kubebuilder:validation:MinLength=1
++kubebuilder:validation:Pattern=`^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$` |  |
+| Type | string| `string` |  | | type of condition in CamelCase or in foo.example.com/CamelCase.
+
+Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be
+useful (see .node.status.conditions), the ability to deconflict is important.
+The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
++required
++kubebuilder:validation:Required
++kubebuilder:validation:Pattern=`^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$`
++kubebuilder:validation:MaxLength=316 |  |
+| lastTransitionTime | [Time](#time)| `Time` |  | |  |  |
 | status | [ConditionStatus](#condition-status)| `ConditionStatus` |  | |  |  |
 
 
@@ -7239,16 +7287,29 @@ It has configuration for all the clusters/namespaces associated with it.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Cluster | [Cluster](#cluster)| `Cluster` |  | |  |  |
-| Config | [ControlPlaneConfiguration](#control-plane-configuration)| `ControlPlaneConfiguration` |  | |  |  |
 | ExternalControlPlane | boolean| `bool` |  | | ExternalControlPlane indicates if the controlplane is managing an external cluster. |  |
 | ID | string| `string` |  | | ID is the control plane ID as known by istiod. |  |
 | IstiodName | string| `string` |  | | IstiodName is the control plane name |  |
 | IstiodNamespace | string| `string` |  | | IstiodNamespace is the namespace name of the deployed control plane |  |
-| ManagedClusters | [][Cluster](#cluster)| `[]*Cluster` |  | | ManagedClusters are the clusters that this controlplane manages.</br>This could include the cluster that the controlplane is running on. |  |
-| ManagesExternal | boolean| `bool` |  | | ManagesExternal indicates if the controlplane manages an external cluster.</br>It could also manage the cluster that it is running on. |  |
-| Revision | string| `string` |  | | Revision is the revision of the controlplane.</br>Can be empty when it's the default revision. |  |
-| Version | [ExternalServiceInfo](#external-service-info)| `ExternalServiceInfo` |  | |  |  |
+| ManagedClusters | [][KubeCluster](#kube-cluster)| `[]*KubeCluster` |  | | ManagedClusters are the clusters that this controlplane manages.
+This could include the cluster that the controlplane is running on. |  |
+| ManagedNamespaces | [][Namespace](#namespace)| `[]*Namespace` |  | | ManagedNamespaces are the namespaces that the controlplane is managing.
+More specifically, it is a namespace with either injection enabled
+or ambient enabled and it matches this controlplane's revision either
+directly or through a tag. |  |
+| ManagesExternal | boolean| `bool` |  | | ManagesExternal indicates if the controlplane manages an external cluster.
+It could also manage the cluster that it is running on. |  |
+| Revision | string| `string` |  | | Revision is the revision of the controlplane.
+Can be empty when it's the default revision. |  |
+| Status | string| `string` |  | | Status is the status of the controlplane as reported by kiali.
+It includes the deployment status and whether kiali can connect
+to the controlplane or not. |  |
+| cluster | [KubeCluster](#kube-cluster)| `KubeCluster` |  | |  |  |
+| config | [ControlPlaneConfiguration](#control-plane-configuration)| `ControlPlaneConfiguration` |  | |  |  |
+| resources | [ResourceRequirements](#resource-requirements)| `ResourceRequirements` |  | |  |  |
+| tag | [Tag](#tag)| `Tag` |  | |  |  |
+| thresholds | [IstiodThresholds](#istiod-thresholds)| `IstiodThresholds` |  | |  |  |
+| version | [ExternalServiceInfo](#external-service-info)| `ExternalServiceInfo` |  | |  |  |
 
 
 
@@ -7263,14 +7324,51 @@ It has configuration for all the clusters/namespaces associated with it.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| DefaultConfig | [interface{}](#interface)| `interface{}` |  | |  |  |
+| Certificates | [][Certificate](#certificate)| `[]*Certificate` |  | |  |  |
+| ConfigMap | map of string| `map[string]string` |  | | Config Map |  |
+| DefaultDestinationRuleExportTo | []string| `[]string` |  | | Default Export To fields, used when objects do not have ExportTo |  |
+| DefaultServiceExportTo | []string| `[]string` |  | |  |  |
+| DefaultVirtualServiceExportTo | []string| `[]string` |  | |  |  |
 | DisableMixerHttpReports | boolean| `bool` |  | |  |  |
-| DiscoverySelectors | [][LabelSelector](#label-selector)| `[]*LabelSelector` |  | |  |  |
+| DiscoverySelectors | [DiscoverySelectorsType](#discovery-selectors-type)| `DiscoverySelectorsType` |  | |  |  |
 | EnableAutoMtls | boolean| `bool` |  | |  |  |
-| MeshMTLS | [interface{}](#interface)| `interface{}` |  | |  |  |
+| MeshMTLS | [ControlPlaneConfigurationMeshMTLS](#control-plane-configuration-mesh-m-tls)| `ControlPlaneConfigurationMeshMTLS` |  | |  |  |
 | Network | string| `string` |  | | Network is the name of the network that the controlplane is using. |  |
-| OutboundTrafficPolicy | [OutboundPolicy](#outbound-policy)| `OutboundPolicy` |  | |  |  |
 | TrustDomain | string| `string` |  | |  |  |
+| defaultConfig | [DefaultConfig](#default-config)| `DefaultConfig` |  | |  |  |
+| outboundTrafficPolicy | [OutboundPolicy](#outbound-policy)| `OutboundPolicy` |  | |  |  |
+
+
+
+#### Inlined models
+
+**<span id="default-config"></span> DefaultConfig**
+
+
+  
+
+
+
+**Properties**
+
+| Name | Type | Go type | Required | Default | Description | Example |
+|------|------|---------|:--------:| ------- |-------------|---------|
+| MeshId | string| `string` |  | |  |  |
+
+
+
+**<span id="control-plane-configuration-mesh-m-tls"></span> ControlPlaneConfigurationMeshMTLS**
+
+
+  
+
+
+
+**Properties**
+
+| Name | Type | Go type | Required | Default | Description | Example |
+|------|------|---------|:--------:| ------- |-------------|---------|
+| MinProtocolVersion | string| `string` |  | |  |  |
 
 
 
@@ -7343,7 +7441,7 @@ It has configuration for all the clusters/namespaces associated with it.
 
 > <!-- crd generation tags
 +cue-gen:DestinationRule:groupName:networking.istio.io
-+cue-gen:DestinationRule:version:v1
++cue-gen:DestinationRule:versions:v1beta1,v1alpha3,v1
 +cue-gen:DestinationRule:annotations:helm.sh/resource-policy=keep
 +cue-gen:DestinationRule:labels:app=istio-pilot,chart=istio,heritage=Tiller,release=istio
 +cue-gen:DestinationRule:subresource:status
@@ -7359,13 +7457,10 @@ Populated by the system. Read-only. Null for lists. More info: https://git.k8s.i
 
 <!-- go code generation tags
 +kubetype-gen
-+kubetype-gen:groupVersion=networking.istio.io/v1
++kubetype-gen:groupVersion=networking.istio.io/v1alpha3
 +genclient
 +k8s:deepcopy-gen=true
 >
-<!-- istio code generation tags
-+istio.io/sync-from:networking/v1alpha3/destination_rule.proto
->
   
 
 
@@ -7376,28 +7471,143 @@ Populated by the system. Read-only. Null for lists. More info: https://git.k8s.i
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| APIVersion | string| `string` |  | | APIVersion defines the versioned schema of this representation of an object.</br>Servers should convert recognized schemas to the latest internal value, and</br>may reject unrecognized values.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources</br>+optional |  |
-| Annotations | map of string| `map[string]string` |  | | Annotations is an unstructured key value map stored with a resource that may be</br>set by external tools to store and retrieve arbitrary metadata. They are not</br>queryable and should be preserved when modifying objects.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations</br>+optional |  |
-| CreationTimestamp | string| `string` |  | | CreationTimestamp is a timestamp representing the server time when this object was</br>created. It is not guaranteed to be set in happens-before order across separate operations.</br>Clients may not set this value. It is represented in RFC3339 form and is in UTC.</br></br>Populated by the system.</br>Read-only.</br>Null for lists.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| DeletionGracePeriodSeconds | int64 (formatted integer)| `int64` |  | | Number of seconds allowed for this object to gracefully terminate before</br>it will be removed from the system. Only set when deletionTimestamp is also set.</br>May only be shortened.</br>Read-only.</br>+optional |  |
-| DeletionTimestamp | string| `string` |  | | DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This</br>field is set by the server when a graceful deletion is requested by the user, and is not</br>directly settable by a client. The resource is expected to be deleted (no longer visible</br>from resource lists, and not reachable by name) after the time in this field, once the</br>finalizers list is empty. As long as the finalizers list contains items, deletion is blocked.</br>Once the deletionTimestamp is set, this value may not be unset or be set further into the</br>future, although it may be shortened or the resource may be deleted prior to this time.</br>For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react</br>by sending a graceful termination signal to the containers in the pod. After that 30 seconds,</br>the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,</br>remove the pod from the API. In the presence of network partitions, this object may still</br>exist after this timestamp, until an administrator or automated process can determine the</br>resource is fully terminated.</br>If not set, graceful deletion of the object has not been requested.</br></br>Populated by the system when a graceful deletion is requested.</br>Read-only.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| Finalizers | []string| `[]string` |  | | Must be empty before the object is deleted from the registry. Each entry</br>is an identifier for the responsible component that will remove the entry</br>from the list. If the deletionTimestamp of the object is non-nil, entries</br>in this list can only be removed.</br>Finalizers may be processed and removed in any order.  Order is NOT enforced</br>because it introduces significant risk of stuck finalizers.</br>finalizers is a shared field, any actor with permission can reorder it.</br>If the finalizer list is processed in order, then this can lead to a situation</br>in which the component responsible for the first finalizer in the list is</br>waiting for a signal (field value, external system, or other) produced by a</br>component responsible for a finalizer later in the list, resulting in a deadlock.</br>Without enforced ordering finalizers are free to order amongst themselves and</br>are not vulnerable to ordering changes in the list.</br>+optional</br>+patchStrategy=merge</br>+listType=set |  |
-| GenerateName | string| `string` |  | | GenerateName is an optional prefix, used by the server, to generate a unique</br>name ONLY IF the Name field has not been provided.</br>If this field is used, the name returned to the client will be different</br>than the name passed. This value will also be combined with a unique suffix.</br>The provided value has the same validation rules as the Name field,</br>and may be truncated by the length of the suffix required to make the value</br>unique on the server.</br></br>If this field is specified and the generated name exists, the server will return a 409.</br></br>Applied only if Name is not specified.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency</br>+optional |  |
-| Generation | int64 (formatted integer)| `int64` |  | | A sequence number representing a specific generation of the desired state.</br>Populated by the system. Read-only.</br>+optional |  |
-| Kind | string| `string` |  | | Kind is a string value representing the REST resource this object represents.</br>Servers may infer this from the endpoint the client submits requests to.</br>Cannot be updated.</br>In CamelCase.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds</br>+optional |  |
-| Labels | map of string| `map[string]string` |  | | Map of string keys and values that can be used to organize and categorize</br>(scope and select) objects. May match selectors of replication controllers</br>and services.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels</br>+optional |  |
-| ManagedFields | [][ManagedFieldsEntry](#managed-fields-entry)| `[]*ManagedFieldsEntry` |  | | ManagedFields maps workflow-id and version to the set of fields</br>that are managed by that workflow. This is mostly for internal</br>housekeeping, and users typically shouldn't need to set or</br>understand this field. A workflow can be the user's name, a</br>controller's name, or the name of a specific apply path like</br>"ci-cd". The set of fields is always in the version that the</br>workflow used when modifying the object.</br></br>+optional</br>+listType=atomic |  |
-| Name | string| `string` |  | | Name must be unique within a namespace. Is required when creating resources, although</br>some resources may allow a client to request the generation of an appropriate name</br>automatically. Name is primarily intended for creation idempotence and configuration</br>definition.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names</br>+optional |  |
-| Namespace | string| `string` |  | | Namespace defines the space within which each name must be unique. An empty namespace is</br>equivalent to the "default" namespace, but "default" is the canonical representation.</br>Not all objects are required to be scoped to a namespace - the value of this field for</br>those objects will be empty.</br></br>Must be a DNS_LABEL.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces</br>+optional |  |
-| OwnerReferences | [][OwnerReference](#owner-reference)| `[]*OwnerReference` |  | | List of objects depended by this object. If ALL objects in the list have</br>been deleted, this object will be garbage collected. If this object is managed by a controller,</br>then an entry in this list will point to this controller, with the controller field set to true.</br>There cannot be more than one managing controller.</br>+optional</br>+patchMergeKey=uid</br>+patchStrategy=merge</br>+listType=map</br>+listMapKey=uid |  |
-| ResourceVersion | string| `string` |  | | An opaque value that represents the internal version of this object that can</br>be used by clients to determine when objects have changed. May be used for optimistic</br>concurrency, change detection, and the watch operation on a resource or set of resources.</br>Clients must treat these values as opaque and passed unmodified back to the server.</br>They may only be valid for a particular resource or set of resources.</br></br>Populated by the system.</br>Read-only.</br>Value must be treated as opaque by clients and .</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency</br>+optional |  |
-| SelfLink | string| `string` |  | | Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.</br>+optional |  |
+| APIVersion | string| `string` |  | | APIVersion defines the versioned schema of this representation of an object.
+Servers should convert recognized schemas to the latest internal value, and
+may reject unrecognized values.
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
++optional |  |
+| Annotations | map of string| `map[string]string` |  | | Annotations is an unstructured key value map stored with a resource that may be
+set by external tools to store and retrieve arbitrary metadata. They are not
+queryable and should be preserved when modifying objects.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations
++optional |  |
+| DeletionGracePeriodSeconds | int64 (formatted integer)| `int64` |  | | Number of seconds allowed for this object to gracefully terminate before
+it will be removed from the system. Only set when deletionTimestamp is also set.
+May only be shortened.
+Read-only.
++optional |  |
+| Finalizers | []string| `[]string` |  | | Must be empty before the object is deleted from the registry. Each entry
+is an identifier for the responsible component that will remove the entry
+from the list. If the deletionTimestamp of the object is non-nil, entries
+in this list can only be removed.
+Finalizers may be processed and removed in any order.  Order is NOT enforced
+because it introduces significant risk of stuck finalizers.
+finalizers is a shared field, any actor with permission can reorder it.
+If the finalizer list is processed in order, then this can lead to a situation
+in which the component responsible for the first finalizer in the list is
+waiting for a signal (field value, external system, or other) produced by a
+component responsible for a finalizer later in the list, resulting in a deadlock.
+Without enforced ordering finalizers are free to order amongst themselves and
+are not vulnerable to ordering changes in the list.
++optional
++patchStrategy=merge
++listType=set |  |
+| GenerateName | string| `string` |  | | GenerateName is an optional prefix, used by the server, to generate a unique
+name ONLY IF the Name field has not been provided.
+If this field is used, the name returned to the client will be different
+than the name passed. This value will also be combined with a unique suffix.
+The provided value has the same validation rules as the Name field,
+and may be truncated by the length of the suffix required to make the value
+unique on the server.
+
+If this field is specified and the generated name exists, the server will return a 409.
+
+Applied only if Name is not specified.
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency
++optional |  |
+| Generation | int64 (formatted integer)| `int64` |  | | A sequence number representing a specific generation of the desired state.
+Populated by the system. Read-only.
++optional |  |
+| Kind | string| `string` |  | | Kind is a string value representing the REST resource this object represents.
+Servers may infer this from the endpoint the client submits requests to.
+Cannot be updated.
+In CamelCase.
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
++optional |  |
+| Labels | map of string| `map[string]string` |  | | Map of string keys and values that can be used to organize and categorize
+(scope and select) objects. May match selectors of replication controllers
+and services.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels
++optional |  |
+| ManagedFields | [][ManagedFieldsEntry](#managed-fields-entry)| `[]*ManagedFieldsEntry` |  | | ManagedFields maps workflow-id and version to the set of fields
+that are managed by that workflow. This is mostly for internal
+housekeeping, and users typically shouldn't need to set or
+understand this field. A workflow can be the user's name, a
+controller's name, or the name of a specific apply path like
+"ci-cd". The set of fields is always in the version that the
+workflow used when modifying the object.
+
++optional
++listType=atomic |  |
+| Name | string| `string` |  | | Name must be unique within a namespace. Is required when creating resources, although
+some resources may allow a client to request the generation of an appropriate name
+automatically. Name is primarily intended for creation idempotence and configuration
+definition.
+Cannot be updated.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names
++optional |  |
+| Namespace | string| `string` |  | | Namespace defines the space within which each name must be unique. An empty namespace is
+equivalent to the "default" namespace, but "default" is the canonical representation.
+Not all objects are required to be scoped to a namespace - the value of this field for
+those objects will be empty.
+
+Must be a DNS_LABEL.
+Cannot be updated.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces
++optional |  |
+| OwnerReferences | [][OwnerReference](#owner-reference)| `[]*OwnerReference` |  | | List of objects depended by this object. If ALL objects in the list have
+been deleted, this object will be garbage collected. If this object is managed by a controller,
+then an entry in this list will point to this controller, with the controller field set to true.
+There cannot be more than one managing controller.
++optional
++patchMergeKey=uid
++patchStrategy=merge
++listType=map
++listMapKey=uid |  |
+| ResourceVersion | string| `string` |  | | An opaque value that represents the internal version of this object that can
+be used by clients to determine when objects have changed. May be used for optimistic
+concurrency, change detection, and the watch operation on a resource or set of resources.
+Clients must treat these values as opaque and passed unmodified back to the server.
+They may only be valid for a particular resource or set of resources.
+
+Populated by the system.
+Read-only.
+Value must be treated as opaque by clients and .
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
++optional |  |
+| SelfLink | string| `string` |  | | Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.
++optional |  |
+| creationTimestamp | [Time](#time)| `Time` |  | |  |  |
+| deletionTimestamp | [Time](#time)| `Time` |  | |  |  |
 | spec | [DestinationRule](#destination-rule)| `DestinationRule` |  | |  |  |
 | status | [IstioStatus](#istio-status)| `IstioStatus` |  | |  |  |
 | uid | [UID](#uid)| `UID` |  | |  |  |
 
 
 
+### <span id="discovery-selector-type"></span> DiscoverySelectorType
+
+
+> we need to play games with a custom unmarshaller/marshaller for metav1.LabelSelector because it has no yaml struct tags so
+it is not processing it the way we want by default (it isn't using camelCase; the fields are lowercase - e.g. matchlabels/matchexpressions)
+  
+
+
+
+
+* composed type [LabelSelector](#label-selector)
+
+### <span id="discovery-selectors-type"></span> DiscoverySelectorsType
+
+
+> we need to play games with a custom unmarshaller/marshaller for metav1.LabelSelector because it has no yaml struct tags so
+it is not processing it the way we want by default (it isn't using camelCase; the fields are lowercase - e.g. matchlabels/matchexpressions)
+  
+
+
+
+[][DiscoverySelectorType](#discovery-selector-type)
+
 ### <span id="duration"></span> Duration
 
 
@@ -7423,8 +7633,8 @@ Populated by the system. Read-only. Null for lists. More info: https://git.k8s.i
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| DestPrincipal | string| `string` |  | | App Fields (not required by Cytoscape) |  |
-| ID | string| `string` |  | | Cytoscape Fields |  |
+| DestPrincipal | string| `string` |  | |  |  |
+| ID | string| `string` |  | |  |  |
 | IsMTLS | string| `string` |  | |  |  |
 | ResponseTime | string| `string` |  | |  |  |
 | Source | string| `string` |  | |  |  |
@@ -7432,6 +7642,7 @@ Populated by the system. Read-only. Null for lists. More info: https://git.k8s.i
 | Target | string| `string` |  | |  |  |
 | Throughput | string| `string` |  | |  |  |
 | traffic | [ProtocolTraffic](#protocol-traffic)| `ProtocolTraffic` |  | |  |  |
+| waypoint | [WaypointEdge](#waypoint-edge)| `WaypointEdge` |  | |  |  |
 
 
 
@@ -7489,75 +7700,41 @@ Populated by the system. Read-only. Null for lists. More info: https://git.k8s.i
 
 [][Endpoint](#endpoint)
 
-### <span id="envoy-filter"></span> EnvoyFilter
-
+### <span id="envoy-proxy-dump"></span> EnvoyProxyDump
 
-> <!-- crd generation tags
-+cue-gen:EnvoyFilter:groupName:networking.istio.io
-+cue-gen:EnvoyFilter:version:v1alpha3
-+cue-gen:EnvoyFilter:storageVersion
-+cue-gen:EnvoyFilter:annotations:helm.sh/resource-policy=keep
-+cue-gen:EnvoyFilter:labels:app=istio-pilot,chart=istio,heritage=Tiller,release=istio
-+cue-gen:EnvoyFilter:subresource:status
-+cue-gen:EnvoyFilter:scope:Namespaced
-+cue-gen:EnvoyFilter:resource:categories=istio-io,networking-istio-io
-+cue-gen:EnvoyFilter:preserveUnknownFields:configPatches.[].patch.value
->
 
-<!-- go code generation tags
-+kubetype-gen
-+kubetype-gen:groupVersion=networking.istio.io/v1alpha3
-+genclient
-+k8s:deepcopy-gen=true
->
   
 
 
 
-
-
 **Properties**
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| APIVersion | string| `string` |  | | APIVersion defines the versioned schema of this representation of an object.</br>Servers should convert recognized schemas to the latest internal value, and</br>may reject unrecognized values.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources</br>+optional |  |
-| Annotations | map of string| `map[string]string` |  | | Annotations is an unstructured key value map stored with a resource that may be</br>set by external tools to store and retrieve arbitrary metadata. They are not</br>queryable and should be preserved when modifying objects.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations</br>+optional |  |
-| CreationTimestamp | string| `string` |  | | CreationTimestamp is a timestamp representing the server time when this object was</br>created. It is not guaranteed to be set in happens-before order across separate operations.</br>Clients may not set this value. It is represented in RFC3339 form and is in UTC.</br></br>Populated by the system.</br>Read-only.</br>Null for lists.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| DeletionGracePeriodSeconds | int64 (formatted integer)| `int64` |  | | Number of seconds allowed for this object to gracefully terminate before</br>it will be removed from the system. Only set when deletionTimestamp is also set.</br>May only be shortened.</br>Read-only.</br>+optional |  |
-| DeletionTimestamp | string| `string` |  | | DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This</br>field is set by the server when a graceful deletion is requested by the user, and is not</br>directly settable by a client. The resource is expected to be deleted (no longer visible</br>from resource lists, and not reachable by name) after the time in this field, once the</br>finalizers list is empty. As long as the finalizers list contains items, deletion is blocked.</br>Once the deletionTimestamp is set, this value may not be unset or be set further into the</br>future, although it may be shortened or the resource may be deleted prior to this time.</br>For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react</br>by sending a graceful termination signal to the containers in the pod. After that 30 seconds,</br>the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,</br>remove the pod from the API. In the presence of network partitions, this object may still</br>exist after this timestamp, until an administrator or automated process can determine the</br>resource is fully terminated.</br>If not set, graceful deletion of the object has not been requested.</br></br>Populated by the system when a graceful deletion is requested.</br>Read-only.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| Finalizers | []string| `[]string` |  | | Must be empty before the object is deleted from the registry. Each entry</br>is an identifier for the responsible component that will remove the entry</br>from the list. If the deletionTimestamp of the object is non-nil, entries</br>in this list can only be removed.</br>Finalizers may be processed and removed in any order.  Order is NOT enforced</br>because it introduces significant risk of stuck finalizers.</br>finalizers is a shared field, any actor with permission can reorder it.</br>If the finalizer list is processed in order, then this can lead to a situation</br>in which the component responsible for the first finalizer in the list is</br>waiting for a signal (field value, external system, or other) produced by a</br>component responsible for a finalizer later in the list, resulting in a deadlock.</br>Without enforced ordering finalizers are free to order amongst themselves and</br>are not vulnerable to ordering changes in the list.</br>+optional</br>+patchStrategy=merge</br>+listType=set |  |
-| GenerateName | string| `string` |  | | GenerateName is an optional prefix, used by the server, to generate a unique</br>name ONLY IF the Name field has not been provided.</br>If this field is used, the name returned to the client will be different</br>than the name passed. This value will also be combined with a unique suffix.</br>The provided value has the same validation rules as the Name field,</br>and may be truncated by the length of the suffix required to make the value</br>unique on the server.</br></br>If this field is specified and the generated name exists, the server will return a 409.</br></br>Applied only if Name is not specified.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency</br>+optional |  |
-| Generation | int64 (formatted integer)| `int64` |  | | A sequence number representing a specific generation of the desired state.</br>Populated by the system. Read-only.</br>+optional |  |
-| Kind | string| `string` |  | | Kind is a string value representing the REST resource this object represents.</br>Servers may infer this from the endpoint the client submits requests to.</br>Cannot be updated.</br>In CamelCase.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds</br>+optional |  |
-| Labels | map of string| `map[string]string` |  | | Map of string keys and values that can be used to organize and categorize</br>(scope and select) objects. May match selectors of replication controllers</br>and services.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels</br>+optional |  |
-| ManagedFields | [][ManagedFieldsEntry](#managed-fields-entry)| `[]*ManagedFieldsEntry` |  | | ManagedFields maps workflow-id and version to the set of fields</br>that are managed by that workflow. This is mostly for internal</br>housekeeping, and users typically shouldn't need to set or</br>understand this field. A workflow can be the user's name, a</br>controller's name, or the name of a specific apply path like</br>"ci-cd". The set of fields is always in the version that the</br>workflow used when modifying the object.</br></br>+optional</br>+listType=atomic |  |
-| Name | string| `string` |  | | Name must be unique within a namespace. Is required when creating resources, although</br>some resources may allow a client to request the generation of an appropriate name</br>automatically. Name is primarily intended for creation idempotence and configuration</br>definition.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names</br>+optional |  |
-| Namespace | string| `string` |  | | Namespace defines the space within which each name must be unique. An empty namespace is</br>equivalent to the "default" namespace, but "default" is the canonical representation.</br>Not all objects are required to be scoped to a namespace - the value of this field for</br>those objects will be empty.</br></br>Must be a DNS_LABEL.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces</br>+optional |  |
-| OwnerReferences | [][OwnerReference](#owner-reference)| `[]*OwnerReference` |  | | List of objects depended by this object. If ALL objects in the list have</br>been deleted, this object will be garbage collected. If this object is managed by a controller,</br>then an entry in this list will point to this controller, with the controller field set to true.</br>There cannot be more than one managing controller.</br>+optional</br>+patchMergeKey=uid</br>+patchStrategy=merge</br>+listType=map</br>+listMapKey=uid |  |
-| ResourceVersion | string| `string` |  | | An opaque value that represents the internal version of this object that can</br>be used by clients to determine when objects have changed. May be used for optimistic</br>concurrency, change detection, and the watch operation on a resource or set of resources.</br>Clients must treat these values as opaque and passed unmodified back to the server.</br>They may only be valid for a particular resource or set of resources.</br></br>Populated by the system.</br>Read-only.</br>Value must be treated as opaque by clients and .</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency</br>+optional |  |
-| SelfLink | string| `string` |  | | Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.</br>+optional |  |
-| spec | [EnvoyFilter](#envoy-filter)| `EnvoyFilter` |  | |  |  |
-| status | [IstioStatus](#istio-status)| `IstioStatus` |  | |  |  |
-| uid | [UID](#uid)| `UID` |  | |  |  |
+| bootstrap | [Bootstrap](#bootstrap)| `Bootstrap` |  | |  |  |
+| clusters | [Clusters](#clusters)| `Clusters` |  | |  |  |
+| config_dump | [ConfigDump](#config-dump)| `ConfigDump` |  | |  |  |
+| listeners | [Listeners](#listeners)| `Listeners` |  | |  |  |
+| routes | [Routes](#routes)| `Routes` |  | |  |  |
 
 
 
-### <span id="envoy-proxy-dump"></span> EnvoyProxyDump
+### <span id="ext-info"></span> ExtInfo
 
 
+> ExtInfo contains client-side info about the extension
   
 
 
 
+
+
 **Properties**
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| bootstrap | [Bootstrap](#bootstrap)| `Bootstrap` |  | |  |  |
-| clusters | [Clusters](#clusters)| `Clusters` |  | |  |  |
-| config_dump | [ConfigDump](#config-dump)| `ConfigDump` |  | |  |  |
-| listeners | [Listeners](#listeners)| `Listeners` |  | |  |  |
-| routes | [Routes](#routes)| `Routes` |  | |  |  |
+| Name | string| `string` |  | |  |  |
+| URL | string| `string` |  | | URL is an optional URL that links to the extension's own external UI |  |
 
 
 
@@ -7622,6 +7799,24 @@ The exact format is defined in sigs.k8s.io/structured-merge-diff
 
 [interface{}](#interface)
 
+### <span id="fraction"></span> Fraction
+
+
+  
+
+
+
+**Properties**
+
+| Name | Type | Go type | Required | Default | Description | Example |
+|------|------|---------|:--------:| ------- |-------------|---------|
+| Denominator | int32 (formatted integer)| `int32` |  | | +optional
++kubebuilder:default=100
++kubebuilder:validation:Minimum=1 |  |
+| Numerator | int32 (formatted integer)| `int32` |  | | +kubebuilder:validation:Minimum=0 |  |
+
+
+
 ### <span id="g-rpc-backend-ref"></span> GRPCBackendRef
 
 
@@ -7657,8 +7852,34 @@ protocol then the backend is considered invalid. Implementations MUST set the
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Filters | [][GRPCRouteFilter](#g-rpc-route-filter)| `[]*GRPCRouteFilter` |  | | Filters defined at this level MUST be executed if and only if the</br>request is being forwarded to the backend defined here.</br></br>Support: Implementation-specific (For broader support of filters, use the</br>Filters field in GRPCRouteRule.)</br></br>+optional</br>+kubebuilder:validation:MaxItems=16</br>+kubebuilder:validation:XValidation:message="RequestHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'RequestHeaderModifier').size() <= 1"</br>+kubebuilder:validation:XValidation:message="ResponseHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'ResponseHeaderModifier').size() <= 1" |  |
-| Weight | int32 (formatted integer)| `int32` |  | | Weight specifies the proportion of requests forwarded to the referenced</br>backend. This is computed as weight/(sum of all weights in this</br>BackendRefs list). For non-zero values, there may be some epsilon from</br>the exact proportion defined here depending on the precision an</br>implementation supports. Weight is not a percentage and the sum of</br>weights does not need to equal 100.</br></br>If only one backend is specified and it has a weight greater than 0, 100%</br>of the traffic is forwarded to that backend. If weight is set to 0, no</br>traffic should be forwarded for this entry. If unspecified, weight</br>defaults to 1.</br></br>Support for this field varies based on the context where used.</br></br>+optional</br>+kubebuilder:default=1</br>+kubebuilder:validation:Minimum=0</br>+kubebuilder:validation:Maximum=1000000 |  |
+| Filters | [][GRPCRouteFilter](#g-rpc-route-filter)| `[]*GRPCRouteFilter` |  | | Filters defined at this level MUST be executed if and only if the
+request is being forwarded to the backend defined here.
+
+Support: Implementation-specific (For broader support of filters, use the
+Filters field in GRPCRouteRule.)
+
++optional
++kubebuilder:validation:MaxItems=16
++kubebuilder:validation:XValidation:message="RequestHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'RequestHeaderModifier').size() <= 1"
++kubebuilder:validation:XValidation:message="ResponseHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'ResponseHeaderModifier').size() <= 1" |  |
+| Weight | int32 (formatted integer)| `int32` |  | | Weight specifies the proportion of requests forwarded to the referenced
+backend. This is computed as weight/(sum of all weights in this
+BackendRefs list). For non-zero values, there may be some epsilon from
+the exact proportion defined here depending on the precision an
+implementation supports. Weight is not a percentage and the sum of
+weights does not need to equal 100.
+
+If only one backend is specified and it has a weight greater than 0, 100%
+of the traffic is forwarded to that backend. If weight is set to 0, no
+traffic should be forwarded for this entry. If unspecified, weight
+defaults to 1.
+
+Support for this field varies based on the context where used.
+
++optional
++kubebuilder:default=1
++kubebuilder:validation:Minimum=0
++kubebuilder:validation:Maximum=1000000 |  |
 | group | [Group](#group)| `Group` |  | |  |  |
 | kind | [Kind](#kind)| `Kind` |  | |  |  |
 | name | [ObjectName](#object-name)| `ObjectName` |  | |  |  |
@@ -7682,9 +7903,46 @@ headers.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Value | string| `string` |  | | Value is the value of the gRPC Header to be matched.</br></br>+kubebuilder:validation:MinLength=1</br>+kubebuilder:validation:MaxLength=4096 |  |
+| Value | string| `string` |  | | Value is the value of the gRPC Header to be matched.
+
++kubebuilder:validation:MinLength=1
++kubebuilder:validation:MaxLength=4096 |  |
 | name | [GRPCHeaderName](#g-rpc-header-name)| `GRPCHeaderName` |  | |  |  |
-| type | [HeaderMatchType](#header-match-type)| `HeaderMatchType` |  | |  |  |
+| type | [GRPCHeaderMatchType](#g-rpc-header-match-type)| `GRPCHeaderMatchType` |  | |  |  |
+
+
+
+### <span id="g-rpc-header-match-type"></span> GRPCHeaderMatchType
+
+
+> "Exact" - Core
+"RegularExpression" - Implementation Specific
+
+Note that new values may be added to this enum in future releases of the API,
+implementations MUST ensure that unknown values will not cause a crash.
+
+Unknown values here MUST result in the implementation setting the Accepted
+Condition for the Route to `status: False`, with a Reason of
+`UnsupportedValue`.
+
++kubebuilder:validation:Enum=Exact;RegularExpression
+  
+
+
+
+| Name | Type | Go type | Default | Description | Example |
+|------|------|---------| ------- |-------------|---------|
+| GRPCHeaderMatchType | string| string | | "Exact" - Core
+"RegularExpression" - Implementation Specific
+
+Note that new values may be added to this enum in future releases of the API,
+implementations MUST ensure that unknown values will not cause a crash.
+
+Unknown values here MUST result in the implementation setting the Accepted
+Condition for the Route to `status: False`, with a Reason of
+`UnsupportedValue`.
+
++kubebuilder:validation:Enum=Exact;RegularExpression |  |
 
 
 
@@ -7715,8 +7973,20 @@ headers.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Method | string| `string` |  | | Value of the method to match against. If left empty or omitted, will</br>match all services.</br></br>At least one of Service and Method MUST be a non-empty string.</br></br>+optional</br>+kubebuilder:validation:MaxLength=1024 |  |
-| Service | string| `string` |  | | Value of the service to match against. If left empty or omitted, will</br>match any service.</br></br>At least one of Service and Method MUST be a non-empty string.</br></br>+optional</br>+kubebuilder:validation:MaxLength=1024 |  |
+| Method | string| `string` |  | | Value of the method to match against. If left empty or omitted, will
+match all services.
+
+At least one of Service and Method MUST be a non-empty string.
+
++optional
++kubebuilder:validation:MaxLength=1024 |  |
+| Service | string| `string` |  | | Value of the service to match against. If left empty or omitted, will
+match any service.
+
+At least one of Service and Method MUST be a non-empty string.
+
++optional
++kubebuilder:validation:MaxLength=1024 |  |
 | type | [GRPCMethodMatchType](#g-rpc-method-match-type)| `GRPCMethodMatchType` |  | |  |  |
 
 
@@ -7738,7 +8008,14 @@ Must not contain `/` character
 
 | Name | Type | Go type | Default | Description | Example |
 |------|------|---------| ------- |-------------|---------|
-| GRPCMethodMatchType | string| string | | "Exact" - Core</br>"RegularExpression" - Implementation Specific</br></br>Exact methods MUST be syntactically valid:</br></br>Must not contain `/` character</br></br>+kubebuilder:validation:Enum=Exact;RegularExpression |  |
+| GRPCMethodMatchType | string| string | | "Exact" - Core
+"RegularExpression" - Implementation Specific
+
+Exact methods MUST be syntactically valid:
+
+Must not contain `/` character
+
++kubebuilder:validation:Enum=Exact;RegularExpression |  |
 
 
 
@@ -7777,22 +8054,114 @@ HTTP/1, i.e. without prior knowledge.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| APIVersion | string| `string` |  | | APIVersion defines the versioned schema of this representation of an object.</br>Servers should convert recognized schemas to the latest internal value, and</br>may reject unrecognized values.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources</br>+optional |  |
-| Annotations | map of string| `map[string]string` |  | | Annotations is an unstructured key value map stored with a resource that may be</br>set by external tools to store and retrieve arbitrary metadata. They are not</br>queryable and should be preserved when modifying objects.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations</br>+optional |  |
-| CreationTimestamp | string| `string` |  | | CreationTimestamp is a timestamp representing the server time when this object was</br>created. It is not guaranteed to be set in happens-before order across separate operations.</br>Clients may not set this value. It is represented in RFC3339 form and is in UTC.</br></br>Populated by the system.</br>Read-only.</br>Null for lists.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| DeletionGracePeriodSeconds | int64 (formatted integer)| `int64` |  | | Number of seconds allowed for this object to gracefully terminate before</br>it will be removed from the system. Only set when deletionTimestamp is also set.</br>May only be shortened.</br>Read-only.</br>+optional |  |
-| DeletionTimestamp | string| `string` |  | | DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This</br>field is set by the server when a graceful deletion is requested by the user, and is not</br>directly settable by a client. The resource is expected to be deleted (no longer visible</br>from resource lists, and not reachable by name) after the time in this field, once the</br>finalizers list is empty. As long as the finalizers list contains items, deletion is blocked.</br>Once the deletionTimestamp is set, this value may not be unset or be set further into the</br>future, although it may be shortened or the resource may be deleted prior to this time.</br>For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react</br>by sending a graceful termination signal to the containers in the pod. After that 30 seconds,</br>the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,</br>remove the pod from the API. In the presence of network partitions, this object may still</br>exist after this timestamp, until an administrator or automated process can determine the</br>resource is fully terminated.</br>If not set, graceful deletion of the object has not been requested.</br></br>Populated by the system when a graceful deletion is requested.</br>Read-only.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| Finalizers | []string| `[]string` |  | | Must be empty before the object is deleted from the registry. Each entry</br>is an identifier for the responsible component that will remove the entry</br>from the list. If the deletionTimestamp of the object is non-nil, entries</br>in this list can only be removed.</br>Finalizers may be processed and removed in any order.  Order is NOT enforced</br>because it introduces significant risk of stuck finalizers.</br>finalizers is a shared field, any actor with permission can reorder it.</br>If the finalizer list is processed in order, then this can lead to a situation</br>in which the component responsible for the first finalizer in the list is</br>waiting for a signal (field value, external system, or other) produced by a</br>component responsible for a finalizer later in the list, resulting in a deadlock.</br>Without enforced ordering finalizers are free to order amongst themselves and</br>are not vulnerable to ordering changes in the list.</br>+optional</br>+patchStrategy=merge</br>+listType=set |  |
-| GenerateName | string| `string` |  | | GenerateName is an optional prefix, used by the server, to generate a unique</br>name ONLY IF the Name field has not been provided.</br>If this field is used, the name returned to the client will be different</br>than the name passed. This value will also be combined with a unique suffix.</br>The provided value has the same validation rules as the Name field,</br>and may be truncated by the length of the suffix required to make the value</br>unique on the server.</br></br>If this field is specified and the generated name exists, the server will return a 409.</br></br>Applied only if Name is not specified.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency</br>+optional |  |
-| Generation | int64 (formatted integer)| `int64` |  | | A sequence number representing a specific generation of the desired state.</br>Populated by the system. Read-only.</br>+optional |  |
-| Kind | string| `string` |  | | Kind is a string value representing the REST resource this object represents.</br>Servers may infer this from the endpoint the client submits requests to.</br>Cannot be updated.</br>In CamelCase.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds</br>+optional |  |
-| Labels | map of string| `map[string]string` |  | | Map of string keys and values that can be used to organize and categorize</br>(scope and select) objects. May match selectors of replication controllers</br>and services.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels</br>+optional |  |
-| ManagedFields | [][ManagedFieldsEntry](#managed-fields-entry)| `[]*ManagedFieldsEntry` |  | | ManagedFields maps workflow-id and version to the set of fields</br>that are managed by that workflow. This is mostly for internal</br>housekeeping, and users typically shouldn't need to set or</br>understand this field. A workflow can be the user's name, a</br>controller's name, or the name of a specific apply path like</br>"ci-cd". The set of fields is always in the version that the</br>workflow used when modifying the object.</br></br>+optional</br>+listType=atomic |  |
-| Name | string| `string` |  | | Name must be unique within a namespace. Is required when creating resources, although</br>some resources may allow a client to request the generation of an appropriate name</br>automatically. Name is primarily intended for creation idempotence and configuration</br>definition.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names</br>+optional |  |
-| Namespace | string| `string` |  | | Namespace defines the space within which each name must be unique. An empty namespace is</br>equivalent to the "default" namespace, but "default" is the canonical representation.</br>Not all objects are required to be scoped to a namespace - the value of this field for</br>those objects will be empty.</br></br>Must be a DNS_LABEL.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces</br>+optional |  |
-| OwnerReferences | [][OwnerReference](#owner-reference)| `[]*OwnerReference` |  | | List of objects depended by this object. If ALL objects in the list have</br>been deleted, this object will be garbage collected. If this object is managed by a controller,</br>then an entry in this list will point to this controller, with the controller field set to true.</br>There cannot be more than one managing controller.</br>+optional</br>+patchMergeKey=uid</br>+patchStrategy=merge</br>+listType=map</br>+listMapKey=uid |  |
-| ResourceVersion | string| `string` |  | | An opaque value that represents the internal version of this object that can</br>be used by clients to determine when objects have changed. May be used for optimistic</br>concurrency, change detection, and the watch operation on a resource or set of resources.</br>Clients must treat these values as opaque and passed unmodified back to the server.</br>They may only be valid for a particular resource or set of resources.</br></br>Populated by the system.</br>Read-only.</br>Value must be treated as opaque by clients and .</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency</br>+optional |  |
-| SelfLink | string| `string` |  | | Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.</br>+optional |  |
+| APIVersion | string| `string` |  | | APIVersion defines the versioned schema of this representation of an object.
+Servers should convert recognized schemas to the latest internal value, and
+may reject unrecognized values.
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
++optional |  |
+| Annotations | map of string| `map[string]string` |  | | Annotations is an unstructured key value map stored with a resource that may be
+set by external tools to store and retrieve arbitrary metadata. They are not
+queryable and should be preserved when modifying objects.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations
++optional |  |
+| DeletionGracePeriodSeconds | int64 (formatted integer)| `int64` |  | | Number of seconds allowed for this object to gracefully terminate before
+it will be removed from the system. Only set when deletionTimestamp is also set.
+May only be shortened.
+Read-only.
++optional |  |
+| Finalizers | []string| `[]string` |  | | Must be empty before the object is deleted from the registry. Each entry
+is an identifier for the responsible component that will remove the entry
+from the list. If the deletionTimestamp of the object is non-nil, entries
+in this list can only be removed.
+Finalizers may be processed and removed in any order.  Order is NOT enforced
+because it introduces significant risk of stuck finalizers.
+finalizers is a shared field, any actor with permission can reorder it.
+If the finalizer list is processed in order, then this can lead to a situation
+in which the component responsible for the first finalizer in the list is
+waiting for a signal (field value, external system, or other) produced by a
+component responsible for a finalizer later in the list, resulting in a deadlock.
+Without enforced ordering finalizers are free to order amongst themselves and
+are not vulnerable to ordering changes in the list.
++optional
++patchStrategy=merge
++listType=set |  |
+| GenerateName | string| `string` |  | | GenerateName is an optional prefix, used by the server, to generate a unique
+name ONLY IF the Name field has not been provided.
+If this field is used, the name returned to the client will be different
+than the name passed. This value will also be combined with a unique suffix.
+The provided value has the same validation rules as the Name field,
+and may be truncated by the length of the suffix required to make the value
+unique on the server.
+
+If this field is specified and the generated name exists, the server will return a 409.
+
+Applied only if Name is not specified.
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency
++optional |  |
+| Generation | int64 (formatted integer)| `int64` |  | | A sequence number representing a specific generation of the desired state.
+Populated by the system. Read-only.
++optional |  |
+| Kind | string| `string` |  | | Kind is a string value representing the REST resource this object represents.
+Servers may infer this from the endpoint the client submits requests to.
+Cannot be updated.
+In CamelCase.
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
++optional |  |
+| Labels | map of string| `map[string]string` |  | | Map of string keys and values that can be used to organize and categorize
+(scope and select) objects. May match selectors of replication controllers
+and services.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels
++optional |  |
+| ManagedFields | [][ManagedFieldsEntry](#managed-fields-entry)| `[]*ManagedFieldsEntry` |  | | ManagedFields maps workflow-id and version to the set of fields
+that are managed by that workflow. This is mostly for internal
+housekeeping, and users typically shouldn't need to set or
+understand this field. A workflow can be the user's name, a
+controller's name, or the name of a specific apply path like
+"ci-cd". The set of fields is always in the version that the
+workflow used when modifying the object.
+
++optional
++listType=atomic |  |
+| Name | string| `string` |  | | Name must be unique within a namespace. Is required when creating resources, although
+some resources may allow a client to request the generation of an appropriate name
+automatically. Name is primarily intended for creation idempotence and configuration
+definition.
+Cannot be updated.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names
++optional |  |
+| Namespace | string| `string` |  | | Namespace defines the space within which each name must be unique. An empty namespace is
+equivalent to the "default" namespace, but "default" is the canonical representation.
+Not all objects are required to be scoped to a namespace - the value of this field for
+those objects will be empty.
+
+Must be a DNS_LABEL.
+Cannot be updated.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces
++optional |  |
+| OwnerReferences | [][OwnerReference](#owner-reference)| `[]*OwnerReference` |  | | List of objects depended by this object. If ALL objects in the list have
+been deleted, this object will be garbage collected. If this object is managed by a controller,
+then an entry in this list will point to this controller, with the controller field set to true.
+There cannot be more than one managing controller.
++optional
++patchMergeKey=uid
++patchStrategy=merge
++listType=map
++listMapKey=uid |  |
+| ResourceVersion | string| `string` |  | | An opaque value that represents the internal version of this object that can
+be used by clients to determine when objects have changed. May be used for optimistic
+concurrency, change detection, and the watch operation on a resource or set of resources.
+Clients must treat these values as opaque and passed unmodified back to the server.
+They may only be valid for a particular resource or set of resources.
+
+Populated by the system.
+Read-only.
+Value must be treated as opaque by clients and .
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
++optional |  |
+| SelfLink | string| `string` |  | | Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.
++optional |  |
+| creationTimestamp | [Time](#time)| `Time` |  | |  |  |
+| deletionTimestamp | [Time](#time)| `Time` |  | |  |  |
 | spec | [GRPCRouteSpec](#g-rpc-route-spec)| `GRPCRouteSpec` |  | |  |  |
 | status | [GRPCRouteStatus](#g-rpc-route-status)| `GRPCRouteStatus` |  | |  |  |
 | uid | [UID](#uid)| `UID` |  | |  |  |
@@ -7865,7 +8234,14 @@ value "v1"
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Headers | [][GRPCHeaderMatch](#g-rpc-header-match)| `[]*GRPCHeaderMatch` |  | | Headers specifies gRPC request header matchers. Multiple match values are</br>ANDed together, meaning, a request MUST match all the specified headers</br>to select the route.</br></br>+listType=map</br>+listMapKey=name</br>+optional</br>+kubebuilder:validation:MaxItems=16 |  |
+| Headers | [][GRPCHeaderMatch](#g-rpc-header-match)| `[]*GRPCHeaderMatch` |  | | Headers specifies gRPC request header matchers. Multiple match values are
+ANDed together, meaning, a request MUST match all the specified headers
+to select the route.
+
++listType=map
++listMapKey=name
++optional
++kubebuilder:validation:MaxItems=16 |  |
 | method | [GRPCMethodMatch](#g-rpc-method-match)| `GRPCMethodMatch` |  | |  |  |
 
 
@@ -7886,52 +8262,127 @@ an API object (backendRefs).
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| BackendRefs | [][GRPCBackendRef](#g-rpc-backend-ref)| `[]*GRPCBackendRef` |  | | BackendRefs defines the backend(s) where matching requests should be</br>sent.</br></br>Failure behavior here depends on how many BackendRefs are specified and</br>how many are invalid.</br></br>If *all* entries in BackendRefs are invalid, and there are also no filters</br>specified in this route rule, *all* traffic which matches this rule MUST</br>receive an `UNAVAILABLE` status.</br></br>See the GRPCBackendRef definition for the rules about what makes a single</br>GRPCBackendRef invalid.</br></br>When a GRPCBackendRef is invalid, `UNAVAILABLE` statuses MUST be returned for</br>requests that would have otherwise been routed to an invalid backend. If</br>multiple backends are specified, and some are invalid, the proportion of</br>requests that would otherwise have been routed to an invalid backend</br>MUST receive an `UNAVAILABLE` status.</br></br>For example, if two backends are specified with equal weights, and one is</br>invalid, 50 percent of traffic MUST receive an `UNAVAILABLE` status.</br>Implementations may choose how that 50 percent is determined.</br></br>Support: Core for Kubernetes Service</br></br>Support: Implementation-specific for any other resource</br></br>Support for weight: Core</br></br>+optional</br>+kubebuilder:validation:MaxItems=16 |  |
-| Filters | [][GRPCRouteFilter](#g-rpc-route-filter)| `[]*GRPCRouteFilter` |  | | Filters define the filters that are applied to requests that match</br>this rule.</br></br>The effects of ordering of multiple behaviors are currently unspecified.</br>This can change in the future based on feedback during the alpha stage.</br></br>Conformance-levels at this level are defined based on the type of filter:</br></br>ALL core filters MUST be supported by all implementations that support</br>GRPCRoute.</br>Implementers are encouraged to support extended filters.</br>Implementation-specific custom filters have no API guarantees across</br>implementations.</br></br>Specifying the same filter multiple times is not supported unless explicitly</br>indicated in the filter.</br></br>If an implementation can not support a combination of filters, it must clearly</br>document that limitation. In cases where incompatible or unsupported</br>filters are specified and cause the `Accepted` condition to be set to status</br>`False`, implementations may use the `IncompatibleFilters` reason to specify</br>this configuration error.</br></br>Support: Core</br></br>+optional</br>+kubebuilder:validation:MaxItems=16</br>+kubebuilder:validation:XValidation:message="RequestHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'RequestHeaderModifier').size() <= 1"</br>+kubebuilder:validation:XValidation:message="ResponseHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'ResponseHeaderModifier').size() <= 1" |  |
-| Matches | [][GRPCRouteMatch](#g-rpc-route-match)| `[]*GRPCRouteMatch` |  | | Matches define conditions used for matching the rule against incoming</br>gRPC requests. Each match is independent, i.e. this rule will be matched</br>if **any** one of the matches is satisfied.</br></br>For example, take the following matches configuration:</br></br>```</br>matches:</br>method:</br>service: foo.bar</br>headers:</br>values:</br>version: 2</br>method:</br>service: foo.bar.v2</br>```</br></br>For a request to match against this rule, it MUST satisfy</br>EITHER of the two conditions:</br></br>service of foo.bar AND contains the header `version: 2`</br>service of foo.bar.v2</br></br>See the documentation for GRPCRouteMatch on how to specify multiple</br>match conditions to be ANDed together.</br></br>If no matches are specified, the implementation MUST match every gRPC request.</br></br>Proxy or Load Balancer routing configuration generated from GRPCRoutes</br>MUST prioritize rules based on the following criteria, continuing on</br>ties. Merging MUST not be done between GRPCRoutes and HTTPRoutes.</br>Precedence MUST be given to the rule with the largest number of:</br></br>Characters in a matching non-wildcard hostname.</br>Characters in a matching hostname.</br>Characters in a matching service.</br>Characters in a matching method.</br>Header matches.</br></br>If ties still exist across multiple Routes, matching precedence MUST be</br>determined in order of the following criteria, continuing on ties:</br></br>The oldest Route based on creation timestamp.</br>The Route appearing first in alphabetical order by</br>"{namespace}/{name}".</br></br>If ties still exist within the Route that has been given precedence,</br>matching precedence MUST be granted to the first matching rule meeting</br>the above criteria.</br></br>+optional</br>+kubebuilder:validation:MaxItems=8 |  |
-| sessionPersistence | [SessionPersistence](#session-persistence)| `SessionPersistence` |  | |  |  |
+| BackendRefs | [][GRPCBackendRef](#g-rpc-backend-ref)| `[]*GRPCBackendRef` |  | | BackendRefs defines the backend(s) where matching requests should be
+sent.
 
+Failure behavior here depends on how many BackendRefs are specified and
+how many are invalid.
 
+If *all* entries in BackendRefs are invalid, and there are also no filters
+specified in this route rule, *all* traffic which matches this rule MUST
+receive an `UNAVAILABLE` status.
 
-### <span id="g-rpc-route-spec"></span> GRPCRouteSpec
+See the GRPCBackendRef definition for the rules about what makes a single
+GRPCBackendRef invalid.
 
+When a GRPCBackendRef is invalid, `UNAVAILABLE` statuses MUST be returned for
+requests that would have otherwise been routed to an invalid backend. If
+multiple backends are specified, and some are invalid, the proportion of
+requests that would otherwise have been routed to an invalid backend
+MUST receive an `UNAVAILABLE` status.
 
-> GRPCRouteSpec defines the desired state of GRPCRoute
-  
+For example, if two backends are specified with equal weights, and one is
+invalid, 50 percent of traffic MUST receive an `UNAVAILABLE` status.
+Implementations may choose how that 50 percent is determined.
 
+Support: Core for Kubernetes Service
 
+Support: Implementation-specific for any other resource
 
+Support for weight: Core
 
++optional
++kubebuilder:validation:MaxItems=16 |  |
+| Filters | [][GRPCRouteFilter](#g-rpc-route-filter)| `[]*GRPCRouteFilter` |  | | Filters define the filters that are applied to requests that match
+this rule.
 
-**Properties**
+The effects of ordering of multiple behaviors are currently unspecified.
+This can change in the future based on feedback during the alpha stage.
 
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| Hostnames | [][Hostname](#hostname)| `[]Hostname` |  | | Hostnames defines a set of hostnames to match against the GRPC</br>Host header to select a GRPCRoute to process the request. This matches</br>the RFC 1123 definition of a hostname with 2 notable exceptions:</br></br>1. IPs are not allowed.</br>2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard</br>label MUST appear by itself as the first label.</br></br>If a hostname is specified by both the Listener and GRPCRoute, there</br>MUST be at least one intersecting hostname for the GRPCRoute to be |  |
-| ParentRefs | [][ParentReference](#parent-reference)| `[]*ParentReference` |  | | ParentRefs references the resources (usually Gateways) that a Route wants</br>to be attached to. Note that the referenced parent resource needs to</br>allow this for the attachment to be complete. For Gateways, that means</br>the Gateway needs to allow attachment from Routes of this kind and</br>namespace. For Services, that means the Service must either be in the same</br>namespace for a "producer" route, or the mesh implementation must support</br>and allow "consumer" routes for the referenced Service. ReferenceGrant is</br>not applicable for governing ParentRefs to Services - it is not possible to</br>create a "producer" route for a Service in a different namespace from the</br>Route.</br></br>There are two kinds of parent resources with "Core" support:</br></br>Gateway (Gateway conformance profile)</br>Service (Mesh conformance profile, ClusterIP Services only)</br></br>This API may be extended in the future to support additional kinds of parent</br>resources.</br></br>ParentRefs must be _distinct_. This means either that:</br></br>They select different objects.  If this is the case, then parentRef</br>entries are distinct. In terms of fields, this means that the</br>multi-part key defined by `group`, `kind`, `namespace`, and `name` must</br>be unique across all parentRef entries in the Route.</br>They do not select different objects, but for each optional field used,</br>each ParentRef that selects the same object must set the same set of</br>optional fields to different values. If one ParentRef sets a</br>combination of optional fields, all must set the same combination.</br></br>Some examples:</br></br>If one ParentRef sets `sectionName`, all ParentRefs referencing the</br>same object must also set `sectionName`.</br>If one ParentRef sets `port`, all ParentRefs referencing the same</br>object must also set `port`.</br>If one ParentRef sets `sectionName` and `port`, all ParentRefs</br>referencing the same object must also set `sectionName` and `port`.</br></br>It is possible to separately reference multiple distinct objects that may</br>be collapsed by an implementation. For example, some implementations may</br>choose to merge compatible Gateway Listeners together. If that is the</br>case, the list of routes attached to those resources should also be</br>merged.</br></br>Note that for ParentRefs that cross namespace boundaries, there are specific</br>rules. Cross-namespace references are only valid if they are explicitly</br>allowed by something in the namespace they are referring to. For example,</br>Gateway has the AllowedRoutes field, and ReferenceGrant provides a</br>generic way to enable other kinds of cross-namespace reference.</br></br><gateway:experimental:description></br>ParentRefs from a Route to a Service in the same namespace are "producer"</br>routes, which apply default routing rules to inbound connections from</br>any namespace to the Service.</br></br>ParentRefs from a Route to a Service in a different namespace are</br>"consumer" routes, and these routing rules are only applied to outbound</br>connections originating from the same namespace as the Route, for which</br>the intended destination of the connections are a Service targeted as a</br>ParentRef of the Route.</br></gateway:experimental:description></br></br>+optional</br>+kubebuilder:validation:MaxItems=32</br><gateway:standard:validation:XValidation:message="sectionName must be specified when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.all(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__ )) ? ((!has(p1.sectionName) || p1.sectionName == '') == (!has(p2.sectionName) || p2.sectionName == '')) : true))"></br><gateway:standard:validation:XValidation:message="sectionName must be unique when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName == '')) || (has(p1.sectionName) && has(p2.sectionName) && p1.sectionName == p2.sectionName))))"></br><gateway:experimental:validation:XValidation:message="sectionName or port must be specified when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.all(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__)) ? ((!has(p1.sectionName) || p1.sectionName == '') == (!has(p2.sectionName) || p2.sectionName == '') && (!has(p1.port) || p1.port == 0) == (!has(p2.port) || p2.port == 0)): true))"></br><gateway:experimental:validation:XValidation:message="sectionName or port must be unique when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName == '')) || ( has(p1.sectionName) && has(p2.sectionName) && p1.sectionName == p2.sectionName)) && (((!has(p1.port) || p1.port == 0) && (!has(p2.port) || p2.port == 0)) || (has(p1.port) && has(p2.port) && p1.port == p2.port))))"> |  |
-| Rules | [][GRPCRouteRule](#g-rpc-route-rule)| `[]*GRPCRouteRule` |  | | Rules are a list of GRPC matchers, filters and actions.</br></br>+optional</br>+kubebuilder:validation:MaxItems=16 |  |
+Conformance-levels at this level are defined based on the type of filter:
 
+ALL core filters MUST be supported by all implementations that support
+GRPCRoute.
+Implementers are encouraged to support extended filters.
+Implementation-specific custom filters have no API guarantees across
+implementations.
 
+Specifying the same filter multiple times is not supported unless explicitly
+indicated in the filter.
 
-### <span id="g-rpc-route-status"></span> GRPCRouteStatus
+If an implementation can not support a combination of filters, it must clearly
+document that limitation. In cases where incompatible or unsupported
+filters are specified and cause the `Accepted` condition to be set to status
+`False`, implementations may use the `IncompatibleFilters` reason to specify
+this configuration error.
 
+Support: Core
 
-  
++optional
++kubebuilder:validation:MaxItems=16
++kubebuilder:validation:XValidation:message="RequestHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'RequestHeaderModifier').size() <= 1"
++kubebuilder:validation:XValidation:message="ResponseHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'ResponseHeaderModifier').size() <= 1" |  |
+| Matches | [][GRPCRouteMatch](#g-rpc-route-match)| `[]*GRPCRouteMatch` |  | | Matches define conditions used for matching the rule against incoming
+gRPC requests. Each match is independent, i.e. this rule will be matched
+if **any** one of the matches is satisfied.
 
+For example, take the following matches configuration:
 
+```
+matches:
+method:
+service: foo.bar
+headers:
+values:
+version: 2
+method:
+service: foo.bar.v2
+```
 
-**Properties**
+For a request to match against this rule, it MUST satisfy
+EITHER of the two conditions:
 
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| Parents | [][RouteParentStatus](#route-parent-status)| `[]*RouteParentStatus` |  | | Parents is a list of parent resources (usually Gateways) that are</br>associated with the route, and the status of the route with respect to</br>each parent. When this route attaches to a parent, the controller that</br>manages the parent must add an entry to this list when the controller</br>first sees the route and should update the entry as appropriate when the</br>route or gateway is modified.</br></br>Note that parent references that cannot be resolved by an implementation</br>of this API will not be added to this list. Implementations of this API</br>can only populate Route status for the Gateways/parent resources they are</br>responsible for.</br></br>A maximum of 32 Gateways will be represented in this list. An empty list</br>means the route has not been attached to any Gateway.</br></br>+kubebuilder:validation:MaxItems=32 |  |
+service of foo.bar AND contains the header `version: 2`
+service of foo.bar.v2
 
+See the documentation for GRPCRouteMatch on how to specify multiple
+match conditions to be ANDed together.
 
+If no matches are specified, the implementation MUST match every gRPC request.
 
-### <span id="g-w-info"></span> GWInfo
+Proxy or Load Balancer routing configuration generated from GRPCRoutes
+MUST prioritize rules based on the following criteria, continuing on
+ties. Merging MUST not be done between GRPCRoutes and HTTPRoutes.
+Precedence MUST be given to the rule with the largest number of:
 
+Characters in a matching non-wildcard hostname.
+Characters in a matching hostname.
+Characters in a matching service.
+Characters in a matching method.
+Header matches.
 
-> GWInfo contains the resolved gateway configuration if the node represents an Istio gateway
+If ties still exist across multiple Routes, matching precedence MUST be
+determined in order of the following criteria, continuing on ties:
+
+The oldest Route based on creation timestamp.
+The Route appearing first in alphabetical order by
+"{namespace}/{name}".
+
+If ties still exist within the Route that has been given precedence,
+matching precedence MUST be granted to the first matching rule meeting
+the above criteria.
+
++optional
++kubebuilder:validation:MaxItems=8 |  |
+| name | [SectionName](#section-name)| `SectionName` |  | |  |  |
+| sessionPersistence | [SessionPersistence](#session-persistence)| `SessionPersistence` |  | |  |  |
+
+
+
+### <span id="g-rpc-route-spec"></span> GRPCRouteSpec
+
+
+> GRPCRouteSpec defines the desired state of GRPCRoute
   
 
 
@@ -7942,19 +8393,98 @@ an API object (backendRefs).
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| egressInfo | [GWInfoIngress](#g-w-info-ingress)| `GWInfoIngress` |  | |  |  |
-| gatewayAPIInfo | [GWInfoIngress](#g-w-info-ingress)| `GWInfoIngress` |  | |  |  |
-| ingressInfo | [GWInfoIngress](#g-w-info-ingress)| `GWInfoIngress` |  | |  |  |
+| Hostnames | [][Hostname](#hostname)| `[]Hostname` |  | | Hostnames defines a set of hostnames to match against the GRPC
+Host header to select a GRPCRoute to process the request. This matches
+the RFC 1123 definition of a hostname with 2 notable exceptions:
 
+1. IPs are not allowed.
+2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard
+label MUST appear by itself as the first label.
+
+If a hostname is specified by both the Listener and GRPCRoute, there
+MUST be at least one intersecting hostname for the GRPCRoute to be |  |
+| ParentRefs | [][ParentReference](#parent-reference)| `[]*ParentReference` |  | | ParentRefs references the resources (usually Gateways) that a Route wants
+to be attached to. Note that the referenced parent resource needs to
+allow this for the attachment to be complete. For Gateways, that means
+the Gateway needs to allow attachment from Routes of this kind and
+namespace. For Services, that means the Service must either be in the same
+namespace for a "producer" route, or the mesh implementation must support
+and allow "consumer" routes for the referenced Service. ReferenceGrant is
+not applicable for governing ParentRefs to Services - it is not possible to
+create a "producer" route for a Service in a different namespace from the
+Route.
+
+There are two kinds of parent resources with "Core" support:
+
+Gateway (Gateway conformance profile)
+Service (Mesh conformance profile, ClusterIP Services only)
 
+This API may be extended in the future to support additional kinds of parent
+resources.
 
-### <span id="g-w-info-ingress"></span> GWInfoIngress
+ParentRefs must be _distinct_. This means either that:
+
+They select different objects.  If this is the case, then parentRef
+entries are distinct. In terms of fields, this means that the
+multi-part key defined by `group`, `kind`, `namespace`, and `name` must
+be unique across all parentRef entries in the Route.
+They do not select different objects, but for each optional field used,
+each ParentRef that selects the same object must set the same set of
+optional fields to different values. If one ParentRef sets a
+combination of optional fields, all must set the same combination.
+
+Some examples:
+
+If one ParentRef sets `sectionName`, all ParentRefs referencing the
+same object must also set `sectionName`.
+If one ParentRef sets `port`, all ParentRefs referencing the same
+object must also set `port`.
+If one ParentRef sets `sectionName` and `port`, all ParentRefs
+referencing the same object must also set `sectionName` and `port`.
+
+It is possible to separately reference multiple distinct objects that may
+be collapsed by an implementation. For example, some implementations may
+choose to merge compatible Gateway Listeners together. If that is the
+case, the list of routes attached to those resources should also be
+merged.
+
+Note that for ParentRefs that cross namespace boundaries, there are specific
+rules. Cross-namespace references are only valid if they are explicitly
+allowed by something in the namespace they are referring to. For example,
+Gateway has the AllowedRoutes field, and ReferenceGrant provides a
+generic way to enable other kinds of cross-namespace reference.
 
+<gateway:experimental:description>
+ParentRefs from a Route to a Service in the same namespace are "producer"
+routes, which apply default routing rules to inbound connections from
+any namespace to the Service.
+
+ParentRefs from a Route to a Service in a different namespace are
+"consumer" routes, and these routing rules are only applied to outbound
+connections originating from the same namespace as the Route, for which
+the intended destination of the connections are a Service targeted as a
+ParentRef of the Route.
+</gateway:experimental:description>
 
-> GWInfoIngress contains the resolved gateway configuration if the node represents an Istio ingress gateway
-  
++optional
++kubebuilder:validation:MaxItems=32
+<gateway:standard:validation:XValidation:message="sectionName must be specified when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.all(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__ )) ? ((!has(p1.sectionName) || p1.sectionName == '') == (!has(p2.sectionName) || p2.sectionName == '')) : true))">
+<gateway:standard:validation:XValidation:message="sectionName must be unique when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName == '')) || (has(p1.sectionName) && has(p2.sectionName) && p1.sectionName == p2.sectionName))))">
+<gateway:experimental:validation:XValidation:message="sectionName or port must be specified when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.all(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__)) ? ((!has(p1.sectionName) || p1.sectionName == '') == (!has(p2.sectionName) || p2.sectionName == '') && (!has(p1.port) || p1.port == 0) == (!has(p2.port) || p2.port == 0)): true))">
+<gateway:experimental:validation:XValidation:message="sectionName or port must be unique when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName == '')) || ( has(p1.sectionName) && has(p2.sectionName) && p1.sectionName == p2.sectionName)) && (((!has(p1.port) || p1.port == 0) && (!has(p2.port) || p2.port == 0)) || (has(p1.port) && has(p2.port) && p1.port == p2.port))))"> |  |
+| Rules | [][GRPCRouteRule](#g-rpc-route-rule)| `[]*GRPCRouteRule` |  | | Rules are a list of GRPC matchers, filters and actions.
+
++optional
++kubebuilder:validation:MaxItems=16
++kubebuilder:validation:XValidation:message="While 16 rules and 64 matches per rule are allowed, the total number of matches across all rules in a route must be less than 128",rule="(self.size() > 0 ? (has(self[0].matches) ? self[0].matches.size() : 0) : 0) + (self.size() > 1 ? (has(self[1].matches) ? self[1].matches.size() : 0) : 0) + (self.size() > 2 ? (has(self[2].matches) ? self[2].matches.size() : 0) : 0) + (self.size() > 3 ? (has(self[3].matches) ? self[3].matches.size() : 0) : 0) + (self.size() > 4 ? (has(self[4].matches) ? self[4].matches.size() : 0) : 0) + (self.size() > 5 ? (has(self[5].matches) ? self[5].matches.size() : 0) : 0) + (self.size() > 6 ? (has(self[6].matches) ? self[6].matches.size() : 0) : 0) + (self.size() > 7 ? (has(self[7].matches) ? self[7].matches.size() : 0) : 0) + (self.size() > 8 ? (has(self[8].matches) ? self[8].matches.size() : 0) : 0) + (self.size() > 9 ? (has(self[9].matches) ? self[9].matches.size() : 0) : 0) + (self.size() > 10 ? (has(self[10].matches) ? self[10].matches.size() : 0) : 0) + (self.size() > 11 ? (has(self[11].matches) ? self[11].matches.size() : 0) : 0) + (self.size() > 12 ? (has(self[12].matches) ? self[12].matches.size() : 0) : 0) + (self.size() > 13 ? (has(self[13].matches) ? self[13].matches.size() : 0) : 0) + (self.size() > 14 ? (has(self[14].matches) ? self[14].matches.size() : 0) : 0) + (self.size() > 15 ? (has(self[15].matches) ? self[15].matches.size() : 0) : 0) <= 128"
+<gateway:experimental:validation:XValidation:message="Rule name must be unique within the route",rule="self.all(l1, !has(l1.name) || self.exists_one(l2, has(l2.name) && l1.name == l2.name))"> |  |
+
+
+
+### <span id="g-rpc-route-status"></span> GRPCRouteStatus
 
 
+  
 
 
 
@@ -7962,15 +8492,29 @@ an API object (backendRefs).
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Hostnames | []string| `[]string` |  | | Hostnames is the list of hosts being served by the associated Istio gateways. |  |
+| Parents | [][RouteParentStatus](#route-parent-status)| `[]*RouteParentStatus` |  | | Parents is a list of parent resources (usually Gateways) that are
+associated with the route, and the status of the route with respect to
+each parent. When this route attaches to a parent, the controller that
+manages the parent must add an entry to this list when the controller
+first sees the route and should update the entry as appropriate when the
+route or gateway is modified.
+
+Note that parent references that cannot be resolved by an implementation
+of this API will not be added to this list. Implementations of this API
+can only populate Route status for the Gateways/parent resources they are
+responsible for.
 
+A maximum of 32 Gateways will be represented in this list. An empty list
+means the route has not been attached to any Gateway.
 
++kubebuilder:validation:MaxItems=32 |  |
 
-### <span id="gateway"></span> Gateway
 
 
-> Gateway represents an instance of a service-traffic handling infrastructure
-by binding Listeners to a set of IP addresses.
+### <span id="g-w-info"></span> GWInfo
+
+
+> GWInfo contains the resolved gateway configuration if the node represents an Istio gateway
   
 
 
@@ -7981,32 +8525,16 @@ by binding Listeners to a set of IP addresses.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| APIVersion | string| `string` |  | | APIVersion defines the versioned schema of this representation of an object.</br>Servers should convert recognized schemas to the latest internal value, and</br>may reject unrecognized values.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources</br>+optional |  |
-| Annotations | map of string| `map[string]string` |  | | Annotations is an unstructured key value map stored with a resource that may be</br>set by external tools to store and retrieve arbitrary metadata. They are not</br>queryable and should be preserved when modifying objects.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations</br>+optional |  |
-| CreationTimestamp | string| `string` |  | | CreationTimestamp is a timestamp representing the server time when this object was</br>created. It is not guaranteed to be set in happens-before order across separate operations.</br>Clients may not set this value. It is represented in RFC3339 form and is in UTC.</br></br>Populated by the system.</br>Read-only.</br>Null for lists.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| DeletionGracePeriodSeconds | int64 (formatted integer)| `int64` |  | | Number of seconds allowed for this object to gracefully terminate before</br>it will be removed from the system. Only set when deletionTimestamp is also set.</br>May only be shortened.</br>Read-only.</br>+optional |  |
-| DeletionTimestamp | string| `string` |  | | DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This</br>field is set by the server when a graceful deletion is requested by the user, and is not</br>directly settable by a client. The resource is expected to be deleted (no longer visible</br>from resource lists, and not reachable by name) after the time in this field, once the</br>finalizers list is empty. As long as the finalizers list contains items, deletion is blocked.</br>Once the deletionTimestamp is set, this value may not be unset or be set further into the</br>future, although it may be shortened or the resource may be deleted prior to this time.</br>For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react</br>by sending a graceful termination signal to the containers in the pod. After that 30 seconds,</br>the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,</br>remove the pod from the API. In the presence of network partitions, this object may still</br>exist after this timestamp, until an administrator or automated process can determine the</br>resource is fully terminated.</br>If not set, graceful deletion of the object has not been requested.</br></br>Populated by the system when a graceful deletion is requested.</br>Read-only.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| Finalizers | []string| `[]string` |  | | Must be empty before the object is deleted from the registry. Each entry</br>is an identifier for the responsible component that will remove the entry</br>from the list. If the deletionTimestamp of the object is non-nil, entries</br>in this list can only be removed.</br>Finalizers may be processed and removed in any order.  Order is NOT enforced</br>because it introduces significant risk of stuck finalizers.</br>finalizers is a shared field, any actor with permission can reorder it.</br>If the finalizer list is processed in order, then this can lead to a situation</br>in which the component responsible for the first finalizer in the list is</br>waiting for a signal (field value, external system, or other) produced by a</br>component responsible for a finalizer later in the list, resulting in a deadlock.</br>Without enforced ordering finalizers are free to order amongst themselves and</br>are not vulnerable to ordering changes in the list.</br>+optional</br>+patchStrategy=merge</br>+listType=set |  |
-| GenerateName | string| `string` |  | | GenerateName is an optional prefix, used by the server, to generate a unique</br>name ONLY IF the Name field has not been provided.</br>If this field is used, the name returned to the client will be different</br>than the name passed. This value will also be combined with a unique suffix.</br>The provided value has the same validation rules as the Name field,</br>and may be truncated by the length of the suffix required to make the value</br>unique on the server.</br></br>If this field is specified and the generated name exists, the server will return a 409.</br></br>Applied only if Name is not specified.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency</br>+optional |  |
-| Generation | int64 (formatted integer)| `int64` |  | | A sequence number representing a specific generation of the desired state.</br>Populated by the system. Read-only.</br>+optional |  |
-| Kind | string| `string` |  | | Kind is a string value representing the REST resource this object represents.</br>Servers may infer this from the endpoint the client submits requests to.</br>Cannot be updated.</br>In CamelCase.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds</br>+optional |  |
-| Labels | map of string| `map[string]string` |  | | Map of string keys and values that can be used to organize and categorize</br>(scope and select) objects. May match selectors of replication controllers</br>and services.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels</br>+optional |  |
-| ManagedFields | [][ManagedFieldsEntry](#managed-fields-entry)| `[]*ManagedFieldsEntry` |  | | ManagedFields maps workflow-id and version to the set of fields</br>that are managed by that workflow. This is mostly for internal</br>housekeeping, and users typically shouldn't need to set or</br>understand this field. A workflow can be the user's name, a</br>controller's name, or the name of a specific apply path like</br>"ci-cd". The set of fields is always in the version that the</br>workflow used when modifying the object.</br></br>+optional</br>+listType=atomic |  |
-| Name | string| `string` |  | | Name must be unique within a namespace. Is required when creating resources, although</br>some resources may allow a client to request the generation of an appropriate name</br>automatically. Name is primarily intended for creation idempotence and configuration</br>definition.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names</br>+optional |  |
-| Namespace | string| `string` |  | | Namespace defines the space within which each name must be unique. An empty namespace is</br>equivalent to the "default" namespace, but "default" is the canonical representation.</br>Not all objects are required to be scoped to a namespace - the value of this field for</br>those objects will be empty.</br></br>Must be a DNS_LABEL.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces</br>+optional |  |
-| OwnerReferences | [][OwnerReference](#owner-reference)| `[]*OwnerReference` |  | | List of objects depended by this object. If ALL objects in the list have</br>been deleted, this object will be garbage collected. If this object is managed by a controller,</br>then an entry in this list will point to this controller, with the controller field set to true.</br>There cannot be more than one managing controller.</br>+optional</br>+patchMergeKey=uid</br>+patchStrategy=merge</br>+listType=map</br>+listMapKey=uid |  |
-| ResourceVersion | string| `string` |  | | An opaque value that represents the internal version of this object that can</br>be used by clients to determine when objects have changed. May be used for optimistic</br>concurrency, change detection, and the watch operation on a resource or set of resources.</br>Clients must treat these values as opaque and passed unmodified back to the server.</br>They may only be valid for a particular resource or set of resources.</br></br>Populated by the system.</br>Read-only.</br>Value must be treated as opaque by clients and .</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency</br>+optional |  |
-| SelfLink | string| `string` |  | | Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.</br>+optional |  |
-| spec | [GatewaySpec](#gateway-spec)| `GatewaySpec` |  | |  |  |
-| status | [GatewayStatus](#gateway-status)| `GatewayStatus` |  | |  |  |
-| uid | [UID](#uid)| `UID` |  | |  |  |
+| egressInfo | [GWInfoIngress](#g-w-info-ingress)| `GWInfoIngress` |  | |  |  |
+| gatewayAPIInfo | [GWInfoIngress](#g-w-info-ingress)| `GWInfoIngress` |  | |  |  |
+| ingressInfo | [GWInfoIngress](#g-w-info-ingress)| `GWInfoIngress` |  | |  |  |
 
 
 
-### <span id="gateway-address"></span> GatewayAddress
+### <span id="g-w-info-ingress"></span> GWInfoIngress
 
 
-> +kubebuilder:validation:XValidation:message="Hostname value must only contain valid characters (matching ^(\\*\\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$)",rule="self.type == 'Hostname' ? self.value.matches(r\"\"\"^(\\*\\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$\"\"\"): true"
+> GWInfoIngress contains the resolved gateway configuration if the node represents an Istio ingress gateway
   
 
 
@@ -8017,8 +8545,7 @@ by binding Listeners to a set of IP addresses.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Value | string| `string` |  | | Value of the address. The validity of the values will depend</br>on the type and support by the controller.</br></br>Examples: `1.2.3.4`, `128::1`, `my-ip-address`.</br></br>+kubebuilder:validation:MinLength=1</br>+kubebuilder:validation:MaxLength=253 |  |
-| type | [AddressType](#address-type)| `AddressType` |  | |  |  |
+| Hostnames | []string| `[]string` |  | | Hostnames is the list of hosts being served by the associated Istio gateways. |  |
 
 
 
@@ -8043,34 +8570,25 @@ Invalid values include:
 
 | Name | Type | Go type | Default | Description | Example |
 |------|------|---------| ------- |-------------|---------|
-| GatewayController | string| string | | Valid values include:</br></br>"example.com/bar"</br></br>Invalid values include:</br></br>"example.com" - must include path</br>"foo.example.com" - must include path</br></br>+kubebuilder:validation:MinLength=1</br>+kubebuilder:validation:MaxLength=253</br>+kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$` |  |
-
-
-
-### <span id="gateway-infrastructure"></span> GatewayInfrastructure
-
-
-  
+| GatewayController | string| string | | Valid values include:
 
+"example.com/bar"
 
+Invalid values include:
 
-**Properties**
+"example.com" - must include path
+"foo.example.com" - must include path
 
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| Annotations | map of [AnnotationValue](#annotation-value)| `map[string]AnnotationValue` |  | | Annotations that SHOULD be applied to any resources created in response to this Gateway.</br></br>For implementations creating other Kubernetes objects, this should be the `metadata.annotations` field on resources.</br>For other implementations, this refers to any relevant (implementation specific) "annotations" concepts.</br></br>An implementation may chose to add additional implementation-specific annotations as they see fit.</br></br>Support: Extended</br></br>+optional</br>+kubebuilder:validation:MaxProperties=8 |  |
-| Labels | map of [AnnotationValue](#annotation-value)| `map[string]AnnotationValue` |  | | Labels that SHOULD be applied to any resources created in response to this Gateway.</br></br>For implementations creating other Kubernetes objects, this should be the `metadata.labels` field on resources.</br>For other implementations, this refers to any relevant (implementation specific) "labels" concepts.</br></br>An implementation may chose to add additional implementation-specific labels as they see fit.</br></br>Support: Extended</br></br>+optional</br>+kubebuilder:validation:MaxProperties=8 |  |
-| parametersRef | [LocalParametersReference](#local-parameters-reference)| `LocalParametersReference` |  | |  |  |
++kubebuilder:validation:MinLength=1
++kubebuilder:validation:MaxLength=253
++kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$` |  |
 
 
 
-### <span id="gateway-spec"></span> GatewaySpec
+### <span id="grafana-info"></span> GrafanaInfo
 
 
-> Not all possible combinations of options specified in the Spec are
-valid. Some invalid configurations can be caught synchronously via CRD
-validation, but there are many cases that will require asynchronous
-signaling via the GatewayStatus block.
+> GrafanaInfo provides information to access Grafana dashboards
   
 
 
@@ -8081,53 +8599,57 @@ signaling via the GatewayStatus block.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Addresses | [][GatewayAddress](#gateway-address)| `[]*GatewayAddress` |  | | Addresses requested for this Gateway. This is optional and behavior can</br>depend on the implementation. If a value is set in the spec and the</br>requested address is invalid or unavailable, the implementation MUST</br>indicate this in the associated entry in GatewayStatus.Addresses.</br></br>The Addresses field represents a request for the address(es) on the</br>"outside of the Gateway", that traffic bound for this Gateway will use.</br>This could be the IP address or hostname of an external load balancer or</br>other networking infrastructure, or some other address that traffic will</br>be sent to.</br></br>If no Addresses are specified, the implementation MAY schedule the</br>Gateway in an implementation-specific manner, assigning an appropriate</br>set of Addresses.</br></br>The implementation MUST bind all Listeners to every GatewayAddress that</br>it assigns to the Gateway and add a corresponding entry in</br>GatewayStatus.Addresses.</br></br>Support: Extended</br></br>+optional</br><gateway:validateIPAddress></br>+kubebuilder:validation:MaxItems=16</br>+kubebuilder:validation:XValidation:message="IPAddress values must be unique",rule="self.all(a1, a1.type == 'IPAddress' ? self.exists_one(a2, a2.type == a1.type && a2.value == a1.value) : true )"</br>+kubebuilder:validation:XValidation:message="Hostname values must be unique",rule="self.all(a1, a1.type == 'Hostname' ? self.exists_one(a2, a2.type == a1.type && a2.value == a1.value) : true )" |  |
-| Listeners | [][Listener](#listener)| `[]*Listener` |  | | Listeners associated with this Gateway. Listeners define</br>logical endpoints that are bound on this Gateway's addresses.</br>At least one Listener MUST be specified.</br></br>Each Listener in a set of Listeners (for example, in a single Gateway)</br>MUST be _distinct_, in that a traffic flow MUST be able to be assigned to</br>exactly one listener. (This section uses "set of Listeners" rather than</br>"Listeners in a single Gateway" because implementations MAY merge configuration</br>from multiple Gateways onto a single data plane, and these rules _also_</br>apply in that case).</br></br>Practically, this means that each listener in a set MUST have a unique</br>combination of Port, Protocol, and, if supported by the protocol, Hostname.</br></br>Some combinations of port, protocol, and TLS settings are considered</br>Core support and MUST be supported by implementations based on their</br>targeted conformance profile:</br></br>HTTP Profile</br></br>1. HTTPRoute, Port: 80, Protocol: HTTP</br>2. HTTPRoute, Port: 443, Protocol: HTTPS, TLS Mode: Terminate, TLS keypair provided</br></br>TLS Profile</br></br>1. TLSRoute, Port: 443, Protocol: TLS, TLS Mode: Passthrough</br></br>"Distinct" Listeners have the following property:</br></br>The implementation can match inbound requests to a single distinct</br>Listener. When multiple Listeners share values for fields (for</br>example, two Listeners with the same Port value), the implementation</br>can match requests to only one of the Listeners using other</br>Listener fields.</br></br>For example, the following Listener scenarios are distinct:</br></br>1. Multiple Listeners with the same Port that all use the "HTTP"</br>Protocol that all have unique Hostname values.</br>2. Multiple Listeners with the same Port that use either the "HTTPS" or</br>"TLS" Protocol that all have unique Hostname values.</br>3. A mixture of "TCP" and "UDP" Protocol Listeners, where no Listener</br>with the same Protocol has the same Port value.</br></br>Some fields in the Listener struct have possible values that affect</br>whether the Listener is distinct. Hostname is particularly relevant</br>for HTTP or HTTPS protocols.</br></br>When using the Hostname value to select between same-Port, same-Protocol</br>Listeners, the Hostname value must be different on each Listener for the</br>Listener to be distinct.</br></br>When the Listeners are distinct based on Hostname, inbound request</br>hostnames MUST match from the most specific to least specific Hostname</br>values to choose the correct Listener and its associated set of Routes.</br></br>Exact matches must be processed before wildcard matches, and wildcard</br>matches must be processed before fallback (empty Hostname value)</br>matches. For example, `"foo.example.com"` takes precedence over</br>`"*.example.com"`, and `"*.example.com"` takes precedence over `""`.</br></br>Additionally, if there are multiple wildcard entries, more specific</br>wildcard entries must be processed before less specific wildcard entries.</br>For example, `"*.foo.example.com"` takes precedence over `"*.example.com"`.</br>The precise definition here is that the higher the number of dots in the</br>hostname to the right of the wildcard character, the higher the precedence.</br></br>The wildcard character will match any number of characters _and dots_ to</br>the left, however, so `"*.example.com"` will match both</br>`"foo.bar.example.com"` _and_ `"bar.example.com"`.</br></br>If a set of Listeners contains Listeners that are not distinct, then those</br>Listeners are Conflicted, and the implementation MUST set the "Conflicted"</br>condition in the Listener Status to "True".</br></br>Implementations MAY choose to accept a Gateway with some Conflicted</br>Listeners only if they only accept the partial Listener set that contains</br>no Conflicted Listeners. To put this another way, implementations may</br>accept a partial Listener set only if they throw out *all* the conflicting</br>Listeners. No picking one of the conflicting listeners as the winner.</br>This also means that the Gateway must have at least one non-conflicting</br>Listener in this case, otherwise it violates the requirement that at</br>least one Listener must be present.</br></br>The implementation MUST set a "ListenersNotValid" condition on the</br>Gateway Status when the Gateway contains Conflicted Listeners whether or</br>not they accept the Gateway. That Condition SHOULD clearly</br>indicate in the Message which Listeners are conflicted, and which are</br>Accepted. Additionally, the Listener status for those listeners SHOULD</br>indicate which Listeners are conflicted and not Accepted.</br></br>A Gateway's Listeners are considered "compatible" if:</br></br>1. They are distinct.</br>2. The implementation can serve them in compliance with the Addresses</br>requirement that all Listeners are available on all assigned</br>addresses.</br></br>Compatible combinations in Extended support are expected to vary across</br>implementations. A combination that is compatible for one implementation</br>may not be compatible for another.</br></br>For example, an implementation that cannot serve both TCP and UDP listeners</br>on the same address, or cannot mix HTTPS and generic TLS listens on the same port</br>would not consider those cases compatible, even though they are distinct.</br></br>Note that requests SHOULD match at most one Listener. For example, if</br>Listeners are defined for "foo.example.com" and "*.example.com", a</br>request to "foo.example.com" SHOULD only be routed using routes attached</br>to the "foo.example.com" Listener (and not the "*.example.com" Listener).</br>This concept is known as "Listener Isolation". Implementations that do</br>not support Listener Isolation MUST clearly document this.</br></br>Implementations MAY merge separate Gateways onto a single set of</br>Addresses if all Listeners across all Gateways are compatible.</br></br>Support: Core</br></br>+listType=map</br>+listMapKey=name</br>+kubebuilder:validation:MinItems=1</br>+kubebuilder:validation:MaxItems=64</br>+kubebuilder:validation:XValidation:message="tls must not be specified for protocols ['HTTP', 'TCP', 'UDP']",rule="self.all(l, l.protocol in ['HTTP', 'TCP', 'UDP'] ? !has(l.tls) : true)"</br>+kubebuilder:validation:XValidation:message="tls mode must be Terminate for protocol HTTPS",rule="self.all(l, (l.protocol == 'HTTPS' && has(l.tls)) ? (l.tls.mode == '' || l.tls.mode == 'Terminate') : true)"</br>+kubebuilder:validation:XValidation:message="hostname must not be specified for protocols ['TCP', 'UDP']",rule="self.all(l, l.protocol in ['TCP', 'UDP']  ? (!has(l.hostname) || l.hostname == '') : true)"</br>+kubebuilder:validation:XValidation:message="Listener name must be unique within the Gateway",rule="self.all(l1, self.exists_one(l2, l1.name == l2.name))"</br>+kubebuilder:validation:XValidation:message="Combination of port, protocol and hostname must be unique for each listener",rule="self.all(l1, self.exists_one(l2, l1.port == l2.port && l1.protocol == l2.protocol && (has(l1.hostname) && has(l2.hostname) ? l1.hostname == l2.hostname : !has(l1.hostname) && !has(l2.hostname))))" |  |
-| gatewayClassName | [ObjectName](#object-name)| `ObjectName` |  | |  |  |
-| infrastructure | [GatewayInfrastructure](#gateway-infrastructure)| `GatewayInfrastructure` |  | |  |  |
-
-
+| ExternalLinks | [][ExternalLink](#external-link)| `[]*ExternalLink` |  | |  |  |
 
-### <span id="gateway-status"></span> GatewayStatus
 
 
-  
+### <span id="group"></span> Group
 
 
+> This validation is based off of the corresponding Kubernetes validation:
+https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/util/validation/validation.go#L208
 
-**Properties**
+Valid values include:
 
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| Addresses | [][GatewayStatusAddress](#gateway-status-address)| `[]*GatewayStatusAddress` |  | | Addresses lists the network addresses that have been bound to the</br>Gateway.</br></br>This list may differ from the addresses provided in the spec under some</br>conditions:</br></br>no addresses are specified, all addresses are dynamically assigned</br>a combination of specified and dynamic addresses are assigned</br>a specified address was unusable (e.g. already in use)</br></br>+optional</br><gateway:validateIPAddress></br>+kubebuilder:validation:MaxItems=16 |  |
-| Conditions | [][Condition](#condition)| `[]*Condition` |  | | Conditions describe the current conditions of the Gateway.</br></br>Implementations should prefer to express Gateway conditions</br>using the `GatewayConditionType` and `GatewayConditionReason`</br>constants so that operators and tools can converge on a common</br>vocabulary to describe Gateway state.</br></br>Known condition types are:</br></br>"Accepted"</br>"Programmed"</br>"Ready"</br></br>+optional</br>+listType=map</br>+listMapKey=type</br>+kubebuilder:validation:MaxItems=8</br>+kubebuilder:default={{type: "Accepted", status: "Unknown", reason:"Pending", message:"Waiting for controller", lastTransitionTime: "1970-01-01T00:00:00Z"},{type: "Programmed", status: "Unknown", reason:"Pending", message:"Waiting for controller", lastTransitionTime: "1970-01-01T00:00:00Z"}} |  |
-| Listeners | [][ListenerStatus](#listener-status)| `[]*ListenerStatus` |  | | Listeners provide status for each unique listener port defined in the Spec.</br></br>+optional</br>+listType=map</br>+listMapKey=name</br>+kubebuilder:validation:MaxItems=64 |  |
+"" - empty string implies core Kubernetes API group
+"gateway.networking.k8s.io"
+"foo.example.com"
 
+Invalid values include:
 
+"example.com/bar" - "/" is an invalid character
 
-### <span id="gateway-status-address"></span> GatewayStatusAddress
++kubebuilder:validation:MaxLength=253
++kubebuilder:validation:Pattern=`^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`
+  
 
 
-> +kubebuilder:validation:XValidation:message="Hostname value must only contain valid characters (matching ^(\\*\\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$)",rule="self.type == 'Hostname' ? self.value.matches(r\"\"\"^(\\*\\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$\"\"\"): true"
-  
 
+| Name | Type | Go type | Default | Description | Example |
+|------|------|---------| ------- |-------------|---------|
+| Group | string| string | | This validation is based off of the corresponding Kubernetes validation:
+https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/util/validation/validation.go#L208
 
+Valid values include:
 
+"" - empty string implies core Kubernetes API group
+"gateway.networking.k8s.io"
+"foo.example.com"
 
+Invalid values include:
 
-**Properties**
+"example.com/bar" - "/" is an invalid character
 
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| Value | string| `string` |  | | Value of the address. The validity of the values will depend</br>on the type and support by the controller.</br></br>Examples: `1.2.3.4`, `128::1`, `my-ip-address`.</br></br>+kubebuilder:validation:MinLength=1</br>+kubebuilder:validation:MaxLength=253 |  |
-| type | [AddressType](#address-type)| `AddressType` |  | |  |  |
++kubebuilder:validation:MaxLength=253
++kubebuilder:validation:Pattern=`^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$` |  |
 
 
 
-### <span id="grafana-info"></span> GrafanaInfo
+### <span id="group-version-kind"></span> GroupVersionKind
 
 
-> GrafanaInfo provides information to access Grafana dashboards
+> GroupVersionKind unambiguously identifies a kind.  It doesn't anonymously include GroupVersion
+to avoid automatic coercion.  It doesn't use a GroupVersion to avoid custom marshalling
   
 
 
@@ -8138,35 +8660,9 @@ signaling via the GatewayStatus block.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| ExternalLinks | [][ExternalLink](#external-link)| `[]*ExternalLink` |  | |  |  |
-
-
-
-### <span id="group"></span> Group
-
-
-> This validation is based off of the corresponding Kubernetes validation:
-https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/util/validation/validation.go#L208
-
-Valid values include:
-
-"" - empty string implies core Kubernetes API group
-"gateway.networking.k8s.io"
-"foo.example.com"
-
-Invalid values include:
-
-"example.com/bar" - "/" is an invalid character
-
-+kubebuilder:validation:MaxLength=253
-+kubebuilder:validation:Pattern=`^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`
-  
-
-
-
-| Name | Type | Go type | Default | Description | Example |
-|------|------|---------| ------- |-------------|---------|
-| Group | string| string | | This validation is based off of the corresponding Kubernetes validation:</br>https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/util/validation/validation.go#L208</br></br>Valid values include:</br></br>"" - empty string implies core Kubernetes API group</br>"gateway.networking.k8s.io"</br>"foo.example.com"</br></br>Invalid values include:</br></br>"example.com/bar" - "/" is an invalid character</br></br>+kubebuilder:validation:MaxLength=253</br>+kubebuilder:validation:Pattern=`^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$` |  |
+| Group | string| `string` |  | |  |  |
+| Kind | string| `string` |  | |  |  |
+| Version | string| `string` |  | |  |  |
 
 
 
@@ -8205,8 +8701,38 @@ protocol then the backend is considered invalid. Implementations MUST set the
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Filters | [][HTTPRouteFilter](#http-route-filter)| `[]*HTTPRouteFilter` |  | | Filters defined at this level should be executed if and only if the</br>request is being forwarded to the backend defined here.</br></br>Support: Implementation-specific (For broader support of filters, use the</br>Filters field in HTTPRouteRule.)</br></br>+optional</br>+kubebuilder:validation:MaxItems=16</br>+kubebuilder:validation:XValidation:message="May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both",rule="!(self.exists(f, f.type == 'RequestRedirect') && self.exists(f, f.type == 'URLRewrite'))"</br>+kubebuilder:validation:XValidation:message="May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both",rule="!(self.exists(f, f.type == 'RequestRedirect') && self.exists(f, f.type == 'URLRewrite'))"</br>+kubebuilder:validation:XValidation:message="RequestHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'RequestHeaderModifier').size() <= 1"</br>+kubebuilder:validation:XValidation:message="ResponseHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'ResponseHeaderModifier').size() <= 1"</br>+kubebuilder:validation:XValidation:message="RequestRedirect filter cannot be repeated",rule="self.filter(f, f.type == 'RequestRedirect').size() <= 1"</br>+kubebuilder:validation:XValidation:message="URLRewrite filter cannot be repeated",rule="self.filter(f, f.type == 'URLRewrite').size() <= 1" |  |
-| Weight | int32 (formatted integer)| `int32` |  | | Weight specifies the proportion of requests forwarded to the referenced</br>backend. This is computed as weight/(sum of all weights in this</br>BackendRefs list). For non-zero values, there may be some epsilon from</br>the exact proportion defined here depending on the precision an</br>implementation supports. Weight is not a percentage and the sum of</br>weights does not need to equal 100.</br></br>If only one backend is specified and it has a weight greater than 0, 100%</br>of the traffic is forwarded to that backend. If weight is set to 0, no</br>traffic should be forwarded for this entry. If unspecified, weight</br>defaults to 1.</br></br>Support for this field varies based on the context where used.</br></br>+optional</br>+kubebuilder:default=1</br>+kubebuilder:validation:Minimum=0</br>+kubebuilder:validation:Maximum=1000000 |  |
+| Filters | [][HTTPRouteFilter](#http-route-filter)| `[]*HTTPRouteFilter` |  | | Filters defined at this level should be executed if and only if the
+request is being forwarded to the backend defined here.
+
+Support: Implementation-specific (For broader support of filters, use the
+Filters field in HTTPRouteRule.)
+
++optional
++kubebuilder:validation:MaxItems=16
++kubebuilder:validation:XValidation:message="May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both",rule="!(self.exists(f, f.type == 'RequestRedirect') && self.exists(f, f.type == 'URLRewrite'))"
++kubebuilder:validation:XValidation:message="May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both",rule="!(self.exists(f, f.type == 'RequestRedirect') && self.exists(f, f.type == 'URLRewrite'))"
++kubebuilder:validation:XValidation:message="RequestHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'RequestHeaderModifier').size() <= 1"
++kubebuilder:validation:XValidation:message="ResponseHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'ResponseHeaderModifier').size() <= 1"
++kubebuilder:validation:XValidation:message="RequestRedirect filter cannot be repeated",rule="self.filter(f, f.type == 'RequestRedirect').size() <= 1"
++kubebuilder:validation:XValidation:message="URLRewrite filter cannot be repeated",rule="self.filter(f, f.type == 'URLRewrite').size() <= 1" |  |
+| Weight | int32 (formatted integer)| `int32` |  | | Weight specifies the proportion of requests forwarded to the referenced
+backend. This is computed as weight/(sum of all weights in this
+BackendRefs list). For non-zero values, there may be some epsilon from
+the exact proportion defined here depending on the precision an
+implementation supports. Weight is not a percentage and the sum of
+weights does not need to equal 100.
+
+If only one backend is specified and it has a weight greater than 0, 100%
+of the traffic is forwarded to that backend. If weight is set to 0, no
+traffic should be forwarded for this entry. If unspecified, weight
+defaults to 1.
+
+Support for this field varies based on the context where used.
+
++optional
++kubebuilder:default=1
++kubebuilder:validation:Minimum=0
++kubebuilder:validation:Maximum=1000000 |  |
 | group | [Group](#group)| `Group` |  | |  |  |
 | kind | [Kind](#kind)| `Kind` |  | |  |  |
 | name | [ObjectName](#object-name)| `ObjectName` |  | |  |  |
@@ -8226,7 +8752,10 @@ protocol then the backend is considered invalid. Implementations MUST set the
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Value | string| `string` |  | | Value is the value of HTTP Header to be matched.</br></br>+kubebuilder:validation:MinLength=1</br>+kubebuilder:validation:MaxLength=4096 |  |
+| Value | string| `string` |  | | Value is the value of HTTP Header to be matched.
+
++kubebuilder:validation:MinLength=1
++kubebuilder:validation:MaxLength=4096 |  |
 | name | [HTTPHeaderName](#http-header-name)| `HTTPHeaderName` |  | |  |  |
 
 
@@ -8250,9 +8779,68 @@ header value formatting, separating each value with a comma.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Add | [][HTTPHeader](#http-header)| `[]*HTTPHeader` |  | | Add adds the given header(s) (name, value) to the request</br>before the action. It appends to any existing values associated</br>with the header name.</br></br>Input:</br>GET /foo HTTP/1.1</br>my-header: foo</br></br>Config:</br>add:</br>name: "my-header"</br>value: "bar,baz"</br></br>Output:</br>GET /foo HTTP/1.1</br>my-header: foo,bar,baz</br></br>+optional</br>+listType=map</br>+listMapKey=name</br>+kubebuilder:validation:MaxItems=16 |  |
-| Remove | []string| `[]string` |  | | Remove the given header(s) from the HTTP request before the action. The</br>value of Remove is a list of HTTP header names. Note that the header</br>names are case-insensitive (see</br>https://datatracker.ietf.org/doc/html/rfc2616#section-4.2).</br></br>Input:</br>GET /foo HTTP/1.1</br>my-header1: foo</br>my-header2: bar</br>my-header3: baz</br></br>Config:</br>remove: ["my-header1", "my-header3"]</br></br>Output:</br>GET /foo HTTP/1.1</br>my-header2: bar</br></br>+optional</br>+listType=set</br>+kubebuilder:validation:MaxItems=16 |  |
-| Set | [][HTTPHeader](#http-header)| `[]*HTTPHeader` |  | | Set overwrites the request with the given header (name, value)</br>before the action.</br></br>Input:</br>GET /foo HTTP/1.1</br>my-header: foo</br></br>Config:</br>set:</br>name: "my-header"</br>value: "bar"</br></br>Output:</br>GET /foo HTTP/1.1</br>my-header: bar</br></br>+optional</br>+listType=map</br>+listMapKey=name</br>+kubebuilder:validation:MaxItems=16 |  |
+| Add | [][HTTPHeader](#http-header)| `[]*HTTPHeader` |  | | Add adds the given header(s) (name, value) to the request
+before the action. It appends to any existing values associated
+with the header name.
+
+Input:
+GET /foo HTTP/1.1
+my-header: foo
+
+Config:
+add:
+name: "my-header"
+value: "bar,baz"
+
+Output:
+GET /foo HTTP/1.1
+my-header: foo,bar,baz
+
++optional
++listType=map
++listMapKey=name
++kubebuilder:validation:MaxItems=16 |  |
+| Remove | []string| `[]string` |  | | Remove the given header(s) from the HTTP request before the action. The
+value of Remove is a list of HTTP header names. Note that the header
+names are case-insensitive (see
+https://datatracker.ietf.org/doc/html/rfc2616#section-4.2).
+
+Input:
+GET /foo HTTP/1.1
+my-header1: foo
+my-header2: bar
+my-header3: baz
+
+Config:
+remove: ["my-header1", "my-header3"]
+
+Output:
+GET /foo HTTP/1.1
+my-header2: bar
+
++optional
++listType=set
++kubebuilder:validation:MaxItems=16 |  |
+| Set | [][HTTPHeader](#http-header)| `[]*HTTPHeader` |  | | Set overwrites the request with the given header (name, value)
+before the action.
+
+Input:
+GET /foo HTTP/1.1
+my-header: foo
+
+Config:
+set:
+name: "my-header"
+value: "bar"
+
+Output:
+GET /foo HTTP/1.1
+my-header: bar
+
++optional
++listType=map
++listMapKey=name
++kubebuilder:validation:MaxItems=16 |  |
 
 
 
@@ -8271,7 +8859,10 @@ headers.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Value | string| `string` |  | | Value is the value of HTTP Header to be matched.</br></br>+kubebuilder:validation:MinLength=1</br>+kubebuilder:validation:MaxLength=4096 |  |
+| Value | string| `string` |  | | Value is the value of HTTP Header to be matched.
+
++kubebuilder:validation:MinLength=1
++kubebuilder:validation:MaxLength=4096 |  |
 | name | [HTTPHeaderName](#http-header-name)| `HTTPHeaderName` |  | |  |  |
 | type | [HeaderMatchType](#header-match-type)| `HeaderMatchType` |  | |  |  |
 
@@ -8303,7 +8894,14 @@ Reason of `UnsupportedValue`.
 
 | Name | Type | Go type | Default | Description | Example |
 |------|------|---------| ------- |-------------|---------|
-| HTTPMethod | string| string | | Note that values may be added to this enum, implementations</br>must ensure that unknown values will not cause a crash.</br></br>Unknown values here must result in the implementation setting the</br>Accepted Condition for the Route to `status: False`, with a</br>Reason of `UnsupportedValue`.</br></br>+kubebuilder:validation:Enum=GET;HEAD;POST;PUT;DELETE;CONNECT;OPTIONS;TRACE;PATCH |  |
+| HTTPMethod | string| string | | Note that values may be added to this enum, implementations
+must ensure that unknown values will not cause a crash.
+
+Unknown values here must result in the implementation setting the
+Accepted Condition for the Route to `status: False`, with a
+Reason of `UnsupportedValue`.
+
++kubebuilder:validation:Enum=GET;HEAD;POST;PUT;DELETE;CONNECT;OPTIONS;TRACE;PATCH |  |
 
 
 
@@ -8331,7 +8929,11 @@ Reason of `UnsupportedValue`.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Value | string| `string` |  | | Value of the HTTP path to match against.</br></br>+optional</br>+kubebuilder:default="/"</br>+kubebuilder:validation:MaxLength=1024 |  |
+| Value | string| `string` |  | | Value of the HTTP path to match against.
+
++optional
++kubebuilder:default="/"
++kubebuilder:validation:MaxLength=1024 |  |
 | type | [PathMatchType](#path-match-type)| `PathMatchType` |  | |  |  |
 
 
@@ -8353,8 +8955,42 @@ Reason of `UnsupportedValue`.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| ReplaceFullPath | string| `string` |  | | ReplaceFullPath specifies the value with which to replace the full path</br>of a request during a rewrite or redirect.</br></br>+kubebuilder:validation:MaxLength=1024</br>+optional |  |
-| ReplacePrefixMatch | string| `string` |  | | ReplacePrefixMatch specifies the value with which to replace the prefix</br>match of a request during a rewrite or redirect. For example, a request</br>to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch</br>of "/xyz" would be modified to "/xyz/bar".</br></br>Note that this matches the behavior of the PathPrefix match type. This</br>matches full path elements. A path element refers to the list of labels</br>in the path split by the `/` separator. When specified, a trailing `/` is</br>ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all</br>match the prefix `/abc`, but the path `/abcd` would not.</br></br>ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch.</br>Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in</br>the implementation setting the Accepted Condition for the Route to `status: False`.</br></br>Request Path | Prefix Match | Replace Prefix | Modified Path</br>--------------|----------------|----------</br>foo/bar     | /foo         | /xyz           | /xyz/bar</br>foo/bar     | /foo         | /xyz/          | /xyz/bar</br>foo/bar     | /foo/        | /xyz           | /xyz/bar</br>foo/bar     | /foo/        | /xyz/          | /xyz/bar</br>foo         | /foo         | /xyz           | /xyz</br>foo/        | /foo         | /xyz           | /xyz/</br>foo/bar     | /foo         | <empty string> | /bar</br>foo/        | /foo         | <empty string> | /</br>foo         | /foo         | <empty string> | /</br>foo/        | /foo         | /              | /</br>foo         | /foo         | /              | /</br></br>+kubebuilder:validation:MaxLength=1024</br>+optional |  |
+| ReplaceFullPath | string| `string` |  | | ReplaceFullPath specifies the value with which to replace the full path
+of a request during a rewrite or redirect.
+
++kubebuilder:validation:MaxLength=1024
++optional |  |
+| ReplacePrefixMatch | string| `string` |  | | ReplacePrefixMatch specifies the value with which to replace the prefix
+match of a request during a rewrite or redirect. For example, a request
+to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch
+of "/xyz" would be modified to "/xyz/bar".
+
+Note that this matches the behavior of the PathPrefix match type. This
+matches full path elements. A path element refers to the list of labels
+in the path split by the `/` separator. When specified, a trailing `/` is
+ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all
+match the prefix `/abc`, but the path `/abcd` would not.
+
+ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch.
+Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in
+the implementation setting the Accepted Condition for the Route to `status: False`.
+
+Request Path | Prefix Match | Replace Prefix | Modified Path
+--------------|----------------|----------
+foo/bar     | /foo         | /xyz           | /xyz/bar
+foo/bar     | /foo         | /xyz/          | /xyz/bar
+foo/bar     | /foo/        | /xyz           | /xyz/bar
+foo/bar     | /foo/        | /xyz/          | /xyz/bar
+foo         | /foo         | /xyz           | /xyz
+foo/        | /foo         | /xyz           | /xyz/
+foo/bar     | /foo         | <empty string> | /bar
+foo/        | /foo         | <empty string> | /
+foo         | /foo         | <empty string> | /
+foo/        | /foo         | /              | /
+foo         | /foo         | /              | /
+
++kubebuilder:validation:MaxLength=1024
++optional |  |
 | type | [HTTPPathModifierType](#http-path-modifier-type)| `HTTPPathModifierType` |  | |  |  |
 
 
@@ -8385,7 +9021,10 @@ query parameters.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Value | string| `string` |  | | Value is the value of HTTP query param to be matched.</br></br>+kubebuilder:validation:MinLength=1</br>+kubebuilder:validation:MaxLength=1024 |  |
+| Value | string| `string` |  | | Value is the value of HTTP query param to be matched.
+
++kubebuilder:validation:MinLength=1
++kubebuilder:validation:MaxLength=1024 |  |
 | name | [HTTPHeaderName](#http-header-name)| `HTTPHeaderName` |  | |  |  |
 | type | [QueryParamMatchType](#query-param-match-type)| `QueryParamMatchType` |  | |  |  |
 
@@ -8402,7 +9041,19 @@ query parameters.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
+| Percent | int32 (formatted integer)| `int32` |  | | Percent represents the percentage of requests that should be
+mirrored to BackendRef. Its minimum value is 0 (indicating 0% of
+requests) and its maximum value is 100 (indicating 100% of requests).
+
+Only one of Fraction or Percent may be specified. If neither field
+is specified, 100% of requests will be mirrored.
+
++optional
++kubebuilder:validation:Minimum=0
++kubebuilder:validation:Maximum=100
+<gateway:experimental> |  |
 | backendRef | [BackendObjectReference](#backend-object-reference)| `BackendObjectReference` |  | |  |  |
+| fraction | [Fraction](#fraction)| `Fraction` |  | |  |  |
 
 
 
@@ -8421,8 +9072,37 @@ MUST NOT be used on the same Route rule as a HTTPURLRewrite filter.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Scheme | string| `string` |  | | Scheme is the scheme to be used in the value of the `Location` header in</br>the response. When empty, the scheme of the request is used.</br></br>Scheme redirects can affect the port of the redirect, for more information,</br>refer to the documentation for the port field of this filter.</br></br>Note that values may be added to this enum, implementations</br>must ensure that unknown values will not cause a crash.</br></br>Unknown values here must result in the implementation setting the</br>Accepted Condition for the Route to `status: False`, with a</br>Reason of `UnsupportedValue`.</br></br>Support: Extended</br></br>+optional</br>+kubebuilder:validation:Enum=http;https |  |
-| StatusCode | int64 (formatted integer)| `int64` |  | | StatusCode is the HTTP status code to be used in response.</br></br>Note that values may be added to this enum, implementations</br>must ensure that unknown values will not cause a crash.</br></br>Unknown values here must result in the implementation setting the</br>Accepted Condition for the Route to `status: False`, with a</br>Reason of `UnsupportedValue`.</br></br>Support: Core</br></br>+optional</br>+kubebuilder:default=302</br>+kubebuilder:validation:Enum=301;302 |  |
+| Scheme | string| `string` |  | | Scheme is the scheme to be used in the value of the `Location` header in
+the response. When empty, the scheme of the request is used.
+
+Scheme redirects can affect the port of the redirect, for more information,
+refer to the documentation for the port field of this filter.
+
+Note that values may be added to this enum, implementations
+must ensure that unknown values will not cause a crash.
+
+Unknown values here must result in the implementation setting the
+Accepted Condition for the Route to `status: False`, with a
+Reason of `UnsupportedValue`.
+
+Support: Extended
+
++optional
++kubebuilder:validation:Enum=http;https |  |
+| StatusCode | int64 (formatted integer)| `int64` |  | | StatusCode is the HTTP status code to be used in response.
+
+Note that values may be added to this enum, implementations
+must ensure that unknown values will not cause a crash.
+
+Unknown values here must result in the implementation setting the
+Accepted Condition for the Route to `status: False`, with a
+Reason of `UnsupportedValue`.
+
+Support: Core
+
++optional
++kubebuilder:default=302
++kubebuilder:validation:Enum=301;302 |  |
 | hostname | [PreciseHostname](#precise-hostname)| `PreciseHostname` |  | |  |  |
 | path | [HTTPPathModifier](#http-path-modifier)| `HTTPPathModifier` |  | |  |  |
 | port | [PortNumber](#port-number)| `PortNumber` |  | |  |  |
@@ -8446,22 +9126,114 @@ requests should be routed.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| APIVersion | string| `string` |  | | APIVersion defines the versioned schema of this representation of an object.</br>Servers should convert recognized schemas to the latest internal value, and</br>may reject unrecognized values.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources</br>+optional |  |
-| Annotations | map of string| `map[string]string` |  | | Annotations is an unstructured key value map stored with a resource that may be</br>set by external tools to store and retrieve arbitrary metadata. They are not</br>queryable and should be preserved when modifying objects.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations</br>+optional |  |
-| CreationTimestamp | string| `string` |  | | CreationTimestamp is a timestamp representing the server time when this object was</br>created. It is not guaranteed to be set in happens-before order across separate operations.</br>Clients may not set this value. It is represented in RFC3339 form and is in UTC.</br></br>Populated by the system.</br>Read-only.</br>Null for lists.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| DeletionGracePeriodSeconds | int64 (formatted integer)| `int64` |  | | Number of seconds allowed for this object to gracefully terminate before</br>it will be removed from the system. Only set when deletionTimestamp is also set.</br>May only be shortened.</br>Read-only.</br>+optional |  |
-| DeletionTimestamp | string| `string` |  | | DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This</br>field is set by the server when a graceful deletion is requested by the user, and is not</br>directly settable by a client. The resource is expected to be deleted (no longer visible</br>from resource lists, and not reachable by name) after the time in this field, once the</br>finalizers list is empty. As long as the finalizers list contains items, deletion is blocked.</br>Once the deletionTimestamp is set, this value may not be unset or be set further into the</br>future, although it may be shortened or the resource may be deleted prior to this time.</br>For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react</br>by sending a graceful termination signal to the containers in the pod. After that 30 seconds,</br>the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,</br>remove the pod from the API. In the presence of network partitions, this object may still</br>exist after this timestamp, until an administrator or automated process can determine the</br>resource is fully terminated.</br>If not set, graceful deletion of the object has not been requested.</br></br>Populated by the system when a graceful deletion is requested.</br>Read-only.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| Finalizers | []string| `[]string` |  | | Must be empty before the object is deleted from the registry. Each entry</br>is an identifier for the responsible component that will remove the entry</br>from the list. If the deletionTimestamp of the object is non-nil, entries</br>in this list can only be removed.</br>Finalizers may be processed and removed in any order.  Order is NOT enforced</br>because it introduces significant risk of stuck finalizers.</br>finalizers is a shared field, any actor with permission can reorder it.</br>If the finalizer list is processed in order, then this can lead to a situation</br>in which the component responsible for the first finalizer in the list is</br>waiting for a signal (field value, external system, or other) produced by a</br>component responsible for a finalizer later in the list, resulting in a deadlock.</br>Without enforced ordering finalizers are free to order amongst themselves and</br>are not vulnerable to ordering changes in the list.</br>+optional</br>+patchStrategy=merge</br>+listType=set |  |
-| GenerateName | string| `string` |  | | GenerateName is an optional prefix, used by the server, to generate a unique</br>name ONLY IF the Name field has not been provided.</br>If this field is used, the name returned to the client will be different</br>than the name passed. This value will also be combined with a unique suffix.</br>The provided value has the same validation rules as the Name field,</br>and may be truncated by the length of the suffix required to make the value</br>unique on the server.</br></br>If this field is specified and the generated name exists, the server will return a 409.</br></br>Applied only if Name is not specified.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency</br>+optional |  |
-| Generation | int64 (formatted integer)| `int64` |  | | A sequence number representing a specific generation of the desired state.</br>Populated by the system. Read-only.</br>+optional |  |
-| Kind | string| `string` |  | | Kind is a string value representing the REST resource this object represents.</br>Servers may infer this from the endpoint the client submits requests to.</br>Cannot be updated.</br>In CamelCase.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds</br>+optional |  |
-| Labels | map of string| `map[string]string` |  | | Map of string keys and values that can be used to organize and categorize</br>(scope and select) objects. May match selectors of replication controllers</br>and services.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels</br>+optional |  |
-| ManagedFields | [][ManagedFieldsEntry](#managed-fields-entry)| `[]*ManagedFieldsEntry` |  | | ManagedFields maps workflow-id and version to the set of fields</br>that are managed by that workflow. This is mostly for internal</br>housekeeping, and users typically shouldn't need to set or</br>understand this field. A workflow can be the user's name, a</br>controller's name, or the name of a specific apply path like</br>"ci-cd". The set of fields is always in the version that the</br>workflow used when modifying the object.</br></br>+optional</br>+listType=atomic |  |
-| Name | string| `string` |  | | Name must be unique within a namespace. Is required when creating resources, although</br>some resources may allow a client to request the generation of an appropriate name</br>automatically. Name is primarily intended for creation idempotence and configuration</br>definition.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names</br>+optional |  |
-| Namespace | string| `string` |  | | Namespace defines the space within which each name must be unique. An empty namespace is</br>equivalent to the "default" namespace, but "default" is the canonical representation.</br>Not all objects are required to be scoped to a namespace - the value of this field for</br>those objects will be empty.</br></br>Must be a DNS_LABEL.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces</br>+optional |  |
-| OwnerReferences | [][OwnerReference](#owner-reference)| `[]*OwnerReference` |  | | List of objects depended by this object. If ALL objects in the list have</br>been deleted, this object will be garbage collected. If this object is managed by a controller,</br>then an entry in this list will point to this controller, with the controller field set to true.</br>There cannot be more than one managing controller.</br>+optional</br>+patchMergeKey=uid</br>+patchStrategy=merge</br>+listType=map</br>+listMapKey=uid |  |
-| ResourceVersion | string| `string` |  | | An opaque value that represents the internal version of this object that can</br>be used by clients to determine when objects have changed. May be used for optimistic</br>concurrency, change detection, and the watch operation on a resource or set of resources.</br>Clients must treat these values as opaque and passed unmodified back to the server.</br>They may only be valid for a particular resource or set of resources.</br></br>Populated by the system.</br>Read-only.</br>Value must be treated as opaque by clients and .</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency</br>+optional |  |
-| SelfLink | string| `string` |  | | Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.</br>+optional |  |
+| APIVersion | string| `string` |  | | APIVersion defines the versioned schema of this representation of an object.
+Servers should convert recognized schemas to the latest internal value, and
+may reject unrecognized values.
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
++optional |  |
+| Annotations | map of string| `map[string]string` |  | | Annotations is an unstructured key value map stored with a resource that may be
+set by external tools to store and retrieve arbitrary metadata. They are not
+queryable and should be preserved when modifying objects.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations
++optional |  |
+| DeletionGracePeriodSeconds | int64 (formatted integer)| `int64` |  | | Number of seconds allowed for this object to gracefully terminate before
+it will be removed from the system. Only set when deletionTimestamp is also set.
+May only be shortened.
+Read-only.
++optional |  |
+| Finalizers | []string| `[]string` |  | | Must be empty before the object is deleted from the registry. Each entry
+is an identifier for the responsible component that will remove the entry
+from the list. If the deletionTimestamp of the object is non-nil, entries
+in this list can only be removed.
+Finalizers may be processed and removed in any order.  Order is NOT enforced
+because it introduces significant risk of stuck finalizers.
+finalizers is a shared field, any actor with permission can reorder it.
+If the finalizer list is processed in order, then this can lead to a situation
+in which the component responsible for the first finalizer in the list is
+waiting for a signal (field value, external system, or other) produced by a
+component responsible for a finalizer later in the list, resulting in a deadlock.
+Without enforced ordering finalizers are free to order amongst themselves and
+are not vulnerable to ordering changes in the list.
++optional
++patchStrategy=merge
++listType=set |  |
+| GenerateName | string| `string` |  | | GenerateName is an optional prefix, used by the server, to generate a unique
+name ONLY IF the Name field has not been provided.
+If this field is used, the name returned to the client will be different
+than the name passed. This value will also be combined with a unique suffix.
+The provided value has the same validation rules as the Name field,
+and may be truncated by the length of the suffix required to make the value
+unique on the server.
+
+If this field is specified and the generated name exists, the server will return a 409.
+
+Applied only if Name is not specified.
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency
++optional |  |
+| Generation | int64 (formatted integer)| `int64` |  | | A sequence number representing a specific generation of the desired state.
+Populated by the system. Read-only.
++optional |  |
+| Kind | string| `string` |  | | Kind is a string value representing the REST resource this object represents.
+Servers may infer this from the endpoint the client submits requests to.
+Cannot be updated.
+In CamelCase.
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
++optional |  |
+| Labels | map of string| `map[string]string` |  | | Map of string keys and values that can be used to organize and categorize
+(scope and select) objects. May match selectors of replication controllers
+and services.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels
++optional |  |
+| ManagedFields | [][ManagedFieldsEntry](#managed-fields-entry)| `[]*ManagedFieldsEntry` |  | | ManagedFields maps workflow-id and version to the set of fields
+that are managed by that workflow. This is mostly for internal
+housekeeping, and users typically shouldn't need to set or
+understand this field. A workflow can be the user's name, a
+controller's name, or the name of a specific apply path like
+"ci-cd". The set of fields is always in the version that the
+workflow used when modifying the object.
+
++optional
++listType=atomic |  |
+| Name | string| `string` |  | | Name must be unique within a namespace. Is required when creating resources, although
+some resources may allow a client to request the generation of an appropriate name
+automatically. Name is primarily intended for creation idempotence and configuration
+definition.
+Cannot be updated.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names
++optional |  |
+| Namespace | string| `string` |  | | Namespace defines the space within which each name must be unique. An empty namespace is
+equivalent to the "default" namespace, but "default" is the canonical representation.
+Not all objects are required to be scoped to a namespace - the value of this field for
+those objects will be empty.
+
+Must be a DNS_LABEL.
+Cannot be updated.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces
++optional |  |
+| OwnerReferences | [][OwnerReference](#owner-reference)| `[]*OwnerReference` |  | | List of objects depended by this object. If ALL objects in the list have
+been deleted, this object will be garbage collected. If this object is managed by a controller,
+then an entry in this list will point to this controller, with the controller field set to true.
+There cannot be more than one managing controller.
++optional
++patchMergeKey=uid
++patchStrategy=merge
++listType=map
++listMapKey=uid |  |
+| ResourceVersion | string| `string` |  | | An opaque value that represents the internal version of this object that can
+be used by clients to determine when objects have changed. May be used for optimistic
+concurrency, change detection, and the watch operation on a resource or set of resources.
+Clients must treat these values as opaque and passed unmodified back to the server.
+They may only be valid for a particular resource or set of resources.
+
+Populated by the system.
+Read-only.
+Value must be treated as opaque by clients and .
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
++optional |  |
+| SelfLink | string| `string` |  | | Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.
++optional |  |
+| creationTimestamp | [Time](#time)| `Time` |  | |  |  |
+| deletionTimestamp | [Time](#time)| `Time` |  | |  |  |
 | spec | [HTTPRouteSpec](#http-route-spec)| `HTTPRouteSpec` |  | |  |  |
 | status | [HTTPRouteStatus](#http-route-status)| `HTTPRouteStatus` |  | |  |  |
 | uid | [UID](#uid)| `UID` |  | |  |  |
@@ -8540,13 +9312,110 @@ value "v1"
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Headers | [][HTTPHeaderMatch](#http-header-match)| `[]*HTTPHeaderMatch` |  | | Headers specifies HTTP request header matchers. Multiple match values are</br>ANDed together, meaning, a request must match all the specified headers</br>to select the route.</br></br>+listType=map</br>+listMapKey=name</br>+optional</br>+kubebuilder:validation:MaxItems=16 |  |
-| QueryParams | [][HTTPQueryParamMatch](#http-query-param-match)| `[]*HTTPQueryParamMatch` |  | | QueryParams specifies HTTP query parameter matchers. Multiple match</br>values are ANDed together, meaning, a request must match all the</br>specified query parameters to select the route.</br></br>Support: Extended</br></br>+listType=map</br>+listMapKey=name</br>+optional</br>+kubebuilder:validation:MaxItems=16 |  |
+| Headers | [][HTTPHeaderMatch](#http-header-match)| `[]*HTTPHeaderMatch` |  | | Headers specifies HTTP request header matchers. Multiple match values are
+ANDed together, meaning, a request must match all the specified headers
+to select the route.
+
++listType=map
++listMapKey=name
++optional
++kubebuilder:validation:MaxItems=16 |  |
+| QueryParams | [][HTTPQueryParamMatch](#http-query-param-match)| `[]*HTTPQueryParamMatch` |  | | QueryParams specifies HTTP query parameter matchers. Multiple match
+values are ANDed together, meaning, a request must match all the
+specified query parameters to select the route.
+
+Support: Extended
+
++listType=map
++listMapKey=name
++optional
++kubebuilder:validation:MaxItems=16 |  |
 | method | [HTTPMethod](#http-method)| `HTTPMethod` |  | |  |  |
 | path | [HTTPPathMatch](#http-path-match)| `HTTPPathMatch` |  | |  |  |
 
 
 
+### <span id="http-route-retry"></span> HTTPRouteRetry
+
+
+> Implementations SHOULD retry on connection errors (disconnect, reset, timeout,
+TCP failure) if a retry stanza is configured.
+  
+
+
+
+
+
+**Properties**
+
+| Name | Type | Go type | Required | Default | Description | Example |
+|------|------|---------|:--------:| ------- |-------------|---------|
+| Attempts | int64 (formatted integer)| `int64` |  | | Attempts specifies the maxmimum number of times an individual request
+from the gateway to a backend should be retried.
+
+If the maximum number of retries has been attempted without a successful
+response from the backend, the Gateway MUST return an error.
+
+When this field is unspecified, the number of times to attempt to retry
+a backend request is implementation-specific.
+
+Support: Extended
+
++optional |  |
+| Codes | [][HTTPRouteRetryStatusCode](#http-route-retry-status-code)| `[]HTTPRouteRetryStatusCode` |  | | Codes defines the HTTP response status codes for which a backend request
+should be retried.
+
+Support: Extended
+
++optional |  |
+| backoff | [Duration](#duration)| `Duration` |  | |  |  |
+
+
+
+### <span id="http-route-retry-status-code"></span> HTTPRouteRetryStatusCode
+
+
+> Implementations MUST support the following status codes as retryable:
+
+500
+502
+503
+504
+
+Implementations MAY support specifying additional discrete values in the
+500-599 range.
+
+Implementations MAY support specifying discrete values in the 400-499 range,
+which are often inadvisable to retry.
+
++kubebuilder:validation:Minimum:=400
++kubebuilder:validation:Maximum:=599
+<gateway:experimental>
+  
+
+
+
+| Name | Type | Go type | Default | Description | Example |
+|------|------|---------| ------- |-------------|---------|
+| HTTPRouteRetryStatusCode | int64 (formatted integer)| int64 | | Implementations MUST support the following status codes as retryable:
+
+500
+502
+503
+504
+
+Implementations MAY support specifying additional discrete values in the
+500-599 range.
+
+Implementations MAY support specifying discrete values in the 400-499 range,
+which are often inadvisable to retry.
+
++kubebuilder:validation:Minimum:=400
++kubebuilder:validation:Maximum:=599
+<gateway:experimental> |  |
+
+
+
 ### <span id="http-route-rule"></span> HTTPRouteRule
 
 
@@ -8565,9 +9434,150 @@ value "v1"
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| BackendRefs | [][HTTPBackendRef](#http-backend-ref)| `[]*HTTPBackendRef` |  | | BackendRefs defines the backend(s) where matching requests should be</br>sent.</br></br>Failure behavior here depends on how many BackendRefs are specified and</br>how many are invalid.</br></br>If *all* entries in BackendRefs are invalid, and there are also no filters</br>specified in this route rule, *all* traffic which matches this rule MUST</br>receive a 500 status code.</br></br>See the HTTPBackendRef definition for the rules about what makes a single</br>HTTPBackendRef invalid.</br></br>When a HTTPBackendRef is invalid, 500 status codes MUST be returned for</br>requests that would have otherwise been routed to an invalid backend. If</br>multiple backends are specified, and some are invalid, the proportion of</br>requests that would otherwise have been routed to an invalid backend</br>MUST receive a 500 status code.</br></br>For example, if two backends are specified with equal weights, and one is</br>invalid, 50 percent of traffic must receive a 500. Implementations may</br>choose how that 50 percent is determined.</br></br>Support: Core for Kubernetes Service</br></br>Support: Extended for Kubernetes ServiceImport</br></br>Support: Implementation-specific for any other resource</br></br>Support for weight: Core</br></br>+optional</br>+kubebuilder:validation:MaxItems=16 |  |
-| Filters | [][HTTPRouteFilter](#http-route-filter)| `[]*HTTPRouteFilter` |  | | Filters define the filters that are applied to requests that match</br>this rule.</br></br>Wherever possible, implementations SHOULD implement filters in the order</br>they are specified.</br></br>Implementations MAY choose to implement this ordering strictly, rejecting</br>any combination or order of filters that can not be supported. If implementations</br>choose a strict interpretation of filter ordering, they MUST clearly document</br>that behavior.</br></br>To reject an invalid combination or order of filters, implementations SHOULD</br>consider the Route Rules with this configuration invalid. If all Route Rules</br>in a Route are invalid, the entire Route would be considered invalid. If only</br>a portion of Route Rules are invalid, implementations MUST set the</br>"PartiallyInvalid" condition for the Route.</br></br>Conformance-levels at this level are defined based on the type of filter:</br></br>ALL core filters MUST be supported by all implementations.</br>Implementers are encouraged to support extended filters.</br>Implementation-specific custom filters have no API guarantees across</br>implementations.</br></br>Specifying the same filter multiple times is not supported unless explicitly</br>indicated in the filter.</br></br>All filters are expected to be compatible with each other except for the</br>URLRewrite and RequestRedirect filters, which may not be combined. If an</br>implementation can not support other combinations of filters, they must clearly</br>document that limitation. In cases where incompatible or unsupported</br>filters are specified and cause the `Accepted` condition to be set to status</br>`False`, implementations may use the `IncompatibleFilters` reason to specify</br>this configuration error.</br></br>Support: Core</br></br>+optional</br>+kubebuilder:validation:MaxItems=16</br>+kubebuilder:validation:XValidation:message="May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both",rule="!(self.exists(f, f.type == 'RequestRedirect') && self.exists(f, f.type == 'URLRewrite'))"</br>+kubebuilder:validation:XValidation:message="RequestHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'RequestHeaderModifier').size() <= 1"</br>+kubebuilder:validation:XValidation:message="ResponseHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'ResponseHeaderModifier').size() <= 1"</br>+kubebuilder:validation:XValidation:message="RequestRedirect filter cannot be repeated",rule="self.filter(f, f.type == 'RequestRedirect').size() <= 1"</br>+kubebuilder:validation:XValidation:message="URLRewrite filter cannot be repeated",rule="self.filter(f, f.type == 'URLRewrite').size() <= 1" |  |
-| Matches | [][HTTPRouteMatch](#http-route-match)| `[]*HTTPRouteMatch` |  | | Matches define conditions used for matching the rule against incoming</br>HTTP requests. Each match is independent, i.e. this rule will be matched</br>if **any** one of the matches is satisfied.</br></br>For example, take the following matches configuration:</br></br>```</br>matches:</br>path:</br>value: "/foo"</br>headers:</br>name: "version"</br>value: "v2"</br>path:</br>value: "/v2/foo"</br>```</br></br>For a request to match against this rule, a request must satisfy</br>EITHER of the two conditions:</br></br>path prefixed with `/foo` AND contains the header `version: v2`</br>path prefix of `/v2/foo`</br></br>See the documentation for HTTPRouteMatch on how to specify multiple</br>match conditions that should be ANDed together.</br></br>If no matches are specified, the default is a prefix</br>path match on "/", which has the effect of matching every</br>HTTP request.</br></br>Proxy or Load Balancer routing configuration generated from HTTPRoutes</br>MUST prioritize matches based on the following criteria, continuing on</br>ties. Across all rules specified on applicable Routes, precedence must be</br>given to the match having:</br></br>"Exact" path match.</br>"Prefix" path match with largest number of characters.</br>Method match.</br>Largest number of header matches.</br>Largest number of query param matches.</br></br>Note: The precedence of RegularExpression path matches are implementation-specific.</br></br>If ties still exist across multiple Routes, matching precedence MUST be</br>determined in order of the following criteria, continuing on ties:</br></br>The oldest Route based on creation timestamp.</br>The Route appearing first in alphabetical order by</br>"{namespace}/{name}".</br></br>If ties still exist within an HTTPRoute, matching precedence MUST be granted</br>to the FIRST matching rule (in list order) with a match meeting the above</br>criteria.</br></br>When no rules matching a request have been successfully attached to the</br>parent a request is coming from, a HTTP 404 status code MUST be returned.</br></br>+optional</br>+kubebuilder:validation:MaxItems=8</br>+kubebuilder:default={{path:{ type: "PathPrefix", value: "/"}}} |  |
+| BackendRefs | [][HTTPBackendRef](#http-backend-ref)| `[]*HTTPBackendRef` |  | | BackendRefs defines the backend(s) where matching requests should be
+sent.
+
+Failure behavior here depends on how many BackendRefs are specified and
+how many are invalid.
+
+If *all* entries in BackendRefs are invalid, and there are also no filters
+specified in this route rule, *all* traffic which matches this rule MUST
+receive a 500 status code.
+
+See the HTTPBackendRef definition for the rules about what makes a single
+HTTPBackendRef invalid.
+
+When a HTTPBackendRef is invalid, 500 status codes MUST be returned for
+requests that would have otherwise been routed to an invalid backend. If
+multiple backends are specified, and some are invalid, the proportion of
+requests that would otherwise have been routed to an invalid backend
+MUST receive a 500 status code.
+
+For example, if two backends are specified with equal weights, and one is
+invalid, 50 percent of traffic must receive a 500. Implementations may
+choose how that 50 percent is determined.
+
+When a HTTPBackendRef refers to a Service that has no ready endpoints,
+implementations SHOULD return a 503 for requests to that backend instead.
+If an implementation chooses to do this, all of the above rules for 500 responses
+MUST also apply for responses that return a 503.
+
+Support: Core for Kubernetes Service
+
+Support: Extended for Kubernetes ServiceImport
+
+Support: Implementation-specific for any other resource
+
+Support for weight: Core
+
++optional
++kubebuilder:validation:MaxItems=16 |  |
+| Filters | [][HTTPRouteFilter](#http-route-filter)| `[]*HTTPRouteFilter` |  | | Filters define the filters that are applied to requests that match
+this rule.
+
+Wherever possible, implementations SHOULD implement filters in the order
+they are specified.
+
+Implementations MAY choose to implement this ordering strictly, rejecting
+any combination or order of filters that can not be supported. If implementations
+choose a strict interpretation of filter ordering, they MUST clearly document
+that behavior.
+
+To reject an invalid combination or order of filters, implementations SHOULD
+consider the Route Rules with this configuration invalid. If all Route Rules
+in a Route are invalid, the entire Route would be considered invalid. If only
+a portion of Route Rules are invalid, implementations MUST set the
+"PartiallyInvalid" condition for the Route.
+
+Conformance-levels at this level are defined based on the type of filter:
+
+ALL core filters MUST be supported by all implementations.
+Implementers are encouraged to support extended filters.
+Implementation-specific custom filters have no API guarantees across
+implementations.
+
+Specifying the same filter multiple times is not supported unless explicitly
+indicated in the filter.
+
+All filters are expected to be compatible with each other except for the
+URLRewrite and RequestRedirect filters, which may not be combined. If an
+implementation can not support other combinations of filters, they must clearly
+document that limitation. In cases where incompatible or unsupported
+filters are specified and cause the `Accepted` condition to be set to status
+`False`, implementations may use the `IncompatibleFilters` reason to specify
+this configuration error.
+
+Support: Core
+
++optional
++kubebuilder:validation:MaxItems=16
++kubebuilder:validation:XValidation:message="May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both",rule="!(self.exists(f, f.type == 'RequestRedirect') && self.exists(f, f.type == 'URLRewrite'))"
++kubebuilder:validation:XValidation:message="RequestHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'RequestHeaderModifier').size() <= 1"
++kubebuilder:validation:XValidation:message="ResponseHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'ResponseHeaderModifier').size() <= 1"
++kubebuilder:validation:XValidation:message="RequestRedirect filter cannot be repeated",rule="self.filter(f, f.type == 'RequestRedirect').size() <= 1"
++kubebuilder:validation:XValidation:message="URLRewrite filter cannot be repeated",rule="self.filter(f, f.type == 'URLRewrite').size() <= 1" |  |
+| Matches | [][HTTPRouteMatch](#http-route-match)| `[]*HTTPRouteMatch` |  | | Matches define conditions used for matching the rule against incoming
+HTTP requests. Each match is independent, i.e. this rule will be matched
+if **any** one of the matches is satisfied.
+
+For example, take the following matches configuration:
+
+```
+matches:
+path:
+value: "/foo"
+headers:
+name: "version"
+value: "v2"
+path:
+value: "/v2/foo"
+```
+
+For a request to match against this rule, a request must satisfy
+EITHER of the two conditions:
+
+path prefixed with `/foo` AND contains the header `version: v2`
+path prefix of `/v2/foo`
+
+See the documentation for HTTPRouteMatch on how to specify multiple
+match conditions that should be ANDed together.
+
+If no matches are specified, the default is a prefix
+path match on "/", which has the effect of matching every
+HTTP request.
+
+Proxy or Load Balancer routing configuration generated from HTTPRoutes
+MUST prioritize matches based on the following criteria, continuing on
+ties. Across all rules specified on applicable Routes, precedence must be
+given to the match having:
+
+"Exact" path match.
+"Prefix" path match with largest number of characters.
+Method match.
+Largest number of header matches.
+Largest number of query param matches.
+
+Note: The precedence of RegularExpression path matches are implementation-specific.
+
+If ties still exist across multiple Routes, matching precedence MUST be
+determined in order of the following criteria, continuing on ties:
+
+The oldest Route based on creation timestamp.
+The Route appearing first in alphabetical order by
+"{namespace}/{name}".
+
+If ties still exist within an HTTPRoute, matching precedence MUST be granted
+to the FIRST matching rule (in list order) with a match meeting the above
+criteria.
+
+When no rules matching a request have been successfully attached to the
+parent a request is coming from, a HTTP 404 status code MUST be returned.
+
++optional
++kubebuilder:validation:MaxItems=64
++kubebuilder:default={{path:{ type: "PathPrefix", value: "/"}}} |  |
+| name | [SectionName](#section-name)| `SectionName` |  | |  |  |
+| retry | [HTTPRouteRetry](#http-route-retry)| `HTTPRouteRetry` |  | |  |  |
 | sessionPersistence | [SessionPersistence](#session-persistence)| `SessionPersistence` |  | |  |  |
 | timeouts | [HTTPRouteTimeouts](#http-route-timeouts)| `HTTPRouteTimeouts` |  | |  |  |
 
@@ -8587,9 +9597,97 @@ value "v1"
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Hostnames | [][Hostname](#hostname)| `[]Hostname` |  | | Hostnames defines a set of hostnames that should match against the HTTP Host</br>header to select a HTTPRoute used to process the request. Implementations</br>MUST ignore any port value specified in the HTTP Host header while</br>performing a match and (absent of any applicable header modification</br>configuration) MUST forward this header unmodified to the backend.</br></br>Valid values for Hostnames are determined by RFC 1123 definition of a</br>hostname with 2 notable exceptions:</br></br>1. IPs are not allowed.</br>2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard</br>label must appear by itself as the first label.</br></br>If a hostname is specified by both the Listener and HTTPRoute, there</br>must be at least one intersecting hostname for the HTTPRoute to be |  |
-| ParentRefs | [][ParentReference](#parent-reference)| `[]*ParentReference` |  | | ParentRefs references the resources (usually Gateways) that a Route wants</br>to be attached to. Note that the referenced parent resource needs to</br>allow this for the attachment to be complete. For Gateways, that means</br>the Gateway needs to allow attachment from Routes of this kind and</br>namespace. For Services, that means the Service must either be in the same</br>namespace for a "producer" route, or the mesh implementation must support</br>and allow "consumer" routes for the referenced Service. ReferenceGrant is</br>not applicable for governing ParentRefs to Services - it is not possible to</br>create a "producer" route for a Service in a different namespace from the</br>Route.</br></br>There are two kinds of parent resources with "Core" support:</br></br>Gateway (Gateway conformance profile)</br>Service (Mesh conformance profile, ClusterIP Services only)</br></br>This API may be extended in the future to support additional kinds of parent</br>resources.</br></br>ParentRefs must be _distinct_. This means either that:</br></br>They select different objects.  If this is the case, then parentRef</br>entries are distinct. In terms of fields, this means that the</br>multi-part key defined by `group`, `kind`, `namespace`, and `name` must</br>be unique across all parentRef entries in the Route.</br>They do not select different objects, but for each optional field used,</br>each ParentRef that selects the same object must set the same set of</br>optional fields to different values. If one ParentRef sets a</br>combination of optional fields, all must set the same combination.</br></br>Some examples:</br></br>If one ParentRef sets `sectionName`, all ParentRefs referencing the</br>same object must also set `sectionName`.</br>If one ParentRef sets `port`, all ParentRefs referencing the same</br>object must also set `port`.</br>If one ParentRef sets `sectionName` and `port`, all ParentRefs</br>referencing the same object must also set `sectionName` and `port`.</br></br>It is possible to separately reference multiple distinct objects that may</br>be collapsed by an implementation. For example, some implementations may</br>choose to merge compatible Gateway Listeners together. If that is the</br>case, the list of routes attached to those resources should also be</br>merged.</br></br>Note that for ParentRefs that cross namespace boundaries, there are specific</br>rules. Cross-namespace references are only valid if they are explicitly</br>allowed by something in the namespace they are referring to. For example,</br>Gateway has the AllowedRoutes field, and ReferenceGrant provides a</br>generic way to enable other kinds of cross-namespace reference.</br></br><gateway:experimental:description></br>ParentRefs from a Route to a Service in the same namespace are "producer"</br>routes, which apply default routing rules to inbound connections from</br>any namespace to the Service.</br></br>ParentRefs from a Route to a Service in a different namespace are</br>"consumer" routes, and these routing rules are only applied to outbound</br>connections originating from the same namespace as the Route, for which</br>the intended destination of the connections are a Service targeted as a</br>ParentRef of the Route.</br></gateway:experimental:description></br></br>+optional</br>+kubebuilder:validation:MaxItems=32</br><gateway:standard:validation:XValidation:message="sectionName must be specified when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.all(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__ )) ? ((!has(p1.sectionName) || p1.sectionName == '') == (!has(p2.sectionName) || p2.sectionName == '')) : true))"></br><gateway:standard:validation:XValidation:message="sectionName must be unique when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName == '')) || (has(p1.sectionName) && has(p2.sectionName) && p1.sectionName == p2.sectionName))))"></br><gateway:experimental:validation:XValidation:message="sectionName or port must be specified when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.all(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__)) ? ((!has(p1.sectionName) || p1.sectionName == '') == (!has(p2.sectionName) || p2.sectionName == '') && (!has(p1.port) || p1.port == 0) == (!has(p2.port) || p2.port == 0)): true))"></br><gateway:experimental:validation:XValidation:message="sectionName or port must be unique when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName == '')) || ( has(p1.sectionName) && has(p2.sectionName) && p1.sectionName == p2.sectionName)) && (((!has(p1.port) || p1.port == 0) && (!has(p2.port) || p2.port == 0)) || (has(p1.port) && has(p2.port) && p1.port == p2.port))))"> |  |
-| Rules | [][HTTPRouteRule](#http-route-rule)| `[]*HTTPRouteRule` |  | | Rules are a list of HTTP matchers, filters and actions.</br></br>+optional</br>+kubebuilder:validation:MaxItems=16</br>+kubebuilder:default={{matches: {{path: {type: "PathPrefix", value: "/"}}}}} |  |
+| Hostnames | [][Hostname](#hostname)| `[]Hostname` |  | | Hostnames defines a set of hostnames that should match against the HTTP Host
+header to select a HTTPRoute used to process the request. Implementations
+MUST ignore any port value specified in the HTTP Host header while
+performing a match and (absent of any applicable header modification
+configuration) MUST forward this header unmodified to the backend.
+
+Valid values for Hostnames are determined by RFC 1123 definition of a
+hostname with 2 notable exceptions:
+
+1. IPs are not allowed.
+2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard
+label must appear by itself as the first label.
+
+If a hostname is specified by both the Listener and HTTPRoute, there
+must be at least one intersecting hostname for the HTTPRoute to be |  |
+| ParentRefs | [][ParentReference](#parent-reference)| `[]*ParentReference` |  | | ParentRefs references the resources (usually Gateways) that a Route wants
+to be attached to. Note that the referenced parent resource needs to
+allow this for the attachment to be complete. For Gateways, that means
+the Gateway needs to allow attachment from Routes of this kind and
+namespace. For Services, that means the Service must either be in the same
+namespace for a "producer" route, or the mesh implementation must support
+and allow "consumer" routes for the referenced Service. ReferenceGrant is
+not applicable for governing ParentRefs to Services - it is not possible to
+create a "producer" route for a Service in a different namespace from the
+Route.
+
+There are two kinds of parent resources with "Core" support:
+
+Gateway (Gateway conformance profile)
+Service (Mesh conformance profile, ClusterIP Services only)
+
+This API may be extended in the future to support additional kinds of parent
+resources.
+
+ParentRefs must be _distinct_. This means either that:
+
+They select different objects.  If this is the case, then parentRef
+entries are distinct. In terms of fields, this means that the
+multi-part key defined by `group`, `kind`, `namespace`, and `name` must
+be unique across all parentRef entries in the Route.
+They do not select different objects, but for each optional field used,
+each ParentRef that selects the same object must set the same set of
+optional fields to different values. If one ParentRef sets a
+combination of optional fields, all must set the same combination.
+
+Some examples:
+
+If one ParentRef sets `sectionName`, all ParentRefs referencing the
+same object must also set `sectionName`.
+If one ParentRef sets `port`, all ParentRefs referencing the same
+object must also set `port`.
+If one ParentRef sets `sectionName` and `port`, all ParentRefs
+referencing the same object must also set `sectionName` and `port`.
+
+It is possible to separately reference multiple distinct objects that may
+be collapsed by an implementation. For example, some implementations may
+choose to merge compatible Gateway Listeners together. If that is the
+case, the list of routes attached to those resources should also be
+merged.
+
+Note that for ParentRefs that cross namespace boundaries, there are specific
+rules. Cross-namespace references are only valid if they are explicitly
+allowed by something in the namespace they are referring to. For example,
+Gateway has the AllowedRoutes field, and ReferenceGrant provides a
+generic way to enable other kinds of cross-namespace reference.
+
+<gateway:experimental:description>
+ParentRefs from a Route to a Service in the same namespace are "producer"
+routes, which apply default routing rules to inbound connections from
+any namespace to the Service.
+
+ParentRefs from a Route to a Service in a different namespace are
+"consumer" routes, and these routing rules are only applied to outbound
+connections originating from the same namespace as the Route, for which
+the intended destination of the connections are a Service targeted as a
+ParentRef of the Route.
+</gateway:experimental:description>
+
++optional
++kubebuilder:validation:MaxItems=32
+<gateway:standard:validation:XValidation:message="sectionName must be specified when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.all(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__ )) ? ((!has(p1.sectionName) || p1.sectionName == '') == (!has(p2.sectionName) || p2.sectionName == '')) : true))">
+<gateway:standard:validation:XValidation:message="sectionName must be unique when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName == '')) || (has(p1.sectionName) && has(p2.sectionName) && p1.sectionName == p2.sectionName))))">
+<gateway:experimental:validation:XValidation:message="sectionName or port must be specified when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.all(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__)) ? ((!has(p1.sectionName) || p1.sectionName == '') == (!has(p2.sectionName) || p2.sectionName == '') && (!has(p1.port) || p1.port == 0) == (!has(p2.port) || p2.port == 0)): true))">
+<gateway:experimental:validation:XValidation:message="sectionName or port must be unique when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName == '')) || ( has(p1.sectionName) && has(p2.sectionName) && p1.sectionName == p2.sectionName)) && (((!has(p1.port) || p1.port == 0) && (!has(p2.port) || p2.port == 0)) || (has(p1.port) && has(p2.port) && p1.port == p2.port))))"> |  |
+| Rules | [][HTTPRouteRule](#http-route-rule)| `[]*HTTPRouteRule` |  | | Rules are a list of HTTP matchers, filters and actions.
+
++optional
+<gateway:experimental:validation:XValidation:message="Rule name must be unique within the route",rule="self.all(l1, !has(l1.name) || self.exists_one(l2, has(l2.name) && l1.name == l2.name))">
++kubebuilder:validation:MaxItems=16
++kubebuilder:default={{matches: {{path: {type: "PathPrefix", value: "/"}}}}}
++kubebuilder:validation:XValidation:message="While 16 rules and 64 matches per rule are allowed, the total number of matches across all rules in a route must be less than 128",rule="(self.size() > 0 ? self[0].matches.size() : 0) + (self.size() > 1 ? self[1].matches.size() : 0) + (self.size() > 2 ? self[2].matches.size() : 0) + (self.size() > 3 ? self[3].matches.size() : 0) + (self.size() > 4 ? self[4].matches.size() : 0) + (self.size() > 5 ? self[5].matches.size() : 0) + (self.size() > 6 ? self[6].matches.size() : 0) + (self.size() > 7 ? self[7].matches.size() : 0) + (self.size() > 8 ? self[8].matches.size() : 0) + (self.size() > 9 ? self[9].matches.size() : 0) + (self.size() > 10 ? self[10].matches.size() : 0) + (self.size() > 11 ? self[11].matches.size() : 0) + (self.size() > 12 ? self[12].matches.size() : 0) + (self.size() > 13 ? self[13].matches.size() : 0) + (self.size() > 14 ? self[14].matches.size() : 0) + (self.size() > 15 ? self[15].matches.size() : 0) <= 128" |  |
 
 
 
@@ -8604,7 +9702,22 @@ value "v1"
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Parents | [][RouteParentStatus](#route-parent-status)| `[]*RouteParentStatus` |  | | Parents is a list of parent resources (usually Gateways) that are</br>associated with the route, and the status of the route with respect to</br>each parent. When this route attaches to a parent, the controller that</br>manages the parent must add an entry to this list when the controller</br>first sees the route and should update the entry as appropriate when the</br>route or gateway is modified.</br></br>Note that parent references that cannot be resolved by an implementation</br>of this API will not be added to this list. Implementations of this API</br>can only populate Route status for the Gateways/parent resources they are</br>responsible for.</br></br>A maximum of 32 Gateways will be represented in this list. An empty list</br>means the route has not been attached to any Gateway.</br></br>+kubebuilder:validation:MaxItems=32 |  |
+| Parents | [][RouteParentStatus](#route-parent-status)| `[]*RouteParentStatus` |  | | Parents is a list of parent resources (usually Gateways) that are
+associated with the route, and the status of the route with respect to
+each parent. When this route attaches to a parent, the controller that
+manages the parent must add an entry to this list when the controller
+first sees the route and should update the entry as appropriate when the
+route or gateway is modified.
+
+Note that parent references that cannot be resolved by an implementation
+of this API will not be added to this list. Implementations of this API
+can only populate Route status for the Gateways/parent resources they are
+responsible for.
+
+A maximum of 32 Gateways will be represented in this list. An empty list
+means the route has not been attached to any Gateway.
+
++kubebuilder:validation:MaxItems=32 |  |
 
 
 
@@ -8666,7 +9779,17 @@ Reason of `UnsupportedValue`.
 
 | Name | Type | Go type | Default | Description | Example |
 |------|------|---------| ------- |-------------|---------|
-| HeaderMatchType | string| string | | "Exact" - Core</br>"RegularExpression" - Implementation Specific</br></br>Note that values may be added to this enum, implementations</br>must ensure that unknown values will not cause a crash.</br></br>Unknown values here must result in the implementation setting the</br>Accepted Condition for the Route to `status: False`, with a</br>Reason of `UnsupportedValue`.</br></br>+kubebuilder:validation:Enum=Exact;RegularExpression |  |
+| HeaderMatchType | string| string | | "Exact" - Core
+"RegularExpression" - Implementation Specific
+
+Note that values may be added to this enum, implementations
+must ensure that unknown values will not cause a crash.
+
+Unknown values here must result in the implementation setting the
+Accepted Condition for the Route to `status: False`, with a
+Reason of `UnsupportedValue`.
+
++kubebuilder:validation:Enum=Exact;RegularExpression |  |
 
 
 
@@ -8683,7 +9806,10 @@ Reason of `UnsupportedValue`.
 
 | Name | Type | Go type | Default | Description | Example |
 |------|------|---------| ------- |-------------|---------|
-| HeaderName | string| string | | +kubebuilder:validation:MinLength=1</br>+kubebuilder:validation:MaxLength=256</br>+kubebuilder:validation:Pattern=`^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$`</br>+k8s:deepcopy-gen=false |  |
+| HeaderName | string| string | | +kubebuilder:validation:MinLength=1
++kubebuilder:validation:MaxLength=256
++kubebuilder:validation:Pattern=`^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$`
++k8s:deepcopy-gen=false |  |
 
 
 
@@ -8712,7 +9838,9 @@ Reason of `UnsupportedValue`.
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
 | Cluster | string| `string` |  | |  |  |
-| CompleteInput | boolean| `bool` |  | | CompleteInput is true when Service, Namespace and Cluster fields are present.</br>It is true for simple service names and FQDN services.</br>It is false for service.namespace format and service entries. |  |
+| CompleteInput | boolean| `bool` |  | | CompleteInput is true when Service, Namespace and Cluster fields are present.
+It is true for simple service names and FQDN services.
+It is false for service.namespace format and service entries. |  |
 | Namespace | string| `string` |  | |  |  |
 | Service | string| `string` |  | |  |  |
 
@@ -8740,170 +9868,55 @@ character. No other punctuation is allowed.
 
 
 
-| Name | Type | Go type | Default | Description | Example |
-|------|------|---------| ------- |-------------|---------|
-| Hostname | string| string | | 1. IPs are not allowed.</br>2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard</br>label must appear by itself as the first label.</br></br>Hostname can be "precise" which is a domain name without the terminating</br>dot of a network host (e.g. "foo.example.com") or "wildcard", which is a</br>domain name prefixed with a single wildcard label (e.g. `*.example.com`).</br></br>Note that as per RFC1035 and RFC1123, a *label* must consist of lower case</br>alphanumeric characters or '-', and must start and end with an alphanumeric</br>character. No other punctuation is allowed.</br></br>+kubebuilder:validation:MinLength=1</br>+kubebuilder:validation:MaxLength=253</br>+kubebuilder:validation:Pattern=`^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$` |  |
-
-
-
-### <span id="istio-check"></span> IstioCheck
-
-
-  
-
-
-
-**Properties**
-
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| Code | string| `string` | ✓ | | The check code used to identify a check | `KIA0001` |
-| Message | string| `string` | ✓ | | Description of the check | `Weight sum should be 100` |
-| Path | string| `string` |  | | String that describes where in the yaml file is the check located | `spec/http[0]/route` |
-| severity | [SeverityLevel](#severity-level)| `SeverityLevel` | ✓ | |  |  |
-
-
-
-### <span id="istio-component-status"></span> IstioComponentStatus
-
-
-  
-
-[][ComponentStatus](#component-status)
-
-### <span id="istio-condition"></span> IstioCondition
-
-
-  
-
-
-
-**Properties**
-
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| Message | string| `string` |  | | Human-readable message indicating details about last transition.</br>+optional |  |
-| Reason | string| `string` |  | | Unique, one-word, CamelCase reason for the condition's last transition.</br>+optional |  |
-| Status | string| `string` |  | | Status is the status of the condition.</br>Can be True, False, Unknown. |  |
-| Type | string| `string` |  | | Type is the type of the condition. |  |
-| last_probe_time | [Timestamp](#timestamp)| `Timestamp` |  | |  |  |
-| last_transition_time | [Timestamp](#timestamp)| `Timestamp` |  | |  |  |
-
-
-
-### <span id="istio-config-details"></span> IstioConfigDetails
-
-
-  
-
-
-
-**Properties**
-
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| IstioConfigHelpFields | [][IstioConfigHelp](#istio-config-help)| `[]*IstioConfigHelp` |  | |  |  |
-| ObjectType | string| `string` |  | |  |  |
-| authorizationPolicy | [AuthorizationPolicy](#authorization-policy)| `AuthorizationPolicy` |  | |  |  |
-| destinationRule | [DestinationRule](#destination-rule)| `DestinationRule` |  | |  |  |
-| envoyFilter | [EnvoyFilter](#envoy-filter)| `EnvoyFilter` |  | |  |  |
-| gateway | [Gateway](#gateway)| `Gateway` |  | |  |  |
-| k8sGRPCRoute | [GRPCRoute](#g-rpc-route)| `GRPCRoute` |  | |  |  |
-| k8sGateway | [Gateway](#gateway)| `Gateway` |  | |  |  |
-| k8sHTTPRoute | [HTTPRoute](#http-route)| `HTTPRoute` |  | |  |  |
-| k8sReferenceGrant | [ReferenceGrant](#reference-grant)| `ReferenceGrant` |  | |  |  |
-| k8sTCPRoute | [TCPRoute](#tcp-route)| `TCPRoute` |  | |  |  |
-| k8sTLSRoute | [TLSRoute](#tls-route)| `TLSRoute` |  | |  |  |
-| namespace | [Namespace](#namespace)| `Namespace` |  | |  |  |
-| peerAuthentication | [PeerAuthentication](#peer-authentication)| `PeerAuthentication` |  | |  |  |
-| permissions | [ResourcePermissions](#resource-permissions)| `ResourcePermissions` |  | |  |  |
-| references | [IstioReferences](#istio-references)| `IstioReferences` |  | |  |  |
-| requestAuthentication | [RequestAuthentication](#request-authentication)| `RequestAuthentication` |  | |  |  |
-| serviceEntry | [ServiceEntry](#service-entry)| `ServiceEntry` |  | |  |  |
-| sidecar | [Sidecar](#sidecar)| `Sidecar` |  | |  |  |
-| telemetry | [Telemetry](#telemetry)| `Telemetry` |  | |  |  |
-| validation | [IstioValidation](#istio-validation)| `IstioValidation` |  | |  |  |
-| virtualService | [VirtualService](#virtual-service)| `VirtualService` |  | |  |  |
-| wasmPlugin | [WasmPlugin](#wasm-plugin)| `WasmPlugin` |  | |  |  |
-| workloadEntry | [WorkloadEntry](#workload-entry)| `WorkloadEntry` |  | |  |  |
-| workloadGroup | [WorkloadGroup](#workload-group)| `WorkloadGroup` |  | |  |  |
-
-
-
-### <span id="istio-config-help"></span> IstioConfigHelp
-
-
-> IstioConfigHelp represents a help message for a given Istio object type and field
-  
-
-
-
-
-
-**Properties**
-
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| Message | string| `string` |  | |  |  |
-| ObjectField | string| `string` |  | |  |  |
-
-
-
-### <span id="istio-config-list"></span> IstioConfigList
-
+| Name | Type | Go type | Default | Description | Example |
+|------|------|---------| ------- |-------------|---------|
+| Hostname | string| string | | 1. IPs are not allowed.
+2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard
+label must appear by itself as the first label.
 
-> IstioConfigList istioConfigList
-This type is used for returning a response of IstioConfigList
-  
+Hostname can be "precise" which is a domain name without the terminating
+dot of a network host (e.g. "foo.example.com") or "wildcard", which is a
+domain name prefixed with a single wildcard label (e.g. `*.example.com`).
 
+Note that as per RFC1035 and RFC1123, a *label* must consist of lower case
+alphanumeric characters or '-', and must start and end with an alphanumeric
+character. No other punctuation is allowed.
 
++kubebuilder:validation:MinLength=1
++kubebuilder:validation:MaxLength=253
++kubebuilder:validation:Pattern=`^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$` |  |
 
 
 
-**Properties**
+### <span id="ip-family"></span> IPFamily
 
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| AuthorizationPolicies | [][AuthorizationPolicy](#authorization-policy)| `[]*AuthorizationPolicy` |  | |  |  |
-| DestinationRules | [][DestinationRule](#destination-rule)| `[]*DestinationRule` |  | |  |  |
-| EnvoyFilters | [][EnvoyFilter](#envoy-filter)| `[]*EnvoyFilter` |  | |  |  |
-| Gateways | [][Gateway](#gateway)| `[]*Gateway` |  | |  |  |
-| K8sGRPCRoutes | [][GRPCRoute](#g-rpc-route)| `[]*GRPCRoute` |  | |  |  |
-| K8sGateways | [][Gateway](#gateway)| `[]*Gateway` |  | |  |  |
-| K8sHTTPRoutes | [][HTTPRoute](#http-route)| `[]*HTTPRoute` |  | |  |  |
-| K8sReferenceGrants | [][ReferenceGrant](#reference-grant)| `[]*ReferenceGrant` |  | |  |  |
-| K8sTCPRoutes | [][TCPRoute](#tcp-route)| `[]*TCPRoute` |  | |  |  |
-| K8sTLSRoutes | [][TLSRoute](#tls-route)| `[]*TLSRoute` |  | |  |  |
-| PeerAuthentications | [][PeerAuthentication](#peer-authentication)| `[]*PeerAuthentication` |  | |  |  |
-| RequestAuthentications | [][RequestAuthentication](#request-authentication)| `[]*RequestAuthentication` |  | |  |  |
-| ServiceEntries | [][ServiceEntry](#service-entry)| `[]*ServiceEntry` |  | |  |  |
-| Sidecars | [][Sidecar](#sidecar)| `[]*Sidecar` |  | |  |  |
-| Telemetries | [][Telemetry](#telemetry)| `[]*Telemetry` |  | |  |  |
-| VirtualServices | [][VirtualService](#virtual-service)| `[]*VirtualService` |  | |  |  |
-| WasmPlugins | [][WasmPlugin](#wasm-plugin)| `[]*WasmPlugin` |  | |  |  |
-| WorkloadEntries | [][WorkloadEntry](#workload-entry)| `[]*WorkloadEntry` |  | |  |  |
-| WorkloadGroups | [][WorkloadGroup](#workload-group)| `[]*WorkloadGroup` |  | |  |  |
-| validations | [IstioValidations](#istio-validations)| `IstioValidations` |  | |  |  |
 
+> IPFamily represents the IP Family (IPv4 or IPv6). This type is used
+to express the family of an IP expressed by a type (e.g. service.spec.ipFamilies).
++enum
+  
 
 
-### <span id="istio-config-permissions"></span> IstioConfigPermissions
 
+| Name | Type | Go type | Default | Description | Example |
+|------|------|---------| ------- |-------------|---------|
+| IPFamily | string| string | | IPFamily represents the IP Family (IPv4 or IPv6). This type is used
+to express the family of an IP expressed by a type (e.g. service.spec.ipFamilies).
++enum |  |
 
-> IstioConfigPermissions holds a map of ResourcesPermissions per namespace
-  
 
 
+### <span id="istio-component-status"></span> IstioComponentStatus
 
-[IstioConfigPermissions](#istio-config-permissions)
 
-### <span id="istio-environment"></span> IstioEnvironment
+  
 
+[][ComponentStatus](#component-status)
 
-> IstioEnvironment describes the Istio implementation environment
-  
+### <span id="istio-condition"></span> IstioCondition
 
 
+  
 
 
 
@@ -8911,51 +9924,56 @@ This type is used for returning a response of IstioConfigList
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| IstioAPIEnabled | boolean| `bool` |  | | Is api enabled |  |
+| Message | string| `string` |  | | Human-readable message indicating details about last transition.
++optional |  |
+| ObservedGeneration | int64 (formatted integer)| `int64` |  | | Resource Generation to which the Condition refers.
++optional
++protoc-gen-crd:validation:XIntOrString |  |
+| Reason | string| `string` |  | | Unique, one-word, CamelCase reason for the condition's last transition.
++optional |  |
+| Status | string| `string` |  | | Status is the status of the condition.
+Can be True, False, Unknown. |  |
+| Type | string| `string` |  | | Type is the type of the condition. |  |
+| last_probe_time | [Timestamp](#timestamp)| `Timestamp` |  | |  |  |
+| last_transition_time | [Timestamp](#timestamp)| `Timestamp` |  | |  |  |
 
 
 
-### <span id="istio-reference"></span> IstioReference
+### <span id="istio-config-details"></span> IstioConfigDetails
 
 
   
 
+[interface{}](#interface)
 
-
-**Properties**
-
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| Name | string| `string` |  | |  |  |
-| Namespace | string| `string` |  | |  |  |
-| ObjectType | string| `string` |  | |  |  |
+### <span id="istio-config-list"></span> IstioConfigList
 
 
+> IstioConfigList istioConfigList
+This type is used for returning a response of IstioConfigList
+  
 
-### <span id="istio-references"></span> IstioReferences
 
 
-> IstioReferences represents a sets of different references
-  
+[interface{}](#interface)
 
+### <span id="istio-config-permissions"></span> IstioConfigPermissions
 
 
+> IstioConfigPermissions holds a map of ResourcesPermissions per namespace
+  
 
 
-**Properties**
 
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| ObjectReferences | [][IstioReference](#istio-reference)| `[]*IstioReference` |  | | Related Istio objects |  |
-| ServiceReferences | [][ServiceReference](#service-reference)| `[]*ServiceReference` |  | | Related Istio objects |  |
-| WorkloadReferences | [][WorkloadReference](#workload-reference)| `[]*WorkloadReference` |  | | Related Istio objects |  |
+[IstioConfigPermissions](#istio-config-permissions)
 
+### <span id="istio-environment"></span> IstioEnvironment
 
 
-### <span id="istio-status"></span> IstioStatus
+> IstioEnvironment describes the Istio implementation environment
+  
 
 
-  
 
 
 
@@ -8963,13 +9981,11 @@ This type is used for returning a response of IstioConfigList
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Conditions | [][IstioCondition](#istio-condition)| `[]*IstioCondition` |  | | Current service state of pod.</br>More info: https://istio.io/docs/reference/config/config-status/</br>+optional</br>+patchMergeKey=type</br>+patchStrategy=merge |  |
-| ObservedGeneration | int64 (formatted integer)| `int64` |  | | Resource Generation to which the Reconciled Condition refers.</br>When this value is not equal to the object's metadata generation, reconciled condition  calculation for the current</br>generation is still in progress.  See https://istio.io/latest/docs/reference/config/config-status/ for more info.</br>+optional |  |
-| ValidationMessages | [][AnalysisMessageBase](#analysis-message-base)| `[]*AnalysisMessageBase` |  | | Includes any errors or warnings detected by Istio's analyzers.</br>+optional</br>+patchMergeKey=type</br>+patchStrategy=merge |  |
+| IstioAPIEnabled | boolean| `bool` |  | | Is api enabled |  |
 
 
 
-### <span id="istio-validation"></span> IstioValidation
+### <span id="istio-status"></span> IstioStatus
 
 
   
@@ -8980,13 +9996,22 @@ This type is used for returning a response of IstioConfigList
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Checks | [][IstioCheck](#istio-check)| `[]*IstioCheck` |  | | Array of checks. It might be empty. |  |
-| Cluster | string| `string` | ✓ | | Cluster of the object | `east` |
-| Name | string| `string` | ✓ | | Name of the object itself | `reviews` |
-| Namespace | string| `string` | ✓ | | Namespace of the object | `bookinfo` |
-| ObjectType | string| `string` | ✓ | | Type of the object | `virtualservice` |
-| References | [][IstioValidationKey](#istio-validation-key)| `[]*IstioValidationKey` |  | | Related objects (only validation errors) |  |
-| Valid | boolean| `bool` | ✓ | | Represents validity of the object: in case of warning, validity remains as true | `false` |
+| Conditions | [][IstioCondition](#istio-condition)| `[]*IstioCondition` |  | | Current service state of the resource.
+More info: https://istio.io/docs/reference/config/config-status/
++optional
++patchMergeKey=type
++patchStrategy=merge |  |
+| ObservedGeneration | int64 (formatted integer)| `int64` |  | | $hide_from_docs
+Deprecated. IstioCondition observed_generation will show the resource generation for which the condition was generated.
+Resource Generation to which the Reconciled Condition refers.
+When this value is not equal to the object's metadata generation, reconciled condition  calculation for the current
+generation is still in progress.  See https://istio.io/latest/docs/reference/config/config-status/ for more info.
++optional
++protoc-gen-crd:validation:XIntOrString |  |
+| ValidationMessages | [][AnalysisMessageBase](#analysis-message-base)| `[]*AnalysisMessageBase` |  | | Includes any errors or warnings detected by Istio's analyzers.
++optional
++patchMergeKey=type
++patchStrategy=merge |  |
 
 
 
@@ -9004,7 +10029,7 @@ This type is used for returning a response of IstioConfigList
 | Cluster | string| `string` |  | |  |  |
 | Name | string| `string` |  | |  |  |
 | Namespace | string| `string` |  | |  |  |
-| ObjectType | string| `string` |  | |  |  |
+| objectGVK | [GroupVersionKind](#group-version-kind)| `GroupVersionKind` |  | |  |  |
 
 
 
@@ -9034,6 +10059,25 @@ This type is used for returning a response of IstioConfigList
 
 [interface{}](#interface)
 
+### <span id="istiod-thresholds"></span> IstiodThresholds
+
+
+> IstiodThresholds contains the resource limits configured in Istiod
+  
+
+
+
+
+
+**Properties**
+
+| Name | Type | Go type | Required | Default | Description | Example |
+|------|------|---------|:--------:| ------- |-------------|---------|
+| CPU | double (formatted number)| `float64` |  | |  |  |
+| Memory | double (formatted number)| `float64` |  | |  |  |
+
+
+
 ### <span id="key-value"></span> KeyValue
 
 
@@ -9067,8 +10111,12 @@ where and how Kiali was deployed.
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
 | Namespace | string| `string` |  | | Namespace is the name of the namespace where is Kiali installed on. |  |
-| OperatorResource | string| `string` |  | | OperatorResource contains the namespace and the name of the Kiali CR that the user</br>created to install Kiali via the operator. This can be blank if the operator wasn't used</br>to install Kiali. This resource is populated from annotations in the Service. It has</br>the format "namespace/resource_name". |  |
-| ServiceName | string| `string` |  | | ServiceName is the name of the Kubernetes service associated to the Kiali installation. The Kiali Service is the</br>entity that is looked for in order to determine if a Kiali instance is available. |  |
+| OperatorResource | string| `string` |  | | OperatorResource contains the namespace and the name of the Kiali CR that the user
+created to install Kiali via the operator. This can be blank if the operator wasn't used
+to install Kiali. This resource is populated from annotations in the Service. It has
+the format "namespace/resource_name". |  |
+| ServiceName | string| `string` |  | | ServiceName is the name of the Kubernetes service associated to the Kiali installation. The Kiali Service is the
+entity that is looked for in order to determine if a Kiali instance is available. |  |
 | Url | string| `string` |  | | Url is the URI that can be used to access Kiali. |  |
 | Version | string| `string` |  | | Version is the Kiali version as reported by annotations in the Service. |  |
 
@@ -9095,7 +10143,44 @@ Invalid values include:
 
 | Name | Type | Go type | Default | Description | Example |
 |------|------|---------| ------- |-------------|---------|
-| Kind | string| string | | Valid values include:</br></br>"Service"</br>"HTTPRoute"</br></br>Invalid values include:</br></br>"invalid/kind" - "/" is an invalid character</br></br>+kubebuilder:validation:MinLength=1</br>+kubebuilder:validation:MaxLength=63</br>+kubebuilder:validation:Pattern=`^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$` |  |
+| Kind | string| string | | Valid values include:
+
+"Service"
+"HTTPRoute"
+
+Invalid values include:
+
+"invalid/kind" - "/" is an invalid character
+
++kubebuilder:validation:MinLength=1
++kubebuilder:validation:MaxLength=63
++kubebuilder:validation:Pattern=`^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$` |  |
+
+
+
+### <span id="kube-cluster"></span> KubeCluster
+
+
+> Cluster holds some metadata about a Kubernetes cluster that is
+part of the mesh.
+  
+
+
+
+
+
+**Properties**
+
+| Name | Type | Go type | Required | Default | Description | Example |
+|------|------|---------|:--------:| ------- |-------------|---------|
+| Accessible | boolean| `bool` |  | | Accessible specifies if the cluster is accessible or not. Clusters that are manually specified in the Kiali config
+but do not have an associated remote cluster secret are considered not accessible. This is helpful when you have
+two disconnected Kialis and want to link them without giving them access to each other. |  |
+| ApiEndpoint | string| `string` |  | | ApiEndpoint is the URL where the Kubernetes/Cluster API Server can be contacted |  |
+| IsKialiHome | boolean| `bool` |  | | IsKialiHome specifies if this cluster is hosting this Kiali instance (and the observed Mesh Control Plane) |  |
+| KialiInstances | [][KialiInstance](#kiali-instance)| `[]*KialiInstance` |  | | KialiInstances is the list of Kialis discovered in the cluster. |  |
+| Name | string| `string` |  | | Name specifies the CLUSTER_ID as known by the Control Plane |  |
+| SecretName | string| `string` |  | | SecretName is the name of the kubernetes "remote cluster secret" that was mounted to the file system and where data of this cluster was resolved |  |
 
 
 
@@ -9116,8 +10201,13 @@ label selector matches no objects.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| MatchExpressions | [][LabelSelectorRequirement](#label-selector-requirement)| `[]*LabelSelectorRequirement` |  | | matchExpressions is a list of label selector requirements. The requirements are ANDed.</br>+optional</br>+listType=atomic |  |
-| MatchLabels | map of string| `map[string]string` |  | | matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels</br>map is equivalent to an element of matchExpressions, whose key field is "key", the</br>operator is "In", and the values array contains only "value". The requirements are ANDed.</br>+optional |  |
+| MatchExpressions | [][LabelSelectorRequirement](#label-selector-requirement)| `[]*LabelSelectorRequirement` |  | | matchExpressions is a list of label selector requirements. The requirements are ANDed.
++optional
++listType=atomic |  |
+| MatchLabels | map of string| `map[string]string` |  | | matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+map is equivalent to an element of matchExpressions, whose key field is "key", the
+operator is "In", and the values array contains only "value". The requirements are ANDed.
++optional |  |
 
 
 
@@ -9148,7 +10238,12 @@ relates the key and values.
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
 | Key | string| `string` |  | | key is the label key that the selector applies to. |  |
-| Values | []string| `[]string` |  | | values is an array of string values. If the operator is In or NotIn,</br>the values array must be non-empty. If the operator is Exists or DoesNotExist,</br>the values array must be empty. This array is replaced during a strategic</br>merge patch.</br>+optional</br>+listType=atomic |  |
+| Values | []string| `[]string` |  | | values is an array of string values. If the operator is In or NotIn,
+the values array must be non-empty. If the operator is Exists or DoesNotExist,
+the values array must be empty. This array is replaced during a strategic
+merge patch.
++optional
++listType=atomic |  |
 | operator | [LabelSelectorOperator](#label-selector-operator)| `LabelSelectorOperator` |  | |  |  |
 
 
@@ -9171,24 +10266,6 @@ relates the key and values.
 
 
 
-### <span id="listener-status"></span> ListenerStatus
-
-
-  
-
-
-
-**Properties**
-
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| AttachedRoutes | int32 (formatted integer)| `int32` |  | | AttachedRoutes represents the total number of Routes that have been</br>successfully attached to this Listener.</br></br>Successful attachment of a Route to a Listener is based solely on the</br>combination of the AllowedRoutes field on the corresponding Listener</br>and the Route's ParentRefs field. A Route is successfully attached to</br>a Listener when it is selected by the Listener's AllowedRoutes field</br>AND the Route has a valid ParentRef selecting the whole Gateway</br>resource or a specific Listener as a parent resource (more detail on</br>attachment semantics can be found in the documentation on the various</br>Route kinds ParentRefs fields). Listener or Route status does not impact</br>successful attachment, i.e. the AttachedRoutes field count MUST be set</br>for Listeners with condition Accepted: false and MUST count successfully</br>attached Routes that may themselves have Accepted: false conditions.</br></br>Uses for this field include troubleshooting Route attachment and</br>measuring blast radius/impact of changes to a Listener. |  |
-| Conditions | [][Condition](#condition)| `[]*Condition` |  | | Conditions describe the current condition of this listener.</br></br>+listType=map</br>+listMapKey=type</br>+kubebuilder:validation:MaxItems=8 |  |
-| SupportedKinds | [][RouteGroupKind](#route-group-kind)| `[]*RouteGroupKind` |  | | SupportedKinds is the list indicating the Kinds supported by this</br>listener. This MUST represent the kinds an implementation supports for</br>that Listener configuration.</br></br>If kinds are specified in Spec that are not supported, they MUST NOT</br>appear in this list and an implementation MUST set the "ResolvedRefs"</br>condition to "False" with the "InvalidRouteKinds" reason. If both valid</br>and invalid Route kinds are specified, the implementation MUST</br>reference the valid Route kinds that have been specified.</br></br>+kubebuilder:validation:MaxItems=8 |  |
-| name | [SectionName](#section-name)| `SectionName` |  | |  |  |
-
-
-
 ### <span id="listeners"></span> Listeners
 
 
@@ -9218,27 +10295,6 @@ on the containing object.
 
 
 
-### <span id="local-parameters-reference"></span> LocalParametersReference
-
-
-> LocalParametersReference identifies an API object containing controller-specific
-configuration resource within the namespace.
-  
-
-
-
-
-
-**Properties**
-
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| Name | string| `string` |  | | Name is the name of the referent.</br></br>+kubebuilder:validation:MinLength=1</br>+kubebuilder:validation:MaxLength=253 |  |
-| group | [Group](#group)| `Group` |  | |  |  |
-| kind | [Kind](#kind)| `Kind` |  | |  |  |
-
-
-
 ### <span id="log"></span> Log
 
 
@@ -9295,13 +10351,23 @@ that the fieldset applies to.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| APIVersion | string| `string` |  | | APIVersion defines the version of this resource that this field set</br>applies to. The format is "group/version" just like the top-level</br>APIVersion field. It is necessary to track the version of a field</br>set because it cannot be automatically converted. |  |
-| FieldsType | string| `string` |  | | FieldsType is the discriminator for the different fields format and version.</br>There is currently only one possible value: "FieldsV1" |  |
+| APIVersion | string| `string` |  | | APIVersion defines the version of this resource that this field set
+applies to. The format is "group/version" just like the top-level
+APIVersion field. It is necessary to track the version of a field
+set because it cannot be automatically converted. |  |
+| FieldsType | string| `string` |  | | FieldsType is the discriminator for the different fields format and version.
+There is currently only one possible value: "FieldsV1" |  |
 | Manager | string| `string` |  | | Manager is an identifier of the workflow managing these fields. |  |
-| Subresource | string| `string` |  | | Subresource is the name of the subresource used to update that object, or</br>empty string if the object was updated through the main resource. The</br>value of this field is used to distinguish between managers, even if they</br>share the same name. For example, a status update will be distinct from a</br>regular update using the same manager name.</br>Note that the APIVersion field is not related to the Subresource field and</br>it always corresponds to the version of the main resource. |  |
-| Time | string| `string` |  | | Time is the timestamp of when the ManagedFields entry was added. The</br>timestamp will also be updated if a field is added, the manager</br>changes any of the owned fields value or removes a field. The</br>timestamp does not update when a field is removed from the entry</br>because another manager took it over.</br>+optional |  |
+| Subresource | string| `string` |  | | Subresource is the name of the subresource used to update that object, or
+empty string if the object was updated through the main resource. The
+value of this field is used to distinguish between managers, even if they
+share the same name. For example, a status update will be distinct from a
+regular update using the same manager name.
+Note that the APIVersion field is not related to the Subresource field and
+it always corresponds to the version of the main resource. |  |
 | fieldsV1 | [FieldsV1](#fields-v1)| `FieldsV1` |  | |  |  |
 | operation | [ManagedFieldsOperationType](#managed-fields-operation-type)| `ManagedFieldsOperationType` |  | |  |  |
+| time | [Time](#time)| `Time` |  | |  |  |
 
 
 
@@ -9449,6 +10515,34 @@ primary can also manage multiple clusters (primary-remote deployment).
 
 
 
+### <span id="namespace"></span> Namespace
+
+
+> A Namespace provide a scope for names
+This type is used to describe a set of objects.
+  
+
+
+
+
+
+**Properties**
+
+| Name | Type | Go type | Required | Default | Description | Example |
+|------|------|---------|:--------:| ------- |-------------|---------|
+| Annotations | map of string| `map[string]string` |  | | Specific annotations used in Kiali |  |
+| Cluster | string| `string` | ✓ | | The name of the cluster | `east` |
+| IsAmbient | boolean| `bool` | ✓ | | If has the Ambient annotations |  |
+| Labels | map of string| `map[string]string` |  | | Labels for Namespace |  |
+| Name | string| `string` | ✓ | | The id of the namespace. | `istio-system` |
+| Revision | string| `string` |  | | Revision managing this namespace.
+If the namespace has 'istio-injection: enabled' label,
+it will be set to the 'default' revision. Otherwise
+it matches on istio.io/rev. Note that his can also
+be a Tag and not the actual revision. |  |
+
+
+
 ### <span id="namespace"></span> Namespace
 
 
@@ -9475,30 +10569,23 @@ Invalid values include:
 
 | Name | Type | Go type | Default | Description | Example |
 |------|------|---------| ------- |-------------|---------|
-| Namespace | string| string | | This validation is based off of the corresponding Kubernetes validation:</br>https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/util/validation/validation.go#L187</br></br>This is used for Namespace name validation here:</br>https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/api/validation/generic.go#L63</br></br>Valid values include:</br></br>"example"</br></br>Invalid values include:</br></br>"example.com" - "." is an invalid character</br></br>+kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?$`</br>+kubebuilder:validation:MinLength=1</br>+kubebuilder:validation:MaxLength=63 |  |
-
-
-
-### <span id="namespace"></span> Namespace
-
-
-> A Namespace provide a scope for names
-This type is used to describe a set of objects.
-  
+| Namespace | string| string | | This validation is based off of the corresponding Kubernetes validation:
+https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/util/validation/validation.go#L187
 
+This is used for Namespace name validation here:
+https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/api/validation/generic.go#L63
 
+Valid values include:
 
+"example"
 
+Invalid values include:
 
-**Properties**
+"example.com" - "." is an invalid character
 
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| Annotations | map of string| `map[string]string` |  | | Specific annotations used in Kiali |  |
-| Cluster | string| `string` | ✓ | | The name of the cluster | `east` |
-| IsAmbient | boolean| `bool` | ✓ | | If has the Ambient annotations |  |
-| Labels | map of string| `map[string]string` |  | | Labels for Namespace |  |
-| Name | string| `string` | ✓ | | The id of the namespace. | `istio-system` |
++kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?$`
++kubebuilder:validation:MinLength=1
++kubebuilder:validation:MaxLength=63 |  |
 
 
 
@@ -9556,7 +10643,7 @@ This type is used to describe a set of objects.
 | HasTrafficShifting | boolean| `bool` |  | |  |  |
 | HasWorkloadEntry | [][WEInfo](#w-e-info)| `[]*WEInfo` |  | |  |  |
 | HealthData | [interface{}](#interface)| `interface{}` |  | |  |  |
-| ID | string| `string` |  | | Cytoscape Fields |  |
+| ID | string| `string` |  | |  |  |
 | IsAmbient | boolean| `bool` |  | |  |  |
 | IsBox | string| `string` |  | |  |  |
 | IsDead | boolean| `bool` |  | |  |  |
@@ -9569,7 +10656,7 @@ This type is used to describe a set of objects.
 | IsWaypoint | boolean| `bool` |  | |  |  |
 | Labels | map of string| `map[string]string` |  | |  |  |
 | Namespace | string| `string` |  | |  |  |
-| NodeType | string| `string` |  | | App Fields (not required by Cytoscape) |  |
+| NodeType | string| `string` |  | |  |  |
 | Parent | string| `string` |  | |  |  |
 | Service | string| `string` |  | |  |  |
 | Traffic | [][ProtocolTraffic](#protocol-traffic)| `[]*ProtocolTraffic` |  | |  |  |
@@ -9577,6 +10664,7 @@ This type is used to describe a set of objects.
 | Workload | string| `string` |  | |  |  |
 | hasHealthConfig | [HealthConfig](#health-config)| `HealthConfig` |  | |  |  |
 | hasVS | [VSInfo](#v-s-info)| `VSInfo` |  | |  |  |
+| isExtension | [ExtInfo](#ext-info)| `ExtInfo` |  | |  |  |
 | isGateway | [GWInfo](#g-w-info)| `GWInfo` |  | |  |  |
 | isServiceEntry | [SEInfo](#s-e-info)| `SEInfo` |  | |  |  |
 
@@ -9608,7 +10696,8 @@ This type is used to describe a set of objects.
 
 | Name | Type | Go type | Default | Description | Example |
 |------|------|---------| ------- |-------------|---------|
-| ObjectName | string| string | | +kubebuilder:validation:MinLength=1</br>+kubebuilder:validation:MaxLength=253 |  |
+| ObjectName | string| string | | +kubebuilder:validation:MinLength=1
++kubebuilder:validation:MaxLength=253 |  |
 
 
 
@@ -9648,10 +10737,21 @@ be cluster-scoped, so there is no namespace field.
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
 | APIVersion | string| `string` |  | | API version of the referent. |  |
-| BlockOwnerDeletion | boolean| `bool` |  | | If true, AND if the owner has the "foregroundDeletion" finalizer, then</br>the owner cannot be deleted from the key-value store until this</br>reference is removed.</br>See https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion</br>for how the garbage collector interacts with this field and enforces the foreground deletion.</br>Defaults to false.</br>To set this field, a user needs "delete" permission of the owner,</br>otherwise 422 (Unprocessable Entity) will be returned.</br>+optional |  |
-| Controller | boolean| `bool` |  | | If true, this reference points to the managing controller.</br>+optional |  |
-| Kind | string| `string` |  | | Kind of the referent.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds |  |
-| Name | string| `string` |  | | Name of the referent.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names |  |
+| BlockOwnerDeletion | boolean| `bool` |  | | If true, AND if the owner has the "foregroundDeletion" finalizer, then
+the owner cannot be deleted from the key-value store until this
+reference is removed.
+See https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion
+for how the garbage collector interacts with this field and enforces the foreground deletion.
+Defaults to false.
+To set this field, a user needs "delete" permission of the owner,
+otherwise 422 (Unprocessable Entity) will be returned.
++optional |  |
+| Controller | boolean| `bool` |  | | If true, this reference points to the managing controller.
++optional |  |
+| Kind | string| `string` |  | | Kind of the referent.
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds |  |
+| Name | string| `string` |  | | Name of the referent.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names |  |
 | uid | [UID](#uid)| `UID` |  | |  |  |
 
 
@@ -9702,174 +10802,33 @@ Note that values may be added to this enum, implementations
 must ensure that unknown values will not cause a crash.
 
 Unknown values here must result in the implementation setting the
-Accepted Condition for the Route to `status: False`, with a
-Reason of `UnsupportedValue`.
-
-+kubebuilder:validation:Enum=Exact;PathPrefix;RegularExpression
-  
-
-
-
-| Name | Type | Go type | Default | Description | Example |
-|------|------|---------| ------- |-------------|---------|
-| PathMatchType | string| string | | "Exact" - Core</br>"PathPrefix" - Core</br>"RegularExpression" - Implementation Specific</br></br>PathPrefix and Exact paths must be syntactically valid:</br></br>Must begin with the `/` character</br>Must not contain consecutive `/` characters (e.g. `/foo///`, `//`).</br></br>Note that values may be added to this enum, implementations</br>must ensure that unknown values will not cause a crash.</br></br>Unknown values here must result in the implementation setting the</br>Accepted Condition for the Route to `status: False`, with a</br>Reason of `UnsupportedValue`.</br></br>+kubebuilder:validation:Enum=Exact;PathPrefix;RegularExpression |  |
-
-
-
-### <span id="peer-authentication"></span> PeerAuthentication
-
-
-> Examples:
-
-Policy to allow mTLS traffic for all workloads under namespace `foo`:
-```yaml
-apiVersion: security.istio.io/v1
-kind: PeerAuthentication
-metadata:
-
-name: default
-namespace: foo
-
-spec:
-
-mtls:
-mode: STRICT
-
-```
-For mesh level, put the policy in root-namespace according to your Istio installation.
-
-Policies to allow both mTLS and plaintext traffic for all workloads under namespace `foo`, but
-require mTLS for workload `finance`.
-```yaml
-apiVersion: security.istio.io/v1
-kind: PeerAuthentication
-metadata:
-
-name: default
-namespace: foo
-
-spec:
-
-mtls:
-mode: PERMISSIVE
-
-
-apiVersion: security.istio.io/v1
-kind: PeerAuthentication
-metadata:
-
-name: finance
-namespace: foo
-
-spec:
-
-selector:
-matchLabels:
-app: finance
-mtls:
-mode: STRICT
-
-```
-Policy that enables strict mTLS for all `finance` workloads, but leaves the port `8080` to
-plaintext. Note the port value in the `portLevelMtls` field refers to the port
-of the workload, not the port of the Kubernetes service.
-```yaml
-apiVersion: security.istio.io/v1
-kind: PeerAuthentication
-metadata:
-
-name: default
-namespace: foo
-
-spec:
-
-selector:
-matchLabels:
-app: finance
-mtls:
-mode: STRICT
-portLevelMtls:
-8080:
-mode: DISABLE
-
-```
-Policy that inherits mTLS mode from namespace (or mesh) settings, and disables
-mTLS for workload port `8080`.
-```yaml
-apiVersion: security.istio.io/v1
-kind: PeerAuthentication
-metadata:
-
-name: default
-namespace: foo
-
-spec:
-
-selector:
-matchLabels:
-app: finance
-mtls:
-mode: UNSET
-portLevelMtls:
-8080:
-mode: DISABLE
-
-```
-
-<!-- crd generation tags
-+cue-gen:PeerAuthentication:groupName:security.istio.io
-+cue-gen:PeerAuthentication:version:v1
-+cue-gen:PeerAuthentication:annotations:helm.sh/resource-policy=keep
-+cue-gen:PeerAuthentication:labels:app=istio-pilot,chart=istio,istio=security,heritage=Tiller,release=istio
-+cue-gen:PeerAuthentication:subresource:status
-+cue-gen:PeerAuthentication:scope:Namespaced
-+cue-gen:PeerAuthentication:resource:categories=istio-io,security-istio-io,shortNames=pa
-+cue-gen:PeerAuthentication:preserveUnknownFields:false
-+cue-gen:PeerAuthentication:printerColumn:name=Mode,type=string,JSONPath=.spec.mtls.mode,description="Defines the mTLS mode used for peer authentication."
-+cue-gen:PeerAuthentication:printerColumn:name=Age,type=date,JSONPath=.metadata.creationTimestamp,description="CreationTimestamp is a timestamp
-representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations.
-Clients may not set this value. It is represented in RFC3339 form and is in UTC.
-Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata"
->
-
-<!-- go code generation tags
-+kubetype-gen
-+kubetype-gen:groupVersion=security.istio.io/v1
-+genclient
-+k8s:deepcopy-gen=true
->
-<!-- istio code generation tags
-+istio.io/sync-from:security/v1beta1/peer_authentication.proto
->
+Accepted Condition for the Route to `status: False`, with a
+Reason of `UnsupportedValue`.
+
++kubebuilder:validation:Enum=Exact;PathPrefix;RegularExpression
   
 
 
 
+| Name | Type | Go type | Default | Description | Example |
+|------|------|---------| ------- |-------------|---------|
+| PathMatchType | string| string | | "Exact" - Core
+"PathPrefix" - Core
+"RegularExpression" - Implementation Specific
 
+PathPrefix and Exact paths must be syntactically valid:
 
-**Properties**
+Must begin with the `/` character
+Must not contain consecutive `/` characters (e.g. `/foo///`, `//`).
 
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| APIVersion | string| `string` |  | | APIVersion defines the versioned schema of this representation of an object.</br>Servers should convert recognized schemas to the latest internal value, and</br>may reject unrecognized values.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources</br>+optional |  |
-| Annotations | map of string| `map[string]string` |  | | Annotations is an unstructured key value map stored with a resource that may be</br>set by external tools to store and retrieve arbitrary metadata. They are not</br>queryable and should be preserved when modifying objects.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations</br>+optional |  |
-| CreationTimestamp | string| `string` |  | | CreationTimestamp is a timestamp representing the server time when this object was</br>created. It is not guaranteed to be set in happens-before order across separate operations.</br>Clients may not set this value. It is represented in RFC3339 form and is in UTC.</br></br>Populated by the system.</br>Read-only.</br>Null for lists.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| DeletionGracePeriodSeconds | int64 (formatted integer)| `int64` |  | | Number of seconds allowed for this object to gracefully terminate before</br>it will be removed from the system. Only set when deletionTimestamp is also set.</br>May only be shortened.</br>Read-only.</br>+optional |  |
-| DeletionTimestamp | string| `string` |  | | DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This</br>field is set by the server when a graceful deletion is requested by the user, and is not</br>directly settable by a client. The resource is expected to be deleted (no longer visible</br>from resource lists, and not reachable by name) after the time in this field, once the</br>finalizers list is empty. As long as the finalizers list contains items, deletion is blocked.</br>Once the deletionTimestamp is set, this value may not be unset or be set further into the</br>future, although it may be shortened or the resource may be deleted prior to this time.</br>For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react</br>by sending a graceful termination signal to the containers in the pod. After that 30 seconds,</br>the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,</br>remove the pod from the API. In the presence of network partitions, this object may still</br>exist after this timestamp, until an administrator or automated process can determine the</br>resource is fully terminated.</br>If not set, graceful deletion of the object has not been requested.</br></br>Populated by the system when a graceful deletion is requested.</br>Read-only.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| Finalizers | []string| `[]string` |  | | Must be empty before the object is deleted from the registry. Each entry</br>is an identifier for the responsible component that will remove the entry</br>from the list. If the deletionTimestamp of the object is non-nil, entries</br>in this list can only be removed.</br>Finalizers may be processed and removed in any order.  Order is NOT enforced</br>because it introduces significant risk of stuck finalizers.</br>finalizers is a shared field, any actor with permission can reorder it.</br>If the finalizer list is processed in order, then this can lead to a situation</br>in which the component responsible for the first finalizer in the list is</br>waiting for a signal (field value, external system, or other) produced by a</br>component responsible for a finalizer later in the list, resulting in a deadlock.</br>Without enforced ordering finalizers are free to order amongst themselves and</br>are not vulnerable to ordering changes in the list.</br>+optional</br>+patchStrategy=merge</br>+listType=set |  |
-| GenerateName | string| `string` |  | | GenerateName is an optional prefix, used by the server, to generate a unique</br>name ONLY IF the Name field has not been provided.</br>If this field is used, the name returned to the client will be different</br>than the name passed. This value will also be combined with a unique suffix.</br>The provided value has the same validation rules as the Name field,</br>and may be truncated by the length of the suffix required to make the value</br>unique on the server.</br></br>If this field is specified and the generated name exists, the server will return a 409.</br></br>Applied only if Name is not specified.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency</br>+optional |  |
-| Generation | int64 (formatted integer)| `int64` |  | | A sequence number representing a specific generation of the desired state.</br>Populated by the system. Read-only.</br>+optional |  |
-| Kind | string| `string` |  | | Kind is a string value representing the REST resource this object represents.</br>Servers may infer this from the endpoint the client submits requests to.</br>Cannot be updated.</br>In CamelCase.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds</br>+optional |  |
-| Labels | map of string| `map[string]string` |  | | Map of string keys and values that can be used to organize and categorize</br>(scope and select) objects. May match selectors of replication controllers</br>and services.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels</br>+optional |  |
-| ManagedFields | [][ManagedFieldsEntry](#managed-fields-entry)| `[]*ManagedFieldsEntry` |  | | ManagedFields maps workflow-id and version to the set of fields</br>that are managed by that workflow. This is mostly for internal</br>housekeeping, and users typically shouldn't need to set or</br>understand this field. A workflow can be the user's name, a</br>controller's name, or the name of a specific apply path like</br>"ci-cd". The set of fields is always in the version that the</br>workflow used when modifying the object.</br></br>+optional</br>+listType=atomic |  |
-| Name | string| `string` |  | | Name must be unique within a namespace. Is required when creating resources, although</br>some resources may allow a client to request the generation of an appropriate name</br>automatically. Name is primarily intended for creation idempotence and configuration</br>definition.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names</br>+optional |  |
-| Namespace | string| `string` |  | | Namespace defines the space within which each name must be unique. An empty namespace is</br>equivalent to the "default" namespace, but "default" is the canonical representation.</br>Not all objects are required to be scoped to a namespace - the value of this field for</br>those objects will be empty.</br></br>Must be a DNS_LABEL.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces</br>+optional |  |
-| OwnerReferences | [][OwnerReference](#owner-reference)| `[]*OwnerReference` |  | | List of objects depended by this object. If ALL objects in the list have</br>been deleted, this object will be garbage collected. If this object is managed by a controller,</br>then an entry in this list will point to this controller, with the controller field set to true.</br>There cannot be more than one managing controller.</br>+optional</br>+patchMergeKey=uid</br>+patchStrategy=merge</br>+listType=map</br>+listMapKey=uid |  |
-| ResourceVersion | string| `string` |  | | An opaque value that represents the internal version of this object that can</br>be used by clients to determine when objects have changed. May be used for optimistic</br>concurrency, change detection, and the watch operation on a resource or set of resources.</br>Clients must treat these values as opaque and passed unmodified back to the server.</br>They may only be valid for a particular resource or set of resources.</br></br>Populated by the system.</br>Read-only.</br>Value must be treated as opaque by clients and .</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency</br>+optional |  |
-| SelfLink | string| `string` |  | | Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.</br>+optional |  |
-| spec | [PeerAuthentication](#peer-authentication)| `PeerAuthentication` |  | |  |  |
-| status | [IstioStatus](#istio-status)| `IstioStatus` |  | |  |  |
-| uid | [UID](#uid)| `UID` |  | |  |  |
+Note that values may be added to this enum, implementations
+must ensure that unknown values will not cause a crash.
+
+Unknown values here must result in the implementation setting the
+Accepted Condition for the Route to `status: False`, with a
+Reason of `UnsupportedValue`.
+
++kubebuilder:validation:Enum=Exact;PathPrefix;RegularExpression |  |
 
 
 
@@ -9896,6 +10855,7 @@ Populated by the system. Read-only. Null for lists. More info: https://git.k8s.i
 | IstioInitContainers | [][ContainerInfo](#container-info)| `[]*ContainerInfo` |  | |  |  |
 | Labels | map of string| `map[string]string` |  | |  |  |
 | Name | string| `string` |  | |  |  |
+| Protocol | string| `string` |  | |  |  |
 | ServiceAccountName | string| `string` |  | |  |  |
 | Status | string| `string` |  | |  |  |
 | StatusMessage | string| `string` |  | |  |  |
@@ -9944,7 +10904,8 @@ Populated by the system. Read-only. Null for lists. More info: https://git.k8s.i
 
 | Name | Type | Go type | Default | Description | Example |
 |------|------|---------| ------- |-------------|---------|
-| PortNumber | int32 (formatted integer)| int32 | | +kubebuilder:validation:Minimum=1</br>+kubebuilder:validation:Maximum=65535 |  |
+| PortNumber | int32 (formatted integer)| int32 | | +kubebuilder:validation:Minimum=1
++kubebuilder:validation:Maximum=65535 |  |
 
 
 
@@ -9971,7 +10932,13 @@ character. No other punctuation is allowed.
 
 | Name | Type | Go type | Default | Description | Example |
 |------|------|---------| ------- |-------------|---------|
-| PreciseHostname | string| string | | Note that as per RFC1035 and RFC1123, a *label* must consist of lower case</br>alphanumeric characters or '-', and must start and end with an alphanumeric</br>character. No other punctuation is allowed.</br></br>+kubebuilder:validation:MinLength=1</br>+kubebuilder:validation:MaxLength=253</br>+kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$` |  |
+| PreciseHostname | string| string | | Note that as per RFC1035 and RFC1123, a *label* must consist of lower case
+alphanumeric characters or '-', and must start and end with an alphanumeric
+character. No other punctuation is allowed.
+
++kubebuilder:validation:MinLength=1
++kubebuilder:validation:MaxLength=253
++kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$` |  |
 
 
 
@@ -10047,6 +11014,80 @@ If at least one variable is false, then the proxy isn't fully sync'ed with pilot
 
 
 
+### <span id="quantity"></span> Quantity
+
+
+> The serialization format is:
+
+```
+<quantity>        ::= <signedNumber><suffix>
+
+(Note that <suffix> may be empty, from the "" case in <decimalSI>.)
+
+<digit>           ::= 0 | 1 | ... | 9
+<digits>          ::= <digit> | <digit><digits>
+<number>          ::= <digits> | <digits>.<digits> | <digits>. | .<digits>
+<sign>            ::= "+" | "-"
+<signedNumber>    ::= <number> | <sign><number>
+<suffix>          ::= <binarySI> | <decimalExponent> | <decimalSI>
+<binarySI>        ::= Ki | Mi | Gi | Ti | Pi | Ei
+
+(International System of units; See: http://physics.nist.gov/cuu/Units/binary.html)
+
+<decimalSI>       ::= m | "" | k | M | G | T | P | E
+
+(Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.)
+
+<decimalExponent> ::= "e" <signedNumber> | "E" <signedNumber>
+```
+
+No matter which of the three exponent forms is used, no quantity may represent
+a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal
+places. Numbers larger or more precise will be capped or rounded up.
+(E.g.: 0.1m will rounded up to 1m.)
+This may be extended in the future if we require larger or smaller quantities.
+
+When a Quantity is parsed from a string, it will remember the type of suffix
+it had, and will use the same type again when it is serialized.
+
+Before serializing, Quantity will be put in "canonical form".
+This means that Exponent/suffix will be adjusted up or down (with a
+corresponding increase or decrease in Mantissa) such that:
+
+No precision is lost
+No fractional digits will be emitted
+The exponent (or suffix) is as large as possible.
+
+The sign will be omitted unless the number is negative.
+
+Examples:
+
+1.5 will be serialized as "1500m"
+1.5Gi will be serialized as "1536Mi"
+
+Note that the quantity will NEVER be internally represented by a
+floating point number. That is the whole point of this exercise.
+
+Non-canonical values will still parse as long as they are well formed,
+but will be re-emitted in their canonical form. (So always use canonical
+form, or don't diff.)
+
+This format is intended to make it difficult to use these numbers without
+writing some sort of special handling code in the hopes that that will
+cause implementors to also use a fixed point implementation.
+
++protobuf=true
++protobuf.embed=string
++protobuf.options.marshal=false
++protobuf.options.(gogoproto.goproto_stringer)=false
++k8s:deepcopy-gen=true
++k8s:openapi-gen=true
+  
+
+
+
+[interface{}](#interface)
+
 ### <span id="query-param-match-type"></span> QueryParamMatchType
 
 
@@ -10067,7 +11108,17 @@ Reason of `UnsupportedValue`.
 
 | Name | Type | Go type | Default | Description | Example |
 |------|------|---------| ------- |-------------|---------|
-| QueryParamMatchType | string| string | | "Exact" - Core</br>"RegularExpression" - Implementation Specific</br></br>Note that values may be added to this enum, implementations</br>must ensure that unknown values will not cause a crash.</br></br>Unknown values here must result in the implementation setting the</br>Accepted Condition for the Route to `status: False`, with a</br>Reason of `UnsupportedValue`.</br></br>+kubebuilder:validation:Enum=Exact;RegularExpression |  |
+| QueryParamMatchType | string| string | | "Exact" - Core
+"RegularExpression" - Implementation Specific
+
+Note that values may be added to this enum, implementations
+must ensure that unknown values will not cause a crash.
+
+Unknown values here must result in the implementation setting the
+Accepted Condition for the Route to `status: False`, with a
+Reason of `UnsupportedValue`.
+
++kubebuilder:validation:Enum=Exact;RegularExpression |  |
 
 
 
@@ -10116,22 +11167,114 @@ that the grant allowed.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| APIVersion | string| `string` |  | | APIVersion defines the versioned schema of this representation of an object.</br>Servers should convert recognized schemas to the latest internal value, and</br>may reject unrecognized values.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources</br>+optional |  |
-| Annotations | map of string| `map[string]string` |  | | Annotations is an unstructured key value map stored with a resource that may be</br>set by external tools to store and retrieve arbitrary metadata. They are not</br>queryable and should be preserved when modifying objects.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations</br>+optional |  |
-| CreationTimestamp | string| `string` |  | | CreationTimestamp is a timestamp representing the server time when this object was</br>created. It is not guaranteed to be set in happens-before order across separate operations.</br>Clients may not set this value. It is represented in RFC3339 form and is in UTC.</br></br>Populated by the system.</br>Read-only.</br>Null for lists.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| DeletionGracePeriodSeconds | int64 (formatted integer)| `int64` |  | | Number of seconds allowed for this object to gracefully terminate before</br>it will be removed from the system. Only set when deletionTimestamp is also set.</br>May only be shortened.</br>Read-only.</br>+optional |  |
-| DeletionTimestamp | string| `string` |  | | DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This</br>field is set by the server when a graceful deletion is requested by the user, and is not</br>directly settable by a client. The resource is expected to be deleted (no longer visible</br>from resource lists, and not reachable by name) after the time in this field, once the</br>finalizers list is empty. As long as the finalizers list contains items, deletion is blocked.</br>Once the deletionTimestamp is set, this value may not be unset or be set further into the</br>future, although it may be shortened or the resource may be deleted prior to this time.</br>For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react</br>by sending a graceful termination signal to the containers in the pod. After that 30 seconds,</br>the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,</br>remove the pod from the API. In the presence of network partitions, this object may still</br>exist after this timestamp, until an administrator or automated process can determine the</br>resource is fully terminated.</br>If not set, graceful deletion of the object has not been requested.</br></br>Populated by the system when a graceful deletion is requested.</br>Read-only.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| Finalizers | []string| `[]string` |  | | Must be empty before the object is deleted from the registry. Each entry</br>is an identifier for the responsible component that will remove the entry</br>from the list. If the deletionTimestamp of the object is non-nil, entries</br>in this list can only be removed.</br>Finalizers may be processed and removed in any order.  Order is NOT enforced</br>because it introduces significant risk of stuck finalizers.</br>finalizers is a shared field, any actor with permission can reorder it.</br>If the finalizer list is processed in order, then this can lead to a situation</br>in which the component responsible for the first finalizer in the list is</br>waiting for a signal (field value, external system, or other) produced by a</br>component responsible for a finalizer later in the list, resulting in a deadlock.</br>Without enforced ordering finalizers are free to order amongst themselves and</br>are not vulnerable to ordering changes in the list.</br>+optional</br>+patchStrategy=merge</br>+listType=set |  |
-| GenerateName | string| `string` |  | | GenerateName is an optional prefix, used by the server, to generate a unique</br>name ONLY IF the Name field has not been provided.</br>If this field is used, the name returned to the client will be different</br>than the name passed. This value will also be combined with a unique suffix.</br>The provided value has the same validation rules as the Name field,</br>and may be truncated by the length of the suffix required to make the value</br>unique on the server.</br></br>If this field is specified and the generated name exists, the server will return a 409.</br></br>Applied only if Name is not specified.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency</br>+optional |  |
-| Generation | int64 (formatted integer)| `int64` |  | | A sequence number representing a specific generation of the desired state.</br>Populated by the system. Read-only.</br>+optional |  |
-| Kind | string| `string` |  | | Kind is a string value representing the REST resource this object represents.</br>Servers may infer this from the endpoint the client submits requests to.</br>Cannot be updated.</br>In CamelCase.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds</br>+optional |  |
-| Labels | map of string| `map[string]string` |  | | Map of string keys and values that can be used to organize and categorize</br>(scope and select) objects. May match selectors of replication controllers</br>and services.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels</br>+optional |  |
-| ManagedFields | [][ManagedFieldsEntry](#managed-fields-entry)| `[]*ManagedFieldsEntry` |  | | ManagedFields maps workflow-id and version to the set of fields</br>that are managed by that workflow. This is mostly for internal</br>housekeeping, and users typically shouldn't need to set or</br>understand this field. A workflow can be the user's name, a</br>controller's name, or the name of a specific apply path like</br>"ci-cd". The set of fields is always in the version that the</br>workflow used when modifying the object.</br></br>+optional</br>+listType=atomic |  |
-| Name | string| `string` |  | | Name must be unique within a namespace. Is required when creating resources, although</br>some resources may allow a client to request the generation of an appropriate name</br>automatically. Name is primarily intended for creation idempotence and configuration</br>definition.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names</br>+optional |  |
-| Namespace | string| `string` |  | | Namespace defines the space within which each name must be unique. An empty namespace is</br>equivalent to the "default" namespace, but "default" is the canonical representation.</br>Not all objects are required to be scoped to a namespace - the value of this field for</br>those objects will be empty.</br></br>Must be a DNS_LABEL.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces</br>+optional |  |
-| OwnerReferences | [][OwnerReference](#owner-reference)| `[]*OwnerReference` |  | | List of objects depended by this object. If ALL objects in the list have</br>been deleted, this object will be garbage collected. If this object is managed by a controller,</br>then an entry in this list will point to this controller, with the controller field set to true.</br>There cannot be more than one managing controller.</br>+optional</br>+patchMergeKey=uid</br>+patchStrategy=merge</br>+listType=map</br>+listMapKey=uid |  |
-| ResourceVersion | string| `string` |  | | An opaque value that represents the internal version of this object that can</br>be used by clients to determine when objects have changed. May be used for optimistic</br>concurrency, change detection, and the watch operation on a resource or set of resources.</br>Clients must treat these values as opaque and passed unmodified back to the server.</br>They may only be valid for a particular resource or set of resources.</br></br>Populated by the system.</br>Read-only.</br>Value must be treated as opaque by clients and .</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency</br>+optional |  |
-| SelfLink | string| `string` |  | | Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.</br>+optional |  |
+| APIVersion | string| `string` |  | | APIVersion defines the versioned schema of this representation of an object.
+Servers should convert recognized schemas to the latest internal value, and
+may reject unrecognized values.
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
++optional |  |
+| Annotations | map of string| `map[string]string` |  | | Annotations is an unstructured key value map stored with a resource that may be
+set by external tools to store and retrieve arbitrary metadata. They are not
+queryable and should be preserved when modifying objects.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations
++optional |  |
+| DeletionGracePeriodSeconds | int64 (formatted integer)| `int64` |  | | Number of seconds allowed for this object to gracefully terminate before
+it will be removed from the system. Only set when deletionTimestamp is also set.
+May only be shortened.
+Read-only.
++optional |  |
+| Finalizers | []string| `[]string` |  | | Must be empty before the object is deleted from the registry. Each entry
+is an identifier for the responsible component that will remove the entry
+from the list. If the deletionTimestamp of the object is non-nil, entries
+in this list can only be removed.
+Finalizers may be processed and removed in any order.  Order is NOT enforced
+because it introduces significant risk of stuck finalizers.
+finalizers is a shared field, any actor with permission can reorder it.
+If the finalizer list is processed in order, then this can lead to a situation
+in which the component responsible for the first finalizer in the list is
+waiting for a signal (field value, external system, or other) produced by a
+component responsible for a finalizer later in the list, resulting in a deadlock.
+Without enforced ordering finalizers are free to order amongst themselves and
+are not vulnerable to ordering changes in the list.
++optional
++patchStrategy=merge
++listType=set |  |
+| GenerateName | string| `string` |  | | GenerateName is an optional prefix, used by the server, to generate a unique
+name ONLY IF the Name field has not been provided.
+If this field is used, the name returned to the client will be different
+than the name passed. This value will also be combined with a unique suffix.
+The provided value has the same validation rules as the Name field,
+and may be truncated by the length of the suffix required to make the value
+unique on the server.
+
+If this field is specified and the generated name exists, the server will return a 409.
+
+Applied only if Name is not specified.
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency
++optional |  |
+| Generation | int64 (formatted integer)| `int64` |  | | A sequence number representing a specific generation of the desired state.
+Populated by the system. Read-only.
++optional |  |
+| Kind | string| `string` |  | | Kind is a string value representing the REST resource this object represents.
+Servers may infer this from the endpoint the client submits requests to.
+Cannot be updated.
+In CamelCase.
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
++optional |  |
+| Labels | map of string| `map[string]string` |  | | Map of string keys and values that can be used to organize and categorize
+(scope and select) objects. May match selectors of replication controllers
+and services.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels
++optional |  |
+| ManagedFields | [][ManagedFieldsEntry](#managed-fields-entry)| `[]*ManagedFieldsEntry` |  | | ManagedFields maps workflow-id and version to the set of fields
+that are managed by that workflow. This is mostly for internal
+housekeeping, and users typically shouldn't need to set or
+understand this field. A workflow can be the user's name, a
+controller's name, or the name of a specific apply path like
+"ci-cd". The set of fields is always in the version that the
+workflow used when modifying the object.
+
++optional
++listType=atomic |  |
+| Name | string| `string` |  | | Name must be unique within a namespace. Is required when creating resources, although
+some resources may allow a client to request the generation of an appropriate name
+automatically. Name is primarily intended for creation idempotence and configuration
+definition.
+Cannot be updated.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names
++optional |  |
+| Namespace | string| `string` |  | | Namespace defines the space within which each name must be unique. An empty namespace is
+equivalent to the "default" namespace, but "default" is the canonical representation.
+Not all objects are required to be scoped to a namespace - the value of this field for
+those objects will be empty.
+
+Must be a DNS_LABEL.
+Cannot be updated.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces
++optional |  |
+| OwnerReferences | [][OwnerReference](#owner-reference)| `[]*OwnerReference` |  | | List of objects depended by this object. If ALL objects in the list have
+been deleted, this object will be garbage collected. If this object is managed by a controller,
+then an entry in this list will point to this controller, with the controller field set to true.
+There cannot be more than one managing controller.
++optional
++patchMergeKey=uid
++patchStrategy=merge
++listType=map
++listMapKey=uid |  |
+| ResourceVersion | string| `string` |  | | An opaque value that represents the internal version of this object that can
+be used by clients to determine when objects have changed. May be used for optimistic
+concurrency, change detection, and the watch operation on a resource or set of resources.
+Clients must treat these values as opaque and passed unmodified back to the server.
+They may only be valid for a particular resource or set of resources.
+
+Populated by the system.
+Read-only.
+Value must be treated as opaque by clients and .
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
++optional |  |
+| SelfLink | string| `string` |  | | Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.
++optional |  |
+| creationTimestamp | [Time](#time)| `Time` |  | |  |  |
+| deletionTimestamp | [Time](#time)| `Time` |  | |  |  |
 | spec | [ReferenceGrantSpec](#reference-grant-spec)| `ReferenceGrantSpec` |  | |  |  |
 | uid | [UID](#uid)| `UID` |  | |  |  |
 
@@ -10169,8 +11312,24 @@ for Gateway API.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| From | [][ReferenceGrantFrom](#reference-grant-from)| `[]*ReferenceGrantFrom` |  | | From describes the trusted namespaces and kinds that can reference the</br>resources described in "To". Each entry in this list MUST be considered</br>to be an additional place that references can be valid from, or to put</br>this another way, entries MUST be combined using OR.</br></br>Support: Core</br></br>+kubebuilder:validation:MinItems=1</br>+kubebuilder:validation:MaxItems=16 |  |
-| To | [][ReferenceGrantTo](#reference-grant-to)| `[]*ReferenceGrantTo` |  | | To describes the resources that may be referenced by the resources</br>described in "From". Each entry in this list MUST be considered to be an</br>additional place that references can be valid to, or to put this another</br>way, entries MUST be combined using OR.</br></br>Support: Core</br></br>+kubebuilder:validation:MinItems=1</br>+kubebuilder:validation:MaxItems=16 |  |
+| From | [][ReferenceGrantFrom](#reference-grant-from)| `[]*ReferenceGrantFrom` |  | | From describes the trusted namespaces and kinds that can reference the
+resources described in "To". Each entry in this list MUST be considered
+to be an additional place that references can be valid from, or to put
+this another way, entries MUST be combined using OR.
+
+Support: Core
+
++kubebuilder:validation:MinItems=1
++kubebuilder:validation:MaxItems=16 |  |
+| To | [][ReferenceGrantTo](#reference-grant-to)| `[]*ReferenceGrantTo` |  | | To describes the resources that may be referenced by the resources
+described in "From". Each entry in this list MUST be considered to be an
+additional place that references can be valid to, or to put this another
+way, entries MUST be combined using OR.
+
+Support: Core
+
++kubebuilder:validation:MinItems=1
++kubebuilder:validation:MaxItems=16 |  |
 
 
 
@@ -10209,261 +11368,62 @@ references.
 
 
 
-### <span id="request-authentication"></span> RequestAuthentication
-
-
-> Require JWT for all request for workloads that have label `app:httpbin`
-
-```yaml
-apiVersion: security.istio.io/v1
-kind: RequestAuthentication
-metadata:
-
-name: httpbin
-namespace: foo
-
-spec:
-
-selector:
-matchLabels:
-app: httpbin
-jwtRules:
-issuer: "issuer-foo"
-jwksUri: https://example.com/.well-known/jwks.json
-
-
-apiVersion: security.istio.io/v1
-kind: AuthorizationPolicy
-metadata:
-
-name: httpbin
-namespace: foo
-
-spec:
-
-selector:
-matchLabels:
-app: httpbin
-rules:
-from:
-source:
-requestPrincipals: ["*"]
-
-```
-
-A policy in the root namespace ("istio-system" by default) applies to workloads in all namespaces
-in a mesh. The following policy makes all workloads only accept requests that contain a
-valid JWT token.
-
-```yaml
-apiVersion: security.istio.io/v1
-kind: RequestAuthentication
-metadata:
-
-name: req-authn-for-all
-namespace: istio-system
-
-spec:
-
-jwtRules:
-issuer: "issuer-foo"
-jwksUri: https://example.com/.well-known/jwks.json
-
-
-apiVersion: security.istio.io/v1
-kind: AuthorizationPolicy
-metadata:
-
-name: require-jwt-for-all
-namespace: istio-system
-
-spec:
-
-rules:
-from:
-source:
-requestPrincipals: ["*"]
-
-```
-
-The next example shows how to set a different JWT requirement for a different `host`. The `RequestAuthentication`
-declares it can accept JWTs issued by either `issuer-foo` or `issuer-bar` (the public key set is implicitly
-set from the OpenID Connect spec).
-
-```yaml
-apiVersion: security.istio.io/v1
-kind: RequestAuthentication
-metadata:
-
-name: httpbin
-namespace: foo
-
-spec:
-
-selector:
-matchLabels:
-app: httpbin
-jwtRules:
-issuer: "issuer-foo"
-issuer: "issuer-bar"
-
-
-apiVersion: security.istio.io/v1
-kind: AuthorizationPolicy
-metadata:
-
-name: httpbin
-namespace: foo
-
-spec:
+### <span id="request-health"></span> RequestHealth
 
-selector:
-matchLabels:
-app: httpbin
-rules:
-from:
-source:
-requestPrincipals: ["issuer-foo/*"]
-to:
-operation:
-hosts: ["example.com"]
-from:
-source:
-requestPrincipals: ["issuer-bar/*"]
-to:
-operation:
-hosts: ["another-host.com"]
 
-```
+> RequestHealth holds several stats about recent request errors
+Inbound//Outbound are the rates of requests by protocol and status_code.
+Example:   Inbound: { "http": {"200": 1.5, "400": 2.3}, "grpc": {"1": 1.2} }
+  
 
-You can fine tune the authorization policy to set different requirement per path. For example,
-to require JWT on all paths, except /healthz, the same `RequestAuthentication` can be used, but the
-authorization policy could be:
 
-```yaml
-apiVersion: security.istio.io/v1
-kind: AuthorizationPolicy
-metadata:
 
-name: httpbin
-namespace: foo
 
-spec:
 
-selector:
-matchLabels:
-app: httpbin
-rules:
-from:
-source:
-requestPrincipals: ["*"]
-to:
-operation:
-paths: ["/healthz"]
+**Properties**
 
-```
+| Name | Type | Go type | Required | Default | Description | Example |
+|------|------|---------|:--------:| ------- |-------------|---------|
+| HealthAnnotations | map of string| `map[string]string` |  | |  |  |
+| Inbound | map of [map[string]float64](#map-string-float64)| `map[string]map[string]float64` |  | |  |  |
+| Outbound | map of [map[string]float64](#map-string-float64)| `map[string]map[string]float64` |  | |  |  |
 
-[Experimental] Routing based on derived [metadata](https://istio.io/latest/docs/reference/config/security/conditions/)
-is now supported. A prefix '@' is used to denote a match against internal metadata instead of the headers in the request.
-Currently this feature is only supported for the following metadata:
 
-`request.auth.claims.{claim-name}[.{nested-claim}]*` which are extracted from validated JWT tokens.
-Use the `.` or `[]` as a separator for nested claim names.
-Examples: `request.auth.claims.sub`, `request.auth.claims.name.givenName` and `request.auth.claims[foo.com/name]`.
-For more information, see [JWT claim based routing](https://istio.io/latest/docs/tasks/security/authentication/jwt-route/).
 
-The use of matches against JWT claim metadata is only supported in Gateways. The following example shows:
+### <span id="resource-claim"></span> ResourceClaim
 
-RequestAuthentication to decode and validate a JWT. This also makes the `@request.auth.claims` available for use in the VirtualService.
-AuthorizationPolicy to check for valid principals in the request. This makes the JWT required for the request.
-VirtualService to route the request based on the "sub" claim.
 
-```yaml
-apiVersion: security.istio.io/v1
-kind: RequestAuthentication
-metadata:
+  
 
-name: jwt-on-ingress
-namespace: istio-system
 
-spec:
 
-selector:
-matchLabels:
-app: istio-ingressgateway
-jwtRules:
-issuer: "example.com"
-jwksUri: https://example.com/.well-known/jwks.json
+**Properties**
 
+| Name | Type | Go type | Required | Default | Description | Example |
+|------|------|---------|:--------:| ------- |-------------|---------|
+| Name | string| `string` |  | | Name must match the name of one entry in pod.spec.resourceClaims of
+the Pod where this field is used. It makes that resource available
+inside a container. |  |
+| Request | string| `string` |  | | Request is the name chosen for a request in the referenced claim.
+If empty, everything from the claim is made available, otherwise
+only the result of this request.
 
-apiVersion: security.istio.io/v1
-kind: AuthorizationPolicy
-metadata:
++optional |  |
 
-name: require-jwt
-namespace: istio-system
 
-spec:
 
-selector:
-matchLabels:
-app: istio-ingressgateway
-rules:
-from:
-source:
-requestPrincipals: ["*"]
+### <span id="resource-list"></span> ResourceList
 
 
-apiVersion: networking.istio.io/v1alpha3
-kind: VirtualService
-metadata:
+  
 
-name: route-jwt
+[ResourceList](#resource-list)
 
-spec:
+### <span id="resource-permissions"></span> ResourcePermissions
 
-hosts:
-foo.prod.svc.cluster.local
-gateways:
-istio-ingressgateway
-http:
-name: "v2"
-match:
-headers:
-"@request.auth.claims.sub":
-exact: "dev"
-route:
-destination:
-host: foo.prod.svc.cluster.local
-subset: v2
-name: "default"
-route:
-destination:
-host: foo.prod.svc.cluster.local
-subset: v1
-
-```
-
-<!-- crd generation tags
-+cue-gen:RequestAuthentication:groupName:security.istio.io
-+cue-gen:RequestAuthentication:version:v1
-+cue-gen:RequestAuthentication:annotations:helm.sh/resource-policy=keep
-+cue-gen:RequestAuthentication:labels:app=istio-pilot,chart=istio,istio=security,heritage=Tiller,release=istio
-+cue-gen:RequestAuthentication:subresource:status
-+cue-gen:RequestAuthentication:scope:Namespaced
-+cue-gen:RequestAuthentication:resource:categories=istio-io,security-istio-io,shortNames=ra
-+cue-gen:RequestAuthentication:preserveUnknownFields:false
->
 
-<!-- go code generation tags
-+kubetype-gen
-+kubetype-gen:groupVersion=security.istio.io/v1
-+genclient
-+k8s:deepcopy-gen=true
->
-<!-- istio code generation tags
-+istio.io/sync-from:security/v1beta1/request_authentication.proto
->
+> ResourcePermissions holds permission flags for an object type
+True means allowed.
   
 
 
@@ -10474,68 +11434,37 @@ subset: v1
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| APIVersion | string| `string` |  | | APIVersion defines the versioned schema of this representation of an object.</br>Servers should convert recognized schemas to the latest internal value, and</br>may reject unrecognized values.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources</br>+optional |  |
-| Annotations | map of string| `map[string]string` |  | | Annotations is an unstructured key value map stored with a resource that may be</br>set by external tools to store and retrieve arbitrary metadata. They are not</br>queryable and should be preserved when modifying objects.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations</br>+optional |  |
-| CreationTimestamp | string| `string` |  | | CreationTimestamp is a timestamp representing the server time when this object was</br>created. It is not guaranteed to be set in happens-before order across separate operations.</br>Clients may not set this value. It is represented in RFC3339 form and is in UTC.</br></br>Populated by the system.</br>Read-only.</br>Null for lists.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| DeletionGracePeriodSeconds | int64 (formatted integer)| `int64` |  | | Number of seconds allowed for this object to gracefully terminate before</br>it will be removed from the system. Only set when deletionTimestamp is also set.</br>May only be shortened.</br>Read-only.</br>+optional |  |
-| DeletionTimestamp | string| `string` |  | | DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This</br>field is set by the server when a graceful deletion is requested by the user, and is not</br>directly settable by a client. The resource is expected to be deleted (no longer visible</br>from resource lists, and not reachable by name) after the time in this field, once the</br>finalizers list is empty. As long as the finalizers list contains items, deletion is blocked.</br>Once the deletionTimestamp is set, this value may not be unset or be set further into the</br>future, although it may be shortened or the resource may be deleted prior to this time.</br>For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react</br>by sending a graceful termination signal to the containers in the pod. After that 30 seconds,</br>the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,</br>remove the pod from the API. In the presence of network partitions, this object may still</br>exist after this timestamp, until an administrator or automated process can determine the</br>resource is fully terminated.</br>If not set, graceful deletion of the object has not been requested.</br></br>Populated by the system when a graceful deletion is requested.</br>Read-only.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| Finalizers | []string| `[]string` |  | | Must be empty before the object is deleted from the registry. Each entry</br>is an identifier for the responsible component that will remove the entry</br>from the list. If the deletionTimestamp of the object is non-nil, entries</br>in this list can only be removed.</br>Finalizers may be processed and removed in any order.  Order is NOT enforced</br>because it introduces significant risk of stuck finalizers.</br>finalizers is a shared field, any actor with permission can reorder it.</br>If the finalizer list is processed in order, then this can lead to a situation</br>in which the component responsible for the first finalizer in the list is</br>waiting for a signal (field value, external system, or other) produced by a</br>component responsible for a finalizer later in the list, resulting in a deadlock.</br>Without enforced ordering finalizers are free to order amongst themselves and</br>are not vulnerable to ordering changes in the list.</br>+optional</br>+patchStrategy=merge</br>+listType=set |  |
-| GenerateName | string| `string` |  | | GenerateName is an optional prefix, used by the server, to generate a unique</br>name ONLY IF the Name field has not been provided.</br>If this field is used, the name returned to the client will be different</br>than the name passed. This value will also be combined with a unique suffix.</br>The provided value has the same validation rules as the Name field,</br>and may be truncated by the length of the suffix required to make the value</br>unique on the server.</br></br>If this field is specified and the generated name exists, the server will return a 409.</br></br>Applied only if Name is not specified.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency</br>+optional |  |
-| Generation | int64 (formatted integer)| `int64` |  | | A sequence number representing a specific generation of the desired state.</br>Populated by the system. Read-only.</br>+optional |  |
-| Kind | string| `string` |  | | Kind is a string value representing the REST resource this object represents.</br>Servers may infer this from the endpoint the client submits requests to.</br>Cannot be updated.</br>In CamelCase.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds</br>+optional |  |
-| Labels | map of string| `map[string]string` |  | | Map of string keys and values that can be used to organize and categorize</br>(scope and select) objects. May match selectors of replication controllers</br>and services.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels</br>+optional |  |
-| ManagedFields | [][ManagedFieldsEntry](#managed-fields-entry)| `[]*ManagedFieldsEntry` |  | | ManagedFields maps workflow-id and version to the set of fields</br>that are managed by that workflow. This is mostly for internal</br>housekeeping, and users typically shouldn't need to set or</br>understand this field. A workflow can be the user's name, a</br>controller's name, or the name of a specific apply path like</br>"ci-cd". The set of fields is always in the version that the</br>workflow used when modifying the object.</br></br>+optional</br>+listType=atomic |  |
-| Name | string| `string` |  | | Name must be unique within a namespace. Is required when creating resources, although</br>some resources may allow a client to request the generation of an appropriate name</br>automatically. Name is primarily intended for creation idempotence and configuration</br>definition.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names</br>+optional |  |
-| Namespace | string| `string` |  | | Namespace defines the space within which each name must be unique. An empty namespace is</br>equivalent to the "default" namespace, but "default" is the canonical representation.</br>Not all objects are required to be scoped to a namespace - the value of this field for</br>those objects will be empty.</br></br>Must be a DNS_LABEL.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces</br>+optional |  |
-| OwnerReferences | [][OwnerReference](#owner-reference)| `[]*OwnerReference` |  | | List of objects depended by this object. If ALL objects in the list have</br>been deleted, this object will be garbage collected. If this object is managed by a controller,</br>then an entry in this list will point to this controller, with the controller field set to true.</br>There cannot be more than one managing controller.</br>+optional</br>+patchMergeKey=uid</br>+patchStrategy=merge</br>+listType=map</br>+listMapKey=uid |  |
-| ResourceVersion | string| `string` |  | | An opaque value that represents the internal version of this object that can</br>be used by clients to determine when objects have changed. May be used for optimistic</br>concurrency, change detection, and the watch operation on a resource or set of resources.</br>Clients must treat these values as opaque and passed unmodified back to the server.</br>They may only be valid for a particular resource or set of resources.</br></br>Populated by the system.</br>Read-only.</br>Value must be treated as opaque by clients and .</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency</br>+optional |  |
-| SelfLink | string| `string` |  | | Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.</br>+optional |  |
-| spec | [RequestAuthentication](#request-authentication)| `RequestAuthentication` |  | |  |  |
-| status | [IstioStatus](#istio-status)| `IstioStatus` |  | |  |  |
-| uid | [UID](#uid)| `UID` |  | |  |  |
+| Create | boolean| `bool` |  | |  |  |
+| Delete | boolean| `bool` |  | |  |  |
+| Update | boolean| `bool` |  | |  |  |
 
 
 
-### <span id="request-health"></span> RequestHealth
+### <span id="resource-requirements"></span> ResourceRequirements
 
 
-> RequestHealth holds several stats about recent request errors
-Inbound//Outbound are the rates of requests by protocol and status_code.
-Example:   Inbound: { "http": {"200": 1.5, "400": 2.3}, "grpc": {"1": 1.2} }
   
 
 
 
-
-
 **Properties**
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| HealthAnnotations | map of string| `map[string]string` |  | |  |  |
-| Inbound | map of [map[string]float64](#map-string-float64)| `map[string]map[string]float64` |  | |  |  |
-| Outbound | map of [map[string]float64](#map-string-float64)| `map[string]map[string]float64` |  | |  |  |
-
-
-
-### <span id="resource-permissions"></span> ResourcePermissions
-
-
-> ResourcePermissions holds permission flags for an object type
-True means allowed.
-  
-
-
+| Claims | [][ResourceClaim](#resource-claim)| `[]*ResourceClaim` |  | | Claims lists the names of resources, defined in spec.resourceClaims,
+that are used by this container.
 
+This is an alpha field and requires enabling the
+DynamicResourceAllocation feature gate.
 
+This field is immutable. It can only be set for containers.
 
-**Properties**
-
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| Create | boolean| `bool` |  | |  |  |
-| Delete | boolean| `bool` |  | |  |  |
-| Update | boolean| `bool` |  | |  |  |
++listType=map
++listMapKey=name
++featureGate=DynamicResourceAllocation
++optional |  |
+| limits | [ResourceList](#resource-list)| `ResourceList` |  | |  |  |
+| requests | [ResourceList](#resource-list)| `ResourceList` |  | |  |  |
 
 
 
@@ -10613,22 +11542,6 @@ True means allowed.
 
 
 
-### <span id="route-group-kind"></span> RouteGroupKind
-
-
-  
-
-
-
-**Properties**
-
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| group | [Group](#group)| `Group` |  | |  |  |
-| kind | [Kind](#kind)| `Kind` |  | |  |  |
-
-
-
 ### <span id="route-parent-status"></span> RouteParentStatus
 
 
@@ -10644,7 +11557,30 @@ associated Parent.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Conditions | [][Condition](#condition)| `[]*Condition` |  | | Conditions describes the status of the route with respect to the Gateway.</br>Note that the route's availability is also subject to the Gateway's own</br>status conditions and listener status.</br></br>If the Route's ParentRef specifies an existing Gateway that supports</br>Routes of this kind AND that Gateway's controller has sufficient access,</br>then that Gateway's controller MUST set the "Accepted" condition on the</br>Route, to indicate whether the route has been accepted or rejected by the</br>Gateway, and why.</br></br>A Route MUST be considered "Accepted" if at least one of the Route's</br>rules is implemented by the Gateway.</br></br>There are a number of cases where the "Accepted" condition may not be set</br>due to lack of controller visibility, that includes when:</br></br>The Route refers to a non-existent parent.</br>The Route is of a type that the controller does not support.</br>The Route is in a namespace the controller does not have access to.</br></br>+listType=map</br>+listMapKey=type</br>+kubebuilder:validation:MinItems=1</br>+kubebuilder:validation:MaxItems=8 |  |
+| Conditions | [][Condition](#condition)| `[]*Condition` |  | | Conditions describes the status of the route with respect to the Gateway.
+Note that the route's availability is also subject to the Gateway's own
+status conditions and listener status.
+
+If the Route's ParentRef specifies an existing Gateway that supports
+Routes of this kind AND that Gateway's controller has sufficient access,
+then that Gateway's controller MUST set the "Accepted" condition on the
+Route, to indicate whether the route has been accepted or rejected by the
+Gateway, and why.
+
+A Route MUST be considered "Accepted" if at least one of the Route's
+rules is implemented by the Gateway.
+
+There are a number of cases where the "Accepted" condition may not be set
+due to lack of controller visibility, that includes when:
+
+The Route refers to a non-existent parent.
+The Route is of a type that the controller does not support.
+The Route is in a namespace the controller does not have access to.
+
++listType=map
++listMapKey=type
++kubebuilder:validation:MinItems=1
++kubebuilder:validation:MaxItems=8 |  |
 | controllerName | [GatewayController](#gateway-controller)| `GatewayController` |  | |  |  |
 | parentRef | [ParentReference](#parent-reference)| `ParentReference` |  | |  |  |
 
@@ -10731,7 +11667,32 @@ Invalid values include:
 
 | Name | Type | Go type | Default | Description | Example |
 |------|------|---------| ------- |-------------|---------|
-| SectionName | string| string | | In the following resources, SectionName is interpreted as the following:</br></br>Gateway: Listener name</br>HTTPRoute: HTTPRouteRule name</br>Service: Port name</br></br>Section names can have a variety of forms, including RFC 1123 subdomains,</br>RFC 1123 labels, or RFC 1035 labels.</br></br>This validation is based off of the corresponding Kubernetes validation:</br>https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/util/validation/validation.go#L208</br></br>Valid values include:</br></br>"example"</br>"foo-example"</br>"example.com"</br>"foo.example.com"</br></br>Invalid values include:</br></br>"example.com/bar" - "/" is an invalid character</br></br>+kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`</br>+kubebuilder:validation:MinLength=1</br>+kubebuilder:validation:MaxLength=253 |  |
+| SectionName | string| string | | In the following resources, SectionName is interpreted as the following:
+
+Gateway: Listener name
+HTTPRoute: HTTPRouteRule name
+Service: Port name
+
+Section names can have a variety of forms, including RFC 1123 subdomains,
+RFC 1123 labels, or RFC 1035 labels.
+
+This validation is based off of the corresponding Kubernetes validation:
+https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/util/validation/validation.go#L208
+
+Valid values include:
+
+"example"
+"foo-example"
+"example.com"
+"foo.example.com"
+
+Invalid values include:
+
+"example.com/bar" - "/" is an invalid character
+
++kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`
++kubebuilder:validation:MinLength=1
++kubebuilder:validation:MaxLength=253 |  |
 
 
 
@@ -10753,6 +11714,8 @@ Invalid values include:
 | ExternalName | string| `string` |  | |  |  |
 | HealthAnnotations | map of string| `map[string]string` |  | |  |  |
 | Ip | string| `string` |  | |  |  |
+| IpFamilies | [][IPFamily](#ip-family)| `[]IPFamily` |  | |  |  |
+| Ips | []string| `[]string` |  | |  |  |
 | Labels | map of string| `map[string]string` |  | |  |  |
 | Name | string| `string` |  | |  |  |
 | Namespace | string| `string` |  | |  |  |
@@ -10775,12 +11738,15 @@ Invalid values include:
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
 | DestinationRules | [][DestinationRule](#destination-rule)| `[]*DestinationRule` |  | |  |  |
+| IsAmbient | boolean| `bool` |  | |  |  |
 | IstioSidecar | boolean| `bool` |  | |  |  |
+| K8sGRPCRoutes | [][GRPCRoute](#g-rpc-route)| `[]*GRPCRoute` |  | |  |  |
 | K8sHTTPRoutes | [][HTTPRoute](#http-route)| `[]*HTTPRoute` |  | |  |  |
 | K8sReferenceGrants | [][ReferenceGrant](#reference-grant)| `[]*ReferenceGrant` |  | |  |  |
 | ServiceEntries | [][ServiceEntry](#service-entry)| `[]*ServiceEntry` |  | |  |  |
 | SubServices | [][ServiceOverview](#service-overview)| `[]*ServiceOverview` |  | |  |  |
 | VirtualServices | [][VirtualService](#virtual-service)| `[]*VirtualService` |  | |  |  |
+| WaypointWorkloads | [][WorkloadReferenceInfo](#workload-reference-info)| `[]*WorkloadReferenceInfo` |  | |  |  |
 | endpoints | [Endpoints](#endpoints)| `Endpoints` |  | |  |  |
 | health | [ServiceHealth](#service-health)| `ServiceHealth` |  | |  |  |
 | istioPermissions | [ResourcePermissions](#resource-permissions)| `ResourcePermissions` |  | |  |  |
@@ -10796,7 +11762,7 @@ Invalid values include:
 
 > <!-- crd generation tags
 +cue-gen:ServiceEntry:groupName:networking.istio.io
-+cue-gen:ServiceEntry:version:v1
++cue-gen:ServiceEntry:versions:v1beta1,v1alpha3,v1
 +cue-gen:ServiceEntry:annotations:helm.sh/resource-policy=keep
 +cue-gen:ServiceEntry:labels:app=istio-pilot,chart=istio,heritage=Tiller,release=istio
 +cue-gen:ServiceEntry:subresource:status
@@ -10812,20 +11778,164 @@ representing the server time when this object was created. It is not guaranteed
 Clients may not set this value. It is represented in RFC3339 form and is in UTC.
 Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata"
 +cue-gen:ServiceEntry:preserveUnknownFields:false
++cue-gen:ServiceEntry:spec:required
+>
+
+<!-- go code generation tags
++kubetype-gen
++kubetype-gen:groupVersion=networking.istio.io/v1alpha3
++genclient
++k8s:deepcopy-gen=true
+istiostatus-override: ServiceEntryStatus: istio.io/api/networking/v1alpha3
 >
++kubebuilder:validation:XValidation:message="only one of WorkloadSelector or Endpoints can be set",rule="oneof(self.workloadSelector, self.endpoints)"
++kubebuilder:validation:XValidation:message="CIDR addresses are allowed only for NONE/STATIC resolution types",rule="!(default(self.addresses, []).exists(k, k.contains('/')) && !(default(self.resolution, 'NONE') in ['STATIC', 'NONE']))"
++kubebuilder:validation:XValidation:message="NONE mode cannot set endpoints",rule="default(self.resolution, 'NONE') == 'NONE' ? !has(self.endpoints) : true"
++kubebuilder:validation:XValidation:message="DNS_ROUND_ROBIN mode cannot have multiple endpoints",rule="default(self.resolution, ”) == 'DNS_ROUND_ROBIN' ? default(self.endpoints, []).size() <= 1 : true"
+  
+
+
+
+
+
+**Properties**
+
+| Name | Type | Go type | Required | Default | Description | Example |
+|------|------|---------|:--------:| ------- |-------------|---------|
+| APIVersion | string| `string` |  | | APIVersion defines the versioned schema of this representation of an object.
+Servers should convert recognized schemas to the latest internal value, and
+may reject unrecognized values.
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
++optional |  |
+| Annotations | map of string| `map[string]string` |  | | Annotations is an unstructured key value map stored with a resource that may be
+set by external tools to store and retrieve arbitrary metadata. They are not
+queryable and should be preserved when modifying objects.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations
++optional |  |
+| DeletionGracePeriodSeconds | int64 (formatted integer)| `int64` |  | | Number of seconds allowed for this object to gracefully terminate before
+it will be removed from the system. Only set when deletionTimestamp is also set.
+May only be shortened.
+Read-only.
++optional |  |
+| Finalizers | []string| `[]string` |  | | Must be empty before the object is deleted from the registry. Each entry
+is an identifier for the responsible component that will remove the entry
+from the list. If the deletionTimestamp of the object is non-nil, entries
+in this list can only be removed.
+Finalizers may be processed and removed in any order.  Order is NOT enforced
+because it introduces significant risk of stuck finalizers.
+finalizers is a shared field, any actor with permission can reorder it.
+If the finalizer list is processed in order, then this can lead to a situation
+in which the component responsible for the first finalizer in the list is
+waiting for a signal (field value, external system, or other) produced by a
+component responsible for a finalizer later in the list, resulting in a deadlock.
+Without enforced ordering finalizers are free to order amongst themselves and
+are not vulnerable to ordering changes in the list.
++optional
++patchStrategy=merge
++listType=set |  |
+| GenerateName | string| `string` |  | | GenerateName is an optional prefix, used by the server, to generate a unique
+name ONLY IF the Name field has not been provided.
+If this field is used, the name returned to the client will be different
+than the name passed. This value will also be combined with a unique suffix.
+The provided value has the same validation rules as the Name field,
+and may be truncated by the length of the suffix required to make the value
+unique on the server.
+
+If this field is specified and the generated name exists, the server will return a 409.
+
+Applied only if Name is not specified.
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency
++optional |  |
+| Generation | int64 (formatted integer)| `int64` |  | | A sequence number representing a specific generation of the desired state.
+Populated by the system. Read-only.
++optional |  |
+| Kind | string| `string` |  | | Kind is a string value representing the REST resource this object represents.
+Servers may infer this from the endpoint the client submits requests to.
+Cannot be updated.
+In CamelCase.
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
++optional |  |
+| Labels | map of string| `map[string]string` |  | | Map of string keys and values that can be used to organize and categorize
+(scope and select) objects. May match selectors of replication controllers
+and services.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels
++optional |  |
+| ManagedFields | [][ManagedFieldsEntry](#managed-fields-entry)| `[]*ManagedFieldsEntry` |  | | ManagedFields maps workflow-id and version to the set of fields
+that are managed by that workflow. This is mostly for internal
+housekeeping, and users typically shouldn't need to set or
+understand this field. A workflow can be the user's name, a
+controller's name, or the name of a specific apply path like
+"ci-cd". The set of fields is always in the version that the
+workflow used when modifying the object.
+
++optional
++listType=atomic |  |
+| Name | string| `string` |  | | Name must be unique within a namespace. Is required when creating resources, although
+some resources may allow a client to request the generation of an appropriate name
+automatically. Name is primarily intended for creation idempotence and configuration
+definition.
+Cannot be updated.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names
++optional |  |
+| Namespace | string| `string` |  | | Namespace defines the space within which each name must be unique. An empty namespace is
+equivalent to the "default" namespace, but "default" is the canonical representation.
+Not all objects are required to be scoped to a namespace - the value of this field for
+those objects will be empty.
+
+Must be a DNS_LABEL.
+Cannot be updated.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces
++optional |  |
+| OwnerReferences | [][OwnerReference](#owner-reference)| `[]*OwnerReference` |  | | List of objects depended by this object. If ALL objects in the list have
+been deleted, this object will be garbage collected. If this object is managed by a controller,
+then an entry in this list will point to this controller, with the controller field set to true.
+There cannot be more than one managing controller.
++optional
++patchMergeKey=uid
++patchStrategy=merge
++listType=map
++listMapKey=uid |  |
+| ResourceVersion | string| `string` |  | | An opaque value that represents the internal version of this object that can
+be used by clients to determine when objects have changed. May be used for optimistic
+concurrency, change detection, and the watch operation on a resource or set of resources.
+Clients must treat these values as opaque and passed unmodified back to the server.
+They may only be valid for a particular resource or set of resources.
+
+Populated by the system.
+Read-only.
+Value must be treated as opaque by clients and .
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
++optional |  |
+| SelfLink | string| `string` |  | | Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.
++optional |  |
+| creationTimestamp | [Time](#time)| `Time` |  | |  |  |
+| deletionTimestamp | [Time](#time)| `Time` |  | |  |  |
+| spec | [ServiceEntry](#service-entry)| `ServiceEntry` |  | |  |  |
+| status | [ServiceEntryStatus](#service-entry-status)| `ServiceEntryStatus` |  | |  |  |
+| uid | [UID](#uid)| `UID` |  | |  |  |
+
+
+
+### <span id="service-entry-address"></span> ServiceEntryAddress
+
+
+  
+
+
+
+**Properties**
+
+| Name | Type | Go type | Required | Default | Description | Example |
+|------|------|---------|:--------:| ------- |-------------|---------|
+| Host | string| `string` |  | | The host name associated with this address |  |
+| Value | string| `string` |  | | The address (e.g. 192.168.0.2) |  |
+
 
-<!-- go code generation tags
-+kubetype-gen
-+kubetype-gen:groupVersion=networking.istio.io/v1
-+genclient
-+k8s:deepcopy-gen=true
->
-<!-- istio code generation tags
-+istio.io/sync-from:networking/v1alpha3/service_entry.proto
->
-  
+
+### <span id="service-entry-status"></span> ServiceEntryStatus
 
 
+  
 
 
 
@@ -10833,25 +11943,21 @@ Populated by the system. Read-only. Null for lists. More info: https://git.k8s.i
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| APIVersion | string| `string` |  | | APIVersion defines the versioned schema of this representation of an object.</br>Servers should convert recognized schemas to the latest internal value, and</br>may reject unrecognized values.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources</br>+optional |  |
-| Annotations | map of string| `map[string]string` |  | | Annotations is an unstructured key value map stored with a resource that may be</br>set by external tools to store and retrieve arbitrary metadata. They are not</br>queryable and should be preserved when modifying objects.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations</br>+optional |  |
-| CreationTimestamp | string| `string` |  | | CreationTimestamp is a timestamp representing the server time when this object was</br>created. It is not guaranteed to be set in happens-before order across separate operations.</br>Clients may not set this value. It is represented in RFC3339 form and is in UTC.</br></br>Populated by the system.</br>Read-only.</br>Null for lists.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| DeletionGracePeriodSeconds | int64 (formatted integer)| `int64` |  | | Number of seconds allowed for this object to gracefully terminate before</br>it will be removed from the system. Only set when deletionTimestamp is also set.</br>May only be shortened.</br>Read-only.</br>+optional |  |
-| DeletionTimestamp | string| `string` |  | | DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This</br>field is set by the server when a graceful deletion is requested by the user, and is not</br>directly settable by a client. The resource is expected to be deleted (no longer visible</br>from resource lists, and not reachable by name) after the time in this field, once the</br>finalizers list is empty. As long as the finalizers list contains items, deletion is blocked.</br>Once the deletionTimestamp is set, this value may not be unset or be set further into the</br>future, although it may be shortened or the resource may be deleted prior to this time.</br>For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react</br>by sending a graceful termination signal to the containers in the pod. After that 30 seconds,</br>the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,</br>remove the pod from the API. In the presence of network partitions, this object may still</br>exist after this timestamp, until an administrator or automated process can determine the</br>resource is fully terminated.</br>If not set, graceful deletion of the object has not been requested.</br></br>Populated by the system when a graceful deletion is requested.</br>Read-only.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| Finalizers | []string| `[]string` |  | | Must be empty before the object is deleted from the registry. Each entry</br>is an identifier for the responsible component that will remove the entry</br>from the list. If the deletionTimestamp of the object is non-nil, entries</br>in this list can only be removed.</br>Finalizers may be processed and removed in any order.  Order is NOT enforced</br>because it introduces significant risk of stuck finalizers.</br>finalizers is a shared field, any actor with permission can reorder it.</br>If the finalizer list is processed in order, then this can lead to a situation</br>in which the component responsible for the first finalizer in the list is</br>waiting for a signal (field value, external system, or other) produced by a</br>component responsible for a finalizer later in the list, resulting in a deadlock.</br>Without enforced ordering finalizers are free to order amongst themselves and</br>are not vulnerable to ordering changes in the list.</br>+optional</br>+patchStrategy=merge</br>+listType=set |  |
-| GenerateName | string| `string` |  | | GenerateName is an optional prefix, used by the server, to generate a unique</br>name ONLY IF the Name field has not been provided.</br>If this field is used, the name returned to the client will be different</br>than the name passed. This value will also be combined with a unique suffix.</br>The provided value has the same validation rules as the Name field,</br>and may be truncated by the length of the suffix required to make the value</br>unique on the server.</br></br>If this field is specified and the generated name exists, the server will return a 409.</br></br>Applied only if Name is not specified.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency</br>+optional |  |
-| Generation | int64 (formatted integer)| `int64` |  | | A sequence number representing a specific generation of the desired state.</br>Populated by the system. Read-only.</br>+optional |  |
-| Kind | string| `string` |  | | Kind is a string value representing the REST resource this object represents.</br>Servers may infer this from the endpoint the client submits requests to.</br>Cannot be updated.</br>In CamelCase.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds</br>+optional |  |
-| Labels | map of string| `map[string]string` |  | | Map of string keys and values that can be used to organize and categorize</br>(scope and select) objects. May match selectors of replication controllers</br>and services.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels</br>+optional |  |
-| ManagedFields | [][ManagedFieldsEntry](#managed-fields-entry)| `[]*ManagedFieldsEntry` |  | | ManagedFields maps workflow-id and version to the set of fields</br>that are managed by that workflow. This is mostly for internal</br>housekeeping, and users typically shouldn't need to set or</br>understand this field. A workflow can be the user's name, a</br>controller's name, or the name of a specific apply path like</br>"ci-cd". The set of fields is always in the version that the</br>workflow used when modifying the object.</br></br>+optional</br>+listType=atomic |  |
-| Name | string| `string` |  | | Name must be unique within a namespace. Is required when creating resources, although</br>some resources may allow a client to request the generation of an appropriate name</br>automatically. Name is primarily intended for creation idempotence and configuration</br>definition.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names</br>+optional |  |
-| Namespace | string| `string` |  | | Namespace defines the space within which each name must be unique. An empty namespace is</br>equivalent to the "default" namespace, but "default" is the canonical representation.</br>Not all objects are required to be scoped to a namespace - the value of this field for</br>those objects will be empty.</br></br>Must be a DNS_LABEL.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces</br>+optional |  |
-| OwnerReferences | [][OwnerReference](#owner-reference)| `[]*OwnerReference` |  | | List of objects depended by this object. If ALL objects in the list have</br>been deleted, this object will be garbage collected. If this object is managed by a controller,</br>then an entry in this list will point to this controller, with the controller field set to true.</br>There cannot be more than one managing controller.</br>+optional</br>+patchMergeKey=uid</br>+patchStrategy=merge</br>+listType=map</br>+listMapKey=uid |  |
-| ResourceVersion | string| `string` |  | | An opaque value that represents the internal version of this object that can</br>be used by clients to determine when objects have changed. May be used for optimistic</br>concurrency, change detection, and the watch operation on a resource or set of resources.</br>Clients must treat these values as opaque and passed unmodified back to the server.</br>They may only be valid for a particular resource or set of resources.</br></br>Populated by the system.</br>Read-only.</br>Value must be treated as opaque by clients and .</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency</br>+optional |  |
-| SelfLink | string| `string` |  | | Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.</br>+optional |  |
-| spec | [ServiceEntry](#service-entry)| `ServiceEntry` |  | |  |  |
-| status | [IstioStatus](#istio-status)| `IstioStatus` |  | |  |  |
-| uid | [UID](#uid)| `UID` |  | |  |  |
+| Addresses | [][ServiceEntryAddress](#service-entry-address)| `[]*ServiceEntryAddress` |  | | List of addresses which were assigned to this ServiceEntry.
++optional |  |
+| Conditions | [][IstioCondition](#istio-condition)| `[]*IstioCondition` |  | | Current service state of ServiceEntry.
+More info: https://istio.io/docs/reference/config/config-status/
++optional
++patchMergeKey=type
++patchStrategy=merge |  |
+| ObservedGeneration | int64 (formatted integer)| `int64` |  | | Resource Generation to which the Reconciled Condition refers.
+When this value is not equal to the object's metadata generation, reconciled condition  calculation for the current
+generation is still in progress.  See https://istio.io/latest/docs/reference/config/config-status/ for more info.
++optional |  |
+| ValidationMessages | [][AnalysisMessageBase](#analysis-message-base)| `[]*AnalysisMessageBase` |  | | Includes any errors or warnings detected by Istio's analyzers.
++optional
++patchMergeKey=type
++patchStrategy=merge |  |
 
 
 
@@ -10922,7 +12028,7 @@ Populated by the system. Read-only. Null for lists. More info: https://git.k8s.i
 | AppLabel | boolean| `bool` | ✓ | | Has label app | `true` |
 | Cluster | string| `string` |  | | The kube cluster where this service is located. |  |
 | HealthAnnotations | map of string| `map[string]string` |  | | Annotations of the service |  |
-| IstioAmbient | boolean| `bool` | ✓ | | Check if it has Ambient enabled | `true` |
+| IsAmbient | boolean| `bool` | ✓ | | Check if it has Ambient enabled | `true` |
 | IstioReferences | [][IstioValidationKey](#istio-validation-key)| `[]*IstioValidationKey` |  | | Istio References |  |
 | IstioSidecar | boolean| `bool` | ✓ | | Define if Pods related to this Service has an IstioSidecar deployed | `true` |
 | KialiWizard | string| `string` |  | | Kiali Wizard scenario, if any |  |
@@ -10931,32 +12037,41 @@ Populated by the system. Read-only. Null for lists. More info: https://git.k8s.i
 | Namespace | string| `string` |  | | Namespace of the Service |  |
 | Ports | map of int64 (formatted integer)| `map[string]int64` |  | | Names and Ports of Service |  |
 | Selector | map of string| `map[string]string` |  | | Selector for Service |  |
-| ServiceRegistry | string| `string` |  | | ServiceRegistry values:</br>Kubernetes: 	is a service registry backed by k8s API server</br>External: 	is a service registry for externally provided ServiceEntries</br>Federation:  special case when registry is provided from a federated environment |  |
+| ServiceRegistry | string| `string` |  | | ServiceRegistry values:
+Kubernetes: 	is a service registry backed by k8s API server
+External: 	is a service registry for externally provided ServiceEntries
+Federation:  special case when registry is provided from a federated environment |  |
 | additionalDetailSample | [AdditionalItem](#additional-item)| `AdditionalItem` |  | |  |  |
 | health | [ServiceHealth](#service-health)| `ServiceHealth` |  | |  |  |
 
 
 
-### <span id="service-reference"></span> ServiceReference
+### <span id="service-reference-info"></span> ServiceReferenceInfo
 
 
+> Used, for example, to link services to Ambient waypoint proxies
   
 
 
 
+
+
 **Properties**
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Name | string| `string` |  | |  |  |
-| Namespace | string| `string` |  | |  |  |
+| Cluster | string| `string` |  | | Cluster |  |
+| LabelType | string| `string` |  | | LabelType in case of waypoint workloads,
+Where the label comes from (namespace, workload or service) | `namespace` |
+| Name | string| `string` | ✓ | | Name for the service |  |
+| Namespace | string| `string` | ✓ | | Namespace where the workload live in | `bookinfo` |
 
 
 
 ### <span id="session-persistence"></span> SessionPersistence
 
 
-> +kubebuilder:validation:XValidation:message="AbsoluteTimeout must be specified when cookie lifetimeType is Permanent",rule="!has(self.cookieConfig.lifetimeType) || self.cookieConfig.lifetimeType != 'Permanent' || has(self.absoluteTimeout)"
+> +kubebuilder:validation:XValidation:message="AbsoluteTimeout must be specified when cookie lifetimeType is Permanent",rule="!has(self.cookieConfig) || !has(self.cookieConfig.lifetimeType) || self.cookieConfig.lifetimeType != 'Permanent' || has(self.absoluteTimeout)"
   
 
 
@@ -10967,7 +12082,15 @@ Populated by the system. Read-only. Null for lists. More info: https://git.k8s.i
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| SessionName | string| `string` |  | | SessionName defines the name of the persistent session token</br>which may be reflected in the cookie or the header. Users</br>should avoid reusing session names to prevent unintended</br>consequences, such as rejection or unpredictable behavior.</br></br>Support: Implementation-specific</br></br>+optional</br>+kubebuilder:validation:MaxLength=128 |  |
+| SessionName | string| `string` |  | | SessionName defines the name of the persistent session token
+which may be reflected in the cookie or the header. Users
+should avoid reusing session names to prevent unintended
+consequences, such as rejection or unpredictable behavior.
+
+Support: Implementation-specific
+
++optional
++kubebuilder:validation:MaxLength=128 |  |
 | absoluteTimeout | [Duration](#duration)| `Duration` |  | |  |  |
 | cookieConfig | [CookieConfig](#cookie-config)| `CookieConfig` |  | |  |  |
 | idleTimeout | [Duration](#duration)| `Duration` |  | |  |  |
@@ -10989,72 +12112,6 @@ Populated by the system. Read-only. Null for lists. More info: https://git.k8s.i
 
 
 
-### <span id="severity-level"></span> SeverityLevel
-
-
-  
-
-| Name | Type | Go type | Default | Description | Example |
-|------|------|---------| ------- |-------------|---------|
-| SeverityLevel | string| string | |  |  |
-
-
-
-### <span id="sidecar"></span> Sidecar
-
-
-> <!-- crd generation tags
-+cue-gen:Sidecar:groupName:networking.istio.io
-+cue-gen:Sidecar:version:v1
-+cue-gen:Sidecar:annotations:helm.sh/resource-policy=keep
-+cue-gen:Sidecar:labels:app=istio-pilot,chart=istio,heritage=Tiller,release=istio
-+cue-gen:Sidecar:subresource:status
-+cue-gen:Sidecar:scope:Namespaced
-+cue-gen:Sidecar:resource:categories=istio-io,networking-istio-io
-+cue-gen:Sidecar:preserveUnknownFields:false
->
-
-<!-- go code generation tags
-+kubetype-gen
-+kubetype-gen:groupVersion=networking.istio.io/v1
-+genclient
-+k8s:deepcopy-gen=true
->
-<!-- istio code generation tags
-+istio.io/sync-from:networking/v1alpha3/sidecar.proto
->
-  
-
-
-
-
-
-**Properties**
-
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| APIVersion | string| `string` |  | | APIVersion defines the versioned schema of this representation of an object.</br>Servers should convert recognized schemas to the latest internal value, and</br>may reject unrecognized values.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources</br>+optional |  |
-| Annotations | map of string| `map[string]string` |  | | Annotations is an unstructured key value map stored with a resource that may be</br>set by external tools to store and retrieve arbitrary metadata. They are not</br>queryable and should be preserved when modifying objects.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations</br>+optional |  |
-| CreationTimestamp | string| `string` |  | | CreationTimestamp is a timestamp representing the server time when this object was</br>created. It is not guaranteed to be set in happens-before order across separate operations.</br>Clients may not set this value. It is represented in RFC3339 form and is in UTC.</br></br>Populated by the system.</br>Read-only.</br>Null for lists.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| DeletionGracePeriodSeconds | int64 (formatted integer)| `int64` |  | | Number of seconds allowed for this object to gracefully terminate before</br>it will be removed from the system. Only set when deletionTimestamp is also set.</br>May only be shortened.</br>Read-only.</br>+optional |  |
-| DeletionTimestamp | string| `string` |  | | DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This</br>field is set by the server when a graceful deletion is requested by the user, and is not</br>directly settable by a client. The resource is expected to be deleted (no longer visible</br>from resource lists, and not reachable by name) after the time in this field, once the</br>finalizers list is empty. As long as the finalizers list contains items, deletion is blocked.</br>Once the deletionTimestamp is set, this value may not be unset or be set further into the</br>future, although it may be shortened or the resource may be deleted prior to this time.</br>For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react</br>by sending a graceful termination signal to the containers in the pod. After that 30 seconds,</br>the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,</br>remove the pod from the API. In the presence of network partitions, this object may still</br>exist after this timestamp, until an administrator or automated process can determine the</br>resource is fully terminated.</br>If not set, graceful deletion of the object has not been requested.</br></br>Populated by the system when a graceful deletion is requested.</br>Read-only.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| Finalizers | []string| `[]string` |  | | Must be empty before the object is deleted from the registry. Each entry</br>is an identifier for the responsible component that will remove the entry</br>from the list. If the deletionTimestamp of the object is non-nil, entries</br>in this list can only be removed.</br>Finalizers may be processed and removed in any order.  Order is NOT enforced</br>because it introduces significant risk of stuck finalizers.</br>finalizers is a shared field, any actor with permission can reorder it.</br>If the finalizer list is processed in order, then this can lead to a situation</br>in which the component responsible for the first finalizer in the list is</br>waiting for a signal (field value, external system, or other) produced by a</br>component responsible for a finalizer later in the list, resulting in a deadlock.</br>Without enforced ordering finalizers are free to order amongst themselves and</br>are not vulnerable to ordering changes in the list.</br>+optional</br>+patchStrategy=merge</br>+listType=set |  |
-| GenerateName | string| `string` |  | | GenerateName is an optional prefix, used by the server, to generate a unique</br>name ONLY IF the Name field has not been provided.</br>If this field is used, the name returned to the client will be different</br>than the name passed. This value will also be combined with a unique suffix.</br>The provided value has the same validation rules as the Name field,</br>and may be truncated by the length of the suffix required to make the value</br>unique on the server.</br></br>If this field is specified and the generated name exists, the server will return a 409.</br></br>Applied only if Name is not specified.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency</br>+optional |  |
-| Generation | int64 (formatted integer)| `int64` |  | | A sequence number representing a specific generation of the desired state.</br>Populated by the system. Read-only.</br>+optional |  |
-| Kind | string| `string` |  | | Kind is a string value representing the REST resource this object represents.</br>Servers may infer this from the endpoint the client submits requests to.</br>Cannot be updated.</br>In CamelCase.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds</br>+optional |  |
-| Labels | map of string| `map[string]string` |  | | Map of string keys and values that can be used to organize and categorize</br>(scope and select) objects. May match selectors of replication controllers</br>and services.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels</br>+optional |  |
-| ManagedFields | [][ManagedFieldsEntry](#managed-fields-entry)| `[]*ManagedFieldsEntry` |  | | ManagedFields maps workflow-id and version to the set of fields</br>that are managed by that workflow. This is mostly for internal</br>housekeeping, and users typically shouldn't need to set or</br>understand this field. A workflow can be the user's name, a</br>controller's name, or the name of a specific apply path like</br>"ci-cd". The set of fields is always in the version that the</br>workflow used when modifying the object.</br></br>+optional</br>+listType=atomic |  |
-| Name | string| `string` |  | | Name must be unique within a namespace. Is required when creating resources, although</br>some resources may allow a client to request the generation of an appropriate name</br>automatically. Name is primarily intended for creation idempotence and configuration</br>definition.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names</br>+optional |  |
-| Namespace | string| `string` |  | | Namespace defines the space within which each name must be unique. An empty namespace is</br>equivalent to the "default" namespace, but "default" is the canonical representation.</br>Not all objects are required to be scoped to a namespace - the value of this field for</br>those objects will be empty.</br></br>Must be a DNS_LABEL.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces</br>+optional |  |
-| OwnerReferences | [][OwnerReference](#owner-reference)| `[]*OwnerReference` |  | | List of objects depended by this object. If ALL objects in the list have</br>been deleted, this object will be garbage collected. If this object is managed by a controller,</br>then an entry in this list will point to this controller, with the controller field set to true.</br>There cannot be more than one managing controller.</br>+optional</br>+patchMergeKey=uid</br>+patchStrategy=merge</br>+listType=map</br>+listMapKey=uid |  |
-| ResourceVersion | string| `string` |  | | An opaque value that represents the internal version of this object that can</br>be used by clients to determine when objects have changed. May be used for optimistic</br>concurrency, change detection, and the watch operation on a resource or set of resources.</br>Clients must treat these values as opaque and passed unmodified back to the server.</br>They may only be valid for a particular resource or set of resources.</br></br>Populated by the system.</br>Read-only.</br>Value must be treated as opaque by clients and .</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency</br>+optional |  |
-| SelfLink | string| `string` |  | | Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.</br>+optional |  |
-| spec | [Sidecar](#sidecar)| `Sidecar` |  | |  |  |
-| status | [IstioStatus](#istio-status)| `IstioStatus` |  | |  |  |
-| uid | [UID](#uid)| `UID` |  | |  |  |
-
-
-
 ### <span id="span"></span> Span
 
 
@@ -11138,175 +12195,20 @@ This is used for returning a response of Kiali Status
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
 | ExternalServices | [][ExternalServiceInfo](#external-service-info)| `[]*ExternalServiceInfo` | ✓ | | An array of external services installed |  |
-| Status | map of string| `map[string]string` | ✓ | | The state of Kiali</br>A hash of key,values with versions of Kiali and state |  |
+| Status | map of string| `map[string]string` | ✓ | | The state of Kiali
+A hash of key,values with versions of Kiali and state |  |
 | WarningMessages | []string| `[]string` |  | | An array of warningMessages. CAUTION: Please read the doc comments the in AddWarningMessages func. |  |
 | istioEnvironment | [IstioEnvironment](#istio-environment)| `IstioEnvironment` | ✓ | |  |  |
 
 
 
-### <span id="tcp-route"></span> TCPRoute
-
-
-> TCPRoute provides a way to route TCP requests. When combined with a Gateway
-listener, it can be used to forward connections on the port specified by the
-listener to a set of backends specified by the TCPRoute.
-  
-
-
-
-
-
-**Properties**
-
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| APIVersion | string| `string` |  | | APIVersion defines the versioned schema of this representation of an object.</br>Servers should convert recognized schemas to the latest internal value, and</br>may reject unrecognized values.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources</br>+optional |  |
-| Annotations | map of string| `map[string]string` |  | | Annotations is an unstructured key value map stored with a resource that may be</br>set by external tools to store and retrieve arbitrary metadata. They are not</br>queryable and should be preserved when modifying objects.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations</br>+optional |  |
-| CreationTimestamp | string| `string` |  | | CreationTimestamp is a timestamp representing the server time when this object was</br>created. It is not guaranteed to be set in happens-before order across separate operations.</br>Clients may not set this value. It is represented in RFC3339 form and is in UTC.</br></br>Populated by the system.</br>Read-only.</br>Null for lists.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| DeletionGracePeriodSeconds | int64 (formatted integer)| `int64` |  | | Number of seconds allowed for this object to gracefully terminate before</br>it will be removed from the system. Only set when deletionTimestamp is also set.</br>May only be shortened.</br>Read-only.</br>+optional |  |
-| DeletionTimestamp | string| `string` |  | | DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This</br>field is set by the server when a graceful deletion is requested by the user, and is not</br>directly settable by a client. The resource is expected to be deleted (no longer visible</br>from resource lists, and not reachable by name) after the time in this field, once the</br>finalizers list is empty. As long as the finalizers list contains items, deletion is blocked.</br>Once the deletionTimestamp is set, this value may not be unset or be set further into the</br>future, although it may be shortened or the resource may be deleted prior to this time.</br>For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react</br>by sending a graceful termination signal to the containers in the pod. After that 30 seconds,</br>the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,</br>remove the pod from the API. In the presence of network partitions, this object may still</br>exist after this timestamp, until an administrator or automated process can determine the</br>resource is fully terminated.</br>If not set, graceful deletion of the object has not been requested.</br></br>Populated by the system when a graceful deletion is requested.</br>Read-only.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| Finalizers | []string| `[]string` |  | | Must be empty before the object is deleted from the registry. Each entry</br>is an identifier for the responsible component that will remove the entry</br>from the list. If the deletionTimestamp of the object is non-nil, entries</br>in this list can only be removed.</br>Finalizers may be processed and removed in any order.  Order is NOT enforced</br>because it introduces significant risk of stuck finalizers.</br>finalizers is a shared field, any actor with permission can reorder it.</br>If the finalizer list is processed in order, then this can lead to a situation</br>in which the component responsible for the first finalizer in the list is</br>waiting for a signal (field value, external system, or other) produced by a</br>component responsible for a finalizer later in the list, resulting in a deadlock.</br>Without enforced ordering finalizers are free to order amongst themselves and</br>are not vulnerable to ordering changes in the list.</br>+optional</br>+patchStrategy=merge</br>+listType=set |  |
-| GenerateName | string| `string` |  | | GenerateName is an optional prefix, used by the server, to generate a unique</br>name ONLY IF the Name field has not been provided.</br>If this field is used, the name returned to the client will be different</br>than the name passed. This value will also be combined with a unique suffix.</br>The provided value has the same validation rules as the Name field,</br>and may be truncated by the length of the suffix required to make the value</br>unique on the server.</br></br>If this field is specified and the generated name exists, the server will return a 409.</br></br>Applied only if Name is not specified.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency</br>+optional |  |
-| Generation | int64 (formatted integer)| `int64` |  | | A sequence number representing a specific generation of the desired state.</br>Populated by the system. Read-only.</br>+optional |  |
-| Kind | string| `string` |  | | Kind is a string value representing the REST resource this object represents.</br>Servers may infer this from the endpoint the client submits requests to.</br>Cannot be updated.</br>In CamelCase.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds</br>+optional |  |
-| Labels | map of string| `map[string]string` |  | | Map of string keys and values that can be used to organize and categorize</br>(scope and select) objects. May match selectors of replication controllers</br>and services.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels</br>+optional |  |
-| ManagedFields | [][ManagedFieldsEntry](#managed-fields-entry)| `[]*ManagedFieldsEntry` |  | | ManagedFields maps workflow-id and version to the set of fields</br>that are managed by that workflow. This is mostly for internal</br>housekeeping, and users typically shouldn't need to set or</br>understand this field. A workflow can be the user's name, a</br>controller's name, or the name of a specific apply path like</br>"ci-cd". The set of fields is always in the version that the</br>workflow used when modifying the object.</br></br>+optional</br>+listType=atomic |  |
-| Name | string| `string` |  | | Name must be unique within a namespace. Is required when creating resources, although</br>some resources may allow a client to request the generation of an appropriate name</br>automatically. Name is primarily intended for creation idempotence and configuration</br>definition.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names</br>+optional |  |
-| Namespace | string| `string` |  | | Namespace defines the space within which each name must be unique. An empty namespace is</br>equivalent to the "default" namespace, but "default" is the canonical representation.</br>Not all objects are required to be scoped to a namespace - the value of this field for</br>those objects will be empty.</br></br>Must be a DNS_LABEL.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces</br>+optional |  |
-| OwnerReferences | [][OwnerReference](#owner-reference)| `[]*OwnerReference` |  | | List of objects depended by this object. If ALL objects in the list have</br>been deleted, this object will be garbage collected. If this object is managed by a controller,</br>then an entry in this list will point to this controller, with the controller field set to true.</br>There cannot be more than one managing controller.</br>+optional</br>+patchMergeKey=uid</br>+patchStrategy=merge</br>+listType=map</br>+listMapKey=uid |  |
-| ResourceVersion | string| `string` |  | | An opaque value that represents the internal version of this object that can</br>be used by clients to determine when objects have changed. May be used for optimistic</br>concurrency, change detection, and the watch operation on a resource or set of resources.</br>Clients must treat these values as opaque and passed unmodified back to the server.</br>They may only be valid for a particular resource or set of resources.</br></br>Populated by the system.</br>Read-only.</br>Value must be treated as opaque by clients and .</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency</br>+optional |  |
-| SelfLink | string| `string` |  | | Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.</br>+optional |  |
-| spec | [TCPRouteSpec](#tcp-route-spec)| `TCPRouteSpec` |  | |  |  |
-| status | [TCPRouteStatus](#tcp-route-status)| `TCPRouteStatus` |  | |  |  |
-| uid | [UID](#uid)| `UID` |  | |  |  |
-
-
-
-### <span id="tcp-route-rule"></span> TCPRouteRule
-
-
-  
-
-
-
-**Properties**
-
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| BackendRefs | [][BackendRef](#backend-ref)| `[]*BackendRef` |  | | BackendRefs defines the backend(s) where matching requests should be</br>sent. If unspecified or invalid (refers to a non-existent resource or a</br>Service with no endpoints), the underlying implementation MUST actively</br>reject connection attempts to this backend. Connection rejections must</br>respect weight; if an invalid backend is requested to have 80% of</br>connections, then 80% of connections must be rejected instead.</br></br>Support: Core for Kubernetes Service</br></br>Support: Extended for Kubernetes ServiceImport</br></br>Support: Implementation-specific for any other resource</br></br>Support for weight: Extended</br></br>+kubebuilder:validation:MinItems=1</br>+kubebuilder:validation:MaxItems=16 |  |
-
-
-
-### <span id="tcp-route-spec"></span> TCPRouteSpec
-
-
-> TCPRouteSpec defines the desired state of TCPRoute
-  
-
-
-
-
-
-**Properties**
-
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| ParentRefs | [][ParentReference](#parent-reference)| `[]*ParentReference` |  | | ParentRefs references the resources (usually Gateways) that a Route wants</br>to be attached to. Note that the referenced parent resource needs to</br>allow this for the attachment to be complete. For Gateways, that means</br>the Gateway needs to allow attachment from Routes of this kind and</br>namespace. For Services, that means the Service must either be in the same</br>namespace for a "producer" route, or the mesh implementation must support</br>and allow "consumer" routes for the referenced Service. ReferenceGrant is</br>not applicable for governing ParentRefs to Services - it is not possible to</br>create a "producer" route for a Service in a different namespace from the</br>Route.</br></br>There are two kinds of parent resources with "Core" support:</br></br>Gateway (Gateway conformance profile)</br>Service (Mesh conformance profile, ClusterIP Services only)</br></br>This API may be extended in the future to support additional kinds of parent</br>resources.</br></br>ParentRefs must be _distinct_. This means either that:</br></br>They select different objects.  If this is the case, then parentRef</br>entries are distinct. In terms of fields, this means that the</br>multi-part key defined by `group`, `kind`, `namespace`, and `name` must</br>be unique across all parentRef entries in the Route.</br>They do not select different objects, but for each optional field used,</br>each ParentRef that selects the same object must set the same set of</br>optional fields to different values. If one ParentRef sets a</br>combination of optional fields, all must set the same combination.</br></br>Some examples:</br></br>If one ParentRef sets `sectionName`, all ParentRefs referencing the</br>same object must also set `sectionName`.</br>If one ParentRef sets `port`, all ParentRefs referencing the same</br>object must also set `port`.</br>If one ParentRef sets `sectionName` and `port`, all ParentRefs</br>referencing the same object must also set `sectionName` and `port`.</br></br>It is possible to separately reference multiple distinct objects that may</br>be collapsed by an implementation. For example, some implementations may</br>choose to merge compatible Gateway Listeners together. If that is the</br>case, the list of routes attached to those resources should also be</br>merged.</br></br>Note that for ParentRefs that cross namespace boundaries, there are specific</br>rules. Cross-namespace references are only valid if they are explicitly</br>allowed by something in the namespace they are referring to. For example,</br>Gateway has the AllowedRoutes field, and ReferenceGrant provides a</br>generic way to enable other kinds of cross-namespace reference.</br></br><gateway:experimental:description></br>ParentRefs from a Route to a Service in the same namespace are "producer"</br>routes, which apply default routing rules to inbound connections from</br>any namespace to the Service.</br></br>ParentRefs from a Route to a Service in a different namespace are</br>"consumer" routes, and these routing rules are only applied to outbound</br>connections originating from the same namespace as the Route, for which</br>the intended destination of the connections are a Service targeted as a</br>ParentRef of the Route.</br></gateway:experimental:description></br></br>+optional</br>+kubebuilder:validation:MaxItems=32</br><gateway:standard:validation:XValidation:message="sectionName must be specified when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.all(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__ )) ? ((!has(p1.sectionName) || p1.sectionName == '') == (!has(p2.sectionName) || p2.sectionName == '')) : true))"></br><gateway:standard:validation:XValidation:message="sectionName must be unique when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName == '')) || (has(p1.sectionName) && has(p2.sectionName) && p1.sectionName == p2.sectionName))))"></br><gateway:experimental:validation:XValidation:message="sectionName or port must be specified when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.all(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__)) ? ((!has(p1.sectionName) || p1.sectionName == '') == (!has(p2.sectionName) || p2.sectionName == '') && (!has(p1.port) || p1.port == 0) == (!has(p2.port) || p2.port == 0)): true))"></br><gateway:experimental:validation:XValidation:message="sectionName or port must be unique when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName == '')) || ( has(p1.sectionName) && has(p2.sectionName) && p1.sectionName == p2.sectionName)) && (((!has(p1.port) || p1.port == 0) && (!has(p2.port) || p2.port == 0)) || (has(p1.port) && has(p2.port) && p1.port == p2.port))))"> |  |
-| Rules | [][TCPRouteRule](#tcp-route-rule)| `[]*TCPRouteRule` |  | | Rules are a list of TCP matchers and actions.</br></br>+kubebuilder:validation:MinItems=1</br>+kubebuilder:validation:MaxItems=16 |  |
-
-
-
-### <span id="tcp-route-status"></span> TCPRouteStatus
-
-
-> TCPRouteStatus defines the observed state of TCPRoute
-  
-
-
-
-
-
-**Properties**
-
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| Parents | [][RouteParentStatus](#route-parent-status)| `[]*RouteParentStatus` |  | | Parents is a list of parent resources (usually Gateways) that are</br>associated with the route, and the status of the route with respect to</br>each parent. When this route attaches to a parent, the controller that</br>manages the parent must add an entry to this list when the controller</br>first sees the route and should update the entry as appropriate when the</br>route or gateway is modified.</br></br>Note that parent references that cannot be resolved by an implementation</br>of this API will not be added to this list. Implementations of this API</br>can only populate Route status for the Gateways/parent resources they are</br>responsible for.</br></br>A maximum of 32 Gateways will be represented in this list. An empty list</br>means the route has not been attached to any Gateway.</br></br>+kubebuilder:validation:MaxItems=32 |  |
-
-
-
-### <span id="tls-route"></span> TLSRoute
-
-
-> If you need to forward traffic to a single target for a TLS listener, you
-could choose to use a TCPRoute with a TLS listener.
-  
-
-
-
-
-
-**Properties**
-
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| APIVersion | string| `string` |  | | APIVersion defines the versioned schema of this representation of an object.</br>Servers should convert recognized schemas to the latest internal value, and</br>may reject unrecognized values.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources</br>+optional |  |
-| Annotations | map of string| `map[string]string` |  | | Annotations is an unstructured key value map stored with a resource that may be</br>set by external tools to store and retrieve arbitrary metadata. They are not</br>queryable and should be preserved when modifying objects.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations</br>+optional |  |
-| CreationTimestamp | string| `string` |  | | CreationTimestamp is a timestamp representing the server time when this object was</br>created. It is not guaranteed to be set in happens-before order across separate operations.</br>Clients may not set this value. It is represented in RFC3339 form and is in UTC.</br></br>Populated by the system.</br>Read-only.</br>Null for lists.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| DeletionGracePeriodSeconds | int64 (formatted integer)| `int64` |  | | Number of seconds allowed for this object to gracefully terminate before</br>it will be removed from the system. Only set when deletionTimestamp is also set.</br>May only be shortened.</br>Read-only.</br>+optional |  |
-| DeletionTimestamp | string| `string` |  | | DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This</br>field is set by the server when a graceful deletion is requested by the user, and is not</br>directly settable by a client. The resource is expected to be deleted (no longer visible</br>from resource lists, and not reachable by name) after the time in this field, once the</br>finalizers list is empty. As long as the finalizers list contains items, deletion is blocked.</br>Once the deletionTimestamp is set, this value may not be unset or be set further into the</br>future, although it may be shortened or the resource may be deleted prior to this time.</br>For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react</br>by sending a graceful termination signal to the containers in the pod. After that 30 seconds,</br>the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,</br>remove the pod from the API. In the presence of network partitions, this object may still</br>exist after this timestamp, until an administrator or automated process can determine the</br>resource is fully terminated.</br>If not set, graceful deletion of the object has not been requested.</br></br>Populated by the system when a graceful deletion is requested.</br>Read-only.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| Finalizers | []string| `[]string` |  | | Must be empty before the object is deleted from the registry. Each entry</br>is an identifier for the responsible component that will remove the entry</br>from the list. If the deletionTimestamp of the object is non-nil, entries</br>in this list can only be removed.</br>Finalizers may be processed and removed in any order.  Order is NOT enforced</br>because it introduces significant risk of stuck finalizers.</br>finalizers is a shared field, any actor with permission can reorder it.</br>If the finalizer list is processed in order, then this can lead to a situation</br>in which the component responsible for the first finalizer in the list is</br>waiting for a signal (field value, external system, or other) produced by a</br>component responsible for a finalizer later in the list, resulting in a deadlock.</br>Without enforced ordering finalizers are free to order amongst themselves and</br>are not vulnerable to ordering changes in the list.</br>+optional</br>+patchStrategy=merge</br>+listType=set |  |
-| GenerateName | string| `string` |  | | GenerateName is an optional prefix, used by the server, to generate a unique</br>name ONLY IF the Name field has not been provided.</br>If this field is used, the name returned to the client will be different</br>than the name passed. This value will also be combined with a unique suffix.</br>The provided value has the same validation rules as the Name field,</br>and may be truncated by the length of the suffix required to make the value</br>unique on the server.</br></br>If this field is specified and the generated name exists, the server will return a 409.</br></br>Applied only if Name is not specified.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency</br>+optional |  |
-| Generation | int64 (formatted integer)| `int64` |  | | A sequence number representing a specific generation of the desired state.</br>Populated by the system. Read-only.</br>+optional |  |
-| Kind | string| `string` |  | | Kind is a string value representing the REST resource this object represents.</br>Servers may infer this from the endpoint the client submits requests to.</br>Cannot be updated.</br>In CamelCase.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds</br>+optional |  |
-| Labels | map of string| `map[string]string` |  | | Map of string keys and values that can be used to organize and categorize</br>(scope and select) objects. May match selectors of replication controllers</br>and services.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels</br>+optional |  |
-| ManagedFields | [][ManagedFieldsEntry](#managed-fields-entry)| `[]*ManagedFieldsEntry` |  | | ManagedFields maps workflow-id and version to the set of fields</br>that are managed by that workflow. This is mostly for internal</br>housekeeping, and users typically shouldn't need to set or</br>understand this field. A workflow can be the user's name, a</br>controller's name, or the name of a specific apply path like</br>"ci-cd". The set of fields is always in the version that the</br>workflow used when modifying the object.</br></br>+optional</br>+listType=atomic |  |
-| Name | string| `string` |  | | Name must be unique within a namespace. Is required when creating resources, although</br>some resources may allow a client to request the generation of an appropriate name</br>automatically. Name is primarily intended for creation idempotence and configuration</br>definition.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names</br>+optional |  |
-| Namespace | string| `string` |  | | Namespace defines the space within which each name must be unique. An empty namespace is</br>equivalent to the "default" namespace, but "default" is the canonical representation.</br>Not all objects are required to be scoped to a namespace - the value of this field for</br>those objects will be empty.</br></br>Must be a DNS_LABEL.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces</br>+optional |  |
-| OwnerReferences | [][OwnerReference](#owner-reference)| `[]*OwnerReference` |  | | List of objects depended by this object. If ALL objects in the list have</br>been deleted, this object will be garbage collected. If this object is managed by a controller,</br>then an entry in this list will point to this controller, with the controller field set to true.</br>There cannot be more than one managing controller.</br>+optional</br>+patchMergeKey=uid</br>+patchStrategy=merge</br>+listType=map</br>+listMapKey=uid |  |
-| ResourceVersion | string| `string` |  | | An opaque value that represents the internal version of this object that can</br>be used by clients to determine when objects have changed. May be used for optimistic</br>concurrency, change detection, and the watch operation on a resource or set of resources.</br>Clients must treat these values as opaque and passed unmodified back to the server.</br>They may only be valid for a particular resource or set of resources.</br></br>Populated by the system.</br>Read-only.</br>Value must be treated as opaque by clients and .</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency</br>+optional |  |
-| SelfLink | string| `string` |  | | Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.</br>+optional |  |
-| spec | [TLSRouteSpec](#tls-route-spec)| `TLSRouteSpec` |  | |  |  |
-| status | [TLSRouteStatus](#tls-route-status)| `TLSRouteStatus` |  | |  |  |
-| uid | [UID](#uid)| `UID` |  | |  |  |
-
-
-
-### <span id="tls-route-rule"></span> TLSRouteRule
-
-
-  
-
-
-
-**Properties**
-
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| BackendRefs | [][BackendRef](#backend-ref)| `[]*BackendRef` |  | | BackendRefs defines the backend(s) where matching requests should be</br>sent. If unspecified or invalid (refers to a non-existent resource or</br>a Service with no endpoints), the rule performs no forwarding; if no</br>filters are specified that would result in a response being sent, the</br>underlying implementation must actively reject request attempts to this</br>backend, by rejecting the connection or returning a 500 status code.</br>Request rejections must respect weight; if an invalid backend is</br>requested to have 80% of requests, then 80% of requests must be rejected</br>instead.</br></br>Support: Core for Kubernetes Service</br></br>Support: Extended for Kubernetes ServiceImport</br></br>Support: Implementation-specific for any other resource</br></br>Support for weight: Extended</br></br>+kubebuilder:validation:MinItems=1</br>+kubebuilder:validation:MaxItems=16 |  |
-
-
-
-### <span id="tls-route-spec"></span> TLSRouteSpec
-
+### <span id="tag"></span> Tag
 
-  
-
-
-
-**Properties**
-
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| Hostnames | [][Hostname](#hostname)| `[]Hostname` |  | | Hostnames defines a set of SNI names that should match against the</br>SNI attribute of TLS ClientHello message in TLS handshake. This matches</br>the RFC 1123 definition of a hostname with 2 notable exceptions:</br></br>1. IPs are not allowed in SNI names per RFC 6066.</br>2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard</br>label must appear by itself as the first label.</br></br>If a hostname is specified by both the Listener and TLSRoute, there</br>must be at least one intersecting hostname for the TLSRoute to be |  |
-| ParentRefs | [][ParentReference](#parent-reference)| `[]*ParentReference` |  | | ParentRefs references the resources (usually Gateways) that a Route wants</br>to be attached to. Note that the referenced parent resource needs to</br>allow this for the attachment to be complete. For Gateways, that means</br>the Gateway needs to allow attachment from Routes of this kind and</br>namespace. For Services, that means the Service must either be in the same</br>namespace for a "producer" route, or the mesh implementation must support</br>and allow "consumer" routes for the referenced Service. ReferenceGrant is</br>not applicable for governing ParentRefs to Services - it is not possible to</br>create a "producer" route for a Service in a different namespace from the</br>Route.</br></br>There are two kinds of parent resources with "Core" support:</br></br>Gateway (Gateway conformance profile)</br>Service (Mesh conformance profile, ClusterIP Services only)</br></br>This API may be extended in the future to support additional kinds of parent</br>resources.</br></br>ParentRefs must be _distinct_. This means either that:</br></br>They select different objects.  If this is the case, then parentRef</br>entries are distinct. In terms of fields, this means that the</br>multi-part key defined by `group`, `kind`, `namespace`, and `name` must</br>be unique across all parentRef entries in the Route.</br>They do not select different objects, but for each optional field used,</br>each ParentRef that selects the same object must set the same set of</br>optional fields to different values. If one ParentRef sets a</br>combination of optional fields, all must set the same combination.</br></br>Some examples:</br></br>If one ParentRef sets `sectionName`, all ParentRefs referencing the</br>same object must also set `sectionName`.</br>If one ParentRef sets `port`, all ParentRefs referencing the same</br>object must also set `port`.</br>If one ParentRef sets `sectionName` and `port`, all ParentRefs</br>referencing the same object must also set `sectionName` and `port`.</br></br>It is possible to separately reference multiple distinct objects that may</br>be collapsed by an implementation. For example, some implementations may</br>choose to merge compatible Gateway Listeners together. If that is the</br>case, the list of routes attached to those resources should also be</br>merged.</br></br>Note that for ParentRefs that cross namespace boundaries, there are specific</br>rules. Cross-namespace references are only valid if they are explicitly</br>allowed by something in the namespace they are referring to. For example,</br>Gateway has the AllowedRoutes field, and ReferenceGrant provides a</br>generic way to enable other kinds of cross-namespace reference.</br></br><gateway:experimental:description></br>ParentRefs from a Route to a Service in the same namespace are "producer"</br>routes, which apply default routing rules to inbound connections from</br>any namespace to the Service.</br></br>ParentRefs from a Route to a Service in a different namespace are</br>"consumer" routes, and these routing rules are only applied to outbound</br>connections originating from the same namespace as the Route, for which</br>the intended destination of the connections are a Service targeted as a</br>ParentRef of the Route.</br></gateway:experimental:description></br></br>+optional</br>+kubebuilder:validation:MaxItems=32</br><gateway:standard:validation:XValidation:message="sectionName must be specified when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.all(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__ )) ? ((!has(p1.sectionName) || p1.sectionName == '') == (!has(p2.sectionName) || p2.sectionName == '')) : true))"></br><gateway:standard:validation:XValidation:message="sectionName must be unique when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName == '')) || (has(p1.sectionName) && has(p2.sectionName) && p1.sectionName == p2.sectionName))))"></br><gateway:experimental:validation:XValidation:message="sectionName or port must be specified when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.all(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__)) ? ((!has(p1.sectionName) || p1.sectionName == '') == (!has(p2.sectionName) || p2.sectionName == '') && (!has(p1.port) || p1.port == 0) == (!has(p2.port) || p2.port == 0)): true))"></br><gateway:experimental:validation:XValidation:message="sectionName or port must be unique when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName == '')) || ( has(p1.sectionName) && has(p2.sectionName) && p1.sectionName == p2.sectionName)) && (((!has(p1.port) || p1.port == 0) && (!has(p2.port) || p2.port == 0)) || (has(p1.port) && has(p2.port) && p1.port == p2.port))))"> |  |
-| Rules | [][TLSRouteRule](#tls-route-rule)| `[]*TLSRouteRule` |  | | Rules are a list of TLS matchers and actions.</br></br>+kubebuilder:validation:MinItems=1</br>+kubebuilder:validation:MaxItems=16 |  |
 
-
-
-### <span id="tls-route-status"></span> TLSRouteStatus
-
-
-> TLSRouteStatus defines the observed state of TLSRoute
+> It allows you to keep your dataplane revision labels stable
+while changing the controlplane revision so that you don't
+need to update all your namespace labels each time you upgrade
+your controlplane.
   
 
 
@@ -11317,7 +12219,9 @@ could choose to use a TCPRoute with a TLS listener.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Parents | [][RouteParentStatus](#route-parent-status)| `[]*RouteParentStatus` |  | | Parents is a list of parent resources (usually Gateways) that are</br>associated with the route, and the status of the route with respect to</br>each parent. When this route attaches to a parent, the controller that</br>manages the parent must add an entry to this list when the controller</br>first sees the route and should update the entry as appropriate when the</br>route or gateway is modified.</br></br>Note that parent references that cannot be resolved by an implementation</br>of this API will not be added to this list. Implementations of this API</br>can only populate Route status for the Gateways/parent resources they are</br>responsible for.</br></br>A maximum of 32 Gateways will be represented in this list. An empty list</br>means the route has not been attached to any Gateway.</br></br>+kubebuilder:validation:MaxItems=32 |  |
+| Cluster | string| `string` |  | | Cluster is the cluster that the tag is associated with. |  |
+| Name | string| `string` |  | | Name is the name of the tag. |  |
+| Revision | string| `string` |  | | Revision is the revision of the controlplane associated with this tag. |  |
 
 
 
@@ -11339,66 +12243,36 @@ could choose to use a TCPRoute with a TLS listener.
 
 
 
-### <span id="telemetry"></span> Telemetry
+### <span id="tempo-config"></span> TempoConfig
 
 
-> <!-- go code generation tags
-+kubetype-gen
-+kubetype-gen:groupVersion=telemetry.istio.io/v1
-+genclient
-+k8s:deepcopy-gen=true
->
->
-<!-- istio code generation tags
-+istio.io/sync-from:telemetry/v1alpha1/telemetry.proto
->
   
 
 
 
-
-
 **Properties**
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| APIVersion | string| `string` |  | | APIVersion defines the versioned schema of this representation of an object.</br>Servers should convert recognized schemas to the latest internal value, and</br>may reject unrecognized values.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources</br>+optional |  |
-| Annotations | map of string| `map[string]string` |  | | Annotations is an unstructured key value map stored with a resource that may be</br>set by external tools to store and retrieve arbitrary metadata. They are not</br>queryable and should be preserved when modifying objects.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations</br>+optional |  |
-| CreationTimestamp | string| `string` |  | | CreationTimestamp is a timestamp representing the server time when this object was</br>created. It is not guaranteed to be set in happens-before order across separate operations.</br>Clients may not set this value. It is represented in RFC3339 form and is in UTC.</br></br>Populated by the system.</br>Read-only.</br>Null for lists.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| DeletionGracePeriodSeconds | int64 (formatted integer)| `int64` |  | | Number of seconds allowed for this object to gracefully terminate before</br>it will be removed from the system. Only set when deletionTimestamp is also set.</br>May only be shortened.</br>Read-only.</br>+optional |  |
-| DeletionTimestamp | string| `string` |  | | DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This</br>field is set by the server when a graceful deletion is requested by the user, and is not</br>directly settable by a client. The resource is expected to be deleted (no longer visible</br>from resource lists, and not reachable by name) after the time in this field, once the</br>finalizers list is empty. As long as the finalizers list contains items, deletion is blocked.</br>Once the deletionTimestamp is set, this value may not be unset or be set further into the</br>future, although it may be shortened or the resource may be deleted prior to this time.</br>For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react</br>by sending a graceful termination signal to the containers in the pod. After that 30 seconds,</br>the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,</br>remove the pod from the API. In the presence of network partitions, this object may still</br>exist after this timestamp, until an administrator or automated process can determine the</br>resource is fully terminated.</br>If not set, graceful deletion of the object has not been requested.</br></br>Populated by the system when a graceful deletion is requested.</br>Read-only.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| Finalizers | []string| `[]string` |  | | Must be empty before the object is deleted from the registry. Each entry</br>is an identifier for the responsible component that will remove the entry</br>from the list. If the deletionTimestamp of the object is non-nil, entries</br>in this list can only be removed.</br>Finalizers may be processed and removed in any order.  Order is NOT enforced</br>because it introduces significant risk of stuck finalizers.</br>finalizers is a shared field, any actor with permission can reorder it.</br>If the finalizer list is processed in order, then this can lead to a situation</br>in which the component responsible for the first finalizer in the list is</br>waiting for a signal (field value, external system, or other) produced by a</br>component responsible for a finalizer later in the list, resulting in a deadlock.</br>Without enforced ordering finalizers are free to order amongst themselves and</br>are not vulnerable to ordering changes in the list.</br>+optional</br>+patchStrategy=merge</br>+listType=set |  |
-| GenerateName | string| `string` |  | | GenerateName is an optional prefix, used by the server, to generate a unique</br>name ONLY IF the Name field has not been provided.</br>If this field is used, the name returned to the client will be different</br>than the name passed. This value will also be combined with a unique suffix.</br>The provided value has the same validation rules as the Name field,</br>and may be truncated by the length of the suffix required to make the value</br>unique on the server.</br></br>If this field is specified and the generated name exists, the server will return a 409.</br></br>Applied only if Name is not specified.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency</br>+optional |  |
-| Generation | int64 (formatted integer)| `int64` |  | | A sequence number representing a specific generation of the desired state.</br>Populated by the system. Read-only.</br>+optional |  |
-| Kind | string| `string` |  | | Kind is a string value representing the REST resource this object represents.</br>Servers may infer this from the endpoint the client submits requests to.</br>Cannot be updated.</br>In CamelCase.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds</br>+optional |  |
-| Labels | map of string| `map[string]string` |  | | Map of string keys and values that can be used to organize and categorize</br>(scope and select) objects. May match selectors of replication controllers</br>and services.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels</br>+optional |  |
-| ManagedFields | [][ManagedFieldsEntry](#managed-fields-entry)| `[]*ManagedFieldsEntry` |  | | ManagedFields maps workflow-id and version to the set of fields</br>that are managed by that workflow. This is mostly for internal</br>housekeeping, and users typically shouldn't need to set or</br>understand this field. A workflow can be the user's name, a</br>controller's name, or the name of a specific apply path like</br>"ci-cd". The set of fields is always in the version that the</br>workflow used when modifying the object.</br></br>+optional</br>+listType=atomic |  |
-| Name | string| `string` |  | | Name must be unique within a namespace. Is required when creating resources, although</br>some resources may allow a client to request the generation of an appropriate name</br>automatically. Name is primarily intended for creation idempotence and configuration</br>definition.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names</br>+optional |  |
-| Namespace | string| `string` |  | | Namespace defines the space within which each name must be unique. An empty namespace is</br>equivalent to the "default" namespace, but "default" is the canonical representation.</br>Not all objects are required to be scoped to a namespace - the value of this field for</br>those objects will be empty.</br></br>Must be a DNS_LABEL.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces</br>+optional |  |
-| OwnerReferences | [][OwnerReference](#owner-reference)| `[]*OwnerReference` |  | | List of objects depended by this object. If ALL objects in the list have</br>been deleted, this object will be garbage collected. If this object is managed by a controller,</br>then an entry in this list will point to this controller, with the controller field set to true.</br>There cannot be more than one managing controller.</br>+optional</br>+patchMergeKey=uid</br>+patchStrategy=merge</br>+listType=map</br>+listMapKey=uid |  |
-| ResourceVersion | string| `string` |  | | An opaque value that represents the internal version of this object that can</br>be used by clients to determine when objects have changed. May be used for optimistic</br>concurrency, change detection, and the watch operation on a resource or set of resources.</br>Clients must treat these values as opaque and passed unmodified back to the server.</br>They may only be valid for a particular resource or set of resources.</br></br>Populated by the system.</br>Read-only.</br>Value must be treated as opaque by clients and .</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency</br>+optional |  |
-| SelfLink | string| `string` |  | | Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.</br>+optional |  |
-| spec | [Telemetry](#telemetry)| `Telemetry` |  | |  |  |
-| status | [IstioStatus](#istio-status)| `IstioStatus` |  | |  |  |
-| uid | [UID](#uid)| `UID` |  | |  |  |
+| CacheCapacity | int64 (formatted integer)| `int64` |  | |  |  |
+| CacheEnabled | boolean| `bool` |  | |  |  |
+| DatasourceUID | string| `string` |  | |  |  |
+| OrgID | string| `string` |  | |  |  |
+| URLFormat | string| `string` |  | |  |  |
 
 
 
-### <span id="tempo-config"></span> TempoConfig
+### <span id="time"></span> Time
 
 
+> +protobuf.options.marshal=false
++protobuf.as=Timestamp
++protobuf.options.(gogoproto.goproto_stringer)=false
   
 
 
 
-**Properties**
-
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| DatasourceUID | string| `string` |  | |  |  |
-| OrgID | string| `string` |  | |  |  |
-
-
+[interface{}](#interface)
 
 ### <span id="timestamp"></span> Timestamp
 
@@ -11496,8 +12370,13 @@ http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Nanos | int32 (formatted integer)| `int32` |  | | Non-negative fractions of a second at nanosecond resolution. Negative</br>second values with fractions must still have non-negative nanos values</br>that count forward in time. Must be from 0 to 999,999,999</br>inclusive. |  |
-| Seconds | int64 (formatted integer)| `int64` |  | | Represents seconds of UTC time since Unix epoch</br>1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to</br>9999-12-31T23:59:59Z inclusive. |  |
+| Nanos | int32 (formatted integer)| `int32` |  | | Non-negative fractions of a second at nanosecond resolution. Negative
+second values with fractions must still have non-negative nanos values
+that count forward in time. Must be from 0 to 999,999,999
+inclusive. |  |
+| Seconds | int64 (formatted integer)| `int64` |  | | Represents seconds of UTC time since Unix epoch
+1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
+9999-12-31T23:59:59Z inclusive. |  |
 
 
 
@@ -11595,7 +12474,9 @@ intent and helps make sure that UIDs and names do not get conflated.
 
 | Name | Type | Go type | Default | Description | Example |
 |------|------|---------| ------- |-------------|---------|
-| UID | string| string | | UID is a type that holds unique ID values, including UUIDs.  Because we</br>don't ONLY use UUIDs, this is an alias to string.  Being a type captures</br>intent and helps make sure that UIDs and names do not get conflated. |  |
+| UID | string| string | | UID is a type that holds unique ID values, including UUIDs.  Because we
+don't ONLY use UUIDs, this is an alias to string.  Being a type captures
+intent and helps make sure that UIDs and names do not get conflated. |  |
 
 
 
@@ -11614,8 +12495,10 @@ This is used for returning the token
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| ExpiresOn | date-time (formatted string)| `strfmt.DateTime` | ✓ | | The expired time for the token</br>A string with the Datetime when the token will be expired | `Thu, 07 Mar 2019 17:50:26 +0000` |
-| Username | string| `string` | ✓ | | The username for the token</br>A string with the user's username | `admin` |
+| ExpiresOn | date-time (formatted string)| `strfmt.DateTime` | ✓ | | The expired time for the token
+A string with the Datetime when the token will be expired | `Thu, 07 Mar 2019 17:50:26 +0000` |
+| Username | string| `string` | ✓ | | The username for the token
+A string with the user's username | `admin` |
 
 
 
@@ -11650,7 +12533,7 @@ This is used for returning the token
 
 > <!-- crd generation tags
 +cue-gen:VirtualService:groupName:networking.istio.io
-+cue-gen:VirtualService:version:v1
++cue-gen:VirtualService:versions:v1beta1,v1alpha3,v1
 +cue-gen:VirtualService:annotations:helm.sh/resource-policy=keep
 +cue-gen:VirtualService:labels:app=istio-pilot,chart=istio,heritage=Tiller,release=istio
 +cue-gen:VirtualService:subresource:status
@@ -11668,13 +12551,10 @@ Populated by the system. Read-only. Null for lists. More info: https://git.k8s.i
 
 <!-- go code generation tags
 +kubetype-gen
-+kubetype-gen:groupVersion=networking.istio.io/v1
++kubetype-gen:groupVersion=networking.istio.io/v1alpha3
 +genclient
 +k8s:deepcopy-gen=true
 >
-<!-- istio code generation tags
-+istio.io/sync-from:networking/v1alpha3/virtual_service.proto
->
   
 
 
@@ -11685,22 +12565,114 @@ Populated by the system. Read-only. Null for lists. More info: https://git.k8s.i
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| APIVersion | string| `string` |  | | APIVersion defines the versioned schema of this representation of an object.</br>Servers should convert recognized schemas to the latest internal value, and</br>may reject unrecognized values.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources</br>+optional |  |
-| Annotations | map of string| `map[string]string` |  | | Annotations is an unstructured key value map stored with a resource that may be</br>set by external tools to store and retrieve arbitrary metadata. They are not</br>queryable and should be preserved when modifying objects.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations</br>+optional |  |
-| CreationTimestamp | string| `string` |  | | CreationTimestamp is a timestamp representing the server time when this object was</br>created. It is not guaranteed to be set in happens-before order across separate operations.</br>Clients may not set this value. It is represented in RFC3339 form and is in UTC.</br></br>Populated by the system.</br>Read-only.</br>Null for lists.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| DeletionGracePeriodSeconds | int64 (formatted integer)| `int64` |  | | Number of seconds allowed for this object to gracefully terminate before</br>it will be removed from the system. Only set when deletionTimestamp is also set.</br>May only be shortened.</br>Read-only.</br>+optional |  |
-| DeletionTimestamp | string| `string` |  | | DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This</br>field is set by the server when a graceful deletion is requested by the user, and is not</br>directly settable by a client. The resource is expected to be deleted (no longer visible</br>from resource lists, and not reachable by name) after the time in this field, once the</br>finalizers list is empty. As long as the finalizers list contains items, deletion is blocked.</br>Once the deletionTimestamp is set, this value may not be unset or be set further into the</br>future, although it may be shortened or the resource may be deleted prior to this time.</br>For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react</br>by sending a graceful termination signal to the containers in the pod. After that 30 seconds,</br>the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,</br>remove the pod from the API. In the presence of network partitions, this object may still</br>exist after this timestamp, until an administrator or automated process can determine the</br>resource is fully terminated.</br>If not set, graceful deletion of the object has not been requested.</br></br>Populated by the system when a graceful deletion is requested.</br>Read-only.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| Finalizers | []string| `[]string` |  | | Must be empty before the object is deleted from the registry. Each entry</br>is an identifier for the responsible component that will remove the entry</br>from the list. If the deletionTimestamp of the object is non-nil, entries</br>in this list can only be removed.</br>Finalizers may be processed and removed in any order.  Order is NOT enforced</br>because it introduces significant risk of stuck finalizers.</br>finalizers is a shared field, any actor with permission can reorder it.</br>If the finalizer list is processed in order, then this can lead to a situation</br>in which the component responsible for the first finalizer in the list is</br>waiting for a signal (field value, external system, or other) produced by a</br>component responsible for a finalizer later in the list, resulting in a deadlock.</br>Without enforced ordering finalizers are free to order amongst themselves and</br>are not vulnerable to ordering changes in the list.</br>+optional</br>+patchStrategy=merge</br>+listType=set |  |
-| GenerateName | string| `string` |  | | GenerateName is an optional prefix, used by the server, to generate a unique</br>name ONLY IF the Name field has not been provided.</br>If this field is used, the name returned to the client will be different</br>than the name passed. This value will also be combined with a unique suffix.</br>The provided value has the same validation rules as the Name field,</br>and may be truncated by the length of the suffix required to make the value</br>unique on the server.</br></br>If this field is specified and the generated name exists, the server will return a 409.</br></br>Applied only if Name is not specified.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency</br>+optional |  |
-| Generation | int64 (formatted integer)| `int64` |  | | A sequence number representing a specific generation of the desired state.</br>Populated by the system. Read-only.</br>+optional |  |
-| Kind | string| `string` |  | | Kind is a string value representing the REST resource this object represents.</br>Servers may infer this from the endpoint the client submits requests to.</br>Cannot be updated.</br>In CamelCase.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds</br>+optional |  |
-| Labels | map of string| `map[string]string` |  | | Map of string keys and values that can be used to organize and categorize</br>(scope and select) objects. May match selectors of replication controllers</br>and services.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels</br>+optional |  |
-| ManagedFields | [][ManagedFieldsEntry](#managed-fields-entry)| `[]*ManagedFieldsEntry` |  | | ManagedFields maps workflow-id and version to the set of fields</br>that are managed by that workflow. This is mostly for internal</br>housekeeping, and users typically shouldn't need to set or</br>understand this field. A workflow can be the user's name, a</br>controller's name, or the name of a specific apply path like</br>"ci-cd". The set of fields is always in the version that the</br>workflow used when modifying the object.</br></br>+optional</br>+listType=atomic |  |
-| Name | string| `string` |  | | Name must be unique within a namespace. Is required when creating resources, although</br>some resources may allow a client to request the generation of an appropriate name</br>automatically. Name is primarily intended for creation idempotence and configuration</br>definition.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names</br>+optional |  |
-| Namespace | string| `string` |  | | Namespace defines the space within which each name must be unique. An empty namespace is</br>equivalent to the "default" namespace, but "default" is the canonical representation.</br>Not all objects are required to be scoped to a namespace - the value of this field for</br>those objects will be empty.</br></br>Must be a DNS_LABEL.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces</br>+optional |  |
-| OwnerReferences | [][OwnerReference](#owner-reference)| `[]*OwnerReference` |  | | List of objects depended by this object. If ALL objects in the list have</br>been deleted, this object will be garbage collected. If this object is managed by a controller,</br>then an entry in this list will point to this controller, with the controller field set to true.</br>There cannot be more than one managing controller.</br>+optional</br>+patchMergeKey=uid</br>+patchStrategy=merge</br>+listType=map</br>+listMapKey=uid |  |
-| ResourceVersion | string| `string` |  | | An opaque value that represents the internal version of this object that can</br>be used by clients to determine when objects have changed. May be used for optimistic</br>concurrency, change detection, and the watch operation on a resource or set of resources.</br>Clients must treat these values as opaque and passed unmodified back to the server.</br>They may only be valid for a particular resource or set of resources.</br></br>Populated by the system.</br>Read-only.</br>Value must be treated as opaque by clients and .</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency</br>+optional |  |
-| SelfLink | string| `string` |  | | Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.</br>+optional |  |
+| APIVersion | string| `string` |  | | APIVersion defines the versioned schema of this representation of an object.
+Servers should convert recognized schemas to the latest internal value, and
+may reject unrecognized values.
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
++optional |  |
+| Annotations | map of string| `map[string]string` |  | | Annotations is an unstructured key value map stored with a resource that may be
+set by external tools to store and retrieve arbitrary metadata. They are not
+queryable and should be preserved when modifying objects.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations
++optional |  |
+| DeletionGracePeriodSeconds | int64 (formatted integer)| `int64` |  | | Number of seconds allowed for this object to gracefully terminate before
+it will be removed from the system. Only set when deletionTimestamp is also set.
+May only be shortened.
+Read-only.
++optional |  |
+| Finalizers | []string| `[]string` |  | | Must be empty before the object is deleted from the registry. Each entry
+is an identifier for the responsible component that will remove the entry
+from the list. If the deletionTimestamp of the object is non-nil, entries
+in this list can only be removed.
+Finalizers may be processed and removed in any order.  Order is NOT enforced
+because it introduces significant risk of stuck finalizers.
+finalizers is a shared field, any actor with permission can reorder it.
+If the finalizer list is processed in order, then this can lead to a situation
+in which the component responsible for the first finalizer in the list is
+waiting for a signal (field value, external system, or other) produced by a
+component responsible for a finalizer later in the list, resulting in a deadlock.
+Without enforced ordering finalizers are free to order amongst themselves and
+are not vulnerable to ordering changes in the list.
++optional
++patchStrategy=merge
++listType=set |  |
+| GenerateName | string| `string` |  | | GenerateName is an optional prefix, used by the server, to generate a unique
+name ONLY IF the Name field has not been provided.
+If this field is used, the name returned to the client will be different
+than the name passed. This value will also be combined with a unique suffix.
+The provided value has the same validation rules as the Name field,
+and may be truncated by the length of the suffix required to make the value
+unique on the server.
+
+If this field is specified and the generated name exists, the server will return a 409.
+
+Applied only if Name is not specified.
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency
++optional |  |
+| Generation | int64 (formatted integer)| `int64` |  | | A sequence number representing a specific generation of the desired state.
+Populated by the system. Read-only.
++optional |  |
+| Kind | string| `string` |  | | Kind is a string value representing the REST resource this object represents.
+Servers may infer this from the endpoint the client submits requests to.
+Cannot be updated.
+In CamelCase.
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
++optional |  |
+| Labels | map of string| `map[string]string` |  | | Map of string keys and values that can be used to organize and categorize
+(scope and select) objects. May match selectors of replication controllers
+and services.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels
++optional |  |
+| ManagedFields | [][ManagedFieldsEntry](#managed-fields-entry)| `[]*ManagedFieldsEntry` |  | | ManagedFields maps workflow-id and version to the set of fields
+that are managed by that workflow. This is mostly for internal
+housekeeping, and users typically shouldn't need to set or
+understand this field. A workflow can be the user's name, a
+controller's name, or the name of a specific apply path like
+"ci-cd". The set of fields is always in the version that the
+workflow used when modifying the object.
+
++optional
++listType=atomic |  |
+| Name | string| `string` |  | | Name must be unique within a namespace. Is required when creating resources, although
+some resources may allow a client to request the generation of an appropriate name
+automatically. Name is primarily intended for creation idempotence and configuration
+definition.
+Cannot be updated.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names
++optional |  |
+| Namespace | string| `string` |  | | Namespace defines the space within which each name must be unique. An empty namespace is
+equivalent to the "default" namespace, but "default" is the canonical representation.
+Not all objects are required to be scoped to a namespace - the value of this field for
+those objects will be empty.
+
+Must be a DNS_LABEL.
+Cannot be updated.
+More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces
++optional |  |
+| OwnerReferences | [][OwnerReference](#owner-reference)| `[]*OwnerReference` |  | | List of objects depended by this object. If ALL objects in the list have
+been deleted, this object will be garbage collected. If this object is managed by a controller,
+then an entry in this list will point to this controller, with the controller field set to true.
+There cannot be more than one managing controller.
++optional
++patchMergeKey=uid
++patchStrategy=merge
++listType=map
++listMapKey=uid |  |
+| ResourceVersion | string| `string` |  | | An opaque value that represents the internal version of this object that can
+be used by clients to determine when objects have changed. May be used for optimistic
+concurrency, change detection, and the watch operation on a resource or set of resources.
+Clients must treat these values as opaque and passed unmodified back to the server.
+They may only be valid for a particular resource or set of resources.
+
+Populated by the system.
+Read-only.
+Value must be treated as opaque by clients and .
+More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
++optional |  |
+| SelfLink | string| `string` |  | | Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.
++optional |  |
+| creationTimestamp | [Time](#time)| `Time` |  | |  |  |
+| deletionTimestamp | [Time](#time)| `Time` |  | |  |  |
 | spec | [VirtualService](#virtual-service)| `VirtualService` |  | |  |  |
 | status | [IstioStatus](#istio-status)| `IstioStatus` |  | |  |  |
 | uid | [UID](#uid)| `UID` |  | |  |  |
@@ -11726,61 +12698,19 @@ associated with a workload node.
 
 
 
-### <span id="wasm-plugin"></span> WasmPlugin
+### <span id="waypoint-edge"></span> WaypointEdge
 
 
-> <!-- crd generation tags
-+cue-gen:WasmPlugin:groupName:extensions.istio.io
-+cue-gen:WasmPlugin:version:v1alpha1
-+cue-gen:WasmPlugin:storageVersion
-+cue-gen:WasmPlugin:annotations:helm.sh/resource-policy=keep
-+cue-gen:WasmPlugin:labels:app=istio-pilot,chart=istio,heritage=Tiller,release=istio
-+cue-gen:WasmPlugin:subresource:status
-+cue-gen:WasmPlugin:spec:required
-+cue-gen:WasmPlugin:scope:Namespaced
-+cue-gen:WasmPlugin:resource:categories=istio-io,extensions-istio-io
-+cue-gen:WasmPlugin:preserveUnknownFields:pluginConfig
-+cue-gen:WasmPlugin:printerColumn:name=Age,type=date,JSONPath=.metadata.creationTimestamp,description="CreationTimestamp is a timestamp
-representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations.
-Clients may not set this value. It is represented in RFC3339 form and is in UTC.
-Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata"
->
-
-<!-- go code generation tags
-+kubetype-gen
-+kubetype-gen:groupVersion=extensions.istio.io/v1alpha1
-+genclient
-+k8s:deepcopy-gen=true
->
   
 
 
 
-
-
 **Properties**
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| APIVersion | string| `string` |  | | APIVersion defines the versioned schema of this representation of an object.</br>Servers should convert recognized schemas to the latest internal value, and</br>may reject unrecognized values.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources</br>+optional |  |
-| Annotations | map of string| `map[string]string` |  | | Annotations is an unstructured key value map stored with a resource that may be</br>set by external tools to store and retrieve arbitrary metadata. They are not</br>queryable and should be preserved when modifying objects.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations</br>+optional |  |
-| CreationTimestamp | string| `string` |  | | CreationTimestamp is a timestamp representing the server time when this object was</br>created. It is not guaranteed to be set in happens-before order across separate operations.</br>Clients may not set this value. It is represented in RFC3339 form and is in UTC.</br></br>Populated by the system.</br>Read-only.</br>Null for lists.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| DeletionGracePeriodSeconds | int64 (formatted integer)| `int64` |  | | Number of seconds allowed for this object to gracefully terminate before</br>it will be removed from the system. Only set when deletionTimestamp is also set.</br>May only be shortened.</br>Read-only.</br>+optional |  |
-| DeletionTimestamp | string| `string` |  | | DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This</br>field is set by the server when a graceful deletion is requested by the user, and is not</br>directly settable by a client. The resource is expected to be deleted (no longer visible</br>from resource lists, and not reachable by name) after the time in this field, once the</br>finalizers list is empty. As long as the finalizers list contains items, deletion is blocked.</br>Once the deletionTimestamp is set, this value may not be unset or be set further into the</br>future, although it may be shortened or the resource may be deleted prior to this time.</br>For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react</br>by sending a graceful termination signal to the containers in the pod. After that 30 seconds,</br>the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,</br>remove the pod from the API. In the presence of network partitions, this object may still</br>exist after this timestamp, until an administrator or automated process can determine the</br>resource is fully terminated.</br>If not set, graceful deletion of the object has not been requested.</br></br>Populated by the system when a graceful deletion is requested.</br>Read-only.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| Finalizers | []string| `[]string` |  | | Must be empty before the object is deleted from the registry. Each entry</br>is an identifier for the responsible component that will remove the entry</br>from the list. If the deletionTimestamp of the object is non-nil, entries</br>in this list can only be removed.</br>Finalizers may be processed and removed in any order.  Order is NOT enforced</br>because it introduces significant risk of stuck finalizers.</br>finalizers is a shared field, any actor with permission can reorder it.</br>If the finalizer list is processed in order, then this can lead to a situation</br>in which the component responsible for the first finalizer in the list is</br>waiting for a signal (field value, external system, or other) produced by a</br>component responsible for a finalizer later in the list, resulting in a deadlock.</br>Without enforced ordering finalizers are free to order amongst themselves and</br>are not vulnerable to ordering changes in the list.</br>+optional</br>+patchStrategy=merge</br>+listType=set |  |
-| GenerateName | string| `string` |  | | GenerateName is an optional prefix, used by the server, to generate a unique</br>name ONLY IF the Name field has not been provided.</br>If this field is used, the name returned to the client will be different</br>than the name passed. This value will also be combined with a unique suffix.</br>The provided value has the same validation rules as the Name field,</br>and may be truncated by the length of the suffix required to make the value</br>unique on the server.</br></br>If this field is specified and the generated name exists, the server will return a 409.</br></br>Applied only if Name is not specified.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency</br>+optional |  |
-| Generation | int64 (formatted integer)| `int64` |  | | A sequence number representing a specific generation of the desired state.</br>Populated by the system. Read-only.</br>+optional |  |
-| Kind | string| `string` |  | | Kind is a string value representing the REST resource this object represents.</br>Servers may infer this from the endpoint the client submits requests to.</br>Cannot be updated.</br>In CamelCase.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds</br>+optional |  |
-| Labels | map of string| `map[string]string` |  | | Map of string keys and values that can be used to organize and categorize</br>(scope and select) objects. May match selectors of replication controllers</br>and services.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels</br>+optional |  |
-| ManagedFields | [][ManagedFieldsEntry](#managed-fields-entry)| `[]*ManagedFieldsEntry` |  | | ManagedFields maps workflow-id and version to the set of fields</br>that are managed by that workflow. This is mostly for internal</br>housekeeping, and users typically shouldn't need to set or</br>understand this field. A workflow can be the user's name, a</br>controller's name, or the name of a specific apply path like</br>"ci-cd". The set of fields is always in the version that the</br>workflow used when modifying the object.</br></br>+optional</br>+listType=atomic |  |
-| Name | string| `string` |  | | Name must be unique within a namespace. Is required when creating resources, although</br>some resources may allow a client to request the generation of an appropriate name</br>automatically. Name is primarily intended for creation idempotence and configuration</br>definition.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names</br>+optional |  |
-| Namespace | string| `string` |  | | Namespace defines the space within which each name must be unique. An empty namespace is</br>equivalent to the "default" namespace, but "default" is the canonical representation.</br>Not all objects are required to be scoped to a namespace - the value of this field for</br>those objects will be empty.</br></br>Must be a DNS_LABEL.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces</br>+optional |  |
-| OwnerReferences | [][OwnerReference](#owner-reference)| `[]*OwnerReference` |  | | List of objects depended by this object. If ALL objects in the list have</br>been deleted, this object will be garbage collected. If this object is managed by a controller,</br>then an entry in this list will point to this controller, with the controller field set to true.</br>There cannot be more than one managing controller.</br>+optional</br>+patchMergeKey=uid</br>+patchStrategy=merge</br>+listType=map</br>+listMapKey=uid |  |
-| ResourceVersion | string| `string` |  | | An opaque value that represents the internal version of this object that can</br>be used by clients to determine when objects have changed. May be used for optimistic</br>concurrency, change detection, and the watch operation on a resource or set of resources.</br>Clients must treat these values as opaque and passed unmodified back to the server.</br>They may only be valid for a particular resource or set of resources.</br></br>Populated by the system.</br>Read-only.</br>Value must be treated as opaque by clients and .</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency</br>+optional |  |
-| SelfLink | string| `string` |  | | Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.</br>+optional |  |
-| spec | [WasmPlugin](#wasm-plugin)| `WasmPlugin` |  | |  |  |
-| status | [IstioStatus](#istio-status)| `IstioStatus` |  | |  |  |
-| uid | [UID](#uid)| `UID` |  | |  |  |
+| Direction | string| `string` |  | |  |  |
+| fromEdge | [EdgeData](#edge-data)| `EdgeData` |  | |  |  |
 
 
 
@@ -11808,8 +12738,14 @@ Populated by the system. Read-only. Null for lists. More info: https://git.k8s.i
 | DashboardAnnotations | map of string| `map[string]string` |  | | Dashboard annotations |  |
 | DesiredReplicas | int32 (formatted integer)| `int32` | ✓ | | Number of desired replicas defined by the user in the controller Spec | `2` |
 | HealthAnnotations | map of string| `map[string]string` |  | | HealthAnnotations |  |
-| IstioAmbient | boolean| `bool` | ✓ | | Define if Pods related to this Workload has an IstioAmbient deployed | `true` |
-| IstioInjectionAnnotation | boolean| `bool` |  | | Define if Workload has an explicit Istio policy annotation</br>Istio supports this as a label as well - this will be defined if the label is set, too.</br>If both annotation and label are set, if any is false, injection is disabled.</br>It's mapped as a pointer to show three values nil, true, false |  |
+| IsAmbient | boolean| `bool` | ✓ | | Define if Pods related to this Workload has an IsAmbient deployed | `true` |
+| IsGateway | boolean| `bool` | ✓ | | Define if this Workload is a gateway (but not a waypoint) | `true` |
+| IsWaypoint | boolean| `bool` | ✓ | | Define if this Workload is an ambient waypoint | `true` |
+| IsZtunnel | boolean| `bool` | ✓ | | Define if this Workload is an ambient ztunnel | `true` |
+| IstioInjectionAnnotation | boolean| `bool` |  | | Define if Workload has an explicit Istio policy annotation
+Istio supports this as a label as well - this will be defined if the label is set, too.
+If both annotation and label are set, if any is false, injection is disabled.
+It's mapped as a pointer to show three values nil, true, false |  |
 | IstioReferences | [][IstioValidationKey](#istio-validation-key)| `[]*IstioValidationKey` |  | | Istio References |  |
 | IstioSidecar | boolean| `bool` | ✓ | | Define if Pods related to this Workload has an IstioSidecar deployed | `true` |
 | Labels | map of string| `map[string]string` |  | | Workload labels |  |
@@ -11820,102 +12756,36 @@ Populated by the system. Read-only. Null for lists. More info: https://git.k8s.i
 | Runtimes | [][Runtime](#runtime)| `[]*Runtime` |  | | Runtimes and associated dashboards |  |
 | ServiceAccountNames | []string| `[]string` |  | | Names of the workload service accounts |  |
 | Services | [][ServiceOverview](#service-overview)| `[]*ServiceOverview` |  | | Services that match workload selector |  |
-| Type | string| `string` | ✓ | | Type of the workload | `deployment` |
+| TemplateAnnotations | map of string| `map[string]string` |  | | TemplateAnnotations are the annotations on the pod template if the workload
+has a pod template. |  |
+| TemplateLabels | map of string| `map[string]string` |  | | TemplateLabels are the labels on the pod template if the workload
+has a pod template. |  |
+| ValidationKey | string| `string` |  | | ValidationKey is a pre-calculated key string: "cluster:namespace:name" |  |
+| ValidationVersion | string| `string` |  | | ValidationVersion is a pre-calculated string representing the workload "version", basically
+the workload information that, if changed, requires re-validation. |  |
 | VersionLabel | boolean| `bool` | ✓ | | Define if Pods related to this Workload has the label Version | `true` |
-| WaypointWorkloads | [][Workload](#workload)| `[]*Workload` |  | | Ambient waypoint workloads |  |
+| WaypointServices | [][ServiceReferenceInfo](#service-reference-info)| `[]*ServiceReferenceInfo` |  | | Ambient waypoint services |  |
+| WaypointWorkloads | [][WorkloadReferenceInfo](#workload-reference-info)| `[]*WorkloadReferenceInfo` |  | | Ambient waypoint workloads |  |
 | additionalDetailSample | [AdditionalItem](#additional-item)| `AdditionalItem` |  | |  |  |
+| gvk | [GroupVersionKind](#group-version-kind)| `GroupVersionKind` | ✓ | |  |  |
 | health | [WorkloadHealth](#workload-health)| `WorkloadHealth` |  | |  |  |
 | pods | [Pods](#pods)| `Pods` |  | |  |  |
 | validations | [IstioValidations](#istio-validations)| `IstioValidations` |  | |  |  |
+| workloadEntries | [WorkloadEntries](#workload-entries)| `WorkloadEntries` |  | |  |  |
 
 
 
-### <span id="workload-entry"></span> WorkloadEntry
-
+### <span id="workload-entries"></span> WorkloadEntries
 
-> <!-- crd generation tags
-+cue-gen:WorkloadEntry:groupName:networking.istio.io
-+cue-gen:WorkloadEntry:version:v1
-+cue-gen:WorkloadEntry:annotations:helm.sh/resource-policy=keep
-+cue-gen:WorkloadEntry:labels:app=istio-pilot,chart=istio,heritage=Tiller,release=istio
-+cue-gen:WorkloadEntry:subresource:status
-+cue-gen:WorkloadEntry:scope:Namespaced
-+cue-gen:WorkloadEntry:resource:categories=istio-io,networking-istio-io,shortNames=we,plural=workloadentries
-+cue-gen:WorkloadEntry:printerColumn:name=Age,type=date,JSONPath=.metadata.creationTimestamp,description="CreationTimestamp is a timestamp
-representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations.
-Clients may not set this value. It is represented in RFC3339 form and is in UTC.
-Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata"
-+cue-gen:WorkloadEntry:printerColumn:name=Address,type=string,JSONPath=.spec.address,description="Address associated with the network endpoint."
-+cue-gen:WorkloadEntry:preserveUnknownFields:false
->
 
-<!-- go code generation tags
-+kubetype-gen
-+kubetype-gen:groupVersion=networking.istio.io/v1
-+genclient
-+k8s:deepcopy-gen=true
->
-<!-- istio code generation tags
-+istio.io/sync-from:networking/v1alpha3/workload_entry.proto
->
   
 
+[][WorkloadEntry](#workload-entry)
 
+### <span id="workload-entry"></span> WorkloadEntry
 
 
-
-**Properties**
-
-| Name | Type | Go type | Required | Default | Description | Example |
-|------|------|---------|:--------:| ------- |-------------|---------|
-| APIVersion | string| `string` |  | | APIVersion defines the versioned schema of this representation of an object.</br>Servers should convert recognized schemas to the latest internal value, and</br>may reject unrecognized values.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources</br>+optional |  |
-| Annotations | map of string| `map[string]string` |  | | Annotations is an unstructured key value map stored with a resource that may be</br>set by external tools to store and retrieve arbitrary metadata. They are not</br>queryable and should be preserved when modifying objects.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations</br>+optional |  |
-| CreationTimestamp | string| `string` |  | | CreationTimestamp is a timestamp representing the server time when this object was</br>created. It is not guaranteed to be set in happens-before order across separate operations.</br>Clients may not set this value. It is represented in RFC3339 form and is in UTC.</br></br>Populated by the system.</br>Read-only.</br>Null for lists.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| DeletionGracePeriodSeconds | int64 (formatted integer)| `int64` |  | | Number of seconds allowed for this object to gracefully terminate before</br>it will be removed from the system. Only set when deletionTimestamp is also set.</br>May only be shortened.</br>Read-only.</br>+optional |  |
-| DeletionTimestamp | string| `string` |  | | DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This</br>field is set by the server when a graceful deletion is requested by the user, and is not</br>directly settable by a client. The resource is expected to be deleted (no longer visible</br>from resource lists, and not reachable by name) after the time in this field, once the</br>finalizers list is empty. As long as the finalizers list contains items, deletion is blocked.</br>Once the deletionTimestamp is set, this value may not be unset or be set further into the</br>future, although it may be shortened or the resource may be deleted prior to this time.</br>For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react</br>by sending a graceful termination signal to the containers in the pod. After that 30 seconds,</br>the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,</br>remove the pod from the API. In the presence of network partitions, this object may still</br>exist after this timestamp, until an administrator or automated process can determine the</br>resource is fully terminated.</br>If not set, graceful deletion of the object has not been requested.</br></br>Populated by the system when a graceful deletion is requested.</br>Read-only.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| Finalizers | []string| `[]string` |  | | Must be empty before the object is deleted from the registry. Each entry</br>is an identifier for the responsible component that will remove the entry</br>from the list. If the deletionTimestamp of the object is non-nil, entries</br>in this list can only be removed.</br>Finalizers may be processed and removed in any order.  Order is NOT enforced</br>because it introduces significant risk of stuck finalizers.</br>finalizers is a shared field, any actor with permission can reorder it.</br>If the finalizer list is processed in order, then this can lead to a situation</br>in which the component responsible for the first finalizer in the list is</br>waiting for a signal (field value, external system, or other) produced by a</br>component responsible for a finalizer later in the list, resulting in a deadlock.</br>Without enforced ordering finalizers are free to order amongst themselves and</br>are not vulnerable to ordering changes in the list.</br>+optional</br>+patchStrategy=merge</br>+listType=set |  |
-| GenerateName | string| `string` |  | | GenerateName is an optional prefix, used by the server, to generate a unique</br>name ONLY IF the Name field has not been provided.</br>If this field is used, the name returned to the client will be different</br>than the name passed. This value will also be combined with a unique suffix.</br>The provided value has the same validation rules as the Name field,</br>and may be truncated by the length of the suffix required to make the value</br>unique on the server.</br></br>If this field is specified and the generated name exists, the server will return a 409.</br></br>Applied only if Name is not specified.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency</br>+optional |  |
-| Generation | int64 (formatted integer)| `int64` |  | | A sequence number representing a specific generation of the desired state.</br>Populated by the system. Read-only.</br>+optional |  |
-| Kind | string| `string` |  | | Kind is a string value representing the REST resource this object represents.</br>Servers may infer this from the endpoint the client submits requests to.</br>Cannot be updated.</br>In CamelCase.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds</br>+optional |  |
-| Labels | map of string| `map[string]string` |  | | Map of string keys and values that can be used to organize and categorize</br>(scope and select) objects. May match selectors of replication controllers</br>and services.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels</br>+optional |  |
-| ManagedFields | [][ManagedFieldsEntry](#managed-fields-entry)| `[]*ManagedFieldsEntry` |  | | ManagedFields maps workflow-id and version to the set of fields</br>that are managed by that workflow. This is mostly for internal</br>housekeeping, and users typically shouldn't need to set or</br>understand this field. A workflow can be the user's name, a</br>controller's name, or the name of a specific apply path like</br>"ci-cd". The set of fields is always in the version that the</br>workflow used when modifying the object.</br></br>+optional</br>+listType=atomic |  |
-| Name | string| `string` |  | | Name must be unique within a namespace. Is required when creating resources, although</br>some resources may allow a client to request the generation of an appropriate name</br>automatically. Name is primarily intended for creation idempotence and configuration</br>definition.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names</br>+optional |  |
-| Namespace | string| `string` |  | | Namespace defines the space within which each name must be unique. An empty namespace is</br>equivalent to the "default" namespace, but "default" is the canonical representation.</br>Not all objects are required to be scoped to a namespace - the value of this field for</br>those objects will be empty.</br></br>Must be a DNS_LABEL.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces</br>+optional |  |
-| OwnerReferences | [][OwnerReference](#owner-reference)| `[]*OwnerReference` |  | | List of objects depended by this object. If ALL objects in the list have</br>been deleted, this object will be garbage collected. If this object is managed by a controller,</br>then an entry in this list will point to this controller, with the controller field set to true.</br>There cannot be more than one managing controller.</br>+optional</br>+patchMergeKey=uid</br>+patchStrategy=merge</br>+listType=map</br>+listMapKey=uid |  |
-| ResourceVersion | string| `string` |  | | An opaque value that represents the internal version of this object that can</br>be used by clients to determine when objects have changed. May be used for optimistic</br>concurrency, change detection, and the watch operation on a resource or set of resources.</br>Clients must treat these values as opaque and passed unmodified back to the server.</br>They may only be valid for a particular resource or set of resources.</br></br>Populated by the system.</br>Read-only.</br>Value must be treated as opaque by clients and .</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency</br>+optional |  |
-| SelfLink | string| `string` |  | | Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.</br>+optional |  |
-| spec | [WorkloadEntry](#workload-entry)| `WorkloadEntry` |  | |  |  |
-| status | [IstioStatus](#istio-status)| `IstioStatus` |  | |  |  |
-| uid | [UID](#uid)| `UID` |  | |  |  |
-
-
-
-### <span id="workload-group"></span> WorkloadGroup
-
-
-> <!-- crd generation tags
-+cue-gen:WorkloadGroup:groupName:networking.istio.io
-+cue-gen:WorkloadGroup:version:v1
-+cue-gen:WorkloadGroup:labels:app=istio-pilot,chart=istio,heritage=Tiller,release=istio
-+cue-gen:WorkloadGroup:subresource:status
-+cue-gen:WorkloadGroup:scope:Namespaced
-+cue-gen:WorkloadGroup:resource:categories=istio-io,networking-istio-io,shortNames=wg,plural=workloadgroups
-+cue-gen:WorkloadGroup:printerColumn:name=Age,type=date,JSONPath=.metadata.creationTimestamp,description="CreationTimestamp is a timestamp
-representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations.
-Clients may not set this value. It is represented in RFC3339 form and is in UTC.
-Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata"
-+cue-gen:WorkloadGroup:preserveUnknownFields:false
->
-
-<!-- go code generation tags
-+kubetype-gen
-+kubetype-gen:groupVersion=networking.istio.io/v1
-+genclient
-+k8s:deepcopy-gen=true
->
-<!-- istio code generation tags
-+istio.io/sync-from:networking/v1alpha3/workload_group.proto
->
+> WorkloadEntry describes networking_v1.WorkloadEntry for Kiali, used in WorkloadGroups
   
 
 
@@ -11926,25 +12796,15 @@ Populated by the system. Read-only. Null for lists. More info: https://git.k8s.i
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| APIVersion | string| `string` |  | | APIVersion defines the versioned schema of this representation of an object.</br>Servers should convert recognized schemas to the latest internal value, and</br>may reject unrecognized values.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources</br>+optional |  |
-| Annotations | map of string| `map[string]string` |  | | Annotations is an unstructured key value map stored with a resource that may be</br>set by external tools to store and retrieve arbitrary metadata. They are not</br>queryable and should be preserved when modifying objects.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations</br>+optional |  |
-| CreationTimestamp | string| `string` |  | | CreationTimestamp is a timestamp representing the server time when this object was</br>created. It is not guaranteed to be set in happens-before order across separate operations.</br>Clients may not set this value. It is represented in RFC3339 form and is in UTC.</br></br>Populated by the system.</br>Read-only.</br>Null for lists.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| DeletionGracePeriodSeconds | int64 (formatted integer)| `int64` |  | | Number of seconds allowed for this object to gracefully terminate before</br>it will be removed from the system. Only set when deletionTimestamp is also set.</br>May only be shortened.</br>Read-only.</br>+optional |  |
-| DeletionTimestamp | string| `string` |  | | DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This</br>field is set by the server when a graceful deletion is requested by the user, and is not</br>directly settable by a client. The resource is expected to be deleted (no longer visible</br>from resource lists, and not reachable by name) after the time in this field, once the</br>finalizers list is empty. As long as the finalizers list contains items, deletion is blocked.</br>Once the deletionTimestamp is set, this value may not be unset or be set further into the</br>future, although it may be shortened or the resource may be deleted prior to this time.</br>For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react</br>by sending a graceful termination signal to the containers in the pod. After that 30 seconds,</br>the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,</br>remove the pod from the API. In the presence of network partitions, this object may still</br>exist after this timestamp, until an administrator or automated process can determine the</br>resource is fully terminated.</br>If not set, graceful deletion of the object has not been requested.</br></br>Populated by the system when a graceful deletion is requested.</br>Read-only.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata</br>+optional |  |
-| Finalizers | []string| `[]string` |  | | Must be empty before the object is deleted from the registry. Each entry</br>is an identifier for the responsible component that will remove the entry</br>from the list. If the deletionTimestamp of the object is non-nil, entries</br>in this list can only be removed.</br>Finalizers may be processed and removed in any order.  Order is NOT enforced</br>because it introduces significant risk of stuck finalizers.</br>finalizers is a shared field, any actor with permission can reorder it.</br>If the finalizer list is processed in order, then this can lead to a situation</br>in which the component responsible for the first finalizer in the list is</br>waiting for a signal (field value, external system, or other) produced by a</br>component responsible for a finalizer later in the list, resulting in a deadlock.</br>Without enforced ordering finalizers are free to order amongst themselves and</br>are not vulnerable to ordering changes in the list.</br>+optional</br>+patchStrategy=merge</br>+listType=set |  |
-| GenerateName | string| `string` |  | | GenerateName is an optional prefix, used by the server, to generate a unique</br>name ONLY IF the Name field has not been provided.</br>If this field is used, the name returned to the client will be different</br>than the name passed. This value will also be combined with a unique suffix.</br>The provided value has the same validation rules as the Name field,</br>and may be truncated by the length of the suffix required to make the value</br>unique on the server.</br></br>If this field is specified and the generated name exists, the server will return a 409.</br></br>Applied only if Name is not specified.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency</br>+optional |  |
-| Generation | int64 (formatted integer)| `int64` |  | | A sequence number representing a specific generation of the desired state.</br>Populated by the system. Read-only.</br>+optional |  |
-| Kind | string| `string` |  | | Kind is a string value representing the REST resource this object represents.</br>Servers may infer this from the endpoint the client submits requests to.</br>Cannot be updated.</br>In CamelCase.</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds</br>+optional |  |
-| Labels | map of string| `map[string]string` |  | | Map of string keys and values that can be used to organize and categorize</br>(scope and select) objects. May match selectors of replication controllers</br>and services.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels</br>+optional |  |
-| ManagedFields | [][ManagedFieldsEntry](#managed-fields-entry)| `[]*ManagedFieldsEntry` |  | | ManagedFields maps workflow-id and version to the set of fields</br>that are managed by that workflow. This is mostly for internal</br>housekeeping, and users typically shouldn't need to set or</br>understand this field. A workflow can be the user's name, a</br>controller's name, or the name of a specific apply path like</br>"ci-cd". The set of fields is always in the version that the</br>workflow used when modifying the object.</br></br>+optional</br>+listType=atomic |  |
-| Name | string| `string` |  | | Name must be unique within a namespace. Is required when creating resources, although</br>some resources may allow a client to request the generation of an appropriate name</br>automatically. Name is primarily intended for creation idempotence and configuration</br>definition.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names</br>+optional |  |
-| Namespace | string| `string` |  | | Namespace defines the space within which each name must be unique. An empty namespace is</br>equivalent to the "default" namespace, but "default" is the canonical representation.</br>Not all objects are required to be scoped to a namespace - the value of this field for</br>those objects will be empty.</br></br>Must be a DNS_LABEL.</br>Cannot be updated.</br>More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces</br>+optional |  |
-| OwnerReferences | [][OwnerReference](#owner-reference)| `[]*OwnerReference` |  | | List of objects depended by this object. If ALL objects in the list have</br>been deleted, this object will be garbage collected. If this object is managed by a controller,</br>then an entry in this list will point to this controller, with the controller field set to true.</br>There cannot be more than one managing controller.</br>+optional</br>+patchMergeKey=uid</br>+patchStrategy=merge</br>+listType=map</br>+listMapKey=uid |  |
-| ResourceVersion | string| `string` |  | | An opaque value that represents the internal version of this object that can</br>be used by clients to determine when objects have changed. May be used for optimistic</br>concurrency, change detection, and the watch operation on a resource or set of resources.</br>Clients must treat these values as opaque and passed unmodified back to the server.</br>They may only be valid for a particular resource or set of resources.</br></br>Populated by the system.</br>Read-only.</br>Value must be treated as opaque by clients and .</br>More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency</br>+optional |  |
-| SelfLink | string| `string` |  | | Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.</br>+optional |  |
-| spec | [WorkloadGroup](#workload-group)| `WorkloadGroup` |  | |  |  |
-| status | [IstioStatus](#istio-status)| `IstioStatus` |  | |  |  |
-| uid | [UID](#uid)| `UID` |  | |  |  |
+| Annotations | map of string| `map[string]string` |  | |  |  |
+| AppLabel | boolean| `bool` |  | |  |  |
+| CreatedAt | string| `string` |  | |  |  |
+| Labels | map of string| `map[string]string` |  | |  |  |
+| Name | string| `string` |  | |  |  |
+| ServiceAccountName | string| `string` |  | |  |  |
+| Status | string| `string` |  | |  |  |
+| StatusReason | string| `string` |  | |  |  |
+| VersionLabel | boolean| `bool` |  | |  |  |
 
 
 
@@ -11978,11 +12838,14 @@ Populated by the system. Read-only. Null for lists. More info: https://git.k8s.i
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| IstioAmbient | boolean| `bool` | ✓ | | Define if belongs to a namespace labeled as ambient | `true` |
+| IsAmbient | boolean| `bool` | ✓ | | Define if belongs to a namespace labeled as ambient | `true` |
 | IstioSidecar | boolean| `bool` | ✓ | | Define if all Pods related to the Workload has an IstioSidecar deployed | `true` |
 | Labels | map of string| `map[string]string` |  | | Labels for Workload |  |
+| Namespace | string| `string` | ✓ | | Namespace of a workload member of an application | `bookinfo` |
 | ServiceAccountNames | []string| `[]string` | ✓ | | List of service accounts involved in this application |  |
+| WaypointWorkloads | [][WorkloadReferenceInfo](#workload-reference-info)| `[]*WorkloadReferenceInfo` |  | | Ambient waypoint workloads |  |
 | WorkloadName | string| `string` | ✓ | | Name of a workload member of an application | `reviews-v1` |
+| workloadGVK | [GroupVersionKind](#group-version-kind)| `GroupVersionKind` | ✓ | |  |  |
 
 
 
@@ -12023,8 +12886,14 @@ Populated by the system. Read-only. Null for lists. More info: https://git.k8s.i
 | CreatedAt | string| `string` | ✓ | | Creation timestamp (in RFC3339 format) | `2018-07-31T12:24:17Z` |
 | DashboardAnnotations | map of string| `map[string]string` |  | | Dashboard annotations |  |
 | HealthAnnotations | map of string| `map[string]string` |  | | HealthAnnotations |  |
-| IstioAmbient | boolean| `bool` | ✓ | | Define if Pods related to this Workload has an IstioAmbient deployed | `true` |
-| IstioInjectionAnnotation | boolean| `bool` |  | | Define if Workload has an explicit Istio policy annotation</br>Istio supports this as a label as well - this will be defined if the label is set, too.</br>If both annotation and label are set, if any is false, injection is disabled.</br>It's mapped as a pointer to show three values nil, true, false |  |
+| IsAmbient | boolean| `bool` | ✓ | | Define if Pods related to this Workload has an IsAmbient deployed | `true` |
+| IsGateway | boolean| `bool` | ✓ | | Define if this Workload is a gateway (but not a waypoint) | `true` |
+| IsWaypoint | boolean| `bool` | ✓ | | Define if this Workload is an ambient waypoint | `true` |
+| IsZtunnel | boolean| `bool` | ✓ | | Define if this Workload is an ambient ztunnel | `true` |
+| IstioInjectionAnnotation | boolean| `bool` |  | | Define if Workload has an explicit Istio policy annotation
+Istio supports this as a label as well - this will be defined if the label is set, too.
+If both annotation and label are set, if any is false, injection is disabled.
+It's mapped as a pointer to show three values nil, true, false |  |
 | IstioReferences | [][IstioValidationKey](#istio-validation-key)| `[]*IstioValidationKey` |  | | Istio References |  |
 | IstioSidecar | boolean| `bool` | ✓ | | Define if Pods related to this Workload has an IstioSidecar deployed | `true` |
 | Labels | map of string| `map[string]string` |  | | Workload labels |  |
@@ -12033,9 +12902,17 @@ Populated by the system. Read-only. Null for lists. More info: https://git.k8s.i
 | PodCount | int64 (formatted integer)| `int64` | ✓ | | Number of current workload pods | `1` |
 | ResourceVersion | string| `string` | ✓ | | Kubernetes ResourceVersion | `192892127` |
 | ServiceAccountNames | []string| `[]string` |  | | Names of the workload service accounts |  |
-| Type | string| `string` | ✓ | | Type of the workload | `deployment` |
+| TemplateAnnotations | map of string| `map[string]string` |  | | TemplateAnnotations are the annotations on the pod template if the workload
+has a pod template. |  |
+| TemplateLabels | map of string| `map[string]string` |  | | TemplateLabels are the labels on the pod template if the workload
+has a pod template. |  |
+| ValidationKey | string| `string` |  | | ValidationKey is a pre-calculated key string: "cluster:namespace:name" |  |
+| ValidationVersion | string| `string` |  | | ValidationVersion is a pre-calculated string representing the workload "version", basically
+the workload information that, if changed, requires re-validation. |  |
 | VersionLabel | boolean| `bool` | ✓ | | Define if Pods related to this Workload has the label Version | `true` |
+| WaypointWorkloads | []string| `[]string` |  | | Names of the waypoint proxy workloads, if any |  |
 | additionalDetailSample | [AdditionalItem](#additional-item)| `AdditionalItem` |  | |  |  |
+| gvk | [GroupVersionKind](#group-version-kind)| `GroupVersionKind` | ✓ | |  |  |
 | health | [WorkloadHealth](#workload-health)| `WorkloadHealth` |  | |  |  |
 
 
@@ -12047,19 +12924,27 @@ Populated by the system. Read-only. Null for lists. More info: https://git.k8s.i
 
 [][WorkloadListItem](#workload-list-item)
 
-### <span id="workload-reference"></span> WorkloadReference
+### <span id="workload-reference-info"></span> WorkloadReferenceInfo
 
 
+> Used, for example, to link services to Ambient waypoint proxies
   
 
 
 
+
+
 **Properties**
 
 | Name | Type | Go type | Required | Default | Description | Example |
 |------|------|---------|:--------:| ------- |-------------|---------|
-| Name | string| `string` |  | |  |  |
-| Namespace | string| `string` |  | |  |  |
+| Cluster | string| `string` |  | | Cluster |  |
+| LabelType | string| `string` |  | | LabelType in case of waypoint workloads,
+Where the label comes from (namespace, workload or service) | `namespace` |
+| Labels | map of string| `map[string]string` |  | | Workload labels |  |
+| Name | string| `string` | ✓ | | Name for the workload |  |
+| Namespace | string| `string` | ✓ | | Namespace where the workload live in | `bookinfo` |
+| Type | string| `string` |  | | In case of waypoints it can be service/workload | `workload/service` |
 
 
 
diff --git a/kubernetes/kubernetes.go b/kubernetes/kubernetes.go
index dbb6c7b5e..0ccf86a74 100644
--- a/kubernetes/kubernetes.go
+++ b/kubernetes/kubernetes.go
@@ -242,9 +242,8 @@ func (in *K8SClient) IsGatewayAPI() bool {
 		v1beta1Types := map[string]string{
 			K8sReferenceGrantType: "referencegrants",
 		}
-		isGatewayAPIV1 := checkGatewayAPIs(in, K8sNetworkingGroupVersionV1.String(), v1Types)
-		isGatewayAPIV1Beta1 := checkGatewayAPIs(in, K8sNetworkingGroupVersionV1Beta1.String(), v1beta1Types)
-		isGatewayAPI := isGatewayAPIV1 && isGatewayAPIV1Beta1
+		isGatewayAPIV1 := checkGatewayAPIs(in, K8sNetworkingGroupVersionV1.String(), v1Types, false)
+		isGatewayAPI := isGatewayAPIV1 && checkGatewayAPIs(in, K8sNetworkingGroupVersionV1Beta1.String(), v1beta1Types, false)
 		in.isGatewayAPI = &isGatewayAPI
 	}
 	return *in.isGatewayAPI
@@ -261,17 +260,19 @@ func (in *K8SClient) IsExpGatewayAPI() bool {
 			K8sTCPRouteType: "tcproutes",
 			K8sTLSRouteType: "tlsroutes",
 		}
-		isGatewayAPIV1Alpha2 := checkGatewayAPIs(in, K8sNetworkingGroupVersionV1Alpha2.String(), v1alpha2Types)
+		isGatewayAPIV1Alpha2 := checkGatewayAPIs(in, K8sNetworkingGroupVersionV1Alpha2.String(), v1alpha2Types, true)
 		in.isExpGatewayAPI = &isGatewayAPIV1Alpha2
 	}
 	return *in.isExpGatewayAPI
 }
 
-func checkGatewayAPIs(in *K8SClient, version string, types map[string]string) bool {
+func checkGatewayAPIs(in *K8SClient, version string, types map[string]string, isExperimental bool) bool {
 	found := 0
 	res, err := in.k8s.Discovery().ServerResourcesForGroupVersion(version)
 	if err != nil {
-		log.Debugf("Error while checking K8s Gateway API CRDs: %s. Required K8s Gateway API version: %s. Gateway API will not be used.", version, err.Error())
+		if !isExperimental {
+			log.Debugf("K8s Gateway API CRDs are not installed. Required K8s Gateway API version: %s. Gateway API will not be used.", version)
+		}
 		return false
 	}
 	for _, r := range res.APIResources {
diff --git a/models/destination_rule.go b/models/destination_rule.go
index 8dcfd53b9..4a5c286de 100644
--- a/models/destination_rule.go
+++ b/models/destination_rule.go
@@ -8,6 +8,14 @@ import (
 	"github.com/kiali/kiali/kubernetes"
 )
 
+type (
+	// DestinationRuleSubsets is a mapping of DestinationRule's hosts to their subsets and associated Host objects
+	// - The first key represents the host in FQDN format
+	// - The second key represents the subset name
+	// - The value is a Host object containing additional details such as the service, cluster, etc.
+	DestinationRuleSubsets map[string]map[string]kubernetes.Host
+)
+
 func HasDRCircuitBreaker(dr *networking_v1.DestinationRule, namespace, serviceName, version string) bool {
 	conf := config.Get()
 	if kubernetes.FilterByHost(dr.Spec.Host, dr.Namespace, serviceName, namespace, conf) {
diff --git a/prometheus/client.go b/prometheus/client.go
index 5f33acba0..05f9ea4b7 100644
--- a/prometheus/client.go
+++ b/prometheus/client.go
@@ -33,11 +33,13 @@ type ClientInterface interface {
 	GetAllRequestRates(namespace, cluster, ratesInterval string, queryTime time.Time) (model.Vector, error)
 	GetAppRequestRates(namespace, cluster, app, ratesInterval string, queryTime time.Time) (model.Vector, model.Vector, error)
 	GetConfiguration() (prom_v1.ConfigResult, error)
+	GetExistingMetricNames(metricNames []string) ([]string, error)
 	GetFlags() (prom_v1.FlagsResult, error)
+	GetMetricsForLabels(metricNames []string, labels string) ([]string, error)
 	GetNamespaceServicesRequestRates(namespace, cluster, ratesInterval string, queryTime time.Time) (model.Vector, error)
+	GetRuntimeinfo() (prom_v1.RuntimeinfoResult, error)
 	GetServiceRequestRates(namespace, cluster, service, ratesInterval string, queryTime time.Time) (model.Vector, error)
 	GetWorkloadRequestRates(namespace, cluster, workload, ratesInterval string, queryTime time.Time) (model.Vector, model.Vector, error)
-	GetMetricsForLabels(metricNames []string, labels string) ([]string, error)
 }
 
 // Client for Prometheus API.
diff --git a/routing/routes.go b/routing/routes.go
index 62c12b821..632f152c7 100644
--- a/routing/routes.go
+++ b/routing/routes.go
@@ -197,7 +197,7 @@ func NewRoutes(
 			"Config",
 			"GET",
 			"/api/config",
-			handlers.Config(conf, discovery),
+			handlers.Config(conf, kialiCache, discovery, clientFactory, prom),
 			true,
 		},
 		// swagger:route GET /crippled kiali getCrippledFeatures
@@ -216,7 +216,7 @@ func NewRoutes(
 			"Crippled",
 			"GET",
 			"/api/crippled",
-			handlers.CrippledFeatures,
+			handlers.CrippledFeatures(prom),
 			true,
 		},
 		// swagger:route GET /istio/permissions config getPermissions
@@ -874,7 +874,7 @@ func NewRoutes(
 			handlers.ControlPlaneMetrics(handlers.DefaultPromClientSupplier),
 			true,
 		},
-		// swagger:route GET /namespaces/{namespace}/{workload}/usage_metrics resource usage metrics
+		// swagger:route GET /namespaces/{namespace}/{app}/usage_metrics resource usageMetrics
 		// ---
 		// Endpoint to fetch metrics to be displayed, related to cpu and memory usage
 		//
@@ -958,7 +958,7 @@ func NewRoutes(
 			handlers.WorkloadDashboard(conf, grafana),
 			true,
 		},
-		// swagger:route GET /namespaces/{namespace}/ztunnel/{workload}/dashboard ztunnel Dashboard
+		// swagger:route GET /namespaces/{namespace}/ztunnel/{workload}/dashboard workloads ztunnelDashboard
 		// ---
 		// Endpoint to fetch dashboard to be displayed, related to a ztunnel workload
 		//
@@ -973,7 +973,7 @@ func NewRoutes(
 		//      200: dashboardResponse
 		//
 		{
-			"ZtunnelMetrics",
+			"ZtunnelDashboard",
 			"GET",
 			"/api/namespaces/{namespace}/ztunnel/{workload}/dashboard",
 			handlers.ZtunnelDashboard(handlers.DefaultPromClientSupplier, conf, grafana),
@@ -1099,7 +1099,7 @@ func NewRoutes(
 		//      500: internalError
 		//
 		{
-			"NamespaceTls",
+			"MeshTls",
 			"GET",
 			"/api/mesh/tls",
 			handlers.MeshTls,
@@ -1465,7 +1465,7 @@ func NewRoutes(
 		},
 		// swagger:route GET /namespaces/{namespace}/pods/{pod}/config_dump/{resource} pods podProxyResource
 		// ---
-		// Endpoint to get pod logs
+		// Endpoint to get pod resource entries
 		//
 		//     Produces:
 		//     - application/json
@@ -1478,13 +1478,13 @@ func NewRoutes(
 		//      200: configDumpResource
 		//
 		{
-			"PodConfigDump",
+			"PodProxyResource",
 			"GET",
 			"/api/namespaces/{namespace}/pods/{pod}/config_dump/{resource}",
 			handlers.ConfigDumpResourceEntries,
 			true,
 		},
-		// swagger:route GET /api/namespaces/{namespace}/pods/{pod}/config_dump_ztunnel
+		// swagger:route GET /namespaces/{namespace}/pods/{pod}/config_dump_ztunnel
 		// ---
 		// Endpoint to get ztunnel pod config dump
 		//
@@ -1496,7 +1496,7 @@ func NewRoutes(
 		// responses:
 		//      500: internalError
 		//      404: notFoundError
-		//      200: ZtunnelConfigDump
+		//      200: ztunnelConfigDump
 		//
 		{
 			"ZtunnelConfigDump",
diff --git a/util/slice.go b/util/slice.go
deleted file mode 100644
index 33b2ba2a6..000000000
--- a/util/slice.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package util
-
-func InSlice(array []string, value string) bool {
-	for _, v := range array {
-		if v == value {
-			return true
-		}
-	}
-	return false
-}
diff --git a/util/sliceutil/slice.go b/util/sliceutil/slice.go
index 3704a09a6..849a150cd 100644
--- a/util/sliceutil/slice.go
+++ b/util/sliceutil/slice.go
@@ -42,6 +42,16 @@ func Some[S ~[]E, E any](slice S, f func(E) bool) bool {
 	return false
 }
 
+// SomeString returns true if any of the elements from array equals to the value provided
+func SomeString(array []string, value string) bool {
+	for _, v := range array {
+		if v == value {
+			return true
+		}
+	}
+	return false
+}
+
 // Find returns first element matching the predicate, otherwise nil
 func Find[S ~[]E, E any](slice S, f func(E) bool) *E {
 	if slice == nil {



Test patch:
diff --git a/business/checkers/authorization/no_host_checker_test.go b/business/checkers/authorization/no_host_checker_test.go
index f5fda404d..51d20f04a 100644
--- a/business/checkers/authorization/no_host_checker_test.go
+++ b/business/checkers/authorization/no_host_checker_test.go
@@ -23,7 +23,7 @@ func TestPresentService(t *testing.T) {
 	validations, valid := NoHostChecker{
 		Conf:                config.Get(),
 		AuthorizationPolicy: authPolicyWithHost([]string{"details", "reviews"}),
-		Namespaces:          models.Namespaces{models.Namespace{Name: "outside"}, models.Namespace{Name: "bookinfo"}},
+		Namespaces:          []string{"outside", "bookinfo"},
 		ServiceEntries:      map[string][]string{},
 		RegistryServices:    append(registryService1, registryService2...),
 		PolicyAllowAny:      true,
@@ -43,7 +43,7 @@ func TestNonExistingService(t *testing.T) {
 	vals, valid := NoHostChecker{
 		Conf:                config.Get(),
 		AuthorizationPolicy: authPolicyWithHost([]string{"details", "wrong"}),
-		Namespaces:          models.Namespaces{models.Namespace{Name: "outside"}, models.Namespace{Name: "bookinfo"}},
+		Namespaces:          []string{"outside", "bookinfo"},
 		ServiceEntries:      map[string][]string{},
 		RegistryServices:    append(registryService1, registryService2...),
 		PolicyAllowAny:      true,
@@ -67,7 +67,7 @@ func TestWildcardHost(t *testing.T) {
 	vals, valid := NoHostChecker{
 		Conf:                config.Get(),
 		AuthorizationPolicy: authPolicyWithHost([]string{"*", "*.bookinfo", "*.bookinfo.svc.cluster.local"}),
-		Namespaces:          models.Namespaces{models.Namespace{Name: "outside"}, models.Namespace{Name: "bookinfo"}},
+		Namespaces:          []string{"outside", "bookinfo"},
 		ServiceEntries:      map[string][]string{},
 		RegistryServices:    append(registryService1, registryService2...),
 	}.Check()
@@ -86,7 +86,7 @@ func TestWildcardHostOutsideNamespace(t *testing.T) {
 	vals, valid := NoHostChecker{
 		Conf:                config.Get(),
 		AuthorizationPolicy: authPolicyWithHost([]string{"*.outside", "*.outside.svc.cluster.local"}),
-		Namespaces:          models.Namespaces{models.Namespace{Name: "outside"}, models.Namespace{Name: "bookinfo"}},
+		Namespaces:          []string{"outside", "bookinfo"},
 		ServiceEntries:      map[string][]string{},
 		RegistryServices:    append(registryService1, registryService2...),
 	}.Check()
@@ -110,7 +110,7 @@ func TestServiceEntryPresent(t *testing.T) {
 	validations, valid := NoHostChecker{
 		Conf:                config.Get(),
 		AuthorizationPolicy: authPolicyWithHost([]string{"wikipedia.org"}),
-		Namespaces:          models.Namespaces{models.Namespace{Name: "outside"}, models.Namespace{Name: "bookinfo"}},
+		Namespaces:          []string{"outside", "bookinfo"},
 		ServiceEntries:      kubernetes.ServiceEntryHostnames([]*networking_v1.ServiceEntry{serviceEntry}),
 	}.Check()
 
@@ -127,7 +127,7 @@ func TestExportedInternalServiceEntryPresent(t *testing.T) {
 	validations, valid := NoHostChecker{
 		Conf:                config.Get(),
 		AuthorizationPolicy: authPolicyWithHost([]string{"details.bookinfo2.svc.cluster.local"}),
-		Namespaces:          models.Namespaces{models.Namespace{Name: "bookinfo"}, models.Namespace{Name: "bookinfo2"}, models.Namespace{Name: "bookinfo3"}},
+		Namespaces:          []string{"bookinfo", "bookinfo2", "bookinfo3"},
 		ServiceEntries:      kubernetes.ServiceEntryHostnames([]*networking_v1.ServiceEntry{serviceEntry}),
 	}.Check()
 
@@ -144,7 +144,7 @@ func TestExportedExternalServiceEntryPresent(t *testing.T) {
 	validations, valid := NoHostChecker{
 		Conf:                config.Get(),
 		AuthorizationPolicy: authPolicyWithHost([]string{"www.myhost.com"}),
-		Namespaces:          models.Namespaces{models.Namespace{Name: "bookinfo"}, models.Namespace{Name: "bookinfo2"}, models.Namespace{Name: "bookinfo3"}},
+		Namespaces:          []string{"bookinfo", "bookinfo2", "bookinfo3"},
 		ServiceEntries:      kubernetes.ServiceEntryHostnames([]*networking_v1.ServiceEntry{serviceEntry}),
 	}.Check()
 
@@ -161,7 +161,7 @@ func TestExportedExternalServiceEntryFail(t *testing.T) {
 	vals, valid := NoHostChecker{
 		Conf:                config.Get(),
 		AuthorizationPolicy: authPolicyWithHost([]string{"www.wrong.com"}),
-		Namespaces:          models.Namespaces{models.Namespace{Name: "bookinfo"}, models.Namespace{Name: "bookinfo2"}, models.Namespace{Name: "bookinfo3"}},
+		Namespaces:          []string{"bookinfo", "bookinfo2", "bookinfo3"},
 		ServiceEntries:      kubernetes.ServiceEntryHostnames([]*networking_v1.ServiceEntry{serviceEntry}),
 	}.Check()
 
@@ -182,7 +182,7 @@ func TestWildcardExportedInternalServiceEntryPresent(t *testing.T) {
 	validations, valid := NoHostChecker{
 		Conf:                config.Get(),
 		AuthorizationPolicy: authPolicyWithHost([]string{"details.bookinfo2.svc.cluster.local"}),
-		Namespaces:          models.Namespaces{models.Namespace{Name: "bookinfo"}, models.Namespace{Name: "bookinfo2"}, models.Namespace{Name: "bookinfo3"}},
+		Namespaces:          []string{"bookinfo", "bookinfo2", "bookinfo3"},
 		ServiceEntries:      kubernetes.ServiceEntryHostnames([]*networking_v1.ServiceEntry{serviceEntry}),
 	}.Check()
 
@@ -199,7 +199,7 @@ func TestWildcardExportedInternalServiceEntryFail(t *testing.T) {
 	vals, valid := NoHostChecker{
 		Conf:                config.Get(),
 		AuthorizationPolicy: authPolicyWithHost([]string{"details.bookinfo3.svc.cluster.local"}),
-		Namespaces:          models.Namespaces{models.Namespace{Name: "bookinfo"}, models.Namespace{Name: "bookinfo2"}, models.Namespace{Name: "bookinfo3"}},
+		Namespaces:          []string{"bookinfo", "bookinfo2", "bookinfo3"},
 		ServiceEntries:      kubernetes.ServiceEntryHostnames([]*networking_v1.ServiceEntry{serviceEntry}),
 	}.Check()
 
@@ -220,7 +220,7 @@ func TestExportedNonFQDNInternalServiceEntryFail(t *testing.T) {
 	vals, valid := NoHostChecker{
 		Conf:                config.Get(),
 		AuthorizationPolicy: authPolicyWithHost([]string{"details.bookinfo2.svc.cluster.local"}),
-		Namespaces:          models.Namespaces{models.Namespace{Name: "bookinfo"}, models.Namespace{Name: "bookinfo2"}, models.Namespace{Name: "bookinfo3"}},
+		Namespaces:          []string{"bookinfo", "bookinfo2", "bookinfo3"},
 		ServiceEntries:      kubernetes.ServiceEntryHostnames([]*networking_v1.ServiceEntry{serviceEntry}),
 	}.Check()
 
@@ -240,7 +240,7 @@ func TestServiceEntryNotPresent(t *testing.T) {
 	vals, valid := NoHostChecker{
 		Conf:                config.Get(),
 		AuthorizationPolicy: authPolicyWithHost([]string{"wrong.org"}),
-		Namespaces:          models.Namespaces{models.Namespace{Name: "outside"}, models.Namespace{Name: "bookinfo"}},
+		Namespaces:          []string{"outside", "bookinfo"},
 		ServiceEntries:      kubernetes.ServiceEntryHostnames([]*networking_v1.ServiceEntry{serviceEntry}),
 	}.Check()
 
@@ -260,7 +260,7 @@ func TestExportedInternalServiceEntryNotPresent(t *testing.T) {
 	vals, valid := NoHostChecker{
 		Conf:                config.Get(),
 		AuthorizationPolicy: authPolicyWithHost([]string{"wrong.bookinfo2.svc.cluster.local"}),
-		Namespaces:          models.Namespaces{models.Namespace{Name: "bookinfo"}, models.Namespace{Name: "bookinfo2"}, models.Namespace{Name: "bookinfo3"}},
+		Namespaces:          []string{"bookinfo", "bookinfo2", "bookinfo3"},
 		ServiceEntries:      kubernetes.ServiceEntryHostnames([]*networking_v1.ServiceEntry{serviceEntry}),
 	}.Check()
 
@@ -280,7 +280,7 @@ func TestVirtualServicePresent(t *testing.T) {
 	validations, valid := NoHostChecker{
 		Conf:                config.Get(),
 		AuthorizationPolicy: authPolicyWithHost([]string{"foo-dev.example.com"}),
-		Namespaces:          models.Namespaces{models.Namespace{Name: "outside"}, models.Namespace{Name: "bookinfo"}},
+		Namespaces:          []string{"outside", "bookinfo"},
 		ServiceEntries:      map[string][]string{},
 		VirtualServices:     []*networking_v1.VirtualService{&virtualService},
 	}.Check()
@@ -296,7 +296,7 @@ func TestVirtualServiceNotPresent(t *testing.T) {
 	vals, valid := NoHostChecker{
 		Conf:                config.Get(),
 		AuthorizationPolicy: authPolicyWithHost([]string{"foo-bogus.example.com"}),
-		Namespaces:          models.Namespaces{models.Namespace{Name: "outside"}, models.Namespace{Name: "bookinfo"}},
+		Namespaces:          []string{"outside", "bookinfo"},
 		ServiceEntries:      map[string][]string{},
 		VirtualServices:     []*networking_v1.VirtualService{&virtualService},
 	}.Check()
@@ -318,7 +318,7 @@ func TestWildcardServiceEntryHost(t *testing.T) {
 	vals, valid := NoHostChecker{
 		Conf:                config.Get(),
 		AuthorizationPolicy: authPolicyWithHost([]string{"maps.google.com"}),
-		Namespaces:          models.Namespaces{models.Namespace{Name: "outside"}, models.Namespace{Name: "bookinfo"}},
+		Namespaces:          []string{"outside", "bookinfo"},
 		ServiceEntries:      kubernetes.ServiceEntryHostnames([]*networking_v1.ServiceEntry{&serviceEntry}),
 	}.Check()
 
@@ -330,7 +330,7 @@ func TestWildcardServiceEntryHost(t *testing.T) {
 	vals, valid = NoHostChecker{
 		Conf:                config.Get(),
 		AuthorizationPolicy: authPolicyWithHost([]string{"maps.apple.com"}),
-		Namespaces:          models.Namespaces{models.Namespace{Name: "outside"}, models.Namespace{Name: "bookinfo"}},
+		Namespaces:          []string{"outside", "bookinfo"},
 		ServiceEntries:      kubernetes.ServiceEntryHostnames([]*networking_v1.ServiceEntry{&serviceEntry}),
 		PolicyAllowAny:      true,
 	}.Check()
@@ -357,7 +357,7 @@ func TestValidServiceRegistry(t *testing.T) {
 	validations, valid := NoHostChecker{
 		Conf:                config.Get(),
 		AuthorizationPolicy: authPolicyWithHost([]string{"ratings.mesh2-bookinfo.svc.mesh1-imports.local"}),
-		Namespaces:          models.Namespaces{models.Namespace{Name: "outside"}, models.Namespace{Name: "bookinfo"}},
+		Namespaces:          []string{"outside", "bookinfo"},
 	}.Check()
 
 	assert.False(valid)
@@ -368,7 +368,7 @@ func TestValidServiceRegistry(t *testing.T) {
 	validations, valid = NoHostChecker{
 		Conf:                config.Get(),
 		AuthorizationPolicy: authPolicyWithHost([]string{"ratings.mesh2-bookinfo.svc.mesh1-imports.local"}),
-		Namespaces:          models.Namespaces{models.Namespace{Name: "outside"}, models.Namespace{Name: "bookinfo"}},
+		Namespaces:          []string{"outside", "bookinfo"},
 		RegistryServices:    registryService,
 	}.Check()
 
@@ -380,7 +380,7 @@ func TestValidServiceRegistry(t *testing.T) {
 	validations, valid = NoHostChecker{
 		Conf:                config.Get(),
 		AuthorizationPolicy: authPolicyWithHost([]string{"ratings.mesh2-bookinfo.svc.mesh1-imports.local"}),
-		Namespaces:          models.Namespaces{models.Namespace{Name: "outside"}, models.Namespace{Name: "bookinfo"}},
+		Namespaces:          []string{"outside", "bookinfo"},
 		RegistryServices:    registryService,
 	}.Check()
 
@@ -392,7 +392,7 @@ func TestValidServiceRegistry(t *testing.T) {
 	validations, valid = NoHostChecker{
 		Conf:                config.Get(),
 		AuthorizationPolicy: authPolicyWithHost([]string{"ratings.bookinfo.svc.cluster.local"}),
-		Namespaces:          models.Namespaces{models.Namespace{Name: "outside"}, models.Namespace{Name: "bookinfo"}},
+		Namespaces:          []string{"outside", "bookinfo"},
 		RegistryServices:    registryService,
 	}.Check()
 
@@ -404,7 +404,7 @@ func TestValidServiceRegistry(t *testing.T) {
 	validations, valid = NoHostChecker{
 		Conf:                config.Get(),
 		AuthorizationPolicy: authPolicyWithHost([]string{"ratings2.bookinfo.svc.cluster.local"}),
-		Namespaces:          models.Namespaces{models.Namespace{Name: "outside"}, models.Namespace{Name: "bookinfo"}},
+		Namespaces:          []string{"outside", "bookinfo"},
 		RegistryServices:    registryService,
 	}.Check()
 
diff --git a/business/checkers/common/export_to_namespace_checker_test.go b/business/checkers/common/export_to_namespace_checker_test.go
index 3d783eee0..b74e327ee 100644
--- a/business/checkers/common/export_to_namespace_checker_test.go
+++ b/business/checkers/common/export_to_namespace_checker_test.go
@@ -106,12 +106,8 @@ func validateIstioObject(scenario string, objectType string, t *testing.T) ([]*m
 	}
 
 	validations, valid := ExportToNamespaceChecker{
-		ExportTo: exportTo,
-		Namespaces: models.Namespaces{
-			models.Namespace{Name: "bookinfo"},
-			models.Namespace{Name: "bookinfo2"},
-			models.Namespace{Name: "default"},
-		},
+		ExportTo:   exportTo,
+		Namespaces: []string{"bookinfo", "bookinfo2", "default"},
 	}.Check()
 
 	return validations, valid
diff --git a/business/checkers/destinationrules/multi_match_checker_test.go b/business/checkers/destinationrules/multi_match_checker_test.go
index ee716193d..771e3a01c 100644
--- a/business/checkers/destinationrules/multi_match_checker_test.go
+++ b/business/checkers/destinationrules/multi_match_checker_test.go
@@ -144,11 +144,8 @@ func TestMultiHostMatchValidShortFormatDiffNamespace(t *testing.T) {
 	}
 
 	vals := MultiMatchChecker{
-		Conf: config.Get(),
-		Namespaces: models.Namespaces{
-			models.Namespace{Name: "bookinfo"},
-			models.Namespace{Name: "test"},
-		},
+		Conf:             config.Get(),
+		Namespaces:       []string{"bookinfo", "test"},
 		DestinationRules: destinationRules,
 	}.Check()
 
diff --git a/business/checkers/destinationrules/multi_match_exported_checker_test.go b/business/checkers/destinationrules/multi_match_exported_checker_test.go
index ec7d87133..d78aea0ee 100644
--- a/business/checkers/destinationrules/multi_match_exported_checker_test.go
+++ b/business/checkers/destinationrules/multi_match_exported_checker_test.go
@@ -56,12 +56,7 @@ func TestExportMultiHostMatchInvalid(t *testing.T) {
 	vals := MultiMatchChecker{
 		Conf:             config.Get(),
 		DestinationRules: append(destinationRules, edr...),
-		Namespaces: models.Namespaces{
-			models.Namespace{Name: "test"},
-			models.Namespace{Name: "test2"},
-			models.Namespace{Name: "test3"},
-			models.Namespace{Name: "default"},
-		},
+		Namespaces:       []string{"test", "test2", "test3", "default"},
 	}.Check()
 
 	assert.NotEmpty(vals)
@@ -94,12 +89,7 @@ func TestExportMultiHostMatchInvalid2(t *testing.T) {
 	vals := MultiMatchChecker{
 		Conf:             config.Get(),
 		DestinationRules: append(destinationRules, edr...),
-		Namespaces: models.Namespaces{
-			models.Namespace{Name: "test"},
-			models.Namespace{Name: "test2"},
-			models.Namespace{Name: "test3"},
-			models.Namespace{Name: "default"},
-		},
+		Namespaces:       []string{"test", "test2", "test3", "default"},
 	}.Check()
 
 	assert.NotEmpty(vals)
@@ -195,12 +185,8 @@ func TestExportMultiHostMatchValidShortFormatDiffNamespace(t *testing.T) {
 	}
 
 	vals := MultiMatchChecker{
-		Conf: config.Get(),
-		Namespaces: models.Namespaces{
-			models.Namespace{Name: "bookinfo"},
-			models.Namespace{Name: "test"},
-			models.Namespace{Name: "test2"},
-		},
+		Conf:             config.Get(),
+		Namespaces:       []string{"bookinfo", "test", "test2"},
 		DestinationRules: append(destinationRules, edr...),
 	}.Check()
 
diff --git a/business/checkers/destinationrules/no_dest_checker_test.go b/business/checkers/destinationrules/no_dest_checker_test.go
index 3e7a858a8..c0a8c5a01 100644
--- a/business/checkers/destinationrules/no_dest_checker_test.go
+++ b/business/checkers/destinationrules/no_dest_checker_test.go
@@ -133,11 +133,8 @@ func TestValidServiceNamespaceInvalid(t *testing.T) {
 	assert := assert.New(t)
 
 	vals, valid := NoDestinationChecker{
-		Conf: config.Get(),
-		Namespaces: models.Namespaces{
-			models.Namespace{Name: "test-namespace"},
-			models.Namespace{Name: "outside-ns"},
-		},
+		Conf:       config.Get(),
+		Namespaces: []string{"test-namespace", "outside-ns"},
 		WorkloadsPerNamespace: map[string]models.Workloads{
 			"test-namespace": {
 				data.CreateWorkload("reviewsv1", appVersionLabel("reviews", "v1")),
@@ -161,11 +158,8 @@ func TestValidServiceNamespaceCrossNamespace(t *testing.T) {
 	assert := assert.New(t)
 
 	vals, valid := NoDestinationChecker{
-		Conf: config.Get(),
-		Namespaces: models.Namespaces{
-			models.Namespace{Name: "test-namespace"},
-			models.Namespace{Name: "outside-ns"},
-		},
+		Conf:       config.Get(),
+		Namespaces: []string{"test-namespace", "outside-ns"},
 		WorkloadsPerNamespace: map[string]models.Workloads{
 			"outside-ns": {
 				data.CreateWorkload("reviewsv1", appVersionLabel("reviews", "v1")),
@@ -325,7 +319,7 @@ func TestSubsetNotReferenced(t *testing.T) {
 
 	vals, valid := NoDestinationChecker{
 		Conf:       config.Get(),
-		Namespaces: models.Namespaces{models.Namespace{Name: "bookinfo2"}, models.Namespace{Name: "bookinfo"}},
+		Namespaces: []string{"bookinfo2", "bookinfo"},
 		WorkloadsPerNamespace: map[string]models.Workloads{
 			"bookinfo": {
 				data.CreateWorkload("reviews", appVersionLabel("reviews", "v1")),
@@ -360,7 +354,7 @@ func TestSubsetReferenced(t *testing.T) {
 
 	vals, valid := NoDestinationChecker{
 		Conf:       config.Get(),
-		Namespaces: models.Namespaces{models.Namespace{Name: "bookinfo2"}, models.Namespace{Name: "bookinfo"}},
+		Namespaces: []string{"bookinfo2", "bookinfo"},
 		WorkloadsPerNamespace: map[string]models.Workloads{
 			"bookinfo": {
 				data.CreateWorkload("reviews", appVersionLabel("reviews", "v1")),
@@ -399,7 +393,7 @@ func TestSubsetPresentMatchingNotReferenced(t *testing.T) {
 
 	vals, valid := NoDestinationChecker{
 		Conf:       config.Get(),
-		Namespaces: models.Namespaces{models.Namespace{Name: "bookinfo"}},
+		Namespaces: []string{"bookinfo"},
 		WorkloadsPerNamespace: map[string]models.Workloads{
 			"bookinfo": {
 				data.CreateWorkload("reviews", appVersionLabel("reviews", "v1")),
@@ -431,7 +425,7 @@ func TestWronglyReferenced(t *testing.T) {
 
 	vals, valid := NoDestinationChecker{
 		Conf:       config.Get(),
-		Namespaces: models.Namespaces{models.Namespace{Name: "bookinfo2"}, models.Namespace{Name: "bookinfo"}},
+		Namespaces: []string{"bookinfo2", "bookinfo"},
 		WorkloadsPerNamespace: map[string]models.Workloads{
 			"bookinfo": {
 				data.CreateWorkload("reviews", appVersionLabel("reviews", "v1")),
diff --git a/business/checkers/virtualservices/no_host_checker_test.go b/business/checkers/virtualservices/no_host_checker_test.go
index a32f427c6..9efc91f88 100644
--- a/business/checkers/virtualservices/no_host_checker_test.go
+++ b/business/checkers/virtualservices/no_host_checker_test.go
@@ -156,11 +156,8 @@ func TestInvalidServiceNamespaceFormatHost(t *testing.T) {
 	)
 
 	vals, valid := NoHostChecker{
-		Conf: config.Get(),
-		Namespaces: models.Namespaces{
-			models.Namespace{Name: "test"},
-			models.Namespace{Name: "outside-namespace"},
-		},
+		Conf:             config.Get(),
+		Namespaces:       []string{"test", "outside-namespace"},
 		RegistryServices: append(registryService1, registryService2...),
 		VirtualService:   virtualService,
 		PolicyAllowAny:   true,
@@ -187,11 +184,8 @@ func TestInvalidServiceNamespaceFormatExportedHost(t *testing.T) {
 	)
 
 	vals, valid := NoHostChecker{
-		Conf: config.Get(),
-		Namespaces: models.Namespaces{
-			models.Namespace{Name: "test"},
-			models.Namespace{Name: "outside-namespace"},
-		},
+		Conf:             config.Get(),
+		Namespaces:       []string{"test", "outside-namespace"},
 		VirtualService:   virtualService,
 		RegistryServices: append(data.CreateFakeRegistryServices("ratings.bookinfo2.svc.cluster.local", "bookinfo2", "*"), append(registryService1, registryService2...)...),
 	}.Check()
@@ -207,11 +201,8 @@ func TestInvalidServiceNamespaceFormatExportedHost(t *testing.T) {
 	)
 
 	vals, valid = NoHostChecker{
-		Conf: config.Get(),
-		Namespaces: models.Namespaces{
-			models.Namespace{Name: "bookinfo"},
-			models.Namespace{Name: "bookinfo2"},
-		},
+		Conf:             config.Get(),
+		Namespaces:       []string{"bookinfo", "bookinfo2"},
 		VirtualService:   virtualService,
 		RegistryServices: append(data.CreateFakeRegistryServices("ratings.bookinfo2.svc.cluster.local", "bookinfo2", "."), append(registryService1, registryService2...)...),
 	}.Check()
diff --git a/business/checkers/virtualservices/single_exported_host_checker_test.go b/business/checkers/virtualservices/single_exported_host_checker_test.go
index 14cf6a2d3..f3dde3b95 100644
--- a/business/checkers/virtualservices/single_exported_host_checker_test.go
+++ b/business/checkers/virtualservices/single_exported_host_checker_test.go
@@ -198,11 +198,8 @@ func TestRepeatingSVCNSHostExported(t *testing.T) {
 		buildVirtualServiceNS("bookinfo2", "virtual-2", "reviews.bookinfo.svc.cluster.local"),
 	}
 	vals := SingleHostChecker{
-		Conf: config.Get(),
-		Namespaces: models.Namespaces{
-			{Name: "bookinfo"},
-			{Name: "bookinfo2"},
-		},
+		Conf:            config.Get(),
+		Namespaces:      []string{"bookinfo", "bookinfo2"},
 		VirtualServices: append(vss, evss...),
 	}.Check()
 
@@ -216,11 +213,8 @@ func TestRepeatingSVCNSHostExported(t *testing.T) {
 		buildVirtualServiceNS("bookinfo2", "virtual-2", "reviews.bookinfo.svc.cluster.local"),
 	}
 	vals = SingleHostChecker{
-		Conf: config.Get(),
-		Namespaces: models.Namespaces{
-			{Name: "bookinfo"},
-			{Name: "bookinfo2"},
-		},
+		Conf:            config.Get(),
+		Namespaces:      []string{"bookinfo", "bookinfo2"},
 		VirtualServices: append(vss, evss...),
 	}.Check()
 
@@ -235,11 +229,8 @@ func TestRepeatingSVCNSHostExported(t *testing.T) {
 		buildVirtualServiceNS("bookinfo2", "virtual-2", "reviews.bookinfo.svc.cluster.local"),
 	}
 	vals = SingleHostChecker{
-		Conf: config.Get(),
-		Namespaces: models.Namespaces{
-			{Name: "bookinfo"},
-			{Name: "bookinfo2"},
-		},
+		Conf:            config.Get(),
+		Namespaces:      []string{"bookinfo", "bookinfo2"},
 		VirtualServices: append(vss, evss...),
 	}.Check()
 
@@ -253,11 +244,8 @@ func TestRepeatingSVCNSHostExported(t *testing.T) {
 		buildVirtualServiceNS("bookinfo2", "virtual-2", "reviews.bookinfo.svc.cluster.local"),
 	}
 	vals = SingleHostChecker{
-		Conf: config.Get(),
-		Namespaces: models.Namespaces{
-			{Name: "bookinfo"},
-			{Name: "bookinfo2"},
-		},
+		Conf:            config.Get(),
+		Namespaces:      []string{"bookinfo", "bookinfo2"},
 		VirtualServices: append(vss, evss...),
 	}.Check()
 
@@ -271,11 +259,8 @@ func TestRepeatingSVCNSHostExported(t *testing.T) {
 		buildVirtualServiceNS("bookinfo2", "virtual-2", "details.bookinfo.svc.cluster.local"),
 	}
 	vals = SingleHostChecker{
-		Conf: config.Get(),
-		Namespaces: models.Namespaces{
-			{Name: "bookinfo"},
-			{Name: "bookinfo2"},
-		},
+		Conf:            config.Get(),
+		Namespaces:      []string{"bookinfo", "bookinfo2"},
 		VirtualServices: append(vss, evss...),
 	}.Check()
 
@@ -291,11 +276,8 @@ func TestRepeatingSVCNSHostExported(t *testing.T) {
 		buildVirtualServiceNS("bookinfo2", "virtual-2", "details.bookinfo.svc.cluster.local"),
 	}
 	vals = SingleHostChecker{
-		Conf: config.Get(),
-		Namespaces: models.Namespaces{
-			{Name: "bookinfo"},
-			{Name: "bookinfo2"},
-		},
+		Conf:            config.Get(),
+		Namespaces:      []string{"bookinfo", "bookinfo2"},
 		VirtualServices: append(vss, evss...),
 	}.Check()
 
diff --git a/business/checkers/virtualservices/single_host_checker_test.go b/business/checkers/virtualservices/single_host_checker_test.go
index 2c3be75bb..2087fe082 100644
--- a/business/checkers/virtualservices/single_host_checker_test.go
+++ b/business/checkers/virtualservices/single_host_checker_test.go
@@ -172,10 +172,8 @@ func TestRepeatingSVCNSHost(t *testing.T) {
 		buildVirtualService("virtual-2", "reviews.bookinfo"),
 	}
 	vals := SingleHostChecker{
-		Conf: config.Get(),
-		Namespaces: models.Namespaces{
-			{Name: "bookinfo"},
-		},
+		Conf:            config.Get(),
+		Namespaces:      []string{"bookinfo"},
 		VirtualServices: vss,
 	}.Check()
 
@@ -187,10 +185,8 @@ func TestRepeatingSVCNSHost(t *testing.T) {
 		buildVirtualService("virtual-2", "reviews.bookinfo"),
 	}
 	vals = SingleHostChecker{
-		Conf: config.Get(),
-		Namespaces: models.Namespaces{
-			{Name: "bookinfo"},
-		},
+		Conf:            config.Get(),
+		Namespaces:      []string{"bookinfo"},
 		VirtualServices: vss,
 	}.Check()
 
@@ -203,10 +199,8 @@ func TestRepeatingSVCNSHost(t *testing.T) {
 		buildVirtualServiceWithGateway("virtual-3", "reviews", "bookinfo-gateway-auto"),
 	}
 	vals = SingleHostChecker{
-		Conf: config.Get(),
-		Namespaces: models.Namespaces{
-			{Name: "bookinfo"},
-		},
+		Conf:            config.Get(),
+		Namespaces:      []string{"bookinfo"},
 		VirtualServices: vss,
 	}.Check()
 
@@ -218,10 +212,8 @@ func TestRepeatingSVCNSHost(t *testing.T) {
 		buildVirtualService("virtual-2", "reviews.bookinfo"),
 	}
 	vals = SingleHostChecker{
-		Conf: config.Get(),
-		Namespaces: models.Namespaces{
-			{Name: "bookinfo"},
-		},
+		Conf:            config.Get(),
+		Namespaces:      []string{"bookinfo"},
 		VirtualServices: vss,
 	}.Check()
 
@@ -233,10 +225,8 @@ func TestRepeatingSVCNSHost(t *testing.T) {
 		buildVirtualService("virtual-2", "details.bookinfo"),
 	}
 	vals = SingleHostChecker{
-		Conf: config.Get(),
-		Namespaces: models.Namespaces{
-			{Name: "bookinfo"},
-		},
+		Conf:            config.Get(),
+		Namespaces:      []string{"bookinfo"},
 		VirtualServices: vss,
 	}.Check()
 
@@ -249,10 +239,8 @@ func TestRepeatingSVCNSHost(t *testing.T) {
 		buildVirtualService("virtual-2", "details.bookinfo"),
 	}
 	vals = SingleHostChecker{
-		Conf: config.Get(),
-		Namespaces: models.Namespaces{
-			{Name: "bookinfo"},
-		},
+		Conf:            config.Get(),
+		Namespaces:      []string{"bookinfo"},
 		VirtualServices: vss,
 	}.Check()
 
diff --git a/business/checkers/virtualservices/subset_presence_checker_test.go b/business/checkers/virtualservices/subset_presence_checker_test.go
index a81e1a0e0..715fdefcd 100644
--- a/business/checkers/virtualservices/subset_presence_checker_test.go
+++ b/business/checkers/virtualservices/subset_presence_checker_test.go
@@ -6,7 +6,10 @@ import (
 
 	core_v1 "k8s.io/api/core/v1"
 
+	networking_v1 "istio.io/client-go/pkg/apis/networking/v1"
+
 	"github.com/kiali/kiali/config"
+	"github.com/kiali/kiali/kubernetes"
 	"github.com/kiali/kiali/models"
 	"github.com/kiali/kiali/tests/testutils/validations"
 )
@@ -79,12 +82,13 @@ func subsetPresenceCheckerPrep(scenario string, t *testing.T) ([]*models.IstioCh
 
 	loader := yamlFixtureLoaderFor(scenario)
 	err := loader.Load()
+	nsNames := namespaceNames(loader.GetNamespaces())
 
 	vals, valid := SubsetPresenceChecker{
-		Conf:             config.Get(),
-		Namespaces:       namespaceNames(loader.GetNamespaces()),
-		DestinationRules: append(loader.FindDestinationRuleIn("bookinfo"), loader.FindDestinationRuleNotIn("bookinfo")...),
-		VirtualService:   loader.GetResources().VirtualServices[0],
+		Conf:           config.Get(),
+		Namespaces:     nsNames,
+		DRSubsets:      prepareSubsetMap(append(loader.FindDestinationRuleIn("bookinfo"), loader.FindDestinationRuleNotIn("bookinfo")...), nsNames, conf),
+		VirtualService: loader.GetResources().VirtualServices[0],
 	}.Check()
 
 	if err != nil {
@@ -121,3 +125,24 @@ func testSubsetPresenceValidationsFound(scenario string, t *testing.T) {
 	tb.AssertValidationAt(0, models.WarningSeverity, "spec/http[0]/route[0]/destination", "virtualservices.subsetpresent.subsetnotfound")
 	tb.AssertValidationAt(1, models.WarningSeverity, "spec/http[1]/route[0]/destination", "virtualservices.subsetpresent.subsetnotfound")
 }
+
+func prepareSubsetMap(destinationRules []*networking_v1.DestinationRule, namespaces []string, conf *config.Config) models.DestinationRuleSubsets {
+	subsetMap := make(models.DestinationRuleSubsets)
+
+	for _, dr := range destinationRules {
+		host := dr.Spec.Host
+		drHost := kubernetes.GetHost(host, dr.Namespace, namespaces, conf)
+
+		if _, exists := subsetMap[drHost.String()]; !exists {
+			subsetMap[drHost.String()] = make(map[string]kubernetes.Host)
+		}
+
+		for _, subset := range dr.Spec.Subsets {
+			if subset != nil {
+				subsetMap[drHost.String()][subset.Name] = drHost
+			}
+		}
+	}
+
+	return subsetMap
+}
diff --git a/business/references/auth_policy_references_test.go b/business/references/auth_policy_references_test.go
index b8bf69fb8..da1577b30 100644
--- a/business/references/auth_policy_references_test.go
+++ b/business/references/auth_policy_references_test.go
@@ -15,13 +15,9 @@ import (
 
 func prepareTestForAuthPolicy(ap *security_v1.AuthorizationPolicy, vs *networking_v1.VirtualService, se *networking_v1.ServiceEntry) models.IstioReferences {
 	drReferences := AuthorizationPolicyReferences{
-		Conf:      config.Get(),
-		Namespace: "bookinfo",
-		Namespaces: models.Namespaces{
-			{Name: "bookinfo"},
-			{Name: "bookinfo2"},
-			{Name: "bookinfo3"},
-		},
+		Conf:                  config.Get(),
+		Namespace:             "bookinfo",
+		Namespaces:            []string{"bookinfo", "bookinfo2", "bookinfo3"},
 		AuthorizationPolicies: []*security_v1.AuthorizationPolicy{ap},
 		ServiceEntries:        []*networking_v1.ServiceEntry{se},
 		VirtualServices:       []*networking_v1.VirtualService{vs},
diff --git a/business/references/destination_rule_references_test.go b/business/references/destination_rule_references_test.go
index e0f13258a..0890df77b 100644
--- a/business/references/destination_rule_references_test.go
+++ b/business/references/destination_rule_references_test.go
@@ -14,13 +14,9 @@ import (
 
 func prepareTestForDestinationRule(dr *networking_v1.DestinationRule, vs *networking_v1.VirtualService) models.IstioReferences {
 	drReferences := DestinationRuleReferences{
-		Conf:      config.Get(),
-		Namespace: "bookinfo",
-		Namespaces: models.Namespaces{
-			{Name: "bookinfo"},
-			{Name: "bookinfo2"},
-			{Name: "bookinfo3"},
-		},
+		Conf:             config.Get(),
+		Namespace:        "bookinfo",
+		Namespaces:       []string{"bookinfo", "bookinfo2", "bookinfo3"},
 		DestinationRules: []*networking_v1.DestinationRule{dr},
 		VirtualServices:  []*networking_v1.VirtualService{vs},
 		WorkloadsPerNamespace: map[string]models.Workloads{
diff --git a/business/references/k8sgrpcroute_references_test.go b/business/references/k8sgrpcroute_references_test.go
index fa8c6928d..85982f868 100644
--- a/business/references/k8sgrpcroute_references_test.go
+++ b/business/references/k8sgrpcroute_references_test.go
@@ -16,12 +16,8 @@ import (
 
 func prepareTestForK8sGRPCRoute(route *k8s_networking_v1.GRPCRoute) models.IstioReferences {
 	routeReferences := K8sGRPCRouteReferences{
-		Conf: config.Get(),
-		Namespaces: models.Namespaces{
-			{Name: "bookinfo"},
-			{Name: "bookinfo2"},
-			{Name: "bookinfo3"},
-		},
+		Conf:               config.Get(),
+		Namespaces:         []string{"bookinfo", "bookinfo2", "bookinfo3"},
 		K8sGRPCRoutes:      []*k8s_networking_v1.GRPCRoute{route},
 		K8sReferenceGrants: []*k8s_networking_v1beta1.ReferenceGrant{data.CreateReferenceGrantByKind("rg", route.Namespace, "bookinfo", k8s_networking_v1beta1.Kind(kubernetes.K8sGRPCRoutes.Kind))},
 	}
diff --git a/business/references/k8shttproute_references_test.go b/business/references/k8shttproute_references_test.go
index de514d79d..1070fbbff 100644
--- a/business/references/k8shttproute_references_test.go
+++ b/business/references/k8shttproute_references_test.go
@@ -16,12 +16,8 @@ import (
 
 func prepareTestForK8sHTTPRoute(route *k8s_networking_v1.HTTPRoute) models.IstioReferences {
 	routeReferences := K8sHTTPRouteReferences{
-		Conf: config.Get(),
-		Namespaces: models.Namespaces{
-			{Name: "bookinfo"},
-			{Name: "bookinfo2"},
-			{Name: "bookinfo3"},
-		},
+		Conf:               config.Get(),
+		Namespaces:         []string{"bookinfo", "bookinfo2", "bookinfo3"},
 		K8sHTTPRoutes:      []*k8s_networking_v1.HTTPRoute{route},
 		K8sReferenceGrants: []*k8s_networking_v1beta1.ReferenceGrant{data.CreateReferenceGrant("rg", route.Namespace, "bookinfo")},
 	}
diff --git a/business/references/service_entry_references_test.go b/business/references/service_entry_references_test.go
index 3ef8c9e53..e1aa75e84 100644
--- a/business/references/service_entry_references_test.go
+++ b/business/references/service_entry_references_test.go
@@ -15,13 +15,9 @@ import (
 
 func prepareTestForServiceEntry(ap *security_v1.AuthorizationPolicy, dr *networking_v1.DestinationRule, se *networking_v1.ServiceEntry, sc *networking_v1.Sidecar) models.IstioReferences {
 	drReferences := ServiceEntryReferences{
-		Conf:      config.Get(),
-		Namespace: "bookinfo",
-		Namespaces: models.Namespaces{
-			{Name: "bookinfo"},
-			{Name: "bookinfo2"},
-			{Name: "bookinfo3"},
-		},
+		Conf:                  config.Get(),
+		Namespace:             "bookinfo",
+		Namespaces:            []string{"bookinfo", "bookinfo2", "bookinfo3"},
 		AuthorizationPolicies: []*security_v1.AuthorizationPolicy{ap},
 		ServiceEntries:        []*networking_v1.ServiceEntry{se},
 		Sidecars:              []*networking_v1.Sidecar{sc},
diff --git a/business/references/virtual_service_references_test.go b/business/references/virtual_service_references_test.go
index a5f1ebb6a..c743672af 100644
--- a/business/references/virtual_service_references_test.go
+++ b/business/references/virtual_service_references_test.go
@@ -17,13 +17,9 @@ import (
 
 func prepareTestForVirtualService(vs *networking_v1.VirtualService, dr *networking_v1.DestinationRule, ap *security_v1.AuthorizationPolicy) models.IstioReferences {
 	virtualServiceReferences := VirtualServiceReferences{
-		Conf:      config.Get(),
-		Namespace: "bookinfo",
-		Namespaces: models.Namespaces{
-			{Name: "bookinfo"},
-			{Name: "bookinfo2"},
-			{Name: "bookinfo3"},
-		},
+		Conf:                  config.Get(),
+		Namespace:             "bookinfo",
+		Namespaces:            []string{"bookinfo", "bookinfo2", "bookinfo3"},
 		VirtualServices:       []*networking_v1.VirtualService{vs},
 		DestinationRules:      []*networking_v1.DestinationRule{dr},
 		AuthorizationPolicies: []*security_v1.AuthorizationPolicy{ap, data.CreateEmptyAuthorizationPolicy("test", "bookinfo")},
diff --git a/graph/telemetry/istio/appender/service_entry_test.go b/graph/telemetry/istio/appender/service_entry_test.go
index bebf20dff..03ba920b1 100644
--- a/graph/telemetry/istio/appender/service_entry_test.go
+++ b/graph/telemetry/istio/appender/service_entry_test.go
@@ -14,20 +14,13 @@ import (
 	"github.com/kiali/kiali/config"
 	"github.com/kiali/kiali/graph"
 	"github.com/kiali/kiali/istio"
+	"github.com/kiali/kiali/istio/istiotest"
 	"github.com/kiali/kiali/kubernetes"
 	"github.com/kiali/kiali/kubernetes/cache"
 	"github.com/kiali/kiali/kubernetes/kubetest"
 	"github.com/kiali/kiali/models"
 )
 
-type fakeMeshDiscovery struct {
-	mesh models.Mesh
-}
-
-func (fmd *fakeMeshDiscovery) Mesh(ctx context.Context) (*models.Mesh, error) {
-	return &fmd.mesh, nil
-}
-
 func setupBusinessLayer(t *testing.T, meshExportTo []string, istioObjects ...runtime.Object) *business.Layer {
 	conf := config.NewConfig()
 	conf.KubernetesConfig.ClusterName = config.DefaultClusterID
@@ -45,8 +38,8 @@ func setupBusinessLayer(t *testing.T, meshExportTo []string, istioObjects ...run
 	k8sclients[config.Get().KubernetesConfig.ClusterName] = k8s
 
 	if len(meshExportTo) != 0 {
-		discovery := &fakeMeshDiscovery{
-			mesh: models.Mesh{
+		discovery := &istiotest.FakeDiscovery{
+			MeshReturn: models.Mesh{
 				ControlPlanes: []models.ControlPlane{{
 					Cluster: &models.KubeCluster{Name: config.DefaultClusterID, IsKialiHome: true},
 					Config: models.ControlPlaneConfiguration{
@@ -223,7 +216,8 @@ func TestServiceEntry(t *testing.T) {
 				Cluster:           config.DefaultClusterID,
 				CreationTimestamp: time.Now(),
 				Name:              "testNamespace",
-			}},
+			},
+		},
 		GraphType: graph.GraphTypeVersionedApp,
 	}
 	a.AppendGraph(trafficMap, globalInfo, namespaceInfo)
@@ -342,7 +336,8 @@ func TestServiceEntryExportAll(t *testing.T) {
 				Cluster:           config.DefaultClusterID,
 				CreationTimestamp: time.Now(),
 				Name:              "testNamespace",
-			}},
+			},
+		},
 		GraphType: graph.GraphTypeVersionedApp,
 	}
 	a.AppendGraph(trafficMap, globalInfo, namespaceInfo)
@@ -455,7 +450,8 @@ func TestServiceEntryExportNamespaceFound(t *testing.T) {
 				Cluster:           config.DefaultClusterID,
 				CreationTimestamp: time.Now(),
 				Name:              "testNamespace",
-			}},
+			},
+		},
 		GraphType: graph.GraphTypeVersionedApp,
 	}
 	a.AppendGraph(trafficMap, globalInfo, namespaceInfo)
@@ -568,7 +564,8 @@ func TestServiceEntryExportDefinitionNamespace(t *testing.T) {
 				Cluster:           config.DefaultClusterID,
 				CreationTimestamp: time.Now(),
 				Name:              "testNamespace",
-			}},
+			},
+		},
 		GraphType: graph.GraphTypeVersionedApp,
 	}
 	a.AppendGraph(trafficMap, globalInfo, namespaceInfo)
@@ -681,7 +678,8 @@ func TestServiceEntryMeshExportDefinitionNamespace(t *testing.T) {
 				Cluster:           config.DefaultClusterID,
 				CreationTimestamp: time.Now(),
 				Name:              "testNamespace",
-			}},
+			},
+		},
 		GraphType: graph.GraphTypeVersionedApp,
 	}
 	a.AppendGraph(trafficMap, globalInfo, namespaceInfo)
@@ -794,7 +792,8 @@ func TestServiceEntryMeshExportAll(t *testing.T) {
 				Cluster:           config.DefaultClusterID,
 				CreationTimestamp: time.Now(),
 				Name:              "testNamespace",
-			}},
+			},
+		},
 		GraphType: graph.GraphTypeVersionedApp,
 	}
 	a.AppendGraph(trafficMap, globalInfo, namespaceInfo)
@@ -907,7 +906,8 @@ func TestServiceEntryExportNamespaceNotFound(t *testing.T) {
 				Cluster:           config.DefaultClusterID,
 				CreationTimestamp: time.Now(),
 				Name:              "testNamespace",
-			}},
+			},
+		},
 		GraphType: graph.GraphTypeVersionedApp,
 	}
 	a.AppendGraph(trafficMap, globalInfo, namespaceInfo)
@@ -1020,11 +1020,13 @@ func TestKiali7153_1(t *testing.T) {
 			testNamespaceKey: &graph.AccessibleNamespace{
 				Cluster:           config.DefaultClusterID,
 				CreationTimestamp: time.Now(),
-				Name:              "testNamespace"},
+				Name:              "testNamespace",
+			},
 			otherNamespaceKey: &graph.AccessibleNamespace{
 				Cluster:           config.DefaultClusterID,
 				CreationTimestamp: time.Now(),
-				Name:              "otherNamespace"},
+				Name:              "otherNamespace",
+			},
 		},
 		GraphType: graph.GraphTypeVersionedApp,
 	}
@@ -1130,7 +1132,8 @@ func TestDisjointMulticlusterEntries(t *testing.T) {
 				Cluster:           config.DefaultClusterID,
 				CreationTimestamp: time.Now(),
 				Name:              "namespace",
-			}},
+			},
+		},
 		GraphType: graph.GraphTypeVersionedApp,
 	}
 	a.AppendGraph(trafficMap, globalInfo, namespaceInfo)
@@ -1273,7 +1276,8 @@ func TestServiceEntrySameHostMatchNamespace(t *testing.T) {
 				Cluster:           config.DefaultClusterID,
 				CreationTimestamp: time.Now(),
 				Name:              "testNamespace",
-			}},
+			},
+		},
 		GraphType: graph.GraphTypeVersionedApp,
 	}
 	a.AppendGraph(trafficMap, globalInfo, namespaceInfo)
@@ -1403,7 +1407,8 @@ func TestServiceEntrySameHostNoMatchNamespace(t *testing.T) {
 				Cluster:           config.DefaultClusterID,
 				CreationTimestamp: time.Now(),
 				Name:              "otherNamespace",
-			}},
+			},
+		},
 		GraphType: graph.GraphTypeVersionedApp,
 	}
 	a.AppendGraph(trafficMap, globalInfo, namespaceInfo)
@@ -1514,7 +1519,8 @@ func TestServiceEntryMultipleEdges(t *testing.T) {
 				Cluster:           config.DefaultClusterID,
 				CreationTimestamp: time.Now(),
 				Name:              "testNamespace",
-			}},
+			},
+		},
 		GraphType: graph.GraphTypeVersionedApp,
 	}
 	a.AppendGraph(trafficMap, globalInfo, namespaceInfo)
@@ -1576,7 +1582,8 @@ func TestSEKiali7305(t *testing.T) {
 				Cluster:           config.DefaultClusterID,
 				CreationTimestamp: time.Now(),
 				Name:              "testNamespace",
-			}},
+			},
+		},
 		GraphType: graph.GraphTypeVersionedApp,
 	}
 	a.AppendGraph(trafficMap, globalInfo, namespaceInfo)
@@ -1673,7 +1680,8 @@ func TestSEKiali7589(t *testing.T) {
 				Cluster:           "cluster2",
 				CreationTimestamp: time.Now(),
 				Name:              namespace,
-			}},
+			},
+		},
 		GraphType: graph.GraphTypeVersionedApp,
 	}
 	a.AppendGraph(trafficMap, globalInfo, namespaceInfo)
diff --git a/handlers/config_test.go b/handlers/config_test.go
new file mode 100644
index 000000000..a7e39168d
--- /dev/null
+++ b/handlers/config_test.go
@@ -0,0 +1,66 @@
+package handlers_test
+
+import (
+	"encoding/json"
+	"io"
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"github.com/gorilla/mux"
+	prom_v1 "github.com/prometheus/client_golang/api/prometheus/v1"
+	"github.com/stretchr/testify/require"
+
+	"github.com/kiali/kiali/config"
+	"github.com/kiali/kiali/handlers"
+	"github.com/kiali/kiali/istio/istiotest"
+	"github.com/kiali/kiali/kubernetes/cache"
+	"github.com/kiali/kiali/kubernetes/kubetest"
+	"github.com/kiali/kiali/prometheus/prometheustest"
+)
+
+type fakePromClient struct {
+	prometheustest.PromClientMock
+}
+
+func (fpc *fakePromClient) GetConfiguration() (prom_v1.ConfigResult, error) {
+	return prom_v1.ConfigResult{}, nil
+}
+
+func (fpc *fakePromClient) GetRuntimeinfo() (prom_v1.RuntimeinfoResult, error) {
+	return prom_v1.RuntimeinfoResult{}, nil
+}
+
+func TestConfigHandler(t *testing.T) {
+	require := require.New(t)
+
+	conf := config.NewConfig()
+	k8s := kubetest.NewFakeK8sClient()
+	cf := kubetest.NewFakeClientFactoryWithClient(conf, k8s)
+	cache := cache.NewTestingCacheWithFactory(t, cf, *conf)
+	discovery := &istiotest.FakeDiscovery{}
+
+	prom := &fakePromClient{PromClientMock: prometheustest.PromClientMock{}}
+
+	handler := handlers.WithFakeAuthInfo(conf, handlers.Config(conf, cache, discovery, cf, prom))
+	mr := mux.NewRouter()
+	mr.Handle("/api/config", handler)
+
+	ts := httptest.NewServer(mr)
+	t.Cleanup(ts.Close)
+
+	url := ts.URL + "/api/config"
+
+	resp, err := http.Get(url)
+	require.NoError(err)
+
+	actual, err := io.ReadAll(resp.Body)
+	require.NoError(err)
+	t.Cleanup(func() { resp.Body.Close() })
+
+	require.NotEmpty(actual)
+	require.Equal(200, resp.StatusCode, string(actual))
+
+	var confResp handlers.PublicConfig
+	require.NoError(json.Unmarshal(actual, &confResp))
+}
diff --git a/istio/istiotest/fake.go b/istio/istiotest/fake.go
index 9b3842e84..ed22e18da 100644
--- a/istio/istiotest/fake.go
+++ b/istio/istiotest/fake.go
@@ -8,6 +8,8 @@ import (
 
 // FakeDiscovery implements the MeshDiscovery interface. Useful for testing.
 type FakeDiscovery struct {
+	// ClustersReturn is the return value of Clusters().
+	ClustersReturn []models.KubeCluster
 	// MeshReturn is the return value of Mesh().
 	MeshReturn models.Mesh
 }
@@ -15,3 +17,7 @@ type FakeDiscovery struct {
 func (fmd *FakeDiscovery) Mesh(ctx context.Context) (*models.Mesh, error) {
 	return &fmd.MeshReturn, nil
 }
+
+func (fmd *FakeDiscovery) Clusters() ([]models.KubeCluster, error) {
+	return fmd.ClustersReturn, nil
+}
diff --git a/prometheus/prometheustest/mock.go b/prometheus/prometheustest/mock.go
index a6bdfce7e..c2888815a 100644
--- a/prometheus/prometheustest/mock.go
+++ b/prometheus/prometheustest/mock.go
@@ -314,6 +314,11 @@ func (o *PromClientMock) GetConfiguration() (prom_v1.ConfigResult, error) {
 	return args.Get(0).(prom_v1.ConfigResult), args.Error(1)
 }
 
+func (o *PromClientMock) GetExistingMetricNames(metricNames []string) ([]string, error) {
+	args := o.Called(metricNames)
+	return args.Get(0).([]string), args.Error(1)
+}
+
 func (o *PromClientMock) GetFlags() (prom_v1.FlagsResult, error) {
 	args := o.Called()
 	return args.Get(0).(prom_v1.FlagsResult), args.Error(1)
@@ -369,6 +374,11 @@ func (o *PromClientMock) GetMetricsForLabels(metricNames []string, labels string
 	return args.Get(0).([]string), args.Error(1)
 }
 
+func (o *PromClientMock) GetRuntimeinfo() (prom_v1.RuntimeinfoResult, error) {
+	args := o.Called()
+	return args.Get(0).(prom_v1.RuntimeinfoResult), args.Error(1)
+}
+
 func (o *PromClientMock) MockMetric(name string, labels string, q *prometheus.RangeQuery, value float64) {
 	o.On("FetchRateRange", name, []string{labels}, "", q).Return(fakeMetric(value))
 }
diff --git a/util/sliceutil/slice_test.go b/util/sliceutil/slice_test.go
index ff0d585e5..c23e11251 100644
--- a/util/sliceutil/slice_test.go
+++ b/util/sliceutil/slice_test.go
@@ -71,3 +71,34 @@ func TestMap(t *testing.T) {
 		})
 	}
 }
+
+func TestSomeString(t *testing.T) {
+	testCases := map[string]struct {
+		slice          []string
+		value          string
+		someStringFunc func(int) string
+		expected       bool
+	}{
+		"array contains value, returns true": {
+			slice:    []string{"bookinfo", "bookinfo2", "default"},
+			value:    "bookinfo",
+			expected: true,
+		},
+		"array does not contain value, returns false": {
+			slice:    []string{"bookinfo", "bookinfo2", "default"},
+			value:    "bookinfo3",
+			expected: false,
+		},
+		"empty array, returns false": {
+			slice:    []string{},
+			value:    "",
+			expected: false,
+		},
+	}
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			assert := assert.New(t)
+			assert.Equal(tc.expected, sliceutil.SomeString(tc.slice, tc.value))
+		})
+	}
+}