@@ -5,7 +5,6 @@ pub use linkerd_tls_route::{find, sni, RouteMatch};
55
66pub type Policy = crate :: RoutePolicy < Filter , ( ) > ;
77pub type Route = tls:: Route < Policy > ;
8- pub type Rule = tls:: Rule < Policy > ;
98
109#[ derive( Clone , Debug , PartialEq , Eq , Hash ) ]
1110pub struct Tls {
@@ -18,15 +17,12 @@ pub enum Filter {}
1817pub fn default ( distribution : crate :: RouteDistribution < Filter > ) -> Route {
1918 Route {
2019 snis : vec ! [ ] ,
21- rules : vec ! [ Rule {
22- matches: vec![ ] ,
23- policy: Policy {
24- meta: crate :: Meta :: new_default( "default" ) ,
25- filters: Arc :: new( [ ] ) ,
26- params: ( ) ,
27- distribution,
28- } ,
29- } ] ,
20+ policy : Policy {
21+ meta : crate :: Meta :: new_default ( "default" ) ,
22+ filters : Arc :: new ( [ ] ) ,
23+ params : ( ) ,
24+ distribution,
25+ } ,
3026 }
3127}
3228
@@ -39,17 +35,175 @@ impl Default for Tls {
3935}
4036
4137#[ cfg( feature = "proto" ) ]
42- pub mod proto {
38+ pub ( crate ) mod proto {
4339 use super :: * ;
44- use crate :: proto:: BackendSet ;
40+ use crate :: {
41+ proto:: { BackendSet , InvalidBackend , InvalidDistribution , InvalidMeta } ,
42+ Meta , RouteBackend , RouteDistribution ,
43+ } ;
44+ use linkerd2_proxy_api:: outbound:: { self , tls_route} ;
45+ use linkerd_tls_route:: sni:: proto:: InvalidSniMatch ;
46+
47+ use once_cell:: sync:: Lazy ;
48+ use std:: sync:: Arc ;
49+
50+ pub ( crate ) static NO_FILTERS : Lazy < Arc < [ Filter ] > > = Lazy :: new ( || Arc :: new ( [ ] ) ) ;
51+
52+ #[ derive( Debug , thiserror:: Error ) ]
53+ pub enum InvalidTlsRoute {
54+ #[ error( "invalid sni match: {0}" ) ]
55+ SniMatch ( #[ from] InvalidSniMatch ) ,
56+
57+ #[ error( "invalid route metadata: {0}" ) ]
58+ Meta ( #[ from] InvalidMeta ) ,
59+
60+ #[ error( "invalid distribution: {0}" ) ]
61+ Distribution ( #[ from] InvalidDistribution ) ,
62+
63+ /// Note: this restriction may be removed in the future, if a way of
64+ /// actually matching rules for TLS routes is added.
65+ #[ error( "a TLS route must have exactly one rule, but {0} were provided" ) ]
66+ OnlyOneRule ( usize ) ,
67+
68+ #[ error( "no filters can be configured on opaque routes yet" ) ]
69+ NoFilters ,
70+
71+ #[ error( "missing {0}" ) ]
72+ Missing ( & ' static str ) ,
73+ }
74+
75+ impl TryFrom < outbound:: proxy_protocol:: Tls > for Tls {
76+ type Error = InvalidTlsRoute ;
77+ fn try_from ( proto : outbound:: proxy_protocol:: Tls ) -> Result < Self , Self :: Error > {
78+ let routes = proto
79+ . routes
80+ . into_iter ( )
81+ . map ( try_route)
82+ . collect :: < Result < Arc < [ _ ] > , _ > > ( ) ?;
83+
84+ Ok ( Self { routes } )
85+ }
86+ }
4587
4688 impl Tls {
4789 pub fn fill_backends ( & self , set : & mut BackendSet ) {
48- for Route { ref rules, .. } in & * self . routes {
49- for Rule { ref policy, .. } in rules {
50- policy. distribution . fill_backends ( set) ;
51- }
90+ for Route { ref policy, .. } in & * self . routes {
91+ policy. distribution . fill_backends ( set) ;
5292 }
5393 }
5494 }
95+
96+ fn try_route ( proto : outbound:: TlsRoute ) -> Result < Route , InvalidTlsRoute > {
97+ let outbound:: TlsRoute {
98+ rules,
99+ snis,
100+ metadata,
101+ ..
102+ } = proto;
103+ let meta = Arc :: new (
104+ metadata
105+ . ok_or ( InvalidMeta ( "missing metadata" ) ) ?
106+ . try_into ( ) ?,
107+ ) ;
108+
109+ let snis = snis
110+ . into_iter ( )
111+ . map ( sni:: MatchSni :: try_from)
112+ . collect :: < Result < Vec < _ > , _ > > ( ) ?;
113+
114+ if rules. len ( ) != 1 {
115+ // Currently, TLS rules have no match expressions, so if there's
116+ // more than one rule, we have no way of determining which one to
117+ // use. Therefore, require that there's exactly one rule.
118+ return Err ( InvalidTlsRoute :: OnlyOneRule ( rules. len ( ) ) ) ;
119+ }
120+
121+ let policy = rules
122+ . into_iter ( )
123+ . map ( |rule| try_rule ( & meta, rule) )
124+ . next ( )
125+ . ok_or ( InvalidTlsRoute :: OnlyOneRule ( 0 ) ) ??;
126+
127+ Ok ( Route { snis, policy } )
128+ }
129+
130+ fn try_rule (
131+ meta : & Arc < Meta > ,
132+ tls_route:: Rule { backends } : tls_route:: Rule ,
133+ ) -> Result < Policy , InvalidTlsRoute > {
134+ let distribution = backends
135+ . ok_or ( InvalidTlsRoute :: Missing ( "distribution" ) ) ?
136+ . try_into ( ) ?;
137+
138+ Ok ( Policy {
139+ meta : meta. clone ( ) ,
140+ filters : NO_FILTERS . clone ( ) ,
141+ params : ( ) ,
142+ distribution,
143+ } )
144+ }
145+
146+ impl TryFrom < tls_route:: Distribution > for RouteDistribution < Filter > {
147+ type Error = InvalidDistribution ;
148+ fn try_from ( distribution : tls_route:: Distribution ) -> Result < Self , Self :: Error > {
149+ use tls_route:: { distribution, WeightedRouteBackend } ;
150+
151+ Ok (
152+ match distribution. kind . ok_or ( InvalidDistribution :: Missing ) ? {
153+ distribution:: Kind :: Empty ( _) => RouteDistribution :: Empty ,
154+ distribution:: Kind :: RandomAvailable ( distribution:: RandomAvailable {
155+ backends,
156+ } ) => {
157+ let backends = backends
158+ . into_iter ( )
159+ . map ( |WeightedRouteBackend { weight, backend } | {
160+ let backend = backend
161+ . ok_or ( InvalidDistribution :: MissingBackend ) ?
162+ . try_into ( ) ?;
163+ Ok ( ( backend, weight) )
164+ } )
165+ . collect :: < Result < Arc < [ _ ] > , InvalidDistribution > > ( ) ?;
166+ if backends. is_empty ( ) {
167+ return Err ( InvalidDistribution :: Empty ( "RandomAvailable" ) ) ;
168+ }
169+ RouteDistribution :: RandomAvailable ( backends)
170+ }
171+ distribution:: Kind :: FirstAvailable ( distribution:: FirstAvailable {
172+ backends,
173+ } ) => {
174+ let backends = backends
175+ . into_iter ( )
176+ . map ( RouteBackend :: try_from)
177+ . collect :: < Result < Arc < [ _ ] > , InvalidBackend > > ( ) ?;
178+ if backends. is_empty ( ) {
179+ return Err ( InvalidDistribution :: Empty ( "FirstAvailable" ) ) ;
180+ }
181+ RouteDistribution :: FirstAvailable ( backends)
182+ }
183+ } ,
184+ )
185+ }
186+ }
187+
188+ impl TryFrom < tls_route:: RouteBackend > for RouteBackend < Filter > {
189+ type Error = InvalidBackend ;
190+ fn try_from (
191+ tls_route:: RouteBackend {
192+ backend,
193+ invalid : _, // TODO
194+ } : tls_route:: RouteBackend ,
195+ ) -> Result < Self , Self :: Error > {
196+ let backend = backend. ok_or ( InvalidBackend :: Missing ( "backend" ) ) ?;
197+ RouteBackend :: try_from_proto ( backend, std:: iter:: empty :: < ( ) > ( ) )
198+ }
199+ }
200+
201+ // Necessary to satisfy `RouteBackend::try_from_proto` type constraints.
202+ // TODO(eliza): if filters are added to opaque routes, change this to a
203+ // proper `TryFrom` impl...
204+ impl From < ( ) > for Filter {
205+ fn from ( _: ( ) ) -> Self {
206+ unreachable ! ( "no filters can be configured on opaque routes yet" )
207+ }
208+ }
55209}
0 commit comments