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",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "crossbeam-utils"
 | 
			
		||||
version = "0.8.20"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "crypto-common"
 | 
			
		||||
version = "0.1.6"
 | 
			
		||||
| 
						 | 
				
			
			@ -682,6 +688,12 @@ version = "0.3.31"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "futures-timer"
 | 
			
		||||
version = "3.0.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "futures-util"
 | 
			
		||||
version = "0.3.31"
 | 
			
		||||
| 
						 | 
				
			
			@ -733,6 +745,25 @@ version = "0.3.1"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
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]]
 | 
			
		||||
name = "gzip-header"
 | 
			
		||||
version = "1.0.0"
 | 
			
		||||
| 
						 | 
				
			
			@ -2012,6 +2043,7 @@ dependencies = [
 | 
			
		|||
name = "linkerd-proxy-server-policy"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "governor",
 | 
			
		||||
 "http",
 | 
			
		||||
 "ipnet",
 | 
			
		||||
 "linkerd-http-route",
 | 
			
		||||
| 
						 | 
				
			
			@ -2385,8 +2417,7 @@ dependencies = [
 | 
			
		|||
[[package]]
 | 
			
		||||
name = "linkerd2-proxy-api"
 | 
			
		||||
version = "0.14.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "26c72fb98d969e1e94e95d52a6fcdf4693764702c369e577934256e72fb5bc61"
 | 
			
		||||
source = "git+https://github.com/linkerd/linkerd2-proxy-api.git?branch=alpeb/v0.14.0-rate-limiting#903aeafd8c2e60790b5de0de7aee28f31964fce2"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "h2",
 | 
			
		||||
 "http",
 | 
			
		||||
| 
						 | 
				
			
			@ -2530,6 +2561,12 @@ dependencies = [
 | 
			
		|||
 "libc",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "no-std-compat"
 | 
			
		||||
version = "0.4.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "nom"
 | 
			
		||||
version = "7.1.3"
 | 
			
		||||
| 
						 | 
				
			
			@ -2540,6 +2577,12 @@ dependencies = [
 | 
			
		|||
 "minimal-lexical",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "nonzero_ext"
 | 
			
		||||
version = "0.3.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "nu-ansi-term"
 | 
			
		||||
version = "0.46.0"
 | 
			
		||||
| 
						 | 
				
			
			@ -2764,6 +2807,12 @@ version = "0.1.0"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "portable-atomic"
 | 
			
		||||
version = "1.9.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "powerfmt"
 | 
			
		||||
version = "0.2.0"
 | 
			
		||||
| 
						 | 
				
			
			@ -2920,6 +2969,21 @@ dependencies = [
 | 
			
		|||
 "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]]
 | 
			
		||||
name = "quick-error"
 | 
			
		||||
version = "1.2.3"
 | 
			
		||||
| 
						 | 
				
			
			@ -2980,6 +3044,15 @@ version = "1.5.1"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
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]]
 | 
			
		||||
name = "rcgen"
 | 
			
		||||
version = "0.12.1"
 | 
			
		||||
| 
						 | 
				
			
			@ -3290,6 +3363,15 @@ version = "0.9.8"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
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]]
 | 
			
		||||
name = "stable_deref_trait"
 | 
			
		||||
version = "1.2.0"
 | 
			
		||||
| 
						 | 
				
			
			@ -3863,6 +3945,16 @@ version = "0.2.93"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
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]]
 | 
			
		||||
name = "widestring"
 | 
			
		||||
version = "1.1.0"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -90,3 +90,6 @@ lto = true
 | 
			
		|||
 | 
			
		||||
