Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
374 commits
Select commit Hold shift + click to select a range
dc475ff
server: fix TAP validation mode (#15932)
Apr 20, 2021
24ba562
Minor cleanup. (#16082)
KBaichoo Apr 20, 2021
476e5d7
Buffer: Track number of allocated bytes across buffers. (#15859)
KBaichoo Apr 20, 2021
e8f8e83
http: refactor out stream rate limiter to common (#14828)
nitgoy Apr 20, 2021
745bf66
grpc_json_transcoder: Switch tests to compare JSON objects (#16085)
nareddyt Apr 20, 2021
840742a
protos: Remove (more) redundant imports (#16086)
phlax Apr 21, 2021
edb7ab8
upgrade rules_go to v0.27.0 (#16065) (#16083)
QIvan Apr 21, 2021
9300cea
udp listener fuzzer (#15974)
DavidKorczynski Apr 21, 2021
b256ffd
Bring parity to the docker images on the install docs pages (#16038)
Apr 22, 2021
6351e40
xray: fix the default sampling rate for AWS X-Ray tracer (#15958)
Apr 22, 2021
5bdf0f9
runtime: remove HCM stream error runtime override (#16040)
akonradi Apr 22, 2021
efc3a07
tooling: Add all pytests checker (#16031)
phlax Apr 22, 2021
eca4c02
Update QUICHE dependency (#16100)
DavidSchinazi Apr 23, 2021
a79905a
Add a missing work to WASM filter doc (#16106)
peterj Apr 23, 2021
8656cd7
fix (#16135)
asraa Apr 23, 2021
6c77508
jwt_authn refactory: move threadlocal from JwksCache into JwksDataImp…
qiwzhang Apr 23, 2021
bbc11c2
Revert "honour routes timeout if max stream duration is set with out …
Apr 23, 2021
3d850ef
dependabot: Resolve updates (#16094)
phlax Apr 23, 2021
443def6
disable tls resumption (#16147)
danzh2010 Apr 23, 2021
35f35aa
api: Update xds_protocol doc to remove v2 and cleanup (#16097)
phlax Apr 24, 2021
b3e1702
Fix protoleak. (#16101)
KBaichoo Apr 26, 2021
564571a
python: Switch to exclusive list for flake8 (#16159)
phlax Apr 26, 2021
8719660
deprecating allow_500_after_100 (#16171)
alyssawilk Apr 26, 2021
9e43177
http: removing envoy.reloadable_features.unify_grpc_handling (#16173)
alyssawilk Apr 26, 2021
4e239f9
http3: turning up more tests (#16175)
alyssawilk Apr 26, 2021
9bfcf1a
metric service: add support for sending tags as labels (#16125)
Apr 26, 2021
489d66c
apple dns: fix crash on invalid dns name (#16028)
junr03 Apr 26, 2021
fcf83d8
docs: Update refs: v2 -> v3 (#16163)
phlax Apr 26, 2021
44e4e45
dependabot: Resolve updates (#16169)
phlax Apr 27, 2021
f38f0a7
Fix tests that link all extensions so that gcc can compile them (#16187)
yanavlasov Apr 27, 2021
0e95698
http: raise max_request_headers_kb limit to 8192 KiB (8MiB) from 96 K…
anirudhaps Apr 27, 2021
eb71d7b
grid: Add a new class for tracking alternate protocols for a connect…
RyanTheOptimist Apr 27, 2021
972758d
docs: Use intersphinx to map old versions and cleanup version history…
phlax Apr 27, 2021
8faa072
Make the members of Upstream::HostDescriptionImpl private. (#16192)
RyanTheOptimist Apr 27, 2021
1c3ec7a
DebugString() -> ShortDebugString() (#16172)
Apr 27, 2021
d1397ac
update zk filter proxy (#16190)
JaredTan95 Apr 27, 2021
91c8ca2
wasm: update proxy-wasm-cpp-host to use refactored code around runtim…
mathetake Apr 27, 2021
533254a
Build win32_scm_test with just core extensions (#16193)
yanavlasov Apr 27, 2021
9ff513b
configs: Validate dynamic xds config (#16145)
phlax Apr 27, 2021
61b464a
http: removing envoy.reloadable_features.http_match_on_all_headers (#…
alyssawilk Apr 28, 2021
2054d3e
h3 config examples (#15987)
alyssawilk Apr 28, 2021
e2c2280
wasm: use in_vm_context_created_ flag for http contexts. (#16202)
mathetake Apr 28, 2021
3ad96b8
Log actual admin port. (#16197)
Apr 28, 2021
0aec425
api: add NonForwardingAction route action type (#16144)
markdroth Apr 28, 2021
79afd6b
shellcheck: Enable and cleanup .github file (#16206)
phlax Apr 28, 2021
676588a
tracing: bump cpp2sky v0.2.1 (#15782)
Shikugawa Apr 28, 2021
fb2178e
http: removing envoy.reloadable_features.http_set_copy_replace_all_he…
alyssawilk Apr 28, 2021
e29dc13
owners: add @phlax as maintainer. (#16212)
htuch Apr 28, 2021
8cb5806
delta-xds: avoid sending resource names for wildcard requests on stre…
adisuissa Apr 28, 2021
99e941a
http: removing envoy.reloadable features.always apply route header ru…
alyssawilk Apr 28, 2021
9a00865
grid: Add a new class for tracking HTTP/3 status (#16067)
RyanTheOptimist Apr 28, 2021
e4eba7c
docs: Improve style for inline literals and update contrib guidance (…
phlax Apr 28, 2021
5876f6c
ext_proc: Support trailer callbacks (#16102)
gbrail Apr 29, 2021
ef28b68
http local_ratelimit: add request_headers_to_add option (#16178)
williamsfu99 Apr 29, 2021
0e4b716
Listener: respect the connection balancer of the redirected listener …
lambdai Apr 29, 2021
725816f
server: fix fips_mode stat (#16140)
raakella Apr 29, 2021
83500a7
http: port stripping for CONNECT (#15975)
alyssawilk Apr 29, 2021
2960c69
quiche: use max header size configured in HCM (#15912)
danzh2010 Apr 29, 2021
67eb5e2
quiche: handle stream blockage during decodeHeaders and decodeTrailer…
danzh2010 Apr 29, 2021
875e059
runtime: refresh QUIC flags when a new runtime config is loaded. (#16…
RenjieTang Apr 29, 2021
8c7e0c0
test: Deflake tsan //test/integration:integration_test (#16238)
yanavlasov Apr 29, 2021
98fb985
add %REQUEST_TX_DURATION% to the access log (#16207)
WeavingGao Apr 29, 2021
37d353f
tools: (mostly) enforcing flag alpha order (#16182)
alyssawilk Apr 29, 2021
32f82c5
python: Revert buggy gitpython version (#16156)
phlax Apr 30, 2021
44bbf4d
wasm: update V8 to v9.1.269.18. (#16220)
PiotrSikora Apr 30, 2021
443fdc9
hcm config: Reject filterchains with unmet decode dependencies (#15462)
Apr 30, 2021
174431b
Config proto for Secure Session Agent (S2A) transport socket extensio…
tavishvaidya Apr 30, 2021
166241d
Typo in test comment and release note (#16245)
Apr 30, 2021
707d3b9
Fix warning in the docs (#16242)
Apr 30, 2021
aa4832e
Matcher: add a "not" matcher (#16149)
aguinet Apr 30, 2021
93ca37a
wasm: Simplify example config and fix docs (#16142)
phlax Apr 30, 2021
0cb5c40
protos: Move simple_http_cache config proto to api (#16230)
phlax May 2, 2021
263a0a8
docs: add fuzzing improvement report. (#16232)
DavidKorczynski May 2, 2021
3df15d2
tls: update BoringSSL to c5ad6dcb (4491). (#16104)
PiotrSikora May 2, 2021
c2dd672
docs: Remove api v2 (#16077)
phlax May 2, 2021
8119596
udp: add new key based hash policy (#15967)
davidkornel May 3, 2021
7366497
Adding distroless image to Envoy CI pipeline (#16268)
oleksiyp May 3, 2021
fcf28ca
http3: respecting header number limits (#15970)
alyssawilk May 3, 2021
bcf0348
dns_cache: Remove getCacheManager() (#16273)
RyanTheOptimist May 3, 2021
ac1d176
protos: Update style guide to try and prevent redundant imports (#16231)
phlax May 3, 2021
cfa681a
thrift_proxy router: fix bug when charging upstream rq_time before (#…
williamsfu99 May 3, 2021
b5be190
docs: Cleanup inline literals (#16280)
phlax May 3, 2021
a921fee
quiche: make flow control configurable (#15865)
danzh2010 May 3, 2021
33ee0c4
bootstrap/runtime: remove support for v2 bootstrap runtime field. (#1…
htuch May 4, 2021
d2f6f8f
tools: allow generate_go_protobuf.py to skip syncing with go-control-…
jamesmulcahy May 4, 2021
7bbec8c
access_log: refactored SubstitutionFormatParser::parseCommand (#16121)
cpakulski May 4, 2021
fe8d26e
[filter]: Add option to disable fault filter stats that trace downstr…
chaoqin-li1123 May 4, 2021
fdfd990
http3: turn up the last upstream tests! (#16279)
alyssawilk May 4, 2021
5ca8184
quic: fix missing cast in assertions (#16301)
goaway May 4, 2021
dfcc7bb
docs: fix type_url for v3.TlsInspector (#16290)
ch-plattner May 4, 2021
89ed219
alts: Fix TsiSocket doWrite on short writes (#15962)
yihuazhang May 4, 2021
8f0f92f
dependabot: Aggregate updates (#16228)
phlax May 4, 2021
7efd4fa
udp: log when BPF is not attempted (#16304)
alyssawilk May 4, 2021
0082d5a
per conn rate limiting
Apr 2, 2021
d202a27
proto changes
Apr 5, 2021
dd5eaf5
Use dispatcher from filter_config
Apr 6, 2021
8c85cec
fix format
Apr 7, 2021
199cb5a
generate api shadow file
Apr 8, 2021
0dd325d
Copy the proto config object
Apr 9, 2021
f00c9fd
clang_tidy format
Apr 9, 2021
c93f6fe
refactor method name
Apr 13, 2021
9b4fef0
add tests
Apr 20, 2021
eccaba5
add unit tests
Apr 22, 2021
ad0242d
Add doc for the proto changes
Apr 23, 2021
8711bd4
use thread local event disptacher
Apr 26, 2021
9e9dfab
refactor config name to be more descriptive
May 3, 2021
a857dd3
eliminate full proto copy and store individual fields under FilterCon…
May 3, 2021
6b0235c
add docs and fix format
May 3, 2021
0417587
Remove auto generated changes to api/BUILD file due to the v2 freeze
May 4, 2021
e6408bb
per conn rate limiting
Apr 2, 2021
9f17367
Use dispatcher from filter_config
Apr 6, 2021
2f603d8
fix format
Apr 7, 2021
562be5e
Copy the proto config object
Apr 9, 2021
add870b
clang_tidy format
Apr 9, 2021
6bf6698
refactor method name
Apr 13, 2021
f7aa00d
use thread local event disptacher
Apr 26, 2021
f712bc8
eliminate full proto copy and store individual fields under FilterCon…
May 3, 2021
0dd2f98
add docs and fix format
May 3, 2021
454fa95
Remove auto generated changes to api/BUILD file due to the v2 freeze
May 4, 2021
65fb735
per conn rate limiting
Apr 2, 2021
ed858b4
proto changes
Apr 5, 2021
badf219
Use dispatcher from filter_config
Apr 6, 2021
26e73c4
fix format
Apr 7, 2021
8e338b2
generate api shadow file
Apr 8, 2021
fbcf203
Copy the proto config object
Apr 9, 2021
33bedd1
clang_tidy format
Apr 9, 2021
0566b86
refactor method name
Apr 13, 2021
762fb6a
add tests
Apr 20, 2021
5a91170
add unit tests
Apr 22, 2021
633098c
Add doc for the proto changes
Apr 23, 2021
1ab6a0c
use thread local event disptacher
Apr 26, 2021
44ae575
refactor config name to be more descriptive
May 3, 2021
1741a79
eliminate full proto copy and store individual fields under FilterCon…
May 3, 2021
50307b6
add docs and fix format
May 3, 2021
41fd116
Remove auto generated changes to api/BUILD file due to the v2 freeze
May 4, 2021
1ff2c4b
per conn rate limiting
Apr 2, 2021
2916b64
proto changes
Apr 5, 2021
27460f6
Use dispatcher from filter_config
Apr 6, 2021
bc12ea0
fix format
Apr 7, 2021
64bb450
generate api shadow file
Apr 8, 2021
cdf57ee
Copy the proto config object
Apr 9, 2021
bb2e153
clang_tidy format
Apr 9, 2021
0e17903
refactor method name
Apr 13, 2021
f921dc5
add tests
Apr 20, 2021
4e54def
add unit tests
Apr 22, 2021
99a6c6c
Add doc for the proto changes
Apr 23, 2021
74fcf4e
use thread local event disptacher
Apr 26, 2021
8e9880a
refactor config name to be more descriptive
May 3, 2021
eacc127
eliminate full proto copy and store individual fields under FilterCon…
May 3, 2021
13577b9
add docs and fix format
May 3, 2021
c014687
Remove auto generated changes to api/BUILD file due to the v2 freeze
May 4, 2021
f75eb68
Return a reference to LocalRateLimiterImpl instead of a shared_ptr
May 5, 2021
f5bae8e
wasm: fix support for non-cloneable Wasm runtimes. (#16263)
PiotrSikora May 4, 2021
a57014f
wasm: fix fail-close streams on VM failure. (#16112)
mathetake May 4, 2021
0e2843c
Win32 docs FAQ (#16176)
May 5, 2021
eb93f69
skywalking: skip gRPC cluster validation by default (#16203)
Shikugawa May 5, 2021
ded5417
skywalking: fix string_view UB while span reporting (#16264)
Shikugawa May 5, 2021
06aa1d8
http::cache: Adds serving HEAD requests from cache. (#15910)
ekiziv May 5, 2021
3146b6a
remove backtrace (#16285)
danzh2010 May 5, 2021
e5065e7
api: Fix generated_api_shadow BUILD (#16330)
phlax May 5, 2021
7eae147
quic: add support for client-side QUIC 0-RTT (#16260)
DavidSchinazi May 5, 2021
d522352
listener: allow changing address (#16134)
tbarrella May 5, 2021
59bd835
protos: Readd v2 legacy protos in v3 (#16338)
phlax May 5, 2021
5d3f343
Support starttls for client connections (#15443)
May 5, 2021
3ce48c8
ext_proc: Support clearing the route cache (#16288)
gbrail May 5, 2021
24be394
test: disabling flaky test (#16341)
alyssawilk May 5, 2021
b6e3303
Cleanup: Remove WatermarkBuffer::setWatermarks(low,high). (#16307)
KBaichoo May 5, 2021
188b61f
delta-xds: avoid sending resource names for wildcard requests on stre…
adisuissa Apr 28, 2021
70ee15b
ext_proc: Support trailer callbacks (#16102)
gbrail Apr 29, 2021
47380a8
http local_ratelimit: add request_headers_to_add option (#16178)
williamsfu99 Apr 29, 2021
14b1705
Listener: respect the connection balancer of the redirected listener …
lambdai Apr 29, 2021
f68f942
quiche: use max header size configured in HCM (#15912)
danzh2010 Apr 29, 2021
cda66d3
quiche: handle stream blockage during decodeHeaders and decodeTrailer…
danzh2010 Apr 29, 2021
c452d32
docs: Remove api v2 (#16077)
phlax May 2, 2021
6ace0e0
http3: respecting header number limits (#15970)
alyssawilk May 3, 2021
7bf71a4
quiche: make flow control configurable (#15865)
danzh2010 May 3, 2021
47d4acc
http3: turn up the last upstream tests! (#16279)
alyssawilk May 4, 2021
4c8af40
per conn rate limiting
Apr 2, 2021
b7db037
proto changes
Apr 5, 2021
6966d3e
Use dispatcher from filter_config
Apr 6, 2021
eda8994
fix format
Apr 7, 2021
a0afd00
generate api shadow file
Apr 8, 2021
99849a0
Copy the proto config object
Apr 9, 2021
1ab83de
clang_tidy format
Apr 9, 2021
420fa93
refactor method name
Apr 13, 2021
22e72c9
add tests
Apr 20, 2021
c67e4ba
add unit tests
Apr 22, 2021
aeeae43
Add doc for the proto changes
Apr 23, 2021
b2322d5
use thread local event disptacher
Apr 26, 2021
1bb38e4
refactor config name to be more descriptive
May 3, 2021
09ff689
eliminate full proto copy and store individual fields under FilterCon…
May 3, 2021
1ac2759
add docs and fix format
May 3, 2021
4c85898
Remove auto generated changes to api/BUILD file due to the v2 freeze
May 4, 2021
9a4dd7b
per conn rate limiting
Apr 2, 2021
c0944a6
Use dispatcher from filter_config
Apr 6, 2021
45a3a17
fix format
Apr 7, 2021
a5d5136
Copy the proto config object
Apr 9, 2021
33cf77c
clang_tidy format
Apr 9, 2021
89ba8f7
refactor method name
Apr 13, 2021
adddd73
use thread local event disptacher
Apr 26, 2021
1a995bb
eliminate full proto copy and store individual fields under FilterCon…
May 3, 2021
cbc0a36
add docs and fix format
May 3, 2021
7b8c058
Remove auto generated changes to api/BUILD file due to the v2 freeze
May 4, 2021
8522075
per conn rate limiting
Apr 2, 2021
6de3b44
proto changes
Apr 5, 2021
293060d
Use dispatcher from filter_config
Apr 6, 2021
5febd9c
fix format
Apr 7, 2021
c8e32e2
generate api shadow file
Apr 8, 2021
d64c987
Copy the proto config object
Apr 9, 2021
671559b
clang_tidy format
Apr 9, 2021
df340bf
refactor method name
Apr 13, 2021
ffe87db
add tests
Apr 20, 2021
1e44f09
add unit tests
Apr 22, 2021
bebdce7
Add doc for the proto changes
Apr 23, 2021
0b047ae
use thread local event disptacher
Apr 26, 2021
4603b74
refactor config name to be more descriptive
May 3, 2021
9d95544
eliminate full proto copy and store individual fields under FilterCon…
May 3, 2021
5861909
add docs and fix format
May 3, 2021
7ca878b
Remove auto generated changes to api/BUILD file due to the v2 freeze
May 4, 2021
39c389f
per conn rate limiting
Apr 2, 2021
d44697c
proto changes
Apr 5, 2021
aab4d01
Use dispatcher from filter_config
Apr 6, 2021
e405cf9
fix format
Apr 7, 2021
e061e08
generate api shadow file
Apr 8, 2021
d7471ea
Copy the proto config object
Apr 9, 2021
14d6198
clang_tidy format
Apr 9, 2021
de06957
refactor method name
Apr 13, 2021
a8b8d4c
add tests
Apr 20, 2021
1d36b8c
add unit tests
Apr 22, 2021
ea3fe62
Add doc for the proto changes
Apr 23, 2021
57bd864
use thread local event disptacher
Apr 26, 2021
fc0415e
refactor config name to be more descriptive
May 3, 2021
52ffa87
eliminate full proto copy and store individual fields under FilterCon…
May 3, 2021
7525e6d
add docs and fix format
May 3, 2021
d4e077a
Remove auto generated changes to api/BUILD file due to the v2 freeze
May 4, 2021
2e77edd
Return a reference to LocalRateLimiterImpl instead of a shared_ptr
May 5, 2021
323eb26
http::cache: Adds serving HEAD requests from cache. (#15910)
ekiziv May 5, 2021
95d8f9a
api: Fix generated_api_shadow BUILD (#16330)
phlax May 5, 2021
318c4dc
quic: add support for client-side QUIC 0-RTT (#16260)
DavidSchinazi May 5, 2021
b076788
listener: allow changing address (#16134)
tbarrella May 5, 2021
8a53a6d
protos: Readd v2 legacy protos in v3 (#16338)
phlax May 5, 2021
a1d6427
ext_proc: Support clearing the route cache (#16288)
gbrail May 5, 2021
43648c2
test: disabling flaky test (#16341)
alyssawilk May 5, 2021
9c76913
Merge branch 'perconn_rl_15637' of github.com:gokulnair/envoy into pe…
May 6, 2021
c1d49bf
Fix version history doc
May 6, 2021
2d12dae
resolve merge conflict
May 6, 2021
c288dc6
code style changes
May 11, 2021
a6b15b0
Merge remote-tracking branch 'origin/main' into perconn_rl_15637
May 20, 2021
d994fee
docs and cleanup
May 21, 2021
b2b2d67
api shadow file
May 21, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions api/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,18 @@ proto_library(
"//envoy/config/common/matcher/v3:pkg",
"//envoy/config/core/v3:pkg",
"//envoy/config/endpoint/v3:pkg",
"//envoy/config/filter/thrift/router/v2alpha1:pkg",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these shouldnt be here - i think they have just been removed

"//envoy/config/grpc_credential/v3:pkg",
"//envoy/config/health_checker/redis/v2:pkg",
"//envoy/config/listener/v3:pkg",
"//envoy/config/metrics/v3:pkg",
"//envoy/config/overload/v3:pkg",
"//envoy/config/ratelimit/v3:pkg",
"//envoy/config/rbac/v3:pkg",
"//envoy/config/resource_monitor/fixed_heap/v2alpha:pkg",
"//envoy/config/resource_monitor/injected_resource/v2alpha:pkg",
"//envoy/config/retry/omit_canary_hosts/v2:pkg",
"//envoy/config/retry/previous_hosts/v2:pkg",
"//envoy/config/route/v3:pkg",
"//envoy/config/tap/v3:pkg",
"//envoy/config/trace/v3:pkg",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE;
// Local Rate limit :ref:`configuration overview <config_http_filters_local_rate_limit>`.
// [#extension: envoy.filters.http.local_ratelimit]

// [#next-free-field: 11]
// [#next-free-field: 12]
message LocalRateLimit {
// The human readable prefix to use when emitting stats.
string stat_prefix = 1 [(validate.rules).string = {min_len: 1}];
Expand Down Expand Up @@ -97,4 +97,12 @@ message LocalRateLimit {
//
// The filter supports a range of 0 - 10 inclusively for stage numbers.
uint32 stage = 9 [(validate.rules).uint32 = {lte: 10}];

// Specifies the scope of the rate limiter's token bucket.
// If set to false, the token bucket is shared across all worker threads,
Comment thread
alyssawilk marked this conversation as resolved.
// thus the rate limits are applied per Envoy process.
// If set to true, a token bucket is allocated for each connection.
// Thus the rate limits are applied per connection thereby allowing
// one to rate limit requests on a per connection basis.
bool local_rate_limit_per_downstream_connection = 11;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible for a proxy to have both per-process and per downstream connection rate limits, or just one or the other?

Another potential question is if we should consider some additional rate limit criteria in the future like downstream IP or HTTP Cookie. If we expect additional criteria in the future, we may want to make this an enum field.

@gokulnair gokulnair May 20, 2021

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's definitely one or the other as it stands currently as I'm not sure the added complexity of dealing with potentially conflicting token bucket quotas between the per process and per connection configurations and the precedence rules we'd have to handle buys us much in the way of functionality.

We did indeed consider an enum initially but it didn't seem like there were very many realistic use cases mainly because a lot of the toggles that were based on certain request characteristics such as IP, Cookie etc can be handled today by rate limiting on request descriptors ...

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ configured to be returned.
<envoy_v3_api_field_extensions.filters.http.local_ratelimit.v3.LocalRateLimit.request_headers_to_add_when_not_enforced>` can be
configured to be added to forwarded requests to the upstream when the local rate limit filter is enabled but not enforced.

.. note::
The token bucket is shared across all workers, thus the rate limits are applied per Envoy process.
Depending on the value of the config :ref:`local_rate_limit_per_downstream_connection <envoy_v3_api_field_extensions.filters.http.local_ratelimit.v3.LocalRateLimit.local_rate_limit_per_downstream_connection>`,
the token bucket is either shared across all workers or on a per connection basis. This results in the local rate limits being applied either per Envoy process or per downstream connection.
If unspecified, this config is set to false by default, which means the rate limits are applied per Envoy process.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably simplify this last sentence into:

By default rate limits are applied per Envoy process.


Example configuration
---------------------
Expand Down Expand Up @@ -55,6 +56,7 @@ Example filter configuration for a globally set rate limiter (e.g.: all vhosts/r
header:
key: x-local-rate-limit
value: 'true'
local_rate_limit_per_downstream_connection: false


Example filter configuration for a globally disabled rate limiter but enabled for a specific route:
Expand Down
1 change: 1 addition & 0 deletions docs/root/version_history/current.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Removed Config or Runtime
New Features
------------

* local_rate_limit_filter: added suppoort for locally rate limiting http requests on a per connection basis. This can be enabled by setting the :ref:`local_rate_limit_per_downstream_connection <envoy_v3_api_field_extensions.filters.http.local_ratelimit.v3.LocalRateLimit.local_rate_limit_per_downstream_connection>` field to true.
* metric service: added support for sending metric tags as labels. This can be enabled by setting the :ref:`emit_tags_as_labels <envoy_v3_api_field_config.metrics.v3.MetricsServiceConfig.emit_tags_as_labels>` field to true.
* udp_proxy: added :ref:`key <envoy_v3_api_msg_extensions.filters.udp.udp_proxy.v3.UdpProxyConfig.HashPolicy>` as another hash policy to support hash based routing on any given key.

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,24 @@ namespace Extensions {
namespace HttpFilters {
namespace LocalRateLimitFilter {

const std::string& PerConnectionRateLimiter::key() {
CONSTRUCT_ON_FIRST_USE(std::string, "per_connection_local_rate_limiter");
}

FilterConfig::FilterConfig(
const envoy::extensions::filters::http::local_ratelimit::v3::LocalRateLimit& config,
const LocalInfo::LocalInfo& local_info, Event::Dispatcher& dispatcher, Stats::Scope& scope,
Runtime::Loader& runtime, const bool per_route)
: status_(toErrorCode(config.status().code())),
stats_(generateStats(config.stat_prefix(), scope)),
fill_interval_(std::chrono::milliseconds(
PROTOBUF_GET_MS_OR_DEFAULT(config.token_bucket(), fill_interval, 0))),
max_tokens_(config.token_bucket().max_tokens()),
tokens_per_fill_(PROTOBUF_GET_WRAPPED_OR_DEFAULT(config.token_bucket(), tokens_per_fill, 1)),
descriptors_(config.descriptors()),
rate_limit_per_connection_(config.local_rate_limit_per_downstream_connection()),
rate_limiter_(Filters::Common::LocalRateLimit::LocalRateLimiterImpl(
std::chrono::milliseconds(
PROTOBUF_GET_MS_OR_DEFAULT(config.token_bucket(), fill_interval, 0)),
config.token_bucket().max_tokens(),
PROTOBUF_GET_WRAPPED_OR_DEFAULT(config.token_bucket(), tokens_per_fill, 1), dispatcher,
config.descriptors())),
fill_interval_, max_tokens_, tokens_per_fill_, dispatcher, descriptors_)),
local_info_(local_info), runtime_(runtime),
filter_enabled_(
config.has_filter_enabled()
Expand Down Expand Up @@ -84,7 +90,10 @@ Http::FilterHeadersStatus Filter::decodeHeaders(Http::RequestHeaderMap& headers,
populateDescriptors(descriptors, headers);
}

if (config->requestAllowed(descriptors)) {
bool isRequestAllowed = config->rateLimitPerConnection() ? requestAllowed(descriptors)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: const bool is_request_allowed = ...

: config->requestAllowed(descriptors);

if (isRequestAllowed) {
config->stats().ok_.inc();
return Http::FilterHeadersStatus::Continue;
}
Expand All @@ -109,6 +118,31 @@ Http::FilterHeadersStatus Filter::decodeHeaders(Http::RequestHeaderMap& headers,
return Http::FilterHeadersStatus::StopIteration;
}

bool Filter::requestAllowed(absl::Span<const RateLimit::LocalDescriptor> request_descriptors) {
return getRateLimiter()->requestAllowed(request_descriptors);
}

LocalRateLimiterImplSharedPtr Filter::getRateLimiter() {
const auto* config = getConfig();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move this closer to where it's used, e.g.: just before decoder_callbacks_->streamInfo().filterState()->setData()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved it back up a couple of lines to add an assertion.


if (!decoder_callbacks_->streamInfo().filterState()->hasData<PerConnectionRateLimiter>(
PerConnectionRateLimiter::key())) {
auto rate_limiter = std::make_shared<Filters::Common::LocalRateLimit::LocalRateLimiterImpl>(
config->fillInterval(), config->maxTokens(), config->tokensPerFill(),
decoder_callbacks_->dispatcher(), config->descriptors());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: extra whitespace?

decoder_callbacks_->streamInfo().filterState()->setData(
PerConnectionRateLimiter::key(), std::make_unique<PerConnectionRateLimiter>(rate_limiter),
StreamInfo::FilterState::StateType::ReadOnly,
StreamInfo::FilterState::LifeSpan::Connection);
}

return decoder_callbacks_->streamInfo()
.filterState()
->getDataReadOnly<PerConnectionRateLimiter>(PerConnectionRateLimiter::key())
.value();
}

void Filter::populateDescriptors(std::vector<RateLimit::LocalDescriptor>& descriptors,
Http::RequestHeaderMap& headers) {
Router::RouteConstSharedPtr route = decoder_callbacks_->route();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,19 @@ struct LocalRateLimitStats {
ALL_LOCAL_RATE_LIMIT_STATS(GENERATE_COUNTER_STRUCT)
};

using LocalRateLimiterImplSharedPtr =
std::shared_ptr<Filters::Common::LocalRateLimit::LocalRateLimiterImpl>;

class PerConnectionRateLimiter : public StreamInfo::FilterState::Object {
public:
PerConnectionRateLimiter(LocalRateLimiterImplSharedPtr rl) : rate_limiter_(rl) {}
static const std::string& key();
LocalRateLimiterImplSharedPtr value() const { return rate_limiter_; }

private:
LocalRateLimiterImplSharedPtr rate_limiter_;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this really need to be shared? Sounds like it could be unique or -- possibly better -- just an instance constructed when PerConnectionRateLimiter is created? value() would then just return a LocalRateLimiterImpl&.

@gokulnair gokulnair Apr 30, 2021

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like this can only be a shared_ptr.
PerConnectionRateLimiter stores the state, i.e. an object of type LocalRateLimiterImpl, inside it but since the latter does not have a copy constructor, you cannot pass in an already created instance nor can you create it within PerConnectionRateLimiter and return it since both of these would need a copy constructor.
A unique_ptr wouldn't work for similar reasons since multiple, potentially concurrent, streams would be operating on a single instance of LocalRateLimiterImpl so transferring ownership of the unique_ptr out of PerConnectionRateLimiter and to each calling stream wouldn't make sense, if I'm understanding this correctly.
Let me know if i'm misunderstanding this.

};

/**
* Global configuration for the HTTP local rate limit filter.
*/
Expand All @@ -62,6 +75,15 @@ class FilterConfig : public Router::RouteSpecificFilterConfig {
Http::Code status() const { return status_; }
uint64_t stage() const { return stage_; }
bool hasDescriptors() const { return has_descriptors_; }
std::chrono::milliseconds fillInterval() const { return fill_interval_; }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit return const std::chrono::milliseconds&

uint32_t maxTokens() const { return max_tokens_; }
uint32_t tokensPerFill() const { return tokens_per_fill_; }
const Protobuf::RepeatedPtrField<
envoy::extensions::common::ratelimit::v3::LocalRateLimitDescriptor>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

 const Protobuf::RepeatedPtrField<
      envoy::extensions::common::ratelimit::v3::LocalRateLimitDescriptor>&

(a reference)

descriptors() const {
return descriptors_;
}
bool rateLimitPerConnection() const { return rate_limit_per_connection_; }

private:
friend class FilterTest;
Expand All @@ -78,6 +100,13 @@ class FilterConfig : public Router::RouteSpecificFilterConfig {

const Http::Code status_;
mutable LocalRateLimitStats stats_;
const std::chrono::milliseconds fill_interval_;
const uint32_t max_tokens_;
const uint32_t tokens_per_fill_;
const Protobuf::RepeatedPtrField<
envoy::extensions::common::ratelimit::v3::LocalRateLimitDescriptor>
descriptors_;
const bool rate_limit_per_connection_;
Filters::Common::LocalRateLimit::LocalRateLimiterImpl rate_limiter_;
const LocalInfo::LocalInfo& local_info_;
Runtime::Loader& runtime_;
Expand Down Expand Up @@ -108,6 +137,8 @@ class Filter : public Http::PassThroughFilter {

void populateDescriptors(std::vector<RateLimit::LocalDescriptor>& descriptors,
Http::RequestHeaderMap& headers);
LocalRateLimiterImplSharedPtr getRateLimiter();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return LocalRateLimiterImpl&?

bool requestAllowed(absl::Span<const RateLimit::LocalDescriptor> request_descriptors);

const FilterConfig* getConfig() const;
FilterConfigSharedPtr config_;
Expand Down
86 changes: 74 additions & 12 deletions test/extensions/filters/http/local_ratelimit/filter_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ stat_prefix: test
header:
key: x-local-ratelimited
value: 'true'
local_rate_limit_per_downstream_connection: {}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the {} is used in substitutions below. It would be good to add an end-of-line comment explaining the {}. I think that the yaml comment character is #

@gokulnair gokulnair May 21, 2021

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added an explanation below.

)";

class FilterTest : public testing::Test {
Expand All @@ -58,12 +59,18 @@ class FilterTest : public testing::Test {
testing::Matcher<const envoy::type::v3::FractionalPercent&>(Percent(100))))
.WillRepeatedly(testing::Return(enforced));

ON_CALL(decoder_callbacks_, dispatcher()).WillByDefault(ReturnRef(dispatcher_));
ON_CALL(decoder_callbacks_2_, dispatcher()).WillByDefault(ReturnRef(dispatcher_));

envoy::extensions::filters::http::local_ratelimit::v3::LocalRateLimit config;
TestUtility::loadFromYaml(yaml, config);
config_ = std::make_shared<FilterConfig>(config, local_info_, dispatcher_, stats_, runtime_,
per_route);
filter_ = std::make_shared<Filter>(config_);
filter_->setDecoderFilterCallbacks(decoder_callbacks_);

filter_2_ = std::make_shared<Filter>(config_);
filter_2_->setDecoderFilterCallbacks(decoder_callbacks_2_);
}
void setup(const std::string& yaml, const bool enabled = true, const bool enforced = true) {
setupPerRoute(yaml, enabled, enforced);
Expand All @@ -78,44 +85,59 @@ class FilterTest : public testing::Test {

Stats::IsolatedStoreImpl stats_;
testing::NiceMock<Http::MockStreamDecoderFilterCallbacks> decoder_callbacks_;
testing::NiceMock<Http::MockStreamDecoderFilterCallbacks> decoder_callbacks_2_;
NiceMock<Event::MockDispatcher> dispatcher_;
NiceMock<Runtime::MockLoader> runtime_;
NiceMock<LocalInfo::MockLocalInfo> local_info_;
std::shared_ptr<FilterConfig> config_;
std::shared_ptr<Filter> filter_;
std::shared_ptr<Filter> filter_2_;
};

TEST_F(FilterTest, Runtime) {
setup(fmt::format(config_yaml, "1"), false, false);
setup(fmt::format(config_yaml, "1", "false"), false, false);
EXPECT_EQ(&runtime_, &(config_->runtime()));
}

TEST_F(FilterTest, ToErrorCode) {
setup(fmt::format(config_yaml, "1"), false, false);
setup(fmt::format(config_yaml, "1", "false"), false, false);
EXPECT_EQ(Http::Code::BadRequest, toErrorCode(400));
}

TEST_F(FilterTest, Disabled) {
setup(fmt::format(config_yaml, "1"), false, false);
setup(fmt::format(config_yaml, "1", "false"), false, false);
auto headers = Http::TestRequestHeaderMapImpl();
EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(headers, false));
EXPECT_EQ(0U, findCounter("test.http_local_rate_limit.enabled"));
EXPECT_EQ(0U, findCounter("test.http_local_rate_limit.enforced"));
}

TEST_F(FilterTest, RequestOk) {
setup(fmt::format(config_yaml, "1"));
setup(fmt::format(config_yaml, "1", "false"));
auto headers = Http::TestRequestHeaderMapImpl();
EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(headers, false));
EXPECT_EQ(1U, findCounter("test.http_local_rate_limit.enabled"));
EXPECT_EQ(0U, findCounter("test.http_local_rate_limit.enforced"));
EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, filter_2_->decodeHeaders(headers, false));
EXPECT_EQ(2U, findCounter("test.http_local_rate_limit.enabled"));
EXPECT_EQ(1U, findCounter("test.http_local_rate_limit.enforced"));
EXPECT_EQ(1U, findCounter("test.http_local_rate_limit.ok"));
EXPECT_EQ(1U, findCounter("test.http_local_rate_limit.rate_limited"));
}

TEST_F(FilterTest, RequestOkPerConnection) {
setup(fmt::format(config_yaml, "1", "true"));
auto headers = Http::TestRequestHeaderMapImpl();
EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(headers, false));
EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_2_->decodeHeaders(headers, false));
EXPECT_EQ(2U, findCounter("test.http_local_rate_limit.enabled"));
EXPECT_EQ(0U, findCounter("test.http_local_rate_limit.enforced"));
EXPECT_EQ(2U, findCounter("test.http_local_rate_limit.ok"));
EXPECT_EQ(0U, findCounter("test.http_local_rate_limit.rate_limited"));
}

TEST_F(FilterTest, RequestRateLimited) {
setup(fmt::format(config_yaml, "0"));
setup(fmt::format(config_yaml, "1", "false"));

EXPECT_CALL(decoder_callbacks_, sendLocalReply(Http::Code::TooManyRequests, _, _, _, _))
EXPECT_CALL(decoder_callbacks_2_, sendLocalReply(Http::Code::TooManyRequests, _, _, _, _))
.WillOnce(Invoke([](Http::Code code, absl::string_view body,
std::function<void(Http::ResponseHeaderMap & headers)> modify_headers,
const absl::optional<Grpc::Status::GrpcStatus> grpc_status,
Expand All @@ -136,16 +158,55 @@ TEST_F(FilterTest, RequestRateLimited) {
auto request_headers = Http::TestRequestHeaderMapImpl();
auto expected_headers = Http::TestRequestHeaderMapImpl();

EXPECT_EQ(Http::FilterHeadersStatus::StopIteration,
filter_->decodeHeaders(request_headers, false));
EXPECT_EQ(request_headers, expected_headers);
EXPECT_EQ(1U, findCounter("test.http_local_rate_limit.enabled"));
EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, false));
EXPECT_EQ(Http::FilterHeadersStatus::StopIteration,
filter_2_->decodeHeaders(request_headers, false));
EXPECT_EQ(2U, findCounter("test.http_local_rate_limit.enabled"));
EXPECT_EQ(1U, findCounter("test.http_local_rate_limit.enforced"));
EXPECT_EQ(1U, findCounter("test.http_local_rate_limit.ok"));
EXPECT_EQ(1U, findCounter("test.http_local_rate_limit.rate_limited"));
}

TEST_F(FilterTest, RequestRateLimitedPerConnection) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WDYT of adding an integration test? I think you can crib off of existing tests in ratelimit_integration_test.cc plus some of the h2 tests to make sure if you stick a limit of one stream, that a second stream on that connection won't (immediately) go upstream but a stream on a separate connection will pass through.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I can take a look at adding an integration test for the above scenario. The remaining comments should be addressed and good to go.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah! After taking a closer look, seems like the tests in ratelimit_integration_test.cc are all targeting the 'rate limiter as an external service' use case and it makes complete sense to have integration tests for that.
For local rate limiting within envoy however, doesn't really look like we have any integration tests and I'm wondering if it buys us anything more than what the unit tests do currently. Thoughts? cc @rgs1

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think integration tests generally have value - I wasn't convinced setting connection data on the per-request StreamInfo would work as expected (there are no currently filters which do this, but I went ahead and tweaked some existing code to verify it worked for my own satiscation =P) but given the review delay this PR already suffered and lack of local rate limit tests to crib off of, I'm inclined to let it go this once though if you want to do a follow-up you'd totally earn brownie points :-)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Brownie points it is then :-) I do have a draft up but I'm fighting the integration test api a bit at the moment, specifically with trying to get it to send multiple requests over the same connection while still ensuring that the first one generates an upstream request over its fake_upstreams_ while the subsequent locally rate limited ones don't. It's holding it up more than necessary so a follow up task is making more sense at this point.

Thanks for taking a look!!

setup(fmt::format(config_yaml, "1", "true"));

EXPECT_CALL(decoder_callbacks_, sendLocalReply(Http::Code::TooManyRequests, _, _, _, _))
.WillOnce(Invoke([](Http::Code code, absl::string_view body,
std::function<void(Http::ResponseHeaderMap & headers)> modify_headers,
const absl::optional<Grpc::Status::GrpcStatus> grpc_status,
absl::string_view details) {
EXPECT_EQ(Http::Code::TooManyRequests, code);
EXPECT_EQ("local_rate_limited", body);

Http::TestResponseHeaderMapImpl response_headers{{":status", "200"}};
modify_headers(response_headers);
EXPECT_EQ("true", response_headers.get(Http::LowerCaseString("x-test-rate-limit"))[0]
->value()
.getStringView());

EXPECT_EQ(grpc_status, absl::nullopt);
EXPECT_EQ(details, "local_rate_limited");
}));

auto request_headers = Http::TestRequestHeaderMapImpl();
auto expected_headers = Http::TestRequestHeaderMapImpl();

EXPECT_EQ(request_headers, expected_headers);
EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, false));
EXPECT_EQ(Http::FilterHeadersStatus::StopIteration,
filter_->decodeHeaders(request_headers, false));
EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_2_->decodeHeaders(request_headers, false));
EXPECT_EQ(Http::FilterHeadersStatus::StopIteration,
filter_2_->decodeHeaders(request_headers, false));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A comment explaining the differences between this test and FilterTest.RequestRateLimited may be helpful for future readers. I think this shows that the limit is applied by connection by verifying that filter_2_ allows requests after filter_ hits the rate limit.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a brief explanation to the test.

EXPECT_EQ(4U, findCounter("test.http_local_rate_limit.enabled"));
EXPECT_EQ(2U, findCounter("test.http_local_rate_limit.enforced"));
EXPECT_EQ(2U, findCounter("test.http_local_rate_limit.ok"));
EXPECT_EQ(2U, findCounter("test.http_local_rate_limit.rate_limited"));
}

TEST_F(FilterTest, RequestRateLimitedButNotEnforced) {
setup(fmt::format(config_yaml, "0"), true, false);
setup(fmt::format(config_yaml, "0", "false"), true, false);

EXPECT_CALL(decoder_callbacks_, sendLocalReply(Http::Code::TooManyRequests, _, _, _, _)).Times(0);

Expand Down Expand Up @@ -181,6 +242,7 @@ stat_prefix: test
header:
key: x-test-rate-limit
value: 'true'
local_rate_limit_per_downstream_connection: true
descriptors:
- entries:
- key: hello
Expand Down