Skip to content

HTTP/2 flow-control policies do not reload despite RECU_DYNAMIC #13694

Description

@bneradt

Problem

proxy.config.http2.flow_control.policy_in and policy_out are declared RECU_DYNAMIC and documented as :reloadable:, but HTTP/2 keeps the policy selected at process startup. traffic_ctl config set reports that a restart is not required, and config get reports the new value even though new connections still use the old policy.

Reproduction and observed behavior

I reproduced the inbound case in a local master-based build at 11e11c7 (the branch of #13447, based on 1e884fa). Current master at 804e5e2 still has the same policy initialization and record declarations. The relevant configuration is:

records:
  http2:
    initial_window_size_in: 65535
    max_concurrent_streams_in: 100
    flow_control:
      policy_in: 0
  1. Start ATS and open a fresh TLS/H2 connection. Send the HTTP/2 connection preface and an empty SETTINGS frame; record connection-level WINDOW_UPDATE increments.
  2. Run traffic_ctl config set proxy.config.http2.flow_control.policy_in 1. It says to wait for synchronization and that a restart is not required.
  3. Wait more than 10 seconds, confirm traffic_ctl config get proxy.config.http2.flow_control.policy_in returns 1, and repeat the probe on a new connection.
  4. Persist policy_in: 1 in records.yaml, restart ATS, and repeat the probe.
State Connection WINDOW_UPDATE increments Effective connection receive window
Started with policy 0 none 65,535
Runtime value reports 1 none 65,535
Restarted with policy 1 6,487,965 6,553,500

The restart control distinguishes this from existing connections retaining their original settings. I measured the inbound policy on the wire; the outbound policy uses the same defective initialization pattern described below.

Cause

In Http2::init(), each policy is read through a function-local uint32_t, then copied once to the static Http2FlowControlPolicy member:

uint32_t flow_control_policy_in_int = 0;
RecEstablishStaticConfigUInt32(flow_control_policy_in_int,
                             "proxy.config.http2.flow_control.policy_in");
// validation ...
flow_control_policy_in = static_cast<Http2FlowControlPolicy>(flow_control_policy_in_int);

RecEstablishStaticConfigUInt32 also registers RecLinkConfigUInt32 using the supplied variable's address. The callback therefore retains a pointer to a local variable whose lifetime ends when Http2::init() returns. It does not update the static enum used by HTTP/2. The outbound policy repeats this pattern.

Expected behavior

A configuration update should safely validate and update storage with sufficient lifetime, and new connections should use the new policy. If runtime policy changes are intentionally unsupported, the records and documentation should instead require a restart, without registering callbacks to local variables.

Persisting the value and restarting ATS is the current workaround.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions