Skip to content

net_consomme: decouple control requests from packet processing path - #4378

Open
Daman Mulye (damanm24) wants to merge 4 commits into
microsoft:mainfrom
damanm24:poll_message_2_clean
Open

net_consomme: decouple control requests from packet processing path#4378
Daman Mulye (damanm24) wants to merge 4 commits into
microsoft:mainfrom
damanm24:poll_message_2_clean

Conversation

@damanm24

Copy link
Copy Markdown
Contributor

Currently, consommé control messages are only dequeued/handled when the backend is being polled for network packets. If a guest stops driving the NIC for packets, control requests are never dequeued/handled by consommé.

This PR moves control requests polling to the endpoint control path, so requests continue to make progress independent of packet flows.

Control requests fall into two categories based on whether they require access to queue-owned consommé state.

Requests such as adding static DNS records, creating virtual addresses, and updating network parameters modify broader protocol state. These requests are buffered by the endpoint and applied when it regains ownership of the consommé state, which requires restarting the network queues.

Port bind and unbind requests only modify the TCP or UDP listener tables. They also occur much more frequently than the other control operations. Restarting the queues for every bind or unbind would repeatedly interrupt packet processing and impose a significant throughput penalty, particularly for workloads that frequently create and remove port forwards.

To avoid that cost, the listener tables use a locking mechanism and expose a separate listener-control capability. Bind and unbind requests can therefore be applied directly while the queues continue running. Requests that require broader mutable state still use the deferred queue-restart path.

@damanm24
Daman Mulye (damanm24) requested a review from a team as a code owner September 3, 2026 17:47
Copilot AI lite review requested due to automatic review settings September 3, 2026 17:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It introduces cross-cutting networking/control-path and concurrency changes (new endpoint action flow + shared listener registries) that warrant final human validation beyond automated review.

Pull request overview

This PR changes net_consomme so control requests (e.g., port bind/unbind, state updates) make progress independently of the packet processing path, avoiding stalls when the guest is idle. It introduces a listener-only control capability backed by shared listener tables, while deferring stateful requests until a queue restart can safely apply them.

Changes:

  • Move control-request draining to the endpoint control path (wait_for_endpoint_action) and buffer restart-requiring requests until the next queue start.
  • Add a queue-independent ListenerControl backed by locked TCP/UDP listener registries so frequent bind/unbind operations don’t require restarting queues.
  • Add an end-to-end ttrpc test that validates Consommé host port forwarding bind/unbind behavior.
File summaries
File Description
vmm_tests/vmm_tests/tests/tests/ttrpc.rs Adds an end-to-end ttrpc-driven port-forwarding test (bind, connect/verify banner, unbind/verify refusal).
vm/devices/net/net_consomme/src/resolver.rs Wires the endpoint to accept a generalized request receiver (renamed from port-only channel).
vm/devices/net/net_consomme/src/lib.rs Implements endpoint-side request draining + buffering, introduces listener-control handling, and adds endpoint actions for restart triggering.
vm/devices/net/net_consomme/consomme/src/udp.rs Makes UDP listeners a shared, lock-protected registry and adds a bind/unbind control surface usable outside the packet loop.
vm/devices/net/net_consomme/consomme/src/tcp/tests.rs Updates TCP tests for the new lock-wrapped listener table.
vm/devices/net/net_consomme/consomme/src/tcp.rs Makes TCP listeners a shared, lock-protected registry and adds a bind/unbind control surface usable outside the packet loop.
vm/devices/net/net_consomme/consomme/src/lib.rs Introduces a public ListenerControl abstraction to manage TCP/UDP listeners without queue-owned state.
vm/devices/net/net_backend_resources/src/lib.rs Expands ConsommeRequest to include DNS-record and virtual-address operations and adds a serializable DNS record config.
Review details

Suppressed comments (1)

vm/devices/net/net_consomme/src/lib.rs:276

  • ConsommeMessageError still defines Bind and DnsRecord variants, but the updated ConsommeControl methods now surface bind/unbind/DNS failures via Remote(mesh::error::RemoteError) instead (no in-file construction of those variants, and no uses across the repo). Keeping unused public variants here is misleading for callers and makes it harder to reason about which errors can actually be returned.