[workspace.dependencies]
 | 
			
		||||
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);
 | 
			
		||||
            tokio::spawn(async move {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -138,6 +138,7 @@ mod tests {
 | 
			
		|||
                    kind: "server".into(),
 | 
			
		||||
                    name: "testsrv".into(),
 | 
			
		||||
                }),
 | 
			
		||||
                local_rate_limit: Default::default(),
 | 
			
		||||
            },
 | 
			
		||||
            None,
 | 
			
		||||
        );
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,6 +35,7 @@ fn allow(protocol: Protocol) -> AllowPolicy {
 | 
			
		|||
                kind: "server".into(),
 | 
			
		||||
                name: "testsrv".into(),
 | 
			
		||||
            }),
 | 
			
		||||
            local_rate_limit: Arc::new(Default::default()),
 | 
			
		||||
        },
 | 
			
		||||
    );
 | 
			
		||||
    allow
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -748,6 +748,7 @@ impl svc::Param<policy::AllowPolicy> for Target {
 | 
			
		|||
                    kind: "server".into(),
 | 
			
		||||
                    name: "testsrv".into(),
 | 
			
		||||
                }),
 | 
			
		||||
                local_rate_limit: Default::default(),
 | 
			
		||||
            },
 | 
			
		||||
        );
 | 
			
		||||
        policy
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -44,7 +44,7 @@ pub trait GetPolicy {
 | 
			
		|||
    fn get_policy(&self, dst: OrigDstAddr) -> AllowPolicy;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug, PartialEq, Eq)]
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub enum DefaultPolicy {
 | 
			
		||||
    Allow(ServerPolicy),
 | 
			
		||||
    Deny,
 | 
			
		||||
| 
						 | 
				
			
			@ -90,6 +90,7 @@ impl From<DefaultPolicy> for ServerPolicy {
 | 
			
		|||
            DefaultPolicy::Allow(p) => p,
 | 
			
		||||
            DefaultPolicy::Deny => ServerPolicy {
 | 
			
		||||
                protocol: Protocol::Opaque(Arc::new([])),
 | 
			
		||||
                local_rate_limit: Default::default(),
 | 
			
		||||
                meta: Meta::new_default("deny"),
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -88,5 +88,6 @@ fn mk(
 | 
			
		|||
    ServerPolicy {
 | 
			
		||||
        meta: Meta::new_default(name),
 | 
			
		||||
        protocol,
 | 
			
		||||
        local_rate_limit: Default::default(),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,6 +29,7 @@ macro_rules! new_svc {
 | 
			
		|||
                    kind: "Server".into(),
 | 
			
		||||
                    name: "testsrv".into(),
 | 
			
		||||
                }),
 | 
			
		||||
                local_rate_limit: Arc::new(Default::default()),
 | 
			
		||||
            },
 | 
			
		||||
        );
 | 
			
		||||
        let svc = HttpPolicyService {
 | 
			
		||||
| 
						 | 
				
			
			@ -197,6 +198,7 @@ async fn http_route() {
 | 
			
		|||
                },
 | 
			
		||||
            ],
 | 
			
		||||
        }])),
 | 
			
		||||
        local_rate_limit: Arc::new(Default::default()),
 | 
			
		||||
    })
 | 
			
		||||
    .expect("must send");
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,7 @@ async fn unauthenticated_allowed() {
 | 
			
		|||
            kind: "server".into(),
 | 
			
		||||
            name: "test".into(),
 | 
			
		||||
        }),
 | 
			
		||||
        local_rate_limit: Arc::new(Default::default()),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let tls = tls::ConditionalServerTls::None(tls::NoServerTls::NoClientHello);
 | 
			
		||||
| 
						 | 
				
			
			@ -75,6 +76,7 @@ async fn authenticated_identity() {
 | 
			
		|||
            kind: "server".into(),
 | 
			
		||||
            name: "test".into(),
 | 
			
		||||
        }),
 | 
			
		||||
        local_rate_limit: Arc::new(Default::default()),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let tls = tls::ConditionalServerTls::Some(tls::ServerTls::Established {
 | 
			
		||||
| 
						 | 
				
			
			@ -138,6 +140,7 @@ async fn authenticated_suffix() {
 | 
			
		|||
            kind: "server".into(),
 | 
			
		||||
            name: "test".into(),
 | 
			
		||||
        }),
 | 
			
		||||
        local_rate_limit: Arc::new(Default::default()),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let tls = tls::ConditionalServerTls::Some(tls::ServerTls::Established {
 | 
			
		||||
| 
						 | 
				
			
			@ -197,6 +200,7 @@ async fn tls_unauthenticated() {
 | 
			
		|||
            kind: "server".into(),
 | 
			
		||||
            name: "test".into(),
 | 
			
		||||
        }),
 | 
			
		||||
        local_rate_limit: Arc::new(Default::default()),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let tls = tls::ConditionalServerTls::Some(tls::ServerTls::Established {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,6 +46,7 @@ pub fn default_config() -> Config {
 | 
			
		|||
                kind: "server".into(),
 | 
			
		||||
                name: "testsrv".into(),
 | 
			
		||||
            }),
 | 
			
		||||
            local_rate_limit: Arc::new(Default::default()),
 | 
			
		||||
        }
 | 
			
		||||
        .into(),
 | 
			
		||||
        ports: Default::default(),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,6 +45,7 @@ pub fn all_unauthenticated() -> inbound::Server {
 | 
			
		|||
                inbound::proxy_protocol::Detect {
 | 
			
		||||
                    timeout: Some(Duration::from_secs(10).try_into().unwrap()),
 | 
			
		||||
                    http_routes: vec![],
 | 
			
		||||
                    http_local_rate_limit: None,
 | 
			
		||||
                },
 | 
			
		||||
            )),
 | 
			
		||||
        }),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,7 @@ publish = false
 | 
			
		|||
