Open-Source Wikis

/

Envoy

/

Systems

/

Listener manager

envoyproxy/envoy

Listener manager

The listener manager is the subsystem that turns a Listener configuration message — static from the bootstrap or dynamic from LDS — into a bound socket on every worker, complete with filter chains and TLS contexts. The implementation lives in source/common/listener_manager/.

Purpose

Concretely the listener manager is responsible for:

  • Parsing envoy::config::listener::v3::Listener messages and constructing in-process ListenerImpl objects.
  • Subscribing to LDS for dynamic listener updates.
  • Selecting the right filter chain for each new connection (by SNI, ALPN, source IP, transport, …).
  • Coordinating listener add/update/remove with workers, including in-place updates that don't drop connections.
  • Draining listeners during shutdown and hot restart.

Layout

source/common/listener_manager/
├── listener_manager_impl.{h,cc}    # The top-level manager (main thread)
├── listener_impl.{h,cc}            # A single listener (large, ~68k lines)
├── filter_chain_manager_impl.{h,cc} # Picks the right filter chain for a connection
├── connection_handler_impl.{h,cc}  # Per-worker accept loop
├── active_tcp_listener.{h,cc}      # Active TCP listener on a worker
├── active_tcp_socket.{h,cc}        # Single accepted socket pre-filter-chain
├── active_stream_listener_base.{h,cc}
├── active_raw_udp_listener_config.{h,cc}
└── lds_api.{h,cc}                  # LDS subscription glue

Key abstractions

Type File Purpose
ListenerManagerImpl listener_manager_impl.h Owns ListenerImpls, processes adds/updates/removes
ListenerImpl listener_impl.h A configured listener: address, options, filter chain manager
FilterChainManagerImpl filter_chain_manager_impl.h Indexes filter chains and matches connections to them
ConnectionHandlerImpl connection_handler_impl.h Per-worker accept dispatcher
ActiveTcpListener active_tcp_listener.h Listener instance running on a single worker
ActiveTcpSocket active_tcp_socket.h An accepted socket while listener filters run
LdsApi lds_api.h xDS subscription that feeds the manager

Lifecycle of a listener

sequenceDiagram
    participant XDS as xDS / Bootstrap
    participant LM as ListenerManagerImpl<br/>(main thread)
    participant LI as ListenerImpl
    participant W as Worker
    participant CH as ConnectionHandlerImpl<br/>(per-worker)

    XDS->>LM: addOrUpdateListener(Listener msg)
    LM->>LI: construct ListenerImpl
    LI->>LI: parse address, build FilterChainManager
    LI->>LI: build TLS contexts
    LM->>W: server_->workers().addListener(listener)
    W->>CH: post addListener
    CH->>CH: bind socket / inherit hot-restart fd
    CH->>CH: start accepting

When a Listener arrives, the manager walks a state machine:

  1. Construct a fresh ListenerImpl on the main thread — including all filter chain factories, transport socket factories, and the SDS subscriptions for any inline TLS contexts.
  2. Wait for any init targets registered by the listener (typically SDS) to complete.
  3. Distribute the listener to every worker via Server::WorkerImpl::addListener. Each worker's ConnectionHandlerImpl then opens the socket and binds it.
  4. If this is an update, the new listener takes over from the old one in-place when configured to do so (LISTENER_REPLACING_VIA_REPLACE on the worker), and the old listener is drained.

Filter chain matching

FilterChainManagerImpl::findFilterChain (filter_chain_manager_impl.cc) is the heart of the listener at request time. Given an ActiveTcpSocket carrying server name (SNI), ALPN, source IP, transport, and connection-time metadata, it finds the matching filter chain by walking a series of indexed lookups (most-specific first):

destination port → server names → transport protocol → application protocols
  → source type → source IPs → source ports → direct source IPs

Each filter chain in the configuration becomes a leaf in this tree, ordered by specificity. The result is a Network::FilterChain* that the ActiveTcpSocket then uses to instantiate the network filters.

Listener filters

Before a filter chain is selected, listener filters (source/extensions/filters/listener/) inspect the bare socket. They can read the first few bytes (TLS ClientHello, proxy protocol, …) to influence matching. The shipped listener filters:

  • tls_inspector — peeks at the TLS ClientHello to discover SNI/ALPN.
  • original_dst — reads the SO_ORIGINAL_DST socket option.
  • original_src — restores the original source IP for transparent proxying.
  • proxy_protocol — parses HAProxy proxy protocol v1/v2.
  • http_inspector — peeks at HTTP/1 first bytes to distinguish HTTP/1 vs HTTP/2 upgrade.

Listener filters run on the worker thread, in ActiveTcpSocket::startFilterChain. They are async: a filter can StopIteration to wait for more bytes and ContinueIteration once it has what it needs.

Network filters

Once a filter chain is selected, ActiveTcpListener::onAcceptWorker constructs a Network::ConnectionImpl and instantiates the chain of network filters (source/extensions/filters/network/). The terminal network filter for HTTP listeners is the HTTP connection manager; for TCP it is tcp_proxy.

In-place updates

A listener update with the same address can be applied without dropping existing connections, provided the new listener's traffic-direction settings, socket options, etc. are compatible. The mechanism is in listener_impl.cc:

  • The new listener inherits the old socket's file descriptor.
  • New connections use the new filter chain manager.
  • Old connections continue with their existing filter chains until they close.
  • The old ListenerImpl lingers (and counts toward stats) until its final connection drains.

This is the same socket-passing pattern used by hot restart, but within a single process.

LDS

LdsApiImpl (lds_api.cc) is the bridge between xDS and the listener manager. It subscribes to envoy.service.listener.v3.ListenerDiscoveryService over a configured ConfigSource, deserialises the Listener resources, and calls ListenerManagerImpl::addOrUpdateListener for each.

LDS supports both state-of-the-world (SotW) and delta variants. The manager treats a missing resource in a SotW response as a removal.

Drain

When a listener is removed (via LDS, POST /drain_listeners, or shutdown), the manager:

  1. Stops accepting new connections immediately.
  2. Asks each worker to begin draining its ActiveTcpListener.
  3. Coordinates with the drain manager to apply the configured drain timing.
  4. Once the last connection is gone, frees the listener.

For HTTP/2 listeners this includes sending GOAWAY; for HTTP/1 it includes adding Connection: close. The behaviour is implemented in the codecs and triggered by the listener's drain state.

Integration points

  • Workers — every worker has its own ConnectionHandlerImpl and per-worker ActiveTcpListener instances. The listener manager is the only entity that adds/removes listeners on workers.
  • xDS — LDS subscription. Bootstrap-static listeners skip xDS entirely.
  • Cluster manager — listener filter chains reference clusters (e.g. tcp_proxy config). The cluster manager must already exist before listeners are constructed.
  • Secret manager — TLS contexts in listener filter chains are populated by SDS.
  • Init manager — listeners with SDS subscriptions register init targets that gate "ready to serve".
  • Drain manager — drives the drain sequence on shutdown / removal.

Entry points for modification

See also

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Listener manager – Envoy wiki | Factory