When microservices call each other through a service mesh, traffic lane routing depends on a header that travels through the entire call chain. If your application already propagates a custom trace ID that differs from the header used for lane selection, you need to configure the lane group with two separate headers -- one for routing at the gateway, and one for maintaining lane affinity across inter-service calls.
This walkthrough sets up permissive-mode traffic lanes in this two-header scenario and verifies that fallback routing works correctly.
Before you begin, read Use traffic lanes in permissive mode to manage end-to-end traffic.
How it works
Two headers serve distinct purposes:
| Header | Purpose | Propagation |
|---|---|---|
x-asm-prefer-tag | Routing header -- the ASM gateway reads this header to select the target lane. | Set by the client. Does not need to be propagated between services. |
my-trace-id | Trace pass-through header -- ASM uses this header to maintain lane affinity across inter-service calls. | Must be propagated by every service in the chain. |
The routing header determines which lane a request enters at the gateway. The trace header maintains lane context as services call each other. Without trace header propagation, downstream calls lose lane affinity and route to the wrong version.
Header propagation is an application-level responsibility. Each service must read the incoming my-trace-id header and include it in all outbound requests. The Envoy sidecar does not propagate trace headers automatically.
Traffic flow and fallback
The following example uses three lanes (s1, s2, s3) and three services (mocka, mockb, mockc):
| Lane | Services | Version |
|---|---|---|
| s1 (baseline) | mocka, mockb, mockc | v1 |
| s2 | mocka, mockc | v2 |
| s3 | mockb | v3 |
When a request with x-asm-prefer-tag: s2 enters the gateway:
The gateway routes the request to mocka v2 in lane s2.
mocka calls mockb. Since mockb does not exist in s2, ASM falls back to mockb v1 in the baseline lane s1.
mockb calls mockc. Because the trace header
my-trace-idcarries the lane context, ASM routes the request back to mockc v2 in lane s2.
This fallback mechanism keeps the call chain intact even when a lane contains only a subset of services.
Prerequisites
Before you begin, make sure that you have:
An ASM instance with an associated ACK cluster
The mocka, mockb, and mockc sample services deployed in the default namespace
Services configured to propagate the
my-trace-idrequest header through the call chain
Step 1: Create a lane group and lanes
Create a lane group
Log on to the ASM console. In the left-side navigation pane, choose Service Mesh > Mesh Management.
On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose Traffic Management Center > Traffic Lane.
On the Traffic Lane page, click Create Swimlane Group. In the Create Swimlane Group panel, configure the following parameters and click OK.
| Parameter | Value |
|---|---|
| Name of swim lane group | test |
| Istio gateway for an ingress gateway | Select ingressgateway. |
| Lane Mode | Select Permissive Mode. |
| Pass-through Mode of Trace Context | Select Pass Through Trace ID. |
| Trace ID Request Header | Enter my-trace-id. The sample services propagate this header through the call chain. |
| Routing Request Header | Enter x-asm-prefer-tag. The ASM gateway uses this header to route traffic to lanes. |
| Swimlane Services | Select the ACK cluster from the Kubernetes Clusters drop-down list and select default from the Namespace drop-down list. Select mocka, mockb, and mockc from the service list and click the |
After the lane group is created, ASM automatically generates a traffic label for each service. To view it, choose Traffic Management Center > TrafficLabel in the left-side navigation pane.
Create lanes
In the Traffic Rule Definition section of the Traffic Lane page, click Create swimlanes.
In the Create swimlanes dialog box, configure the following parameters and click OK.
| Parameter | Value |
|---|---|
| Swimlane Name | Create three lanes: s1, s2, and s3. |
| Configure Service Tag | Label Key: Select ASM_TRAFFIC_TAG. Label Value: Select v1 for s1, v2 for s2, and v3 for s3. |
| Add Service | s1: Select mocka(default), mockb(default), and mockc(default). s2: Select mocka(default) and mockc(default). s3: Select mockb(default). |
The following figure shows the s1 lane configuration.

After the three lanes are created, they appear in the Traffic Rule Definition section.

The first lane created in a lane group is the baseline lane by default. When a service does not exist in the target lane, traffic falls back to the baseline lane. To change the baseline lane, see Change the baseline lane.
ASM automatically generates a destination rule and a virtual service for each service in the lanes. To view them, choose Traffic Management Center > DestinationRule or VirtualService in the left-side navigation pane.
Create ingress traffic rules
In the Traffic Rule Definition section, find the lane and click Ingress traffic rules in the Actions column.
In the Add drainage rule dialog box, configure the following parameters and click OK.
All services in this example use /mock as the inbound request path. Configure the same traffic routing rule for each lane.
| Parameter | Value |
|---|---|
| Ingress service | Select mocka.default.svc.cluster.local. |
| Ingress traffic rules | Set Name to r1, r2, and r3 for the three lanes respectively. Set realm name to *. |
| Matching request URI | Set Method to Exact and Content to /mock. |
The following figure shows the traffic routing rule for the s1 lane.

After traffic routing rules are created, they appear in the Traffic Rule Definition section.

Step 2: Verify the traffic lanes
Get the public IP address of the ingress gateway. For more information, see Obtain the IP address of the ASM ingress gateway.
Set the gateway IP as an environment variable. Replace
<gateway-ip>with the actual IP address.export ASM_GATEWAY_IP=<gateway-ip>Send test requests to each lane and verify the output.
Test lane s1 (baseline):
for i in {1..100}; do curl -H 'x-asm-prefer-tag: s1' -H 'my-trace-id: x000'$i \ http://${ASM_GATEWAY_IP}/mock echo '' sleep 1 doneExpected output:
-> mocka(version: v1, ip: 172.17.0.54)-> mockb(version: v1, ip: 172.17.0.129)-> mockc(version: v1, ip: 172.17.0.130)All three services are in lane s1, so traffic stays within the baseline lane.
Test lane s2:
for i in {1..100}; do curl -H 'x-asm-prefer-tag: s2' -H 'my-trace-id: x000'$i \ http://${ASM_GATEWAY_IP}/mock echo '' sleep 1 doneExpected output:
-> mocka(version: v2, ip: 172.17.0.9)-> mockb(version: v1, ip: 172.17.0.129)-> mockc(version: v2, ip: 172.17.0.128)mocka (v2) and mockc (v2) are served from lane s2. mockb does not exist in s2, so it falls back to mockb (v1) in the baseline lane s1. After the fallback, mockc is still correctly routed to s2 because the
my-trace-idheader preserves lane context through the call chain.Test lane s3:
for i in {1..100}; do curl -H 'x-asm-prefer-tag: s3' -H 'my-trace-id: x000'$i \ http://${ASM_GATEWAY_IP}/mock echo '' sleep 1 doneExpected output:
mocka(version: v1, ip: 192.168.1.103)-> mockb(version: v3, ip: 192.168.1.120)-> mockc(version: v1, ip: 192.168.1.105)mockb (v3) is served from lane s3. mocka and mockc do not exist in s3, so they fall back to v1 in the baseline lane s1.
Change the baseline lane
You can change the baseline lane only in a permissive-mode lane group with at least two lanes.
Log on to the ASM console. In the left-side navigation pane, choose Service Mesh > Mesh Management.
On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose Traffic Management Center > Traffic Lane.
On the Traffic Lane page, click the tab of the target lane group. In the Traffic Rule Definition section, click the
icon next to Baseline Lane.Select the new baseline lane and click confirm edit.
What's next
Use traffic lanes in permissive mode to manage end-to-end traffic -- Learn about permissive-mode traffic lanes in detail.