package vpnruntime import "strings" const ( DefaultFabricTunnelPoolID = "ipv4-egress" DefaultFabricTunnelServiceKind = "ipv4-tunnel" DefaultFabricTunnelClass = "vpn_packets" DefaultFabricTunnelRole = "ipv4-egress" DefaultFabricTunnelDataPlane = "fabric_quic_streams" DefaultFabricTransportOwner = "fabric_farm" DefaultFabricRouteVisibility = "opaque_to_service" FabricServiceTunnelSchemaVersion = "rap.fabric_service_tunnel.v1" FabricServiceTrafficControl = "control" FabricServiceTrafficDNS = "dns" FabricServiceTrafficInteractive = "interactive" FabricServiceTrafficReliable = "reliable" FabricServiceTrafficBulk = "bulk" FabricServiceTrafficDroppable = "droppable" DefaultFabricServiceStreamShards = 8 ) type FabricServiceTunnel struct { TunnelID string `json:"tunnel_id"` PoolID string `json:"pool_id"` ServiceID string `json:"service_id"` LocalServiceID string `json:"local_service_id"` RemoteServiceID string `json:"remote_service_id"` ServiceKind string `json:"service_kind"` ServiceClass string `json:"service_class"` ServiceRole string `json:"service_role"` RouteLeaseID string `json:"route_lease_id,omitempty"` RouteGeneration string `json:"route_generation,omitempty"` DataPlane string `json:"data_plane,omitempty"` TransportOwner string `json:"transport_owner,omitempty"` RouteVisibility string `json:"route_visibility,omitempty"` TrafficClasses []string `json:"traffic_classes,omitempty"` StreamShards int `json:"stream_shards,omitempty"` } type FabricServiceTunnelDefaults struct { PoolID string ServiceKind string ServiceClass string ServiceRole string DataPlane string TransportOwner string RouteVisibility string TrafficClasses []string StreamShards int } func NormalizeServiceTunnel(tunnel FabricServiceTunnel, fallbackID string) FabricServiceTunnel { return NormalizeServiceTunnelWithDefaults(tunnel, fallbackID, DefaultVPNServiceTunnelDefaults()) } func NormalizeServiceTunnelWithDefaults(tunnel FabricServiceTunnel, fallbackID string, defaults FabricServiceTunnelDefaults) FabricServiceTunnel { defaults = normalizeServiceTunnelDefaults(defaults) tunnel.TunnelID = strings.TrimSpace(firstNonEmptyTunnelString(tunnel.TunnelID, fallbackID)) tunnel.PoolID = strings.TrimSpace(firstNonEmptyTunnelString(tunnel.PoolID, defaults.PoolID)) tunnel.ServiceID = strings.TrimSpace(firstNonEmptyTunnelString(tunnel.ServiceID, "svc-"+tunnel.TunnelID)) tunnel.LocalServiceID = strings.TrimSpace(firstNonEmptyTunnelString(tunnel.LocalServiceID, "svc-local-"+tunnel.TunnelID)) tunnel.RemoteServiceID = strings.TrimSpace(firstNonEmptyTunnelString(tunnel.RemoteServiceID, "svc-remote-"+tunnel.TunnelID)) tunnel.ServiceKind = strings.TrimSpace(firstNonEmptyTunnelString(tunnel.ServiceKind, defaults.ServiceKind)) tunnel.ServiceClass = strings.TrimSpace(firstNonEmptyTunnelString(tunnel.ServiceClass, defaults.ServiceClass)) tunnel.ServiceRole = strings.TrimSpace(firstNonEmptyTunnelString(tunnel.ServiceRole, defaults.ServiceRole)) tunnel.DataPlane = strings.TrimSpace(firstNonEmptyTunnelString(tunnel.DataPlane, defaults.DataPlane)) tunnel.TransportOwner = strings.TrimSpace(firstNonEmptyTunnelString(tunnel.TransportOwner, defaults.TransportOwner)) tunnel.RouteVisibility = strings.TrimSpace(firstNonEmptyTunnelString(tunnel.RouteVisibility, defaults.RouteVisibility)) tunnel.TrafficClasses = normalizeTunnelTrafficClasses(tunnel.TrafficClasses, defaults.TrafficClasses) if tunnel.StreamShards <= 0 { tunnel.StreamShards = defaults.StreamShards } return tunnel } func (t FabricServiceTunnel) Snapshot() map[string]any { t = NormalizeServiceTunnelWithDefaults(t, t.TunnelID, FabricServiceTunnelDefaults{ PoolID: t.PoolID, ServiceKind: t.ServiceKind, ServiceClass: t.ServiceClass, ServiceRole: t.ServiceRole, DataPlane: t.DataPlane, TransportOwner: t.TransportOwner, RouteVisibility: t.RouteVisibility, TrafficClasses: t.TrafficClasses, StreamShards: t.StreamShards, }) return map[string]any{ "schema_version": FabricServiceTunnelSchemaVersion, "tunnel_id": t.TunnelID, "pool_id": t.PoolID, "service_id": t.ServiceID, "local_service_id": t.LocalServiceID, "remote_service_id": t.RemoteServiceID, "service_kind": t.ServiceKind, "service_class": t.ServiceClass, "service_role": t.ServiceRole, "route_lease_id": t.RouteLeaseID, "route_generation": t.RouteGeneration, "data_plane": t.DataPlane, "transport_owner": t.TransportOwner, "route_visibility": t.RouteVisibility, "traffic_classes": append([]string(nil), t.TrafficClasses...), "stream_shards": t.StreamShards, "selected_node_known": false, } } func DefaultVPNServiceTunnelDefaults() FabricServiceTunnelDefaults { return FabricServiceTunnelDefaults{ PoolID: DefaultFabricTunnelPoolID, ServiceKind: DefaultFabricTunnelServiceKind, ServiceClass: DefaultFabricTunnelClass, ServiceRole: DefaultFabricTunnelRole, DataPlane: DefaultFabricTunnelDataPlane, TransportOwner: DefaultFabricTransportOwner, RouteVisibility: DefaultFabricRouteVisibility, TrafficClasses: []string{ FabricServiceTrafficControl, FabricServiceTrafficDNS, FabricServiceTrafficInteractive, FabricServiceTrafficReliable, FabricServiceTrafficBulk, FabricServiceTrafficDroppable, }, StreamShards: DefaultFabricServiceStreamShards, } } func normalizeServiceTunnelDefaults(defaults FabricServiceTunnelDefaults) FabricServiceTunnelDefaults { fallback := DefaultVPNServiceTunnelDefaults() defaults.PoolID = firstNonEmptyTunnelString(defaults.PoolID, fallback.PoolID) defaults.ServiceKind = firstNonEmptyTunnelString(defaults.ServiceKind, fallback.ServiceKind) defaults.ServiceClass = firstNonEmptyTunnelString(defaults.ServiceClass, fallback.ServiceClass) defaults.ServiceRole = firstNonEmptyTunnelString(defaults.ServiceRole, fallback.ServiceRole) defaults.DataPlane = firstNonEmptyTunnelString(defaults.DataPlane, fallback.DataPlane) defaults.TransportOwner = firstNonEmptyTunnelString(defaults.TransportOwner, fallback.TransportOwner) defaults.RouteVisibility = firstNonEmptyTunnelString(defaults.RouteVisibility, fallback.RouteVisibility) defaults.TrafficClasses = normalizeTunnelTrafficClasses(defaults.TrafficClasses, fallback.TrafficClasses) if defaults.StreamShards <= 0 { defaults.StreamShards = fallback.StreamShards } return defaults } func normalizeTunnelTrafficClasses(values []string, fallback []string) []string { if len(values) == 0 { return append([]string(nil), fallback...) } out := make([]string, 0, len(values)) seen := map[string]struct{}{} for _, value := range values { value = strings.TrimSpace(value) if value == "" { continue } if _, ok := seen[value]; ok { continue } seen[value] = struct{}{} out = append(out, value) } if len(out) == 0 { return append([]string(nil), fallback...) } return out } func firstNonEmptyTunnelString(values ...string) string { for _, value := range values { if trimmed := strings.TrimSpace(value); trimmed != "" { return trimmed } } return "" }