proto = ["linkerd-http-route/proto", "linkerd2-proxy-api", "prost-types"]
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
governor = { version = "0.6", default-features = false, features = ["std", "jitter", "quanta"] }
 | 
			
		||||
ipnet = "2"
 | 
			
		||||
http = "0.2"
 | 
			
		||||
prost-types = { version = "0.12", optional = true }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,11 +1,13 @@
 | 
			
		|||
#![deny(rust_2018_idioms, clippy::disallowed_methods, clippy::disallowed_types)]
 | 
			
		||||
#![forbid(unsafe_code)]
 | 
			
		||||
 | 
			
		||||
use local_rate_limit::HttpLocalRateLimit;
 | 
			
		||||
use std::{hash::Hash, sync::Arc, time};
 | 
			
		||||
 | 
			
		||||
pub mod authz;
 | 
			
		||||
pub mod grpc;
 | 
			
		||||
pub mod http;
 | 
			
		||||
pub mod local_rate_limit;
 | 
			
		||||
pub mod meta;
 | 
			
		||||
 | 
			
		||||
pub use self::{
 | 
			
		||||
| 
						 | 
				
			
			@ -14,10 +16,11 @@ pub use self::{
 | 
			
		|||
};
 | 
			
		||||
pub use linkerd_http_route as route;
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug, PartialEq, Eq)]
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub struct ServerPolicy {
 | 
			
		||||
    pub protocol: Protocol,
 | 
			
		||||
    pub meta: Arc<Meta>,
 | 
			
		||||
    pub local_rate_limit: Arc<HttpLocalRateLimit>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
 | 
			
		||||
| 
						 | 
				
			
			@ -65,6 +68,7 @@ impl ServerPolicy {
 | 
			
		|||
                }]),
 | 
			
		||||
                tcp_authorizations: Arc::new([]),
 | 
			
		||||
            },
 | 
			
		||||
            local_rate_limit: Arc::new(HttpLocalRateLimit::default()),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -131,6 +135,28 @@ pub mod proto {
 | 
			
		|||
                server_ips: _,
 | 
			
		||||
            } = 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 = {
 | 
			
		||||
                // Always permit traffic from localhost.
 | 
			
		||||
                let localhost = Authorization {
 | 
			
		||||
| 
						 | 
				
			
			@ -154,6 +180,7 @@ pub mod proto {
 | 
			
		|||
                api::proxy_protocol::Kind::Detect(api::proxy_protocol::Detect {
 | 
			
		||||
                    http_routes,
 | 
			
		||||
                    timeout,
 | 
			
		||||
                    ..
 | 
			
		||||
                }) => Protocol::Detect {
 | 
			
		||||
                    http: mk_routes!(http, http_routes, authorizations.clone())?,
 | 
			
		||||
                    timeout: timeout
 | 
			
		||||
| 
						 | 
				
			
			@ -162,11 +189,11 @@ pub mod proto {
 | 
			
		|||
                    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)?)
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                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)?)
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -182,7 +209,11 @@ pub mod proto {
 | 
			
		|||
            // avoid label inference.
 | 
			
		||||
            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