/// Error type returned from some dynamic update functions like bind_port.
#[derive(Debug, Error)]
pub enum ConsommeMessageError {
    /// Communication error with running instance.
    #[error("communication error")]
  • Files reviewed: 8/8 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown

Copilot AI review requested due to automatic review settings September 11, 2026 17:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved TCP refresh, unnecessary queue restart, and process-cleanup issues remain.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (2)

Previously missed (1) — in code that hasn't changed since the last review.

vmm_tests/vmm_tests/tests/tests/ttrpc.rs:1229

  • This test owns a raw PolledChild, but std::process::Child does not kill the process when dropped. Any ?/panic before the explicit Quit and wait below can therefore leave an OpenVMM VM and ttrpc socket running, interfering with later tests. Use the OpenvmmChild guard defined in this file, as launch_openvmm does.

vm/devices/net/net_consomme/src/lib.rs:543

  • drain_channels returns false when a bind or unbind is handled through listener_control, but this result is discarded and every completed request is reported as RestartRequired. That still stops and restarts the queues for each listener operation, defeating the decoupling and throughput goal; only queue-owned requests should complete this future with RestartRequired.
        EndpointAction::RestartRequired
  • Files reviewed: 9/9 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread vm/devices/net/net_consomme/consomme/src/tcp.rs
Copilot AI review requested due to automatic review settings September 11, 2026 17:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Critical listener-lock starvation and additional API, cleanup, and regression-test issues remain unresolved.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (4)

Previously missed (1) — in code that hasn't changed since the last review.

vmm_tests/vmm_tests/tests/tests/ttrpc.rs:1229

  • This test constructs a raw PolledChild, but std::process::Child is not killed when dropped. Any failure or panic after this line, including the unwraps before the explicit teardown, can leave OpenVMM running and holding the ttrpc socket for later tests. Use the existing OpenvmmChild guard used by launch_openvmm so all error paths kill and reap the process.

vm/devices/net/net_consomme/src/lib.rs:310

  • Adding Sync here unnecessarily tightens this public callback contract. StateUpdateRequest is transported through a mesh channel and the channel is explicitly Sync even for non-Sync payloads such as Cell<T> (see support/mesh/mesh_channel_core/src/mpsc.rs:73-75,927-932), so existing callers with a Send-but-not-Sync captured value now fail to compile even though the callback is moved to and invoked by one consumer. Keep the previous Send bound unless shared concurrent invocation is required.
pub type ConsommeParamsUpdateFn = Box<dyn Fn(&mut ConsommeParams) + Send + Sync>;

vm/devices/net/net_consomme/src/lib.rs:306

  • This changes the public ConsommeControl error contract: bind_port, unbind_port, and add_dns_record now route failures through RemoteError, so the existing typed Bind and DnsRecord variants are no longer returned (the only constructors are now in the enum definition). ConsommeControl is the in-process API created by new_dynamic, so callers matching those variants will silently stop handling bind/DNS failures; preserve typed errors for that path or make this breaking change explicit and remove/update the obsolete variants.
    /// Error from a remote operation on the endpoint.
    #[error(transparent)]
    Remote(mesh::error::RemoteError),

vmm_tests/vmm_tests/tests/tests/ttrpc.rs:1354

  • The bind request is sent while the guest is actively running udhcpc and the nc listener, so packet-driven queue polls are occurring. The old implementation could therefore still drain this request when packet processing happened, allowing this test to pass without exercising the new endpoint control path during an idle NIC. Add an idle-guest phase (or explicitly wait for packet activity to stop) and issue the control request with a bounded timeout to cover the regression.
                    vmservice::Vm::ModifyResource,
  • Files reviewed: 9/9 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment on lines +368 to +376
let mut listeners = self.inner.udp.listeners.lock();
for listener in listeners.values_mut() {
listener.poll_listener(
cx,
&mut self.inner.state,
self.client,
&self.inner.udp.connections,
);
}
@github-actions

Copy link
Copy Markdown

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants