Skip to content

Commit

Permalink
extensions: add http bandwidth limit filter (envoyproxy#16358)
Browse files Browse the repository at this point in the history
the filter smoothens the flow of data in both direction up to the specified bandwidth limit.

Risk Level: Low, new filter
Testing: UTs added. Adding more UTs and integration tests.
Docs Changes: Added
Release Notes: Added
Fixes envoyproxy#13604

Signed-off-by: Nitin Goyal <nigoyal@microsoft.com>
  • Loading branch information
nitgoy authored and Le Yao committed Sep 30, 2021
1 parent 1fd2d49 commit 0077d04
Show file tree
Hide file tree
Showing 28 changed files with 1,519 additions and 5 deletions.
2 changes: 2 additions & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ extensions/filters/http/oauth2 @rgs1 @derekargueta @snowp
/*/extensions/filters/common/ext_authz @esmet @gsagula @dio
/*/extensions/filters/http/ext_authz @esmet @gsagula @dio
/*/extensions/filters/network/ext_authz @esmet @gsagula @dio
# HTTP Bandwidth Limit
/*/extensions/filters/http/bandwidth_limit @nitgoy @mattklein123 @yanavlasov @tonya11en
# Original IP detection
/*/extensions/http/original_ip_detection/custom_header @rgs1 @alyssawilk @antoniovicente
/*/extensions/http/original_ip_detection/xff @rgs1 @alyssawilk @antoniovicente
Expand Down
1 change: 1 addition & 0 deletions api/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ proto_library(
"//envoy/extensions/filters/http/admission_control/v3alpha:pkg",
"//envoy/extensions/filters/http/aws_lambda/v3:pkg",
"//envoy/extensions/filters/http/aws_request_signing/v3:pkg",
"//envoy/extensions/filters/http/bandwidth_limit/v3alpha:pkg",
"//envoy/extensions/filters/http/buffer/v3:pkg",
"//envoy/extensions/filters/http/cache/v3alpha:pkg",
"//envoy/extensions/filters/http/cdn_loop/v3alpha:pkg",
Expand Down
6 changes: 3 additions & 3 deletions api/STYLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,11 @@ organization](#package-organization) above.
To add an extension config to the API, the steps below should be followed:

1. If this is still WiP and subject to breaking changes, use `vNalpha` instead of `vN` in steps
below. Refer to the [Cache filter config](envoy/extensions/filter/http/cache/v3alpha/cache.proto)
below. Refer to the [Cache filter config](envoy/extensions/filters/http/cache/v3alpha/cache.proto)
as an example of `v3alpha`, and the
[Buffer filter config](envoy/extensions/filter/http/buffer/v3/buffer.proto) as an example of `v3`.
[Buffer filter config](envoy/extensions/filters/http/buffer/v3/buffer.proto) as an example of `v3`.
1. Place the v3 extension configuration `.proto` in `api/envoy/extensions`, e.g.
`api/envoy/extensions/filter/http/foobar/v3/foobar.proto` together with an initial BUILD file:
`api/envoy/extensions/filters/http/foobar/v3/foobar.proto` together with an initial BUILD file:
```bazel
load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package")

Expand Down
12 changes: 12 additions & 0 deletions api/envoy/extensions/filters/http/bandwidth_limit/v3alpha/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py.

load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package")

licenses(["notice"]) # Apache 2

api_proto_package(
deps = [
"//envoy/config/core/v3:pkg",
"@com_github_cncf_udpa//udpa/annotations:pkg",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
syntax = "proto3";

package envoy.extensions.filters.http.bandwidth_limit.v3alpha;

import "envoy/config/core/v3/base.proto";

import "google/protobuf/duration.proto";
import "google/protobuf/wrappers.proto";

import "udpa/annotations/status.proto";
import "validate/validate.proto";

option java_package = "io.envoyproxy.envoy.extensions.filters.http.bandwidth_limit.v3alpha";
option java_outer_classname = "BandwidthLimitProto";
option java_multiple_files = true;
option (udpa.annotations.file_status).work_in_progress = true;
option (udpa.annotations.file_status).package_version_status = ACTIVE;

// [#protodoc-title: Bandwidth limit]
// Bandwidth limit :ref:`configuration overview <config_http_filters_bandwidth_limit>`.
// [#extension: envoy.filters.http.bandwidth_limit]

// [#next-free-field: 6]
message BandwidthLimit {
// Defines the mode for the bandwidth limit filter.
// Values represent bitmask.
enum EnableMode {
// Filter is disabled.
DISABLED = 0;

// Filter enabled only for incoming traffic.
REQUEST = 1;

// Filter enabled only for outgoing traffic.
RESPONSE = 2;

// Filter enabled for both incoming and outgoing traffic.
REQUEST_AND_RESPONSE = 3;
}

// The human readable prefix to use when emitting stats.
string stat_prefix = 1 [(validate.rules).string = {min_len: 1}];

// The enable mode for the bandwidth limit filter.
// Default is Disabled.
EnableMode enable_mode = 2 [(validate.rules).enum = {defined_only: true}];

// The limit supplied in KiB/s.
//
// .. note::
// It's fine for the limit to be unset for the global configuration since the bandwidth limit
// can be applied at a the virtual host or route level. Thus, the limit must be set for the
// per route configuration otherwise the config will be rejected.
//
// .. note::
// When using per route configuration, the limit becomes unique to that route.
//
google.protobuf.UInt64Value limit_kbps = 3 [(validate.rules).uint64 = {gte: 1}];

// Optional Fill interval in milliseconds for the token refills. Defaults to 50ms.
// It must be at least 20ms to avoid too aggressive refills.
google.protobuf.Duration fill_interval = 4 [(validate.rules).duration = {
lte {seconds: 1}
gte {nanos: 20000000}
}];

// Runtime flag that controls whether the filter is enabled or not. If not specified, defaults
// to enabled.
config.core.v3.RuntimeFeatureFlag runtime_enabled = 5;
}
1 change: 1 addition & 0 deletions api/versioning/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ proto_library(
"//envoy/extensions/filters/http/admission_control/v3alpha:pkg",
"//envoy/extensions/filters/http/aws_lambda/v3:pkg",
"//envoy/extensions/filters/http/aws_request_signing/v3:pkg",
"//envoy/extensions/filters/http/bandwidth_limit/v3alpha:pkg",
"//envoy/extensions/filters/http/buffer/v3:pkg",
"//envoy/extensions/filters/http/cache/v3alpha:pkg",
"//envoy/extensions/filters/http/cdn_loop/v3alpha:pkg",
Expand Down
2 changes: 1 addition & 1 deletion docs/root/api-v3/config/filter/http/http.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ HTTP filters
:maxdepth: 2

*/empty/*
../../../extensions/filters/http/*/v3/*
../../../extensions/filters/http/*/v3*/*
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
static_resources:
listeners:
- address:
socket_address:
address: 0.0.0.0
port_value: 8000
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
codec_type: AUTO
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match: { prefix: "/path/with/bandwidth/limit" }
route: { cluster: service_protected_by_bandwidth_limit }
typed_per_filter_config:
envoy.filters.http.bandwidth_limit:
"@type": type.googleapis.com/envoy.extensions.filters.http.bandwidth_limit.v3alpha.BandwidthLimit
stat_prefix: bandwidth_limiter_custom_route
enable_mode: REQUEST_AND_RESPONSE
limit_kbps: 500
fill_interval: 0.1s
- match: { prefix: "/" }
route: { cluster: web_service }
http_filters:
- name: envoy.filters.http.bandwidth_limit
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.bandwidth_limit.v3alpha.BandwidthLimit
stat_prefix: bandwidth_limiter_default
- name: envoy.filters.http.router
typed_config: {}

clusters:
- name: service_protected_by_bandwidth_limit
connect_timeout: 0.25s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: service1
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: web_service
port_value: 9000
- name: web_service
connect_timeout: 0.25s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: service1
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: web_service
port_value: 9000
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
.. _config_http_filters_bandwidth_limit:

Bandwidth limit
====================

* Bandwidth limiting :ref:`architecture overview <arch_overview_bandwidth_limit>`
* :ref:`v3 API reference <envoy_v3_api_msg_extensions.filters.http.bandwidth_limit.v3alpha.BandwidthLimit>`
* This filter should be configured with the name ``envoy.filters.http.bandwidth_limit``.

The HTTP Bandwidth limit filter limits the size of data flow to the max bandwidth set in the ``limit_kbps``
when the request's route, virtual host or filter chain has a
:ref:`bandwidth limit configuration <envoy_v3_api_msg_extensions.filters.http.bandwidth_limit.v3alpha.BandwidthLimit>`.

If the bandwidth limit has been exhausted the filter stops further transfer until more bandwidth gets allocated
according to the ``fill_interval`` (default is 50 milliseconds). If the connection buffer fills up with accumulated
data then the source of data will have ``readDisable(true)`` set as described in the :repo:`flow control doc<source/docs/flow_control.md>`.

.. note::
The token bucket is shared across all workers, thus the limits are applied per Envoy process.

Example configuration
---------------------

Example filter configuration for a globally disabled bandwidth limiter but enabled for a specific route:

.. literalinclude:: _include/bandwidth-limit-filter.yaml
:language: yaml
:lines: 11-53
:emphasize-lines: 9-25
:caption: :download:`bandwidth-limit-filter.yaml <_include/bandwidth-limit-filter.yaml>`

Note that if this filter is configured as globally disabled and there are no virtual host or route level
token buckets, no bandwidth limiting will be applied.

Statistics
----------

The HTTP bandwidth limit filter outputs statistics in the ``<stat_prefix>.http_bandwidth_limit.`` namespace.

.. csv-table::
:header: Name, Type, Description
:widths: 1, 1, 2

request_enabled, Counter, Total number of request streams for which the bandwidth limiter was consulted
request_pending, GAUGE, Number of request streams which are currently pending transfer in bandwidth limiter
request_incoming_size, GAUGE, Size in bytes of incoming request data to bandwidth limiter
request_allowed_size, GAUGE, Size in bytes of outgoing request data from bandwidth limiter
request_transfer_duration, HISTOGRAM, Total time (including added delay) it took for the request stream transfer
response_enabled, Counter, Total number of response streams for which the bandwidth limiter was consulted
response_pending, GAUGE, Number of response streams which are currently pending transfer in bandwidth limiter
response_incoming_size, GAUGE, Size in bytes of incoming response data to bandwidth limiter
response_allowed_size, GAUGE, Size in bytes of outgoing response data from bandwidth limiter
response_transfer_duration, HISTOGRAM, Total time (including added delay) it took for the response stream transfer

.. _config_http_filters_bandwidth_limit_runtime:

Runtime
-------

The HTTP bandwidth limit filter supports the following runtime settings:

The bandwidth limit filter can be runtime feature flagged via the :ref:`enabled
<envoy_v3_api_field_extensions.filters.http.bandwidth_limit.v3alpha.BandwidthLimit.runtime_enabled>`
configuration field.
1 change: 1 addition & 0 deletions docs/root/configuration/http/http_filters/http_filters.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ HTTP filters
admission_control_filter
aws_lambda_filter
aws_request_signing_filter
bandwidth_limit_filter
buffer_filter
cdn_loop_filter
compressor_filter
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.. _arch_overview_bandwidth_limit:

Bandwidth limiting
===================

Envoy supports local (non-distributed) bandwidth limiting of HTTP requests and response via the
:ref:`HTTP bandwidth limit filter <config_http_filters_bandwidth_limit>`. This can be activated
globally at the listener level or at a more specific level (e.g.: the virtual host or route level).

Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Other features

local_rate_limiting
global_rate_limiting
bandwidth_limiting
scripting
ip_transparency
compression/libraries
3 changes: 2 additions & 1 deletion docs/root/version_history/current.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ Removed Config or Runtime

New Features
------------
* crash support: restore crash context when continuing to processing requests or responses as a result of an asynchronous callback that invokes a filter directly. This is unlike the call stacks that go through the various network layers, to eventually reach the filter. For a concrete example see: ``Envoy::Extensions::HttpFilters::Cache::CacheFilter::getHeaders`` which posts a callback on the dispatcher that will invoke the filter directly.
* bandwidth_limit: added new :ref:`HTTP bandwidth limit filter <config_http_filters_bandwidth_limit>`.
* crash support: restore crash context when continuing to processing requests or responses as a result of an asynchronous callback that invokes a filter directly. This is unlike the call stacks that go through the various network layers, to eventually reach the filter. For a concrete example see: ``Envoy::Extensions::HttpFilters::Cache::CacheFilter::getHeaders`` which posts a callback on the dispatcher that will invoke the filter directly.
* http: a new field `is_optional` is added to `extensions.filters.network.http_connection_manager.v3.HttpFilter`. When
value is `true`, the unsupported http filter will be ignored by envoy. This is also same with unsupported http filter
in the typed per filter config. For more information, please reference
Expand Down
1 change: 1 addition & 0 deletions generated_api_shadow/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ proto_library(
"//envoy/extensions/filters/http/admission_control/v3alpha:pkg",
"//envoy/extensions/filters/http/aws_lambda/v3:pkg",
"//envoy/extensions/filters/http/aws_request_signing/v3:pkg",
"//envoy/extensions/filters/http/bandwidth_limit/v3alpha:pkg",
"//envoy/extensions/filters/http/buffer/v3:pkg",
"//envoy/extensions/filters/http/cache/v3alpha:pkg",
"//envoy/extensions/filters/http/cdn_loop/v3alpha:pkg",
Expand Down

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

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

1 change: 1 addition & 0 deletions source/extensions/extensions_build_config.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ EXTENSIONS = {
"envoy.filters.http.admission_control": "//source/extensions/filters/http/admission_control:config",
"envoy.filters.http.aws_lambda": "//source/extensions/filters/http/aws_lambda:config",
"envoy.filters.http.aws_request_signing": "//source/extensions/filters/http/aws_request_signing:config",
"envoy.filters.http.bandwidth_limit": "//source/extensions/filters/http/bandwidth_limit:config",
"envoy.filters.http.buffer": "//source/extensions/filters/http/buffer:config",
"envoy.filters.http.cache": "//source/extensions/filters/http/cache:config",
"envoy.filters.http.cdn_loop": "//source/extensions/filters/http/cdn_loop:config",
Expand Down
Loading

0 comments on commit 0077d04

Please sign in to comment.