Proxy-Wasm plugin that dynamically routes connections to different upstream clusters based on the source IP address.
This example operates at the TCP stream context (L4) rather than the HTTP application layer, making it useful for use cases where application-layer processing should be avoided for performance or protocol-agnostic routing decisions.
This example is inspired by the wasmerang project, which demonstrates advanced TCP routing patterns in Envoy/Istio/K8s using Wasm filters.
This example demonstrates how to build a Proxy-Wasm plugin that:
- Inspects incoming TCP connections
- Retrieves the source IP address
- Routes traffic to different upstream clusters based on a custom logic:
- Even last octet → routes to
egress-router1 - Odd last octet → routes to
egress-router2
- Even last octet → routes to
This plugin uses Envoy's set_envoy_filter_state foreign function to dynamically override the default TCP proxy cluster at runtime,
requiring proper protobuf encoding via the included set_envoy_filter_state.proto file.
$ cargo build --target wasm32-wasip1 --releaseThis example can be run with docker compose
and has a matching Envoy configuration.
$ docker compose upSend HTTP request to envoy:10000/ip using client IP 127.22.0.10:
$ docker run --rm -it --network envoy_tcp_routing_envoy-tcp-routing --ip 172.22.0.10 curlimages/curl curl http://envoy:10000/ip -H "Host: httpbin.org"
{
"origin": "172.22.0.3"
}Expected Envoy logs:
[...] [TCP WASM] Routed source 172.22.0.10:42148 to egress-router1
[...] src=172.22.0.10:42148 via=172.22.0.3:10000 dst=172.22.0.2:8080 (egress-router1)Send HTTP request to envoy:10000/ip using client IP 127.22.0.11:
$ docker run --rm -it --network envoy_tcp_routing_envoy-tcp-routing --ip 172.22.0.11 curlimages/curl curl http://envoy:10000/ip -H "Host: httpbin.org"
{
"origin": "172.22.0.3"
}Expected Envoy logs:
[...] [TCP WASM] Routed source 172.22.0.11:35736 to egress-router2
[...] src=172.22.0.11:35736 via=172.22.0.3:10000 dst=172.22.0.2:8080 (egress-router2)The access log confirms that traffic is routed to the expected cluster (egress-router1 for even IPs, egress-router2 for odd IPs).