Skip to content

Conversation

@SiiiTschiii
Copy link

@SiiiTschiii SiiiTschiii commented Nov 20, 2025

Introduce a new Proxy-Wasm TCP filter example that demonstrates dynamic routing of TCP connections based on source IP addresses at the TCP stream context (L4). This example showcases application-layer routing decisions without HTTP processing, filling a gap in the existing HTTP-focused examples.

Inspired by the wasmerang project, this example demonstrates advanced TCP routing patterns in Envoy/Istio/K8s environments using WASM filters.

Key Features

  • Source-based routing: Dynamic cluster selection based on source IP last octet (even → egress-router1, odd → egress-router2)
  • TCP stream context: Operates at L4 rather than HTTP layer for protocol-agnostic routing
  • Envoy filter state API: Uses set_envoy_filter_state foreign function with protobuf encoding
  • Complete Docker setup: Includes Docker Compose environment for testing with httpbin.org
  • Comprehensive documentation: Usage examples, expected output, and technical context

Implementation Details

  • Protobuf definitions for Envoy's filter state API with build-time code generation
  • MSRV-compatible dependencies (Rust 1.65) with explicit pinning for CI compatibility
  • Envoy v1.34.1 configuration with dual upstream clusters

Documentation Highlights

  • Links to Proxy-Wasm spec for TCP stream context
  • Explanation of TCP vs HTTP layer routing trade-offs
  • Future enhancement ideas: PROXY protocol support for source-based egress routing in managed K8s environments

This example is useful for scenarios requiring performance-critical or protocol-agnostic routing decisions where application-layer processing should be avoided.

@SiiiTschiii SiiiTschiii force-pushed the SiiiTschiii/example-tcp-re-routing branch from 01cba93 to 0d6580d Compare November 20, 2025 03:43
Copy link
Member

@PiotrSikora PiotrSikora left a comment

Choose a reason for hiding this comment

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

Thanks, this is great real-world example!

@SiiiTschiii SiiiTschiii force-pushed the SiiiTschiii/example-tcp-re-routing branch from ec7f2b2 to 82184ae Compare November 29, 2025 01:26
@SiiiTschiii
Copy link
Author

@PiotrSikora thanks for the review. I believe I addressed all of them.

@SiiiTschiii SiiiTschiii changed the title Add TCP rerouting example with dynamic cluster selection Add TCP routing example with dynamic cluster selection Nov 29, 2025
@SiiiTschiii SiiiTschiii changed the title Add TCP routing example with dynamic cluster selection Add Envoy TCP Routing example demonstrating source-based dynamic cluster selection Nov 29, 2025
Introduce a new Proxy-Wasm TCP filter example that demonstrates dynamic
routing of TCP connections based on source IP addresses. This example
showcases TCP-level filtering, filling a gap in the existing HTTP-focused
examples.

Key features:
- Dynamic cluster selection based on source IP last octet (even/odd)
- Uses Envoy's set_envoy_filter_state foreign function with protobuf encoding
- Includes comprehensive Docker Compose setup for testing
- Full documentation with usage examples and expected output

Implementation details:
- Protobuf definitions for Envoy's filter state API
- Build script for code generation from proto files
- Unit tests for IP parsing and routing logic
- Envoy configuration with dual upstream clusters

Signed-off-by: Christof Gerber <[email protected]>
- Remove trailing whitespace
- Use next_back() instead of last() for better performance

Signed-off-by: Christof Gerber <[email protected]>
- Update log 0.4.27 → 0.4.28
- Update proc-macro2 1.0.101 → 1.0.103
- Update quote 1.0.41 → 1.0.42
- Update unicode-ident 1.0.19 → 1.0.22

Generated by: bazelisk run //bazel/cargo:crates_vendor -- --repin all

