xDS中LDS API的定义和实现
- 1: LDS API的概述
- 2: LDS API中的Listener配置
- 3: LDS API中的Filter配置
- 4: LDS API中的Filter Chain配置
- 5: LDS API中的Listener Filter配置
1 - LDS API的概述
LDS服务定义
LDS的服务定义如下:
https://github.com/envoyproxy/envoy/blob/main/api/envoy/service/listener/v3/lds.proto
service ListenerDiscoveryService {
option (envoy.annotations.resource).type = "envoy.config.listener.v3.Listener";
rpc DeltaListeners(stream discovery.v3.DeltaDiscoveryRequest)
returns (stream discovery.v3.DeltaDiscoveryResponse) {
}
rpc StreamListeners(stream discovery.v3.DiscoveryRequest)
returns (stream discovery.v3.DiscoveryResponse) {
}
rpc FetchListeners(discovery.v3.DiscoveryRequest) returns (discovery.v3.DiscoveryResponse) {
option (google.api.http).post = "/v3/discovery:listeners";
option (google.api.http).body = "*";
}
}
请求参数
对于 DeltaDiscoveryRequest 和 DiscoveryRequest,请求参数中的 type_url 字段的取值是 “type.googleapis.com/envoy.config.listener.v3.Listener” (或者隐含)。
应答参数
对于 DiscoveryResponse 和 DeltaDiscoveryResponse,返回的资源类型被抽象为 google.protobuf.Any
,对于LDS返回的实际是 Listener 这个消息体,定义在 api/envoy/config/listener/v3/listener.proto
文件中:
package envoy.config.listener.v3;
message Listener {
string name = 1;
core.v3.Address address = 2 [(validate.rules).message = {required: true}];
repeated FilterChain filter_chains = 3;
repeated ListenerFilter listener_filters = 9;
......
}
详细的字段定义请见后续的详细解说。
2 - LDS API中的Listener配置
Listener配置
Listener 的配置详细定义在 xDS API 中 Linsenter 的 proto 定义文件中,地址如下:
https://github.com/envoyproxy/envoy/blob/main/api/envoy/config/listener/v3/listener.proto#L39
Json格式
Listerner配置的JSON格式如下所示:
{
"name": "...",
"address": "{...}",
"stat_prefix": "...",
"filter_chains": [],
"use_original_dst": "{...}",
"default_filter_chain": "{...}",
"per_connection_buffer_limit_bytes": "{...}",
"metadata": "{...}",
"drain_type": "...",
"listener_filters": [],
"listener_filters_timeout": "{...}",
"continue_on_listener_filters_timeout": "...",
"transparent": "{...}",
"freebind": "{...}",
"socket_options": [],
"tcp_fast_open_queue_length": "{...}",
"traffic_direction": "...",
"udp_listener_config": "{...}",
"api_listener": "{...}",
"connection_balance_config": "{...}",
"reuse_port": "...",
"enable_reuse_port": "{...}",
"access_log": [],
"tcp_backlog_size": "{...}",
"bind_to_port": "{...}"
}
proto格式
proto 文件定义如下:
message Listener {
option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.Listener";
string name = 1;
core.v3.Address address = 2 [(validate.rules).message = {required: true}];
string stat_prefix = 28;
repeated FilterChain filter_chains = 3;
google.protobuf.BoolValue use_original_dst = 4;
FilterChain default_filter_chain = 25;
google.protobuf.UInt32Value per_connection_buffer_limit_bytes = 5
[(udpa.annotations.security).configure_for_untrusted_downstream = true];
core.v3.Metadata metadata = 6;
DrainType drain_type = 8;
repeated ListenerFilter listener_filters = 9;
google.protobuf.Duration listener_filters_timeout = 15;
bool continue_on_listener_filters_timeout = 17;
google.protobuf.BoolValue transparent = 10;
google.protobuf.BoolValue freebind = 11;
repeated core.v3.SocketOption socket_options = 13;
google.protobuf.UInt32Value tcp_fast_open_queue_length = 12;
core.v3.TrafficDirection traffic_direction = 16;
UdpListenerConfig udp_listener_config = 18;
ApiListener api_listener = 19;
ConnectionBalanceConfig connection_balance_config = 20;
google.protobuf.BoolValue enable_reuse_port = 29;
repeated accesslog.v3.AccessLog access_log = 22;
google.protobuf.UInt32Value tcp_backlog_size = 24;
google.protobuf.BoolValue bind_to_port = 26;
}
Listener字段说明
具体字段的说明:
字段 | 格式 | 说明 |
---|---|---|
name | string | 该监听器的唯一名称。如果没有提供名称,Envoy将为监听器分配一个内部UUID。如果监听器要通过LDS动态更新或删除,必须提供唯一的名字。 |
address | core.v3.Address, REQUIRED | 听众应该收听的地址。一般来说,这个地址必须是唯一的,不过这要由操作系统的绑定规则决定。例如,多个监听器可以在Linux上监听端口0,因为实际的端口将由操作系统分配。 |
stat_prefix | string | 可选的前缀,用于监听器的统计信息。如果为空,统计信息将以 listener.<address as string> 为根。如果非空,统计信息将以listener.<stat_prefix> 为根。 |
filter_chains | FilterChain, REQUIRED | 考虑用于这个监听器的过滤链列表。最符合 FilterChainMatch 条件的 FilterChain 将用于连接。 |
use_original_dst | google.protobuf.BoolValue | 如果使用iptables重定向连接,代理接收连接的端口可能与原始目标地址不同。当这个标志被设置为 “true” 时,监听器会将重定向的连接交给与原始目标地址相关的监听器。如果没有与原始目标地址相关联的监听器,连接将由接收它的监听器处理。默认为false。 |
default_filter_chain | FilterChain | 如果没有一个过滤器链相匹配,则为默认过滤器链。如果没有提供默认的过滤链,连接将被关闭。在这个字段中,过滤链的匹配被忽略。 |
per_connection_buffer_limit_bytes | UInt32Value | 对监听器新建连接的读写缓冲区大小的软限制。如果未指定,则使用实现定义的默认值(1MiB)。 |
metadata | core.v3.Metadata | 监听器元数据 |
drain_type | DrainType | 在监听器范围内执行的逐出类型。 |
listener_filters | ListenerFilter[] | Listener 过滤器有机会操作和增加连接元数据,例如在连接过滤器链匹配中使用。这些过滤器会在任何过滤器链之前运行。顺序很重要,因为过滤器是在监听器接受套接字后,在创建连接前,按顺序处理的。当监听器套接字地址中的协议是UDP时,可以指定UDP监听器过滤器。UDP监听器目前只支持一个过滤器。 |
listener_filters_timeout | google.protobuf.Duration | 等待所有监听器过滤器完成操作的超时时间。如果达到超时,接受的套接字将被关闭,而不创建连接,除非continue_on_listener_filters_timeout 被设置为true。指定0来禁用超时。如果不指定,将使用默认的15s超时。 |
continue_on_listener_filters_timeout | bool | 当监听器过滤器超时时,是否应该创建连接。默认为false。 |
transparent | google.protobuf.BoolValue | 监听器是否应该被设置为透明套接字。 当这个标志设置为 “true “时,连接可以使用iptables TPROXY目标重定向到监听器,在这种情况下,接受的连接会保留原来的源地址和目的地址以及端口。这个标志应该与 original_dst 监听器过滤器结合使用,以标记连接的本地地址为 “restored”。这可以用来把每个重定向的连接移交给与该连接的目的地址相关的另一个监听器。没有使用TPROXY的套接字的直接连接无法与使用TPROXY重定向的连接区分开来,因此会被当作重定向的连接。当这个标志被设置为false时,监听器的套接字会被明确地重置为非透明的。设置这个标志需要Envoy以CAP_NET_ADMIN能力运行。当这个标志没有设置时(默认),套接字不会被修改,也就是说,透明选项既不会被设置也不会被重置。 |
freebind | google.protobuf.BoolValue | 监听器是否应设置 IP_FREEBIND 套接字选项。 当此标志设置为true时,可以将监听器绑定到未在运行Envoy的系统上配置的IP地址。 当此标志设置为false时,套接字上的选项 IP_FREEBIND 被禁用。 如果未设置此标志(默认值),则不会修改套接字,即既未启用也未禁用该选项。 |
socket_options | core.v3.SocketOption | Envoy源代码或预编译二进制文件中可能不存在的其他套接字选项。 |
tcp_fast_open_queue_length | UInt32Value | 监听器是否应接受 TCP Fast Open(TFO)连接。 当此标志设置为大于0的值时,将在套接字上启用选项TCP_FASTOPEN,其队列长度为指定大小(请参阅RFC7413中的详细信息)。 当此标志设置为0时,套接字上禁用选项TCP_FASTOPEN。 如果未设置此标志(默认值),则不会修改套接字,即既未启用也未禁用该选项。 |
traffic_direction | core.v3.TrafficDirection | 指定流量相对于本地 envoy 的预期方向。对于使用原始目的地过滤器的 listener 来说,这个属性在Windows下是必需的,见原始目的地 |
udp_listener_config | UdpListenerConfig | 如果协议中的监听器套接字地址的协议是UDP,这个字段指定UDP监听器的具体配置。 |
api_listener | ApiListener | 用于表示一个API监听器,在非代理客户端中使用。暴露给非代理应用程序的API类型取决于API监听器的类型。当这个字段被设置时,除了名字之外,其他字段都不应该被设置。 |
connection_balance_config | ConnectionBalanceConfig | 监听器的连接平衡器配置,目前只适用于TCP监听器。如果没有指定配置,Envoy将不会尝试在工作线程之间平衡活动连接。 在这种情况下,监听器X通过在X中设置use_original_dst,在Y1和Y2中设置bind_to_port为false,将所有连接重定向到监听器Y1和Y2,建议禁用监听器X中的平衡配置,以避免平衡的成本,并启用Y1和Y2中的平衡配置,在工作者之间平衡连接。 |
reuse_port | bool | 弃用。请使用 enable_reuse_port |
enable_reuse_port | google.protobuf.BoolValue | 当这个标志被设置为 “true” 时,监听器会设置SO_REUSEPORT套接字选项,为每个工作线程创建一个套接字。这使得在连接数较多的情况下,入站连接在工作线程之间大致均匀分布。当这个标志被设置为false时,所有工作线程共享一个套接字。这个字段的默认值是true。 |
access_log | accesslog.v3.AccessLog[] | 该监听器发出的访问日志的配置。 |
tcp_backlog_size | google.protobuf.UInt32Value | tcp 监听器的待处理连接队列可以增长的最大长度。如果没有提供net.core.somaxconn的值,在Linux上将会使用,否则将使用128。 |
bind_to_port | google.protobuf.BoolValue | 监听器是否应该与端口绑定。不绑定的监听器只能接收从其他设置use_original_dst为true的监听器重定向的连接。默认为true。 |
3 - LDS API中的Filter配置
Listener Filter的配置详细定义在 xDS API 中 Linsenter Components 的 proto 定义文件中,地址如下:
Json格式
Listerner Filter配置的JSON格式如下所示:
{
"name": "...",
"typed_config": "{...}"
}
proto格式
proto 文件定义如下:
message Filter {
string name = 1 [(validate.rules).string = {min_len: 1}];
oneof config_type {
google.protobuf.Any typed_config = 4;
core.v3.ExtensionConfigSource config_discovery = 5;
}
}
Listener字段说明
具体字段的说明:
字段 | 格式 | 说明 |
---|---|---|
name | string | 要实例化的过滤器的名称。该名称必须符合支持的过滤器 |
typed_config | google.protobuf.Any | 过滤器的具体配置,取决于正在实例化的过滤器。参见支持的过滤器的进一步的文档。 |
config_discovery | core.v3.ExtensionConfigSource | 扩展配置发现服务的配置源指定器。在失败和没有默认配置的情况下,监听器会关闭连接。 |
如果是通过 typed_config 来配置 filter,则 name 必须是已经被支持的 filter,具体目前支持的filter列表见:
4 - LDS API中的Filter Chain配置
Filter Chain
过滤器链包裹着一组匹配判据,一个选项TLS上下文,一组过滤器,以及其他各种参数。
Listener Filter Chain的配置详细定义在 xDS API 中 Linsenter Components 的 proto 定义文件中,地址如下:
Json格式
Listerner Filter Chain配置的JSON格式如下所示:
{
"filter_chain_match": "{...}",
"filters": [],
"use_proxy_proto": "{...}",
"transport_socket": "{...}",
"transport_socket_connect_timeout": "{...}"
}
proto格式
proto 文件定义如下:
message FilterChain {
option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.listener.FilterChain";
FilterChainMatch filter_chain_match = 1;
repeated Filter filters = 3;
google.protobuf.BoolValue use_proxy_proto = 4
[deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"];
core.v3.Metadata metadata = 5;
core.v3.TransportSocket transport_socket = 6;
google.protobuf.Duration transport_socket_connect_timeout = 9;
string name = 7;
OnDemandConfiguration on_demand_configuration = 8;
}
字段说明
具体字段的说明:
字段 | 格式 | 说明 |
---|---|---|
filter_chain_match | FilterChainMatch | 匹配连接到该过滤链时使用的判据。 |
filters | Filter | 一个单独的网络过滤器的列表,它构成了与监听器建立的连接的过滤器链。顺序很重要,因为过滤器会随着连接事件的发生按顺序处理。注意:如果过滤器列表为空,连接将默认关闭。 |
use_proxy_proto | google.protobuf.BoolValue | 监听器是否应该在新连接上期待一个PROXY协议V1头。如果该选项被启用,监听器将假定连接的远程地址是头中指定的地址。包括AWS ELB在内的一些负载均衡器支持这个选项。如果该选项不存在或设置为false,Envoy将使用连接的物理对等地址作为远程地址。 这个字段已经废弃了。可以明确地添加PROXY协议监听器过滤器来代替。 |
metadata | core.v3.Metadata | 过滤链元数据 |
transport_socket | core.v3.TransportSocket | 可选的自定义传输套接字实现,用于下游连接。要设置TLS,在typed_config中设置一个名称为envoy.transport_sockets.tls的传输套接字和DownstreamTlsContext。如果没有指定传输套接字的配置,新的连接将用纯文本建立。 |
transport_socket_connect_timeout | google.protobuf.Duration | 如果存在并且不为零,允许传入的连接完成任何传输套接字协商的时间量。如果这个时间在传输报告连接建立之前过期,连接将被立即关闭。 |
FilterChainMatch
指定为 Listener 选择特定过滤链的匹配判据。
为了选择一个过滤链,它的所有判据必须被传入的连接满足,其属性由网络堆栈和/或监听器过滤器设置。
以下顺序适用:
- 目的地端口。
- 目的地IP地址。
- 服务器名称(例如:TLS协议的SNI)。
- 传输协议。
- 应用协议(例如:TLS协议的ALPN)。
- 直接连接的源IP地址(这只有在使用覆盖源地址的监听器过滤器时才会与源IP地址不同,如代理协议监听器过滤器)。
- 源类型(例如,任何,本地或外部网络)。
- 源IP地址。
- 源端口
对于允许范围或通配符的标准,将使用任何配置的过滤链中与传入连接相匹配的最具体的值(例如,对于SNI www.example.com,最具体的匹配将是www.example.com,然后是*.example.com,然后是*.com,然后是任何没有server_names要求的过滤链)。
用另一种方式来推理过滤链的匹配。假设存在N个过滤链。使用上述8个步骤对过滤链集进行修剪。在每个步骤中,与属性最具体匹配的过滤链继续进入下一个步骤。监听器保证在所有的步骤之后最多剩下1个过滤链。
例如:
对于目的端口,指定传入流量的目的端口的过滤链是最具体的匹配。如果没有一个过滤链指定确切的目的端口,那么不指定端口的过滤链是最具体的匹配。指定错误端口的过滤链永远不可能成为最具体的匹配。
Listener Filter Chain Match的配置详细定义在 xDS API 中 Linsenter Components 的 proto 定义文件中,地址如下:
Json格式
Listerner Filter Chain Match配置的JSON格式如下所示:
{
"destination_port": "{...}",
"prefix_ranges": [],
"direct_source_prefix_ranges": [],
"source_type": "...",
"source_prefix_ranges": [],
"source_ports": [],
"server_names": [],
"transport_protocol": "...",
"application_protocols": []
}
proto格式
proto 文件定义如下:
message FilterChainMatch {
option (udpa.annotations.versioning).previous_message_type =
"envoy.api.v2.listener.FilterChainMatch";
google.protobuf.UInt32Value destination_port = 8 [(validate.rules).uint32 = {lte: 65535 gte: 1}];
repeated core.v3.CidrRange prefix_ranges = 3;
string address_suffix = 4;
google.protobuf.UInt32Value suffix_len = 5;
repeated core.v3.CidrRange direct_source_prefix_ranges = 13;
ConnectionSourceType source_type = 12 [(validate.rules).enum = {defined_only: true}];
repeated core.v3.CidrRange source_prefix_ranges = 6;
repeated uint32 source_ports = 7
[(validate.rules).repeated = {items {uint32 {lte: 65535 gte: 1}}}];
repeated string server_names = 11;
string transport_protocol = 9;
repeated string application_protocols = 10;
}
字段说明
具体字段的说明:
字段 | 格式 | 说明 |
---|---|---|
destination_port | google.protobuf.UInt32Value | 当监听器上设置use_original_dst时,在确定过滤链匹配时要考虑的可选目标端口。 |
prefix_ranges | core.v3.CidrRange[] | 如果非空,则是一个IP地址和前缀长度,以便在监听器被绑定到0.0.0.0/::或指定use_original_dst时匹配地址。 |
direct_source_prefix_ranges | core.v3.CidrRange[] | 如果下游连接的直接连接源IP地址包含在至少一个指定的子网中,则满足该条件。如果没有指定参数或者列表为空,直接连接的源IP地址将被忽略。 |
source_type | ConnectionSourceType | 指定连接源IP匹配类型。可以是任何,本地或外部网络。 |
source_prefix_ranges | core.v3.CidrRange[] | 如果下游连接的源IP地址包含在至少一个指定的子网中,则满足该条件。如果没有指定参数或列表为空,则源IP地址被忽略。 |
source_ports | uint32[] | 如果下游连接的源端口包含在至少一个指定的端口中,则满足该条件。如果没有指定该参数,源端口将被忽略。 |
server_names | string[] | 如果非空,则是一个服务器名称的列表(例如TLS协议的SNI),在确定过滤器链匹配时要考虑。这些值将与新连接的服务器名称进行比较,当被一个监听器过滤器检测到时。 服务器名称将与所有通配符域名进行匹配,即www.example.com,然后是*.example.com,然后是*.com。 注意,不支持部分通配符,像*w.example.com这样的值是无效的。 |
transport_protocol | string | 如果非空,在确定过滤器链匹配时要考虑的传输协议。这个值将与新连接的传输协议进行比较,当它被一个监听器过滤器检测到时。 建议的值包括: - raw_buffer - 默认值,在没有检测到传输协议时使用。 - tls - 当检测到TLS协议时由envoy.filters.listener.tls_inspector设置。 |
application_protocols | string[] | 如果非空,则是一个应用协议的列表(例如,TLS协议的ALPN),在确定过滤器链的匹配时要考虑。这些值将与新连接的应用协议进行比较,当被一个监听器过滤器检测到时。 建议的值包括。 - http/1.1 - 由 envoy. filters.listener.tls_inspector 设置。 - h2 - 由 envoy.filters.listener.tls_inspector 设置。 |
5 - LDS API中的Listener Filter配置
Listener Filter的配置详细定义在 xDS API 中 Linsenter Components 的 proto 定义文件中,地址如下:
Json格式
Listerner Filter Chain配置的JSON格式如下所示:
{
"name": "...",
"typed_config": "{...}",
"filter_disabled": "{...}"
}
proto格式
proto 文件定义如下:
message ListenerFilter {
option (udpa.annotations.versioning).previous_message_type =
"envoy.api.v2.listener.ListenerFilter";
string name = 1 [(validate.rules).string = {min_len: 1}];
oneof config_type {
google.protobuf.Any typed_config = 3;
}
ListenerFilterChainMatchPredicate filter_disabled = 4;
}
字段说明
具体字段的说明:
字段 | 格式 | 说明 |
---|---|---|
name | string | 要实例化的过滤器的名称。该名称必须符合支持的过滤器。 |
typed_config | google.protobuf.Any | 过滤器的具体配置,取决于正在实例化的过滤器。参见支持的过滤器的进一步文件。 |
filter_disabled | ListenerFilterChainMatchPredicate | 用于禁用过滤器的可选匹配谓词。当这个字段为空时,过滤器被启用。更多例子见ListenerFilterChainMatchPredicate。 |
如果是通过 typed_config 来配置 filter,则 name 必须是已经被支持的 filter,具体目前支持的filter列表见: