hashing_test - openconfig/featureprofiles GitHub Wiki
Verify Dataplane Hashing (ECMP, WCMP, and Intra-LAG) using physical loopback ports across multiple Network Instances (DEFAULT, SELF_SITE, EGRESS).
The test suite validates hashing uniformity, weight enforcement, and anti-polarization across two traffic profiles:
- Plain IPv4/IPv6 Traffic (5-tuple entropy).
- IPnIP Encapsulated Traffic (Outer IP static, inner 5-tuple entropy).
The testbed requires a DUT (dut_8_loop_2_ate.testbed) and an ATE.
The topology utilizes physical loopback pairs to route and verify traffic across multiple hashing stages on the DUT without relying on software drop loops.
graph LR
subgraph ATE ["ATE (Traffic Generator)"]
ate2["Port 1 (ixia2) - Ingress"]
ate1["Port 10 (ixia1) - Egress"]
end
subgraph DUT ["DUT (dut_8_loop_2_ate)"]
inPort["lc2_p10 (Ingress Port 1)"]
egPort["lc2_p9 (Egress Port 10)"]
subgraph PhysLoops ["Physical Loopbacks (8 Loops)"]
l1["lc1_p3 <--> lc2_p3 (Loop 1: Ingress -> SelfSite)"]
l2["lc1_p4 <--> lc2_p4 (Loop 2: Ingress -> SelfSite)"]
l3["lc1_p5 <--> lc2_p5 (Loop 3: Ingress -> Egress)"]
l4["lc1_p6 <--> lc2_p6 (Loop 4: Ingress -> Egress)"]
l5["lc1_p1 <--> lc2_p1 (Loop 5: SelfSite -> Egress)"]
l6["lc1_p8 <--> lc2_p8 (Loop 6: SelfSite -> Egress)"]
l7["lc1_p7 <--> lc2_p7 (Loop 7: SelfSite -> Egress)"]
l8["lc1_p2 <--> lc2_p2 (Loop 8: SelfSite -> Egress)"]
end
end
ate2 <-->|Ingress Link| inPort
egPort <-->|Egress Link| ate1
The test utilizes all 8 physical loopback cables and 2 ATE links on dut_8_loop_2_ate.testbed:
-
Physical Loopbacks:
-
Loop 1 (Port 2):
lc1_p3(Ingress) <->lc2_p3(SelfSite) -
Loop 2 (Port 3):
lc1_p4(Ingress) <->lc2_p4(SelfSite) -
Loop 3 (Port 4):
lc1_p5(Ingress) <->lc2_p5(Egress) -
Loop 4 (Port 5):
lc1_p6(Ingress) <->lc2_p6(Egress) -
Loop 5 (Port 6):
lc1_p1(SelfSite) <->lc2_p1(Egress) -
Loop 6 (Port 7):
lc1_p8(SelfSite) <->lc2_p8(Egress) -
Loop 7 (Port 8):
lc1_p7(SelfSite) <->lc2_p7(Egress) -
Loop 8 (Port 9):
lc1_p2(SelfSite) <->lc2_p2(Egress)
-
Loop 1 (Port 2):
-
ATE Connections:
-
ATE Ingress Port 1 (
ixia2) connects to DUT Port lc2_p10 (Ingress source). -
ATE Egress Port 10 (
ixia1) connects to DUT Port lc2_p9 (Egress sink).
-
ATE Ingress Port 1 (
All test scenarios are executed against the following two traffic profiles:
- Header Structure: Standard Ethernet + IPv4/IPv6 + UDP/TCP.
-
Entropy Generation:
- Destination IP: Random within target subnet
198.51.100.0/24. - Source IP: Incrementing / pseudo-random addresses across a /16 range.
- L4 Ports: Source and Destination UDP ports incremented across 1024–65535.
- Destination IP: Random within target subnet
- Verification: Evaluates native 5-tuple hash distribution across member next-hops.
- Header Structure: Outer IPv4 Header + Inner IPv4 Header + UDP Payload.
-
Outer Header:
- Source IP: Static
10.10.10.1. - Destination IP: Incrementing across
172.16.0.1to172.16.0.254(count 254).
- Source IP: Static
- Inner Header: 5-tuple varied IPv4 + UDP packets (1,009 src IPs, 1,013 dst IPs, 1,019 src UDP ports, 1,021 dst UDP ports).
- Verification: Verifies that the DUT hashing engine parses and computes hash keys from both outer and inner packet headers, ensuring uniform distribution without tunnel polarization.
The acceptable hashing distribution across any set of next-hops or LAG member links is defined with a
Examples:
- Expected 20.00% (1/5 share)
$\rightarrow$ Acceptable Range: 19.60% to 20.40% - Expected 33.33% (3-wide equal)
$\rightarrow$ Acceptable Range: 32.66% to 34.00% - Expected 60.00% (6/10 weight)
$\rightarrow$ Acceptable Range: 58.80% to 61.20% - Expected 14.28% (7-member LAG)
$\rightarrow$ Acceptable Range: 14.00% to 14.57% - Expected 42.86% (3:2:2 weight)
$\rightarrow$ Acceptable Range: 42.00% to 43.71%
Verifies end-to-end dataplane hashing across DEFAULT (Ingress), SELF_SITE, and EGRESS network instances using an 8-loop topology across two sub-cases:
-
Ingress VRF (
DEFAULT): Evaluates 4-way WCMP (4:3:2:1 weights) across:-
Port 2 (
lc1_p3-> SelfSite): Weight 4 (40.0%) -
Port 3 (
lc1_p4-> SelfSite): Weight 3 (30.0%) -
Port 4 (
lc1_p5-> Egress): Weight 2 (20.0%) -
Port 5 (
lc1_p6-> Egress): Weight 1 (10.0%) Total weight: 10. Split is 70% toSELF_SITE(Ports 2 & 3) and 30% direct toEGRESS(Ports 4 & 5).
-
Port 2 (
-
SelfSite VRF (
SELF_SITE): Receives 70% of traffic. Evaluates 4-way ECMP (1:1:1:1 equal weight) across:-
Port 6 (
lc1_p1-> Egress): 17.5% of total traffic (25% of SelfSite share) -
Port 7 (
lc1_p8-> Egress): 17.5% of total traffic (25% of SelfSite share) -
Port 8 (
lc1_p7-> Egress): 17.5% of total traffic (25% of SelfSite share) -
Port 9 (
lc1_p2-> Egress): 17.5% of total traffic (25% of SelfSite share)
-
Port 6 (
-
Egress VRF (
EGRESS): Recombines all 6 forwarded streams:- Direct from Ingress: Port 4 (20%), Port 5 (10%)
- Indirect via SelfSite: Ports 6, 7, 8, 9 (17.5% each)
Total arriving: 100%. All forwarded out Port 10 (
lc2_p9) to ATE Egress (ixia1).
graph TD
Ixia["ATE Ingress: Port 1 (ixia2)"] --> IngressPort1["Ingress: Port 1 (lc2_p10)"]
subgraph IngressVRF ["Ingress VRF (NHG_01: 4:3:2:1 WCMP)"]
IngressPort1 -->|"40% (Weight 4)"| IngressP2["Port 2 (lc1_p3)"]
IngressPort1 -->|"30% (Weight 3)"| IngressP3["Port 3 (lc1_p4)"]
IngressPort1 -->|"20% (Weight 2)"| IngressP4["Port 4 (lc1_p5)"]
IngressPort1 -->|"10% (Weight 1)"| IngressP5["Port 5 (lc1_p6)"]
end
IngressP2 -->|"Loop 1 (40%)"| SelfSiteP2["SelfSite: Port 2 (lc2_p3)"]
IngressP3 -->|"Loop 2 (30%)"| SelfSiteP3["SelfSite: Port 3 (lc2_p4)"]
IngressP4 -->|"Loop 3 (20%)"| EgressP4["Egress: Port 4 (lc2_p5)"]
IngressP5 -->|"Loop 4 (10%)"| EgressP5["Egress: Port 5 (lc2_p6)"]
subgraph SelfSiteVRF ["SelfSite VRF (NHG_02: 1:1:1:1 ECMP - 70% Share)"]
SelfSiteP2 -.->|ECMP| SelfSiteP6["Port 6 (lc1_p1): 17.5%"]
SelfSiteP2 -.->|ECMP| SelfSiteP7["Port 7 (lc1_p8): 17.5%"]
SelfSiteP2 -.->|ECMP| SelfSiteP8["Port 8 (lc1_p7): 17.5%"]
SelfSiteP2 -.->|ECMP| SelfSiteP9["Port 9 (lc1_p2): 17.5%"]
SelfSiteP3 -.->|ECMP| SelfSiteP6
SelfSiteP3 -.->|ECMP| SelfSiteP7
SelfSiteP3 -.->|ECMP| SelfSiteP8
SelfSiteP3 -.->|ECMP| SelfSiteP9
end
SelfSiteP6 -->|"Loop 5 (17.5%)"| EgressP6["Egress: Port 6 (lc2_p1)"]
SelfSiteP7 -->|"Loop 6 (17.5%)"| EgressP7["Egress: Port 7 (lc2_p8)"]
SelfSiteP8 -->|"Loop 7 (17.5%)"| EgressP8["Egress: Port 8 (lc2_p7)"]
SelfSiteP9 -->|"Loop 8 (17.5%)"| EgressP9["Egress: Port 9 (lc2_p2)"]
subgraph EgressVRF ["Egress VRF (6-Stream Arrival)"]
EgressP4 --> EgressOut["Port 10 (lc2_p9)"]
EgressP5 --> EgressOut
EgressP6 --> EgressOut
EgressP7 --> EgressOut
EgressP8 --> EgressOut
EgressP9 --> EgressOut
end
EgressOut --> ATE_Egress["ATE Egress: Port 10 (ixia1)"]
-
Ingress VRF (
DEFAULT): Evaluates 4-way ECMP (1:1:1:1 equal weight) across Ports 2, 3, 4, 5 (25.0% each). Total weight: 4. Split is 50% toSELF_SITE(Ports 2 & 3) and 50% toEGRESS(Ports 4 & 5). -
SelfSite VRF (
SELF_SITE): Receives 50% of traffic. Evaluates 4-way ECMP (1:1:1:1) across Ports 6, 7, 8, 9 (12.5% of total traffic each). -
Egress VRF (
EGRESS): Recombines all 6 streams:- Direct from Ingress: Port 4 (25%), Port 5 (25%)
- Indirect via SelfSite: Ports 6, 7, 8, 9 (12.5% each)
Total arriving: 100%. All forwarded out Port 10 (
lc2_p9) to ATE Egress (ixia1).
graph TD
Ixia["ATE Ingress: Port 1 (ixia2)"] --> IngressPort1["Ingress: Port 1 (lc2_p10)"]
subgraph IngressVRF_ECMP ["Ingress VRF (NHG_01: 1:1:1:1 ECMP)"]
IngressPort1 -->|"25% (Weight 1)"| IngressP2_e["Port 2 (lc1_p3)"]
IngressPort1 -->|"25% (Weight 1)"| IngressP3_e["Port 3 (lc1_p4)"]
IngressPort1 -->|"25% (Weight 1)"| IngressP4_e["Port 4 (lc1_p5)"]
IngressPort1 -->|"25% (Weight 1)"| IngressP5_e["Port 5 (lc1_p6)"]
end
IngressP2_e -->|"Loop 1 (25%)"| SelfSiteP2_e["SelfSite: Port 2 (lc2_p3)"]
IngressP3_e -->|"Loop 2 (25%)"| SelfSiteP3_e["SelfSite: Port 3 (lc2_p4)"]
IngressP4_e -->|"Loop 3 (25%)"| EgressP4_e["Egress: Port 4 (lc2_p5)"]
IngressP5_e -->|"Loop 4 (25%)"| EgressP5_e["Egress: Port 5 (lc2_p6)"]
subgraph SelfSiteVRF_ECMP ["SelfSite VRF (NHG_02: 1:1:1:1 ECMP - 50% Share)"]
SelfSiteP2_e -.->|ECMP| SelfSiteP6_e["Port 6 (lc1_p1): 12.5%"]
SelfSiteP2_e -.->|ECMP| SelfSiteP7_e["Port 7 (lc1_p8): 12.5%"]
SelfSiteP2_e -.->|ECMP| SelfSiteP8_e["Port 8 (lc1_p7): 12.5%"]
SelfSiteP2_e -.->|ECMP| SelfSiteP9_e["Port 9 (lc1_p2): 12.5%"]
SelfSiteP3_e -.->|ECMP| SelfSiteP6_e
SelfSiteP3_e -.->|ECMP| SelfSiteP7_e
SelfSiteP3_e -.->|ECMP| SelfSiteP8_e
SelfSiteP3_e -.->|ECMP| SelfSiteP9_e
end
SelfSiteP6_e -->|"Loop 5 (12.5%)"| EgressP6_e["Egress: Port 6 (lc2_p1)"]
SelfSiteP7_e -->|"Loop 6 (12.5%)"| EgressP7_e["Egress: Port 7 (lc2_p8)"]
SelfSiteP8_e -->|"Loop 7 (12.5%)"| EgressP8_e["Egress: Port 8 (lc2_p7)"]
SelfSiteP9_e -->|"Loop 8 (12.5%)"| EgressP9_e["Egress: Port 9 (lc2_p2)"]
subgraph EgressVRF_ECMP ["Egress VRF (6-Stream Arrival)"]
EgressP4_e --> EgressOut_e["Port 10 (lc2_p9)"]
EgressP5_e --> EgressOut_e
EgressP6_e --> EgressOut_e
EgressP7_e --> EgressOut_e
EgressP8_e --> EgressOut_e
EgressP9_e --> EgressOut_e
end
EgressOut_e --> ATE_Egress_e["ATE Egress: Port 10 (ixia1)"]
-
Sub-case 1.1 (WCMP 4:3:2:1 Expected):
-
Stage 1 (Ingress): Port 2: 40.0%, Port 3: 30.0%, Port 4: 20.0%, Port 5: 10.0% (acceptable:
$\pm2%$ relative). - Stage 2 (SelfSite): Ports 6, 7, 8, 9: 25.0% each of SelfSite volume.
- Stage 3 (Egress Multi-Stream): Port 4 (20.0%), Port 5 (10.0%), Ports 6, 7, 8, 9 (17.5% each).
- Stage 4 (ATE Arrival): 100% full arrival on ATE Port 10 (0 packet loss).
-
Stage 1 (Ingress): Port 2: 40.0%, Port 3: 30.0%, Port 4: 20.0%, Port 5: 10.0% (acceptable:
-
Sub-case 1.2 (ECMP 1:1:1:1 Expected):
-
Stage 1 (Ingress): Ports 2, 3, 4, 5: 25.0% each (acceptable:
$\pm2%$ relative). - Stage 2 (SelfSite): Ports 6, 7, 8, 9: 25.0% each of SelfSite volume.
- Stage 3 (Egress Multi-Stream): Port 4 (25.0%), Port 5 (25.0%), Ports 6, 7, 8, 9 (12.5% each).
- Stage 4 (ATE Arrival): 100% full arrival on ATE Port 10 (0 packet loss).
-
Stage 1 (Ingress): Ports 2, 3, 4, 5: 25.0% each (acceptable:
-
Traffic Profiles: Execute for Plain IP and IPnIP Encap.
Verifies traffic load balancing across member links within a single Link Aggregation Group (LAG). Traffic received on the Ingress interface is looked up in the TRANSIT VRF and routed to a single Next-Hop consisting of a 7-member LAG bundle.
graph TD
Ingress["ATE Ingress: Port 2 (ixia2)"] --> IngressPort["DUT Ingress: lc2_p10"]
IngressPort --> DefaultVRF["Default VRF (Loop 1 -> Transit)"]
DefaultVRF --> TransitVRF["Transit VRF"]
subgraph SingleNH ["Single Next-Hop: 7-Member LAG"]
TransitVRF --> M1["Member Port 1: ~14.28%"]
TransitVRF --> M2["Member Port 2: ~14.28%"]
TransitVRF --> M3["Member Port 3: ~14.28%"]
TransitVRF --> M4["Member Port 4: ~14.28%"]
TransitVRF --> M5["Member Port 5: ~14.28%"]
TransitVRF --> M6["Member Port 6: ~14.28%"]
TransitVRF --> M7["Member Port 7: ~14.28%"]
end
SingleNH --> EgressVRF["Egress VRF"] --> EgressPort["DUT Egress: lc2_p9"] --> Egress["ATE Egress (ixia1)"]
-
Expected Distribution: Uniform distribution across all 7 active member links:
- Per-Member Expected: ~14.28% (acceptable range: 14.00% – 14.57%).
- Traffic Profiles: Execute for Plain IP and IPnIP Encap.
Assesses the ability of the dataplane hashing engine to handle asymmetric next-hop capacities and verifies that software-programmed weights either align with or override physical member link counts.
The TRANSIT VRF is configured with 3 Next-Hops having unequal member link capacities:
- LAG A: 3 member links.
- LAG B: 2 member links.
- LAG C: 2 member links.
graph TD
TransitVRF["Transit VRF (3 Next-Hops with Asymmetric Capacity)"]
subgraph AsymmetricPaths ["3 Next-Hops (Unequal Members)"]
TransitVRF -->|LAG A| LagA["LAG A: 3 Member Links"]
TransitVRF -->|LAG B| LagB["LAG B: 2 Member Links"]
TransitVRF -->|LAG C| LagC["LAG C: 2 Member Links"]
end
LagA --> EgressVRF["Egress VRF"]
LagB --> EgressVRF
LagC --> EgressVRF
EgressVRF --> Egress["ATE Egress (ixia1)"]
- Goal: Validates proportional distribution when weights align with physical link capacity.
-
gRIBI Programming: Program NHG with weights
3 : 2 : 2matching the member counts of LAG A, LAG B, and LAG C. -
Expected Distribution:
- LAG A (weight 3): ~42.86% (acceptable range: 42.00% – 43.71%).
- LAG B (weight 2): ~28.57% (acceptable range: 28.00% – 29.14%).
- LAG C (weight 2): ~28.57% (acceptable range: 28.00% – 29.14%).
- Traffic Profiles: Execute for Plain IP and IPnIP Encap.
- Goal: Validates that software-configured weights strictly override physical underlying capacity.
-
gRIBI Programming: Program NHG with uniform weights
1 : 1 : 1across LAG A, LAG B, and LAG C. -
Expected Distribution:
- LAG A (weight 1): ~33.33% (acceptable range: 32.66% – 34.00%).
- LAG B (weight 1): ~33.33% (acceptable range: 32.66% – 34.00%).
- LAG C (weight 1): ~33.33% (acceptable range: 32.66% – 34.00%).
- Traffic Profiles: Execute for Plain IP and IPnIP Encap.
{
"interfaces": {
"interface": [
{
"config": {
"enabled": true,
"name": "ae1",
"type": "ieee8023adLag"
},
"name": "ae1"
},
{
"config": {
"enabled": true,
"name": "ae2",
"type": "ieee8023adLag"
},
"name": "ae2"
},
{
"config": {
"enabled": true,
"name": "eth1",
"type": "ethernetCsmacd"
},
"ethernet": {
"config": {
"aggregate-id": "ae1"
}
},
"name": "eth1"
},
{
"config": {
"enabled": true,
"loopback-mode": "TERMINAL",
"name": "eth2",
"type": "ethernetCsmacd"
},
"ethernet": {
"config": {
"aggregate-id": "ae2"
}
},
"name": "eth2"
}
]
},
"network-instances": {
"network-instance": [
{
"config": {
"name": "DEFAULT",
"type": "DEFAULT_INSTANCE"
},
"interfaces": {
"interface": [
{
"config": {
"id": "ae1",
"interface": "ae1"
},
"id": "ae1"
}
]
},
"name": "DEFAULT"
},
{
"config": {
"name": "TRANSIT",
"type": "L3VRF"
},
"interfaces": {
"interface": [
{
"config": {
"id": "ae2",
"interface": "ae2"
},
"id": "ae2"
}
]
},
"name": "TRANSIT"
},
{
"config": {
"name": "SELF_SITE",
"type": "L3VRF"
},
"name": "SELF_SITE"
},
{
"config": {
"name": "EGRESS",
"type": "L3VRF"
},
"name": "EGRESS"
}
]
}
}paths:
/interfaces/interface/config/name:
/interfaces/interface/config/enabled:
/interfaces/interface/config/loopback-mode:
/interfaces/interface/ethernet/config/aggregate-id:
/interfaces/interface/aggregation/config/lag-type:
/interfaces/interface/state/counters/in-pkts:
/interfaces/interface/state/counters/out-pkts:
/network-instances/network-instance/config/name:
/network-instances/network-instance/config/type:
/network-instances/network-instance/interfaces/interface/config/id:
/network-instances/network-instance/interfaces/interface/config/interface:
/acl/interfaces/interface/ingress-acl-sets/ingress-acl-set/config/set-name:
/acl/interfaces/interface/ingress-acl-sets/ingress-acl-set/config/type:
rpcs:
gribi:
gRIBI.Modify:
gRIBI.Flush:
gnmi:
gNMI.Set:
gNMI.Get:
gNMI.Subscribe: