Skip to content

Commit 580cb28

Browse files
authored
Skip endpoint resolution when profile lookup is rejected (#691)
When profile lookup is rejected, this error propagates to the stack and is handled by falling back to an alternate stack. In order to move profile discovery out of the HTTP stack and onto the initial TCP accept stack, we want to avoid this sort of fallback behavior. So this change modifies profile discovery to make the profile optional. When a profile lookup is rejected/skipped, we now simply return a `None` profile; and in these cases we avoid performing endpoint resolution by omitting a concrete address.
1 parent 9870faa commit 580cb28

File tree

15 files changed

+403
-410
lines changed

15 files changed

+403
-410
lines changed

linkerd/app/inbound/src/endpoint.rs

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use linkerd2_app_core::{
77
transport::{listen, tls},
88
Addr, Conditional, CANONICAL_DST_HEADER, DST_OVERRIDE_HEADER,
99
};
10-
use std::{convert::TryInto, fmt, net::SocketAddr, sync::Arc};
10+
use std::{convert::TryInto, net::SocketAddr, sync::Arc};
1111
use tracing::debug;
1212

1313
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
@@ -21,7 +21,7 @@ pub struct Target {
2121
#[derive(Clone, Debug)]
2222
pub struct Logical {
2323
target: Target,
24-
profiles: profiles::Receiver,
24+
profiles: Option<profiles::Receiver>,
2525
}
2626

2727
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
@@ -114,18 +114,13 @@ pub(super) fn route((route, logical): (profiles::http::Route, Logical)) -> dst::
114114

115115
// === impl Target ===
116116

117+
/// Used for profile discovery.
117118
impl Into<Addr> for &'_ Target {
118119
fn into(self) -> Addr {
119120
self.dst.clone()
120121
}
121122
}
122123

123-
impl AsRef<Addr> for Target {
124-
fn as_ref(&self) -> &Addr {
125-
&self.dst
126-
}
127-
}
128-
129124
impl tls::HasPeerIdentity for Target {
130125
fn peer_identity(&self) -> tls::PeerIdentity {
131126
Conditional::None(tls::ReasonForNoPeerName::Loopback.into())
@@ -197,12 +192,6 @@ impl tap::Inspect for Target {
197192
}
198193
}
199194

200-
impl fmt::Display for Target {
201-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202-
self.dst.fmt(f)
203-
}
204-
}
205-
206195
impl stack_tracing::GetSpan<()> for Target {
207196
fn get_span(&self, _: &()) -> tracing::Span {
208197
use tracing::info_span;
@@ -275,14 +264,14 @@ impl From<Logical> for Target {
275264

276265
// === impl Logical ===
277266

278-
impl From<(profiles::Receiver, Target)> for Logical {
279-
fn from((profiles, target): (profiles::Receiver, Target)) -> Self {
267+
impl From<(Option<profiles::Receiver>, Target)> for Logical {
268+
fn from((profiles, target): (Option<profiles::Receiver>, Target)) -> Self {
280269
Self { profiles, target }
281270
}
282271
}
283272

284-
impl AsRef<profiles::Receiver> for Logical {
285-
fn as_ref(&self) -> &profiles::Receiver {
286-
&self.profiles
273+
impl Into<Option<profiles::Receiver>> for &'_ Logical {
274+
fn into(self) -> Option<profiles::Receiver> {
275+
self.profiles.clone()
287276
}
288277
}

linkerd/app/inbound/src/lib.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -248,14 +248,9 @@ impl Config {
248248
.push_on_response(svc::layers().box_http_response())
249249
.check_new_service::<Target, http::Request<http::boxed::Payload>>();
250250

251-
let forward = target
252-
.instrument(|_: &Target| debug_span!("forward"))
253-
.check_new_service::<Target, http::Request<http::boxed::Payload>>();
254-
255251
// Attempts to resolve the target as a service profile or, if that
256252
// fails, skips that stack to forward to the local endpoint.
257253
profile
258-
.push_fallback(forward)
259254
.check_new_service::<Target, http::Request<http::boxed::Payload>>()
260255
// If the traffic is targeted at the inbound port, send it through
261256
// the loopback service (i.e. as a gateway).

linkerd/app/outbound/src/endpoint.rs

Lines changed: 39 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use crate::http::uri::Authority;
22
use indexmap::IndexMap;
33
use linkerd2_app_core::{
4-
dst,
5-
metric_labels,
4+
dst, metric_labels,
65
metric_labels::{prefix_labels, EndpointLabels, TlsStatus},
76
profiles,
87
proxy::{
@@ -15,8 +14,7 @@ use linkerd2_app_core::{
1514
},
1615
router,
1716
transport::{listen, tls},
18-
Addr,
19-
Conditional, //L5D_REQUIRE_ID,
17+
Addr, Conditional,
2018
};
2119
use std::{net::SocketAddr, sync::Arc};
2220

@@ -38,7 +36,7 @@ pub struct HttpLogical {
3836

3937
#[derive(Clone, Debug, Eq, PartialEq)]
4038
pub struct HttpConcrete {
41-
pub dst: Addr,
39+
pub resolve: Option<Addr>,
4240
pub logical: HttpLogical,
4341
}
4442

@@ -47,7 +45,7 @@ pub struct LogicalPerRequest(HttpAccept);
4745

4846
#[derive(Clone, Debug)]
4947
pub struct Profile {
50-
pub rx: profiles::Receiver,
48+
pub rx: Option<profiles::Receiver>,
5149
pub logical: HttpLogical,
5250
}
5351

@@ -81,21 +79,17 @@ impl From<listen::Addrs> for TcpLogical {
8179
}
8280
}
8381

82+
/// Used as a default destination when resolution is rejected.
8483
impl Into<SocketAddr> for &'_ TcpLogical {
8584
fn into(self) -> SocketAddr {
8685
self.addr
8786
}
8887
}
8988

90-
impl Into<Addr> for &'_ TcpLogical {
91-
fn into(self) -> Addr {
92-
self.addr.into()
93-
}
94-
}
95-
96-
impl std::fmt::Display for TcpLogical {
97-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98-
self.addr.fmt(f)
89+
/// Used to resolve endpoints.
90+
impl Into<Option<Addr>> for &'_ TcpLogical {
91+
fn into(self) -> Option<Addr> {
92+
Some(self.addr.into())
9993
}
10094
}
10195

@@ -118,102 +112,63 @@ impl Into<SocketAddr> for &'_ HttpAccept {
118112

119113
// === impl HttpConrete ===
120114

121-
impl From<(Addr, Profile)> for HttpConcrete {
122-
fn from((dst, Profile { logical, .. }): (Addr, Profile)) -> Self {
123-
Self { dst, logical }
124-
}
125-
}
126-
127-
impl AsRef<Addr> for HttpConcrete {
128-
fn as_ref(&self) -> &Addr {
129-
&self.dst
115+
impl From<(Option<Addr>, Profile)> for HttpConcrete {
116+
fn from((resolve, Profile { logical, .. }): (Option<Addr>, Profile)) -> Self {
117+
Self { resolve, logical }
130118
}
131119
}
132120

133-
impl Into<Addr> for &'_ HttpConcrete {
134-
fn into(self) -> Addr {
135-
self.dst.clone()
121+
/// Produces an address to resolve to individual endpoints. This address is only
122+
/// present if the initial profile resolution was not rejected.
123+
impl Into<Option<Addr>> for &'_ HttpConcrete {
124+
fn into(self) -> Option<Addr> {
125+
self.resolve.clone()
136126
}
137127
}
138128

129+
/// Produces an address to be used if resolution is rejected.
139130
impl Into<SocketAddr> for &'_ HttpConcrete {
140131
fn into(self) -> SocketAddr {
141-
self.dst
142-
.socket_addr()
132+
self.resolve
133+
.as_ref()
134+
.and_then(|a| a.socket_addr())
143135
.unwrap_or_else(|| self.logical.orig_dst)
144136
}
145137
}
146138

147-
impl std::fmt::Display for HttpConcrete {
148-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149-
self.dst.fmt(f)
150-
}
151-
}
152-
153-
impl From<HttpLogical> for HttpConcrete {
154-
fn from(logical: HttpLogical) -> Self {
155-
Self {
156-
dst: logical.dst.clone(),
157-
logical,
158-
}
159-
}
160-
}
161-
162139
// === impl HttpLogical ===
163140

164-
impl std::fmt::Display for HttpLogical {
165-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166-
self.dst.fmt(f)
167-
}
168-
}
169-
170-
impl<'t> From<&'t HttpLogical> for http::header::HeaderValue {
171-
fn from(target: &'t HttpLogical) -> Self {
172-
http::header::HeaderValue::from_str(&target.dst.to_string())
173-
.expect("addr must be a valid header")
174-
}
175-
}
176-
177-
impl Into<SocketAddr> for HttpLogical {
178-
fn into(self) -> SocketAddr {
179-
self.orig_dst
180-
}
181-
}
182-
141+
/// Produces an address for profile discovery.
183142
impl Into<Addr> for &'_ HttpLogical {
184143
fn into(self) -> Addr {
185144
self.dst.clone()
186145
}
187146
}
188147

148+
/// Needed for canonicalization.
189149
impl AsRef<Addr> for HttpLogical {
190150
fn as_ref(&self) -> &Addr {
191151
&self.dst
192152
}
193153
}
194154

155+
/// Needed for canonicalization.
195156
impl AsMut<Addr> for HttpLogical {
196157
fn as_mut(&mut self) -> &mut Addr {
197158
&mut self.dst
198159
}
199160
}
200161

201-
// === impl HttpEndpoint ===
202-
203-
impl From<HttpLogical> for HttpEndpoint {
204-
fn from(logical: HttpLogical) -> Self {
205-
Self {
206-
addr: logical.orig_dst,
207-
settings: logical.version.into(),
208-
identity: Conditional::None(
209-
tls::ReasonForNoPeerName::NotProvidedByServiceDiscovery.into(),
210-
),
211-
concrete: logical.into(),
212-
metadata: Metadata::default(),
213-
}
162+
// Used to set the l5d-canonical-dst header.
163+
impl<'t> From<&'t HttpLogical> for http::header::HeaderValue {
164+
fn from(target: &'t HttpLogical) -> Self {
165+
http::header::HeaderValue::from_str(&target.dst.to_string())
166+
.expect("addr must be a valid header")
214167
}
215168
}
216169

170+
// === impl HttpEndpoint ===
171+
217172
impl std::hash::Hash for HttpEndpoint {
218173
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
219174
self.addr.hash(state);
@@ -461,8 +416,8 @@ pub fn route((route, profile): (profiles::http::Route, Profile)) -> dst::Route {
461416

462417
// === impl Profile ===
463418

464-
impl From<(profiles::Receiver, HttpLogical)> for Profile {
465-
fn from((rx, logical): (profiles::Receiver, HttpLogical)) -> Self {
419+
impl From<(Option<profiles::Receiver>, HttpLogical)> for Profile {
420+
fn from((rx, logical): (Option<profiles::Receiver>, HttpLogical)) -> Self {
466421
Self { rx, logical }
467422
}
468423
}
@@ -473,14 +428,14 @@ impl AsRef<Addr> for Profile {
473428
}
474429
}
475430

476-
impl AsRef<profiles::Receiver> for Profile {
477-
fn as_ref(&self) -> &profiles::Receiver {
478-
&self.rx
431+
impl Into<Addr> for &'_ Profile {
432+
fn into(self) -> Addr {
433+
self.logical.dst.clone()
479434
}
480435
}
481436

482-
impl From<Profile> for HttpLogical {
483-
fn from(Profile { logical, .. }: Profile) -> Self {
484-
logical
437+
impl Into<Option<profiles::Receiver>> for &'_ Profile {
438+
fn into(self) -> Option<profiles::Receiver> {
439+
self.rx.clone()
485440
}
486441
}

0 commit comments

Comments
 (0)