Signed-off-by: Christof Gerber <[email protected]>
Pin proc-macro2 and quote in build-dependencies to versions compatible
with Rust 1.65 (the SDK's MSRV). Without these pins, cargo may select
newer versions (e.g., quote 1.0.42) that require Rust 1.68+, causing
CI builds to fail.

This follows best practices by explicitly pinning problematic transitive
dependencies rather than setting rust-version, which is not used by
other examples.

Signed-off-by: Christof Gerber <[email protected]>
- Add Apache 2.0 license header to set_envoy_filter_state.proto
- Remove rust-version field from tcp_rerouting example Cargo.toml
- Keep explicit dependency pins for proc-macro2 and quote to ensure
  Rust 1.65 compatibility

This approach follows the pattern of other examples (no rust-version)
while ensuring MSRV compatibility through explicit dependency pinning
rather than relying on rust-version, which doesn't prevent Cargo from
selecting incompatible dependency versions.

Signed-off-by: Christof Gerber <[email protected]>
Remove examples/tcp_rerouting/src/generated/ from git tracking and
add to .gitignore. Generated code should not be committed as it:
- Can be regenerated from the .proto file via build.rs
- Creates unnecessary diff noise when dependencies update
- Can get out of sync with source

The file is automatically generated during build by prost-build,
so this does not affect functionality.

Signed-off-by: Christof Gerber <[email protected]>
Rename tcp_rerouting to envoy_tcp_routing to:
- Clearly indicate this is an Envoy-specific example
- Use "routing" instead of "rerouting" for better terminology

Changes:
- Renamed directory: examples/tcp_rerouting → examples/envoy_tcp_routing
- Updated package name: proxy-wasm-example-envoy-tcp-routing
- Updated all references in README.md files
- Updated Docker Compose network name and WASM filename
- Updated Envoy config filter names and WASM path
- Updated .gitignore path

Signed-off-by: Christof Gerber <[email protected]>
Remove the statement about most examples focusing on HTTP, as it's
not essential information for the README.

Signed-off-by: Christof Gerber <[email protected]>
Add explanation that the example operates at the TCP stream context
(L4) rather than the HTTP application layer, highlighting its
usefulness for scenarios where application-layer processing should
be avoided.

Signed-off-by: Christof Gerber <[email protected]>
Add links to TCP stream and HTTP stream contexts in the Proxy-Wasm
spec, and clarify that operating at the TCP level is useful for
performance and protocol-agnostic routing decisions.

Signed-off-by: Christof Gerber <[email protected]>
…ure enhancements

- Fix grammar: "In separate terminals" → "In a separate terminal"
- Add consistency: "routes to" → "routes via" in output examples
- Add "Note on Destination Information" section explaining:
  - Hardcoded httpbin.org endpoints in both clusters
  - PROXY protocol for preserving metadata across TCP hops
  - Implementation approach using WASM stream context + Envoy config
- Document future enhancement for source-based egress router use case:
  - Routing via different external IPs (e.g., even vs. odd source IP)
  - Explain conventional network approach (routing tables + IP rules)
  - Note challenges in managed K8s (requires plugins like Multus CNI)
  - Clarify how K8s abstracts layer 3 routing configuration

Signed-off-by: Christof Gerber <[email protected]>
This reverts commit 467e8d6.

The Bazel dependency updates are not related to the envoy_tcp_routing
example, which builds using cargo with wasm32-wasip1 target. The example
has its own dependency pins in Cargo.toml for MSRV compatibility and does
not use the Bazel build system.

Signed-off-by: Christof Gerber <[email protected]>
…ble deps

- Change build target from wasm32-wasip1 to wasm32-wasi for MSRV (1.65) compatibility
- Update docker-compose.yaml to mount wasm32-wasi artifact path
- Pin build dependencies to latest MSRV-compatible versions:
  - prost-build 0.11.9, quote 1.0.41, proc-macro2 1.0 (existing pins)
  - indexmap 2.11.4, home 0.5.5 (pinned transitive deps)
- Update README.md build instructions to reflect new target

The wasm32-wasip1 target is not available in Rust 1.65. By switching to
wasm32-wasi and constraining transitive dependencies that require newer
Rust editions (indexmap 2.12+ needs edition 2024, home 0.5.12+ needs
edition 2024), we ensure the example builds with the project's MSRV.

Signed-off-by: Christof Gerber <[email protected]>
@SiiiTschiii SiiiTschiii force-pushed the SiiiTschiii/example-tcp-re-routing branch from 0e3019b to 1745d75 Compare November 29, 2025 02:48
@SiiiTschiii
Copy link
Author

@PiotrSikora Note on cargo outdated CI Check that is failing

The cargo outdated check in CI currently fails for this example because it runs with the latest stable Rust (1.83) rather than the project's MSRV (1.65). When analyzing available updates, it encounters transitive dependencies like home 0.5.12 which require edition 2024 (not yet stabilized in Rust 1.83).

The example itself builds successfully with MSRV 1.65 because we've pinned the problematic transitive dependencies (indexmap = "=2.11.4", home = "=0.5.5"). However, cargo outdated doesn't respect these pins when checking the crates.io index for newer versions—it attempts to parse manifests of all available versions and fails on edition 2024 crates.

Potential solutions:

  1. Run the cargo outdated CI step with the MSRV toolchain (1.65)
  2. Skip the outdated check for examples that explicitly manage MSRV-constrained dependencies
  3. Document this as a known limitation when maintaining MSRV-compatible examples

The dependency pins are intentional and necessary to maintain MSRV compatibility while still using the latest compatible versions of direct dependencies.

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