Skip to content

Commit

Permalink
Merge branch 'main' into update-protobuf
Browse files Browse the repository at this point in the history
  • Loading branch information
yanavlasov committed Jun 25, 2024
2 parents 748fccc + 3456d51 commit bb1efe6
Show file tree
Hide file tree
Showing 19 changed files with 389 additions and 133 deletions.
6 changes: 3 additions & 3 deletions bazel/repository_locations.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -1191,12 +1191,12 @@ REPOSITORY_LOCATIONS_SPEC = dict(
project_name = "QUICHE",
project_desc = "QUICHE (QUIC, HTTP/2, Etc) is Google‘s implementation of QUIC and related protocols",
project_url = "https://github.com/google/quiche",
version = "134dcbea61d892245bb2000553eb88650a0c0541",
sha256 = "89444d8dbe3b8a5b9164c5291fd46aba1c047ed9df5f7a08bed5fece857f5aaf",
version = "cf8d05ab435919878ca0db342e05e64620b43173",
sha256 = "a0b89cf43edb6e17126d536ee522127f7a71ee38d2813ba0464ed1a8c62db25f",
urls = ["https://github.com/google/quiche/archive/{version}.tar.gz"],
strip_prefix = "quiche-{version}",
use_category = ["controlplane", "dataplane_core"],
release_date = "2024-06-17",
release_date = "2024-06-21",
cpe = "N/A",
license = "BSD-3-Clause",
license_url = "https://github.com/google/quiche/blob/{version}/LICENSE",
Expand Down
3 changes: 3 additions & 0 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ bug_fixes:
Set the SNI value from the requested server name if it isn't available on the connection/socket. This applies when
``include_tls_session`` is true. The requested server name is set on a connection when filters such as the TLS
inspector are used.
- area: oauth
change: |
The id token cookie now expires at the same time the id token itself expires, instead of when the access token expires.
- area: decompression
change: |
Fixed a bug where Envoy will go into an endless loop when using the brotli decompressor. If the input stream has
Expand Down
39 changes: 30 additions & 9 deletions docs/root/start/docker.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
Using the Envoy Docker Image
============================

The following examples use the :ref:`official Envoy Docker image <start_install_docker>`.
.. note::
Envoy OCI images are built using Docker and have been extensively tested in large scale
deployments running with Docker. Use of other container technologies such as Podman might
function correctly but have not been extensively tested and are not expressly supported.

The following examples use the :ref:`official Envoy OCI image <start_install_docker>`.

These instructions are known to work for the ``x86_64`` and ``arm64`` architectures.

Expand All @@ -29,13 +34,13 @@ either by ensuring the correct permissions on the file, or making it world-reada
below.


Build and run a Docker image
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Build and run an Envoy image with Docker
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Create a simple Dockerfile to execute Envoy.
Create a simple ``Dockerfile`` to execute Envoy.

If you create a custom ``envoy.yaml`` you can create your own Docker image with it using the following
Dockerfile recipe:
``Dockerfile`` recipe:

.. substitution-code-block:: dockerfile

Expand All @@ -50,16 +55,32 @@ Build the Docker image using:
$ docker build -t envoy:v1 .
Assuming Envoy is configured to listen on ports ``9901`` and ``10000``, you can now start it
with:
in Docker with:

.. code-block:: console
$ docker run -d --name envoy -p 9901:9901 -p 10000:10000 envoy:v1
Permissions for running Docker Envoy containers as a non-root user
or in Podman (unsupported) with:

.. code-block:: console
$ podman run -d --name envoy -p 9901:9901 -p 10000:10000 envoy:v1
Root filesystem permissions for running Envoy in containers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The Envoy container image can be run with the container's root filesystem mounted read-only.
For example, using Docker and Podman, you can use the ``--read-only`` option of the ``run`` command.

With Kubernetes, this means setting ``podSpec.containers.securityContext.readOnlyFilesystem`` to ``true``.

With Nomad, this means setting ``readonly_rootfs = true`` in the task's ``config`` block when using the ``docker`` or ``podman`` driver.

Permissions for running Envoy in containers as a non-root user
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

By default, the Envoy Docker image will start as the root user but will switch to the ``envoy``
By default, the Envoy OCI image will start as the root user but will switch to the ``envoy``
user created at build time, in the Docker ``ENTRYPOINT``.

Alternatively, you can start the container specifying the Docker ``user``.
Expand Down Expand Up @@ -125,7 +146,7 @@ host user's ``uid``, for example:

$ docker run -d --name envoy -v $(pwd)/envoy.yaml:/etc/envoy/envoy.yaml -e ENVOY_UID=$(id -u) envoyproxy/|envoy_docker_image|

Listen only on ports > 1024 inside the Docker Envoy container
Listen only on ports > 1024 inside the Envoy container
*************************************************************

Unix-based systems restrict opening ``well-known`` ports (ie. with a port number < ``1024``) to the ``root`` user.
Expand Down
81 changes: 41 additions & 40 deletions source/common/http/conn_pool_grid.cc
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ void ConnectivityGrid::WrapperCallbacks::onConnectionAttemptFailed(
}
maybeMarkHttp3Broken();

auto delete_this_on_return = attempt->removeFromList(connection_attempts_);
grid_.dispatcher_.deferredDelete(attempt->removeFromList(connection_attempts_));

// If there is another connection attempt in flight then let that proceed.
if (!connection_attempts_.empty()) {
Expand Down Expand Up @@ -111,8 +111,8 @@ void ConnectivityGrid::WrapperCallbacks::signalFailureAndDeleteSelf(
}

void ConnectivityGrid::WrapperCallbacks::deleteThis() {
// By removing the entry from the list, it will be deleted.
removeFromList(grid_.wrapped_callbacks_);
// Set this to delete on the next dispatcher loop.
grid_.dispatcher_.deferredDelete(removeFromList(grid_.wrapped_callbacks_));
}

ConnectivityGrid::StreamCreationResult
Expand All @@ -139,7 +139,7 @@ void ConnectivityGrid::WrapperCallbacks::onConnectionAttemptReady(
maybeMarkHttp3Broken();
}

auto delete_this_on_return = attempt->removeFromList(connection_attempts_);
grid_.dispatcher_.deferredDelete(attempt->removeFromList(connection_attempts_));
ConnectionPool::Callbacks* callbacks = inner_callbacks_;
inner_callbacks_ = nullptr;
// If an HTTP/3 connection attempts is in progress, let it complete so that if it succeeds
Expand Down Expand Up @@ -207,9 +207,8 @@ ConnectivityGrid::WrapperCallbacks::tryAnotherConnection() {
// return true regardless of if newStream resulted in an immediate result or
// an async call, as either way the attempt will result in success/failure
// callbacks.
grid_.createNextPool(); // Make sure the HTTP/2 pool exists
has_attempted_http2_ = true;
return newStream(*grid_.http2_pool_);
return newStream(*grid_.getOrCreateHttp2Pool());
}

ConnectivityGrid::ConnectivityGrid(
Expand Down Expand Up @@ -263,31 +262,40 @@ void ConnectivityGrid::deleteIsPending() {
}
}

ConnectionPool::Instance* ConnectivityGrid::createNextPool() {
ConnectionPool::Instance* ConnectivityGrid::getOrCreateHttp3Pool() {
ASSERT(!deferred_deleting_);
// Pools are created by newStream, which should not be called during draining.
ASSERT(!draining_);
// If both pools exist we're done.
if ((http2_pool_ && http3_pool_) || draining_) {
return nullptr;
if (http3_pool_ == nullptr) {
http3_pool_ = createHttp3Pool();
pools_.push_back(http3_pool_.get());
setupPool(*http3_pool_.get());
}
return http3_pool_.get();
}

// HTTP/3 is hard-coded as higher priority, H2 as secondary.
if (!http3_pool_) {
http3_pool_ = Http3::allocateConnPool(
dispatcher_, random_generator_, host_, priority_, options_, transport_socket_options_,
state_, quic_stat_names_, *alternate_protocols_, scope_,
makeOptRefFromPtr<Http3::PoolConnectResultCallback>(this), quic_info_);
pools_.push_back(http3_pool_.get());
} else {
http2_pool_ = std::make_unique<HttpConnPoolImplMixed>(
dispatcher_, random_generator_, host_, priority_, options_, transport_socket_options_,
state_, origin_, alternate_protocols_);
ConnectionPool::Instance* ConnectivityGrid::getOrCreateHttp2Pool() {
ASSERT(!deferred_deleting_);
ASSERT(!draining_);
if (http2_pool_ == nullptr) {
http2_pool_ = createHttp2Pool();
pools_.push_back(http2_pool_.get());
setupPool(*http2_pool_.get());
}

setupPool(*pools_.back());
return pools_.back();
return http2_pool_.get();
}

ConnectionPool::InstancePtr ConnectivityGrid::createHttp2Pool() {
return std::make_unique<HttpConnPoolImplMixed>(dispatcher_, random_generator_, host_, priority_,
options_, transport_socket_options_, state_,
origin_, alternate_protocols_);
}

ConnectionPool::InstancePtr ConnectivityGrid::createHttp3Pool() {
return Http3::allocateConnPool(
dispatcher_, random_generator_, host_, priority_, options_, transport_socket_options_, state_,
quic_stat_names_, *alternate_protocols_, scope_,
makeOptRefFromPtr<Http3::PoolConnectResultCallback>(this), quic_info_);
}

void ConnectivityGrid::setupPool(ConnectionPool::Instance& pool) {
Expand All @@ -311,10 +319,7 @@ ConnectionPool::Cancellable* ConnectivityGrid::newStream(Http::ResponseDecoder&
ASSERT(!draining_);

// Always start with the HTTP/3 pool if it exists.
ConnectionPool::Instance* pool = http3_pool_ ? http3_pool_.get() : http2_pool_.get();
if (!pool) {
pool = createNextPool();
}
ConnectionPool::Instance* pool = getOrCreateHttp3Pool();
Instance::StreamOptions overriding_options = options;
bool delay_tcp_attempt = true;
if (shouldAttemptHttp3() && options.can_use_http3_) {
Expand All @@ -323,9 +328,7 @@ ConnectionPool::Cancellable* ConnectivityGrid::newStream(Http::ResponseDecoder&
delay_tcp_attempt = false;
}
} else {
// Make sure the HTTP/2 pool is created.
createNextPool();
pool = http2_pool_.get();
pool = getOrCreateHttp2Pool();
}
auto wrapped_callback =
std::make_unique<WrapperCallbacks>(*this, decoder, callbacks, overriding_options);
Expand All @@ -334,18 +337,17 @@ ConnectionPool::Cancellable* ConnectivityGrid::newStream(Http::ResponseDecoder&
if (ret->newStream(*pool) == StreamCreationResult::ImmediateResult) {
// If newStream succeeds, return nullptr as the caller has received their
// callback and does not need a cancellable handle. At this point the
// WrappedCallbacks object has also been deleted.
// WrappedCallbacks object is queued to be deleted.
return nullptr;
}
if (!delay_tcp_attempt) {
// Immediately start TCP attempt if HTTP/3 failed recently.
absl::optional<StreamCreationResult> result = ret->tryAnotherConnection();
if (result.has_value() && result.value() == StreamCreationResult::ImmediateResult) {
// As above, if we have an immediate success, return nullptr.
return nullptr;
}
ret->tryAnotherConnection();
}
return ret;

// Return a handle if the caller hasn't yet been notified of success/failure.
// There may still be connection attempts, if the wrapper is waiting on a slow H3 connection.
return ret->hasNotifiedCaller() ? nullptr : ret;
}

void ConnectivityGrid::addIdleCallback(IdleCb cb) {
Expand All @@ -356,8 +358,7 @@ void ConnectivityGrid::addIdleCallback(IdleCb cb) {

void ConnectivityGrid::drainConnections(Envoy::ConnectionPool::DrainBehavior drain_behavior) {
if (drain_behavior == Envoy::ConnectionPool::DrainBehavior::DrainAndDelete) {
// Note that no new pools can be created from this point on
// as createNextPool fast-fails if `draining_` is true.
// Note that no new pools should be created from this point on.
draining_ = true;
}
for (auto& pool : pools_) {
Expand Down
22 changes: 17 additions & 5 deletions source/common/http/conn_pool_grid.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,26 @@ class ConnectivityGrid : public ConnectionPool::Instance,
// It also relays cancellation calls between the original caller and the
// current connection attempts.
class WrapperCallbacks : public ConnectionPool::Cancellable,
public LinkedObject<WrapperCallbacks> {
public LinkedObject<WrapperCallbacks>,
public Event::DeferredDeletable {
public:
WrapperCallbacks(ConnectivityGrid& grid, Http::ResponseDecoder& decoder,
ConnectionPool::Callbacks& callbacks, const Instance::StreamOptions& options);

bool hasNotifiedCaller() { return inner_callbacks_ == nullptr; }

// Event::DeferredDeletable
// The wrapper is being deleted - cancel all alarms.
void deleteIsPending() override { next_attempt_timer_.reset(); }

// This holds state for a single connection attempt to a specific pool.
class ConnectionAttemptCallbacks : public ConnectionPool::Callbacks,
public LinkedObject<ConnectionAttemptCallbacks> {
public LinkedObject<ConnectionAttemptCallbacks>,
public Event::DeferredDeletable {
public:
ConnectionAttemptCallbacks(WrapperCallbacks& parent, ConnectionPool::Instance& pool);
~ConnectionAttemptCallbacks() override;
void deleteIsPending() override {}

StreamCreationResult newStream();

Expand Down Expand Up @@ -206,9 +215,12 @@ class ConnectivityGrid : public ConnectionPool::Instance,
// that specifies HTTP/3 and HTTP/3 is not broken.
bool shouldAttemptHttp3();

// Creates the next pool in the priority list, or nullptr if all pools have been created.
// TODO(alyssawilk) replace this now we have explicit pools.
virtual ConnectionPool::Instance* createNextPool();
// Returns the specified pool, which will be created if necessary
ConnectionPool::Instance* getOrCreateHttp3Pool();
ConnectionPool::Instance* getOrCreateHttp2Pool();

virtual ConnectionPool::InstancePtr createHttp3Pool();
virtual ConnectionPool::InstancePtr createHttp2Pool();

// This batch of member variables are latched objects required for pool creation.
Event::Dispatcher& dispatcher_;
Expand Down
12 changes: 6 additions & 6 deletions source/common/quic/envoy_quic_client_stream.cc
Original file line number Diff line number Diff line change
Expand Up @@ -368,15 +368,15 @@ void EnvoyQuicClientStream::ResetWithError(quic::QuicResetStreamError error) {
}
}

void EnvoyQuicClientStream::OnConnectionClosed(quic::QuicErrorCode error,
void EnvoyQuicClientStream::OnConnectionClosed(const quic::QuicConnectionCloseFrame& frame,
quic::ConnectionCloseSource source) {
if (!end_stream_decoded_) {
runResetCallbacks(
source == quic::ConnectionCloseSource::FROM_SELF
? quicErrorCodeToEnvoyLocalResetReason(error, session()->OneRttKeysAvailable())
: quicErrorCodeToEnvoyRemoteResetReason(error));
runResetCallbacks(source == quic::ConnectionCloseSource::FROM_SELF
? quicErrorCodeToEnvoyLocalResetReason(frame.quic_error_code,
session()->OneRttKeysAvailable())
: quicErrorCodeToEnvoyRemoteResetReason(frame.quic_error_code));
}
quic::QuicSpdyClientStream::OnConnectionClosed(error, source);
quic::QuicSpdyClientStream::OnConnectionClosed(frame, source);
}

void EnvoyQuicClientStream::OnClose() {
Expand Down
3 changes: 2 additions & 1 deletion source/common/quic/envoy_quic_client_stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ class EnvoyQuicClientStream : public quic::QuicSpdyClientStream,
void OnClose() override;
void OnCanWrite() override;
// quic::Stream
void OnConnectionClosed(quic::QuicErrorCode error, quic::ConnectionCloseSource source) override;
void OnConnectionClosed(const quic::QuicConnectionCloseFrame& frame,
quic::ConnectionCloseSource source) override;

void clearWatermarkBuffer();

Expand Down
12 changes: 6 additions & 6 deletions source/common/quic/envoy_quic_server_stream.cc
Original file line number Diff line number Diff line change
Expand Up @@ -358,17 +358,17 @@ void EnvoyQuicServerStream::ResetWithError(quic::QuicResetStreamError error) {
quic::QuicSpdyServerStreamBase::ResetWithError(error);
}

void EnvoyQuicServerStream::OnConnectionClosed(quic::QuicErrorCode error,
void EnvoyQuicServerStream::OnConnectionClosed(const quic::QuicConnectionCloseFrame& frame,
quic::ConnectionCloseSource source) {
// Run reset callback before closing the stream so that the watermark change will not trigger
// callbacks.
if (!local_end_stream_) {
runResetCallbacks(
source == quic::ConnectionCloseSource::FROM_SELF
? quicErrorCodeToEnvoyLocalResetReason(error, session()->OneRttKeysAvailable())
: quicErrorCodeToEnvoyRemoteResetReason(error));
runResetCallbacks(source == quic::ConnectionCloseSource::FROM_SELF
? quicErrorCodeToEnvoyLocalResetReason(frame.quic_error_code,
session()->OneRttKeysAvailable())
: quicErrorCodeToEnvoyRemoteResetReason(frame.quic_error_code));
}
quic::QuicSpdyServerStreamBase::OnConnectionClosed(error, source);
quic::QuicSpdyServerStreamBase::OnConnectionClosed(frame, source);
}

void EnvoyQuicServerStream::CloseWriteSide() {
Expand Down
3 changes: 2 additions & 1 deletion source/common/quic/envoy_quic_server_stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ class EnvoyQuicServerStream : public quic::QuicSpdyServerStreamBase,
void OnClose() override;
void OnCanWrite() override;
// quic::QuicSpdyServerStreamBase
void OnConnectionClosed(quic::QuicErrorCode error, quic::ConnectionCloseSource source) override;
void OnConnectionClosed(const quic::QuicConnectionCloseFrame& frame,
quic::ConnectionCloseSource source) override;
void CloseWriteSide() override;

void clearWatermarkBuffer();
Expand Down
Loading

0 comments on commit bb1efe6

Please sign in to comment.