Add rate-limiters to ServerPolicy
This adds the local_rate_limit module to the server-policy crate, that `ServerPolicy` uses for its new `local_rate_limit` field, containing three optional rate-limiters: total, identity, overrides (this one is really a vector of limiters, one per configured override). I tried putting that under `Protocol` instead, but the `PartialEq` requirement made it very hard to follow. `Server` OTOH doesn't really require that trait, so I was able to remove it and accommodate the limiters. I made sure to avoid pulling the dashmap dependency in `governor`; I haven't checked yet the necessity of the "jitter" and "quanta" features. This temporarily overrides linkerd2-proxy-api dependency to pick changes from linkerd/linkerd2-proxy-api#388
This commit is contained in:
parent
c2687744a0
commit
b580e657e5
96
Cargo.lock
96
Cargo.lock
|
|
@ -379,6 +379,12 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.8.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crypto-common"
|
name = "crypto-common"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
|
|
@ -682,6 +688,12 @@ version = "0.3.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
|
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-timer"
|
||||||
|
version = "3.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-util"
|
name = "futures-util"
|
||||||
version = "0.3.31"
|
version = "0.3.31"
|
||||||
|
|
@ -733,6 +745,25 @@ version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "governor"
|
||||||
|
version = "0.6.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"futures",
|
||||||
|
"futures-timer",
|
||||||
|
"no-std-compat",
|
||||||
|
"nonzero_ext",
|
||||||
|
"parking_lot",
|
||||||
|
"portable-atomic",
|
||||||
|
"quanta",
|
||||||
|
"rand",
|
||||||
|
"smallvec",
|
||||||
|
"spinning_top",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gzip-header"
|
name = "gzip-header"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
|
@ -2012,6 +2043,7 @@ dependencies = [
|
||||||
name = "linkerd-proxy-server-policy"
|
name = "linkerd-proxy-server-policy"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"governor",
|
||||||
"http",
|
"http",
|
||||||
"ipnet",
|
"ipnet",
|
||||||
"linkerd-http-route",
|
"linkerd-http-route",
|
||||||
|
|
@ -2385,8 +2417,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linkerd2-proxy-api"
|
name = "linkerd2-proxy-api"
|
||||||
version = "0.14.0"
|
version = "0.14.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/linkerd/linkerd2-proxy-api.git?branch=alpeb/v0.14.0-rate-limiting#903aeafd8c2e60790b5de0de7aee28f31964fce2"
|
||||||
checksum = "26c72fb98d969e1e94e95d52a6fcdf4693764702c369e577934256e72fb5bc61"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"h2",
|
"h2",
|
||||||
"http",
|
"http",
|
||||||
|
|
@ -2530,6 +2561,12 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "no-std-compat"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nom"
|
name = "nom"
|
||||||
version = "7.1.3"
|
version = "7.1.3"
|
||||||
|
|
@ -2540,6 +2577,12 @@ dependencies = [
|
||||||
"minimal-lexical",
|
"minimal-lexical",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nonzero_ext"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-ansi-term"
|
name = "nu-ansi-term"
|
||||||
version = "0.46.0"
|
version = "0.46.0"
|
||||||
|
|
@ -2764,6 +2807,12 @@ version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "portable-atomic"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "powerfmt"
|
name = "powerfmt"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
|
@ -2920,6 +2969,21 @@ dependencies = [
|
||||||
"prost",
|
"prost",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quanta"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
"raw-cpuid",
|
||||||
|
"wasi",
|
||||||
|
"web-sys",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quick-error"
|
name = "quick-error"
|
||||||
version = "1.2.3"
|
version = "1.2.3"
|
||||||
|
|
@ -2980,6 +3044,15 @@ version = "1.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684"
|
checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "raw-cpuid"
|
||||||
|
version = "11.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.4.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rcgen"
|
name = "rcgen"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
|
|
@ -3290,6 +3363,15 @@ version = "0.9.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spinning_top"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stable_deref_trait"
|
name = "stable_deref_trait"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
|
@ -3863,6 +3945,16 @@ version = "0.2.93"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
|
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "web-sys"
|
||||||
|
version = "0.3.70"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0"
|
||||||
|
dependencies = [
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "widestring"
|
name = "widestring"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
|
|
||||||
|
|
@ -90,3 +90,6 @@ lto = true
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
linkerd2-proxy-api = "0.14.0"
|
linkerd2-proxy-api = "0.14.0"
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
linkerd2-proxy-api = { git = "https://github.com/linkerd/linkerd2-proxy-api.git", branch = "alpeb/v0.14.0-rate-limiting" }
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,7 @@ async fn upgraded_request_remains_relative_form() {
|
||||||
}),
|
}),
|
||||||
}]))]),
|
}]))]),
|
||||||
},
|
},
|
||||||
|
local_rate_limit: Arc::new(Default::default()),
|
||||||
};
|
};
|
||||||
let (policy, tx) = inbound::policy::AllowPolicy::for_test(self.param(), policy);
|
let (policy, tx) = inbound::policy::AllowPolicy::for_test(self.param(), policy);
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,7 @@ mod tests {
|
||||||
kind: "server".into(),
|
kind: "server".into(),
|
||||||
name: "testsrv".into(),
|
name: "testsrv".into(),
|
||||||
}),
|
}),
|
||||||
|
local_rate_limit: Default::default(),
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ fn allow(protocol: Protocol) -> AllowPolicy {
|
||||||
kind: "server".into(),
|
kind: "server".into(),
|
||||||
name: "testsrv".into(),
|
name: "testsrv".into(),
|
||||||
}),
|
}),
|
||||||
|
local_rate_limit: Arc::new(Default::default()),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
allow
|
allow
|
||||||
|
|
|
||||||
|
|
@ -748,6 +748,7 @@ impl svc::Param<policy::AllowPolicy> for Target {
|
||||||
kind: "server".into(),
|
kind: "server".into(),
|
||||||
name: "testsrv".into(),
|
name: "testsrv".into(),
|
||||||
}),
|
}),
|
||||||
|
local_rate_limit: Default::default(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
policy
|
policy
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ pub trait GetPolicy {
|
||||||
fn get_policy(&self, dst: OrigDstAddr) -> AllowPolicy;
|
fn get_policy(&self, dst: OrigDstAddr) -> AllowPolicy;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum DefaultPolicy {
|
pub enum DefaultPolicy {
|
||||||
Allow(ServerPolicy),
|
Allow(ServerPolicy),
|
||||||
Deny,
|
Deny,
|
||||||
|
|
@ -90,6 +90,7 @@ impl From<DefaultPolicy> for ServerPolicy {
|
||||||
DefaultPolicy::Allow(p) => p,
|
DefaultPolicy::Allow(p) => p,
|
||||||
DefaultPolicy::Deny => ServerPolicy {
|
DefaultPolicy::Deny => ServerPolicy {
|
||||||
protocol: Protocol::Opaque(Arc::new([])),
|
protocol: Protocol::Opaque(Arc::new([])),
|
||||||
|
local_rate_limit: Default::default(),
|
||||||
meta: Meta::new_default("deny"),
|
meta: Meta::new_default("deny"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,5 +88,6 @@ fn mk(
|
||||||
ServerPolicy {
|
ServerPolicy {
|
||||||
meta: Meta::new_default(name),
|
meta: Meta::new_default(name),
|
||||||
protocol,
|
protocol,
|
||||||
|
local_rate_limit: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ macro_rules! new_svc {
|
||||||
kind: "Server".into(),
|
kind: "Server".into(),
|
||||||
name: "testsrv".into(),
|
name: "testsrv".into(),
|
||||||
}),
|
}),
|
||||||
|
local_rate_limit: Arc::new(Default::default()),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let svc = HttpPolicyService {
|
let svc = HttpPolicyService {
|
||||||
|
|
@ -197,6 +198,7 @@ async fn http_route() {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}])),
|
}])),
|
||||||
|
local_rate_limit: Arc::new(Default::default()),
|
||||||
})
|
})
|
||||||
.expect("must send");
|
.expect("must send");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ async fn unauthenticated_allowed() {
|
||||||
kind: "server".into(),
|
kind: "server".into(),
|
||||||
name: "test".into(),
|
name: "test".into(),
|
||||||
}),
|
}),
|
||||||
|
local_rate_limit: Arc::new(Default::default()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let tls = tls::ConditionalServerTls::None(tls::NoServerTls::NoClientHello);
|
let tls = tls::ConditionalServerTls::None(tls::NoServerTls::NoClientHello);
|
||||||
|
|
@ -75,6 +76,7 @@ async fn authenticated_identity() {
|
||||||
kind: "server".into(),
|
kind: "server".into(),
|
||||||
name: "test".into(),
|
name: "test".into(),
|
||||||
}),
|
}),
|
||||||
|
local_rate_limit: Arc::new(Default::default()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let tls = tls::ConditionalServerTls::Some(tls::ServerTls::Established {
|
let tls = tls::ConditionalServerTls::Some(tls::ServerTls::Established {
|
||||||
|
|
@ -138,6 +140,7 @@ async fn authenticated_suffix() {
|
||||||
kind: "server".into(),
|
kind: "server".into(),
|
||||||
name: "test".into(),
|
name: "test".into(),
|
||||||
}),
|
}),
|
||||||
|
local_rate_limit: Arc::new(Default::default()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let tls = tls::ConditionalServerTls::Some(tls::ServerTls::Established {
|
let tls = tls::ConditionalServerTls::Some(tls::ServerTls::Established {
|
||||||
|
|
@ -197,6 +200,7 @@ async fn tls_unauthenticated() {
|
||||||
kind: "server".into(),
|
kind: "server".into(),
|
||||||
name: "test".into(),
|
name: "test".into(),
|
||||||
}),
|
}),
|
||||||
|
local_rate_limit: Arc::new(Default::default()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let tls = tls::ConditionalServerTls::Some(tls::ServerTls::Established {
|
let tls = tls::ConditionalServerTls::Some(tls::ServerTls::Established {
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ pub fn default_config() -> Config {
|
||||||
kind: "server".into(),
|
kind: "server".into(),
|
||||||
name: "testsrv".into(),
|
name: "testsrv".into(),
|
||||||
}),
|
}),
|
||||||
|
local_rate_limit: Arc::new(Default::default()),
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
ports: Default::default(),
|
ports: Default::default(),
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ pub fn all_unauthenticated() -> inbound::Server {
|
||||||
inbound::proxy_protocol::Detect {
|
inbound::proxy_protocol::Detect {
|
||||||
timeout: Some(Duration::from_secs(10).try_into().unwrap()),
|
timeout: Some(Duration::from_secs(10).try_into().unwrap()),
|
||||||
http_routes: vec![],
|
http_routes: vec![],
|
||||||
|
http_local_rate_limit: None,
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ publish = false
|
||||||
proto = ["linkerd-http-route/proto", "linkerd2-proxy-api", "prost-types"]
|
proto = ["linkerd-http-route/proto", "linkerd2-proxy-api", "prost-types"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
governor = { version = "0.6", default-features = false, features = ["std", "jitter", "quanta"] }
|
||||||
ipnet = "2"
|
ipnet = "2"
|
||||||
http = "0.2"
|
http = "0.2"
|
||||||
prost-types = { version = "0.12", optional = true }
|
prost-types = { version = "0.12", optional = true }
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
#![deny(rust_2018_idioms, clippy::disallowed_methods, clippy::disallowed_types)]
|
#![deny(rust_2018_idioms, clippy::disallowed_methods, clippy::disallowed_types)]
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
|
|
||||||
|
use local_rate_limit::HttpLocalRateLimit;
|
||||||
use std::{hash::Hash, sync::Arc, time};
|
use std::{hash::Hash, sync::Arc, time};
|
||||||
|
|
||||||
pub mod authz;
|
pub mod authz;
|
||||||
pub mod grpc;
|
pub mod grpc;
|
||||||
pub mod http;
|
pub mod http;
|
||||||
|
pub mod local_rate_limit;
|
||||||
pub mod meta;
|
pub mod meta;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
|
|
@ -14,10 +16,11 @@ pub use self::{
|
||||||
};
|
};
|
||||||
pub use linkerd_http_route as route;
|
pub use linkerd_http_route as route;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ServerPolicy {
|
pub struct ServerPolicy {
|
||||||
pub protocol: Protocol,
|
pub protocol: Protocol,
|
||||||
pub meta: Arc<Meta>,
|
pub meta: Arc<Meta>,
|
||||||
|
pub local_rate_limit: Arc<HttpLocalRateLimit>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
|
@ -65,6 +68,7 @@ impl ServerPolicy {
|
||||||
}]),
|
}]),
|
||||||
tcp_authorizations: Arc::new([]),
|
tcp_authorizations: Arc::new([]),
|
||||||
},
|
},
|
||||||
|
local_rate_limit: Arc::new(HttpLocalRateLimit::default()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -131,6 +135,28 @@ pub mod proto {
|
||||||
server_ips: _,
|
server_ips: _,
|
||||||
} = proto;
|
} = proto;
|
||||||
|
|
||||||
|
let local_rate_limit = {
|
||||||
|
match protocol
|
||||||
|
.clone()
|
||||||
|
.and_then(|api::ProxyProtocol { kind }| kind)
|
||||||
|
.ok_or(InvalidServer::MissingProxyProtocol)?
|
||||||
|
{
|
||||||
|
api::proxy_protocol::Kind::Detect(api::proxy_protocol::Detect {
|
||||||
|
http_local_rate_limit,
|
||||||
|
..
|
||||||
|
}) => http_local_rate_limit.unwrap_or_default().into(),
|
||||||
|
api::proxy_protocol::Kind::Http1(api::proxy_protocol::Http1 {
|
||||||
|
local_rate_limit,
|
||||||
|
..
|
||||||
|
})
|
||||||
|
| api::proxy_protocol::Kind::Http2(api::proxy_protocol::Http2 {
|
||||||
|
local_rate_limit,
|
||||||
|
..
|
||||||
|
}) => local_rate_limit.unwrap_or_default().into(),
|
||||||
|
_ => Default::default(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let authorizations = {
|
let authorizations = {
|
||||||
// Always permit traffic from localhost.
|
// Always permit traffic from localhost.
|
||||||
let localhost = Authorization {
|
let localhost = Authorization {
|
||||||
|
|
@ -154,6 +180,7 @@ pub mod proto {
|
||||||
api::proxy_protocol::Kind::Detect(api::proxy_protocol::Detect {
|
api::proxy_protocol::Kind::Detect(api::proxy_protocol::Detect {
|
||||||
http_routes,
|
http_routes,
|
||||||
timeout,
|
timeout,
|
||||||
|
..
|
||||||
}) => Protocol::Detect {
|
}) => Protocol::Detect {
|
||||||
http: mk_routes!(http, http_routes, authorizations.clone())?,
|
http: mk_routes!(http, http_routes, authorizations.clone())?,
|
||||||
timeout: timeout
|
timeout: timeout
|
||||||
|
|
@ -162,11 +189,11 @@ pub mod proto {
|
||||||
tcp_authorizations: authorizations,
|
tcp_authorizations: authorizations,
|
||||||
},
|
},
|
||||||
|
|
||||||
api::proxy_protocol::Kind::Http1(api::proxy_protocol::Http1 { routes }) => {
|
api::proxy_protocol::Kind::Http1(api::proxy_protocol::Http1 { routes, .. }) => {
|
||||||
Protocol::Http1(mk_routes!(http, routes, authorizations)?)
|
Protocol::Http1(mk_routes!(http, routes, authorizations)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
api::proxy_protocol::Kind::Http2(api::proxy_protocol::Http2 { routes }) => {
|
api::proxy_protocol::Kind::Http2(api::proxy_protocol::Http2 { routes, .. }) => {
|
||||||
Protocol::Http2(mk_routes!(http, routes, authorizations)?)
|
Protocol::Http2(mk_routes!(http, routes, authorizations)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -182,7 +209,11 @@ pub mod proto {
|
||||||
// avoid label inference.
|
// avoid label inference.
|
||||||
let meta = Meta::try_new_with_default(labels, "policy.linkerd.io", "server")?;
|
let meta = Meta::try_new_with_default(labels, "policy.linkerd.io", "server")?;
|
||||||
|
|
||||||
Ok(ServerPolicy { protocol, meta })
|
Ok(ServerPolicy {
|
||||||
|
protocol,
|
||||||
|
meta,
|
||||||
|
local_rate_limit: Arc::new(local_rate_limit),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
use governor::{
|
||||||
|
clock::DefaultClock,
|
||||||
|
state::{keyed::DefaultKeyedStateStore, InMemoryState, NotKeyed, RateLimiter},
|
||||||
|
Quota,
|
||||||
|
};
|
||||||
|
use std::num::NonZeroU32;
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct HttpLocalRateLimit {
|
||||||
|
pub total: Option<RateLimiter<NotKeyed, InMemoryState, DefaultClock>>,
|
||||||
|
pub identity: Option<RateLimiter<String, DefaultKeyedStateStore<String>, DefaultClock>>,
|
||||||
|
pub overrides: Vec<HttpLocalRateLimitOverride>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct HttpLocalRateLimitOverride {
|
||||||
|
pub ids: Vec<String>,
|
||||||
|
pub rate_limit: RateLimiter<Vec<String>, DefaultKeyedStateStore<Vec<String>>, DefaultClock>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for HttpLocalRateLimitOverride {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
ids: vec![],
|
||||||
|
rate_limit: RateLimiter::keyed(Quota::per_second(NonZeroU32::new(1).unwrap())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "proto")]
|
||||||
|
pub mod proto {
|
||||||
|
use super::*;
|
||||||
|
use linkerd2_proxy_api::inbound::{self as api};
|
||||||
|
|
||||||
|
impl From<api::HttpLocalRateLimit> for HttpLocalRateLimit {
|
||||||
|
fn from(proto: api::HttpLocalRateLimit) -> Self {
|
||||||
|
let total = proto.total.map(|lim| {
|
||||||
|
let quota = Quota::per_second(NonZeroU32::new(lim.requests_per_second).unwrap());
|
||||||
|
RateLimiter::direct(quota)
|
||||||
|
});
|
||||||
|
|
||||||
|
let identity = proto.identity.map(|lim| {
|
||||||
|
let quota = Quota::per_second(NonZeroU32::new(lim.requests_per_second).unwrap());
|
||||||
|
RateLimiter::keyed(quota)
|
||||||
|
});
|
||||||
|
|
||||||
|
let overrides = proto
|
||||||
|
.overrides
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|ovr| {
|
||||||
|
ovr.limit.map(|lim| {
|
||||||
|
let ids = ovr
|
||||||
|
.clients
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|cl| cl.identities.into_iter().map(|id| id.name))
|
||||||
|
.collect();
|
||||||
|
let quota =
|
||||||
|
Quota::per_second(NonZeroU32::new(lim.requests_per_second).unwrap());
|
||||||
|
let rate_limit = RateLimiter::keyed(quota);
|
||||||
|
HttpLocalRateLimitOverride { ids, rate_limit }
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
total,
|
||||||
|
identity,
|
||||||
|
overrides,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue