http2: add keepalive observer hook #44299
Envoy/Checks (failure)
Check has finished
Details
Check run finished (failure ❌)
The check run can be viewed here:
Envoy/Checks (pr/44299/main@8eab6d2)
Check started by
Request (pr/44299/main@8eab6d2)
@roll-no-21
8eab6d2 #44299
merge main@c33796b
http2: add keepalive observer hook
Expose HTTP/2 keepalive send and ack events through a small observer interface so higher layers can react to codec keepalives without coupling reverse-tunnel logic into the core codec.
Commit Message: http2: add keepalive observer hook
Additional Description:Today, higher-level extensions (e.g. reverse tunnel lifecycle logging) that
need to react to HTTP/2 keepalive events must either parse raw HTTP/2 frames
from network filter buffers or embed extension-specific logic directly in the
codec. Both approaches are undesirable — the first is fragile and works against
Envoy's layered architecture, and the second couples domain logic into core
protocol code.This PR introduces a lightweight
KeepaliveObserverinterface that the HTTP/2
codec queries via connection FilterState on keepalive ping send and ack events.
If no observer is registered, the codec does nothing (null-check only). If an
observer is present, it receives callbacks with the connection'sStreamInfo
and the PING opaque data.New interface (
keepalive_observer.h)
KeepaliveObserverextendsStreamInfo::FilterState::Objectand defines:
onKeepalivePingSent(StreamInfo::StreamInfo&, uint64_t opaque_data)— called
immediately after the codec submits an HTTP/2 PING frame via the adapter.onKeepalivePingAck(StreamInfo::StreamInfo&, uint64_t opaque_data)— called
when the codec receives a PING ACK frame from the peer.pendingKeepalivePingId()— returns the opaque data of the outstanding PING,
if any, allowing the observer to correlate send/ack pairs.The observer is looked up from FilterState under the key
envoy.http2.keepalive_observer.Codec changes (
codec_impl.cc)
sendKeepalive(): afteradapter_->SubmitPing(), checks for an observer
and callsonKeepalivePingSent()(~3 lines added).onPing()(ACK path): after logging the PING ACK, checks for an observer
and callsonKeepalivePingAck()(~3 lines added).- New private helper
keepaliveObserver()retrieves the observer from
connection_.streamInfo().filterState()(~6 lines).Usage pattern
An upstream network filter sets a
KeepaliveObserverimplementation in
the connection's FilterState duringonNewConnection(). The codec picks it
up automatically on the next keepalive cycle. Example:filter_state.setData( kKeepaliveObserverFilterStateKey, std::make_shared<MyObserverImpl>(), StreamInfo::FilterState::StateType::ReadOnly, StreamInfo::FilterState::LifeSpan::Connection); No observer registered → zero overhead beyond a null-check per ping event. Risk Level: Low — opt-in via FilterState; no behavioral change when no observer is registered. The null-check in the keepalive hot path is negligible. Testing: New ConnectionKeepaliveObserver test in codec_impl_test.cc validates that onKeepalivePingSent and onKeepalivePingAck are called in correct sequence with proper timer interactions using a MockKeepaliveObserver. Docs Changes: N/A Release Notes: N/A Platform Specific Features: N/A
Environment
Request variables
| Key | Value |
|---|---|
| ref | 281511f |
| sha | 8eab6d2 |
| pr | 44299 |
| base-sha | c33796b |
| actor | |
| message | http2: add keepalive observer hook... |
| started | 1775548661.206039 |
| target-branch | main |
| trusted | false |
Build image
Container image/s (as used in this CI run)
| Key | Value |
|---|---|
| default | docker.io/envoyproxy/envoy-build:86873047235e9b8232df989a5999b9bebf9db69c |
| mobile | docker.io/envoyproxy/envoy-build:mobile-86873047235e9b8232df989a5999b9bebf9db69c |
Version
Envoy version (as used in this CI run)
| Key | Value |
|---|---|
| major | 1 |
| minor | 38 |
| patch | 0 |
| dev | true |