diff --git a/feature/staticroute/otg_tests/basic_static_route_support_test/README.md b/feature/staticroute/otg_tests/basic_static_route_support_test/README.md index a50aa04c701..1127cffe981 100644 --- a/feature/staticroute/otg_tests/basic_static_route_support_test/README.md +++ b/feature/staticroute/otg_tests/basic_static_route_support_test/README.md @@ -16,8 +16,8 @@ #### Initial Setup: -* Connect DUT port-1, port-2 and port-3 to ATE port-1, port-2 and port-3 - respectively +* Connect DUT port-1, port-2, port-3 and port-4 to ATE port-1, port-2, port-3 + and port-4 respectively * Configure IPv4/IPv6 addresses on DUT and ATE the interfaces * Configure one IPv4 destination i.e. `ipv4-network = 203.0.113.0/24` connected to ATE port 1 and 2 @@ -177,9 +177,24 @@ 203.0.113.0/24` and `ipv6-network 2001:db8:128:128::/64` * Validate that traffic is NOT received from DUT +### RT-1.26.9 + +#### Test to validate add and remove to next-hops in a static route + +* Configure one IPv4 static route i.e. ipv4-route with the next hop set to the + IPv4 address of ATE port-2(0 index) and port-3(1 index). +* Validate next-hops of `ipv4-route` static route and indexes. +* Update IPv4 static route i.e. ipv4-route with the next hop set to the IPv4 + address of ATE port-1(0 index), port-2(1 index), port-3(2 index) and + port-4(3 index). +* Validate next-hops of `ipv4-route` static route and indexes. +* Remove two next hops at index 0 and 3 added in previous step. +* Validate next-hops of `ipv4-route` static route and indexes. + ## OpenConfig Path and RPC Coverage -The below yaml defines the OC paths intended to be covered by this test. OC paths used for test setup are not listed here. +The below yaml defines the OC paths intended to be covered by this test. OC +paths used for test setup are not listed here. ```yaml paths: diff --git a/feature/staticroute/otg_tests/basic_static_route_support_test/basic_static_route_support_test.go b/feature/staticroute/otg_tests/basic_static_route_support_test/basic_static_route_support_test.go index fbfd8da98ef..932e28281af 100644 --- a/feature/staticroute/otg_tests/basic_static_route_support_test/basic_static_route_support_test.go +++ b/feature/staticroute/otg_tests/basic_static_route_support_test/basic_static_route_support_test.go @@ -102,6 +102,23 @@ var ( IPv6: "2001:db8::192:0:2:a", IPv6Len: ipv6PrefixLen, } + + dutPort4 = attrs.Attributes{ + Desc: "dutPort4", + IPv4: "192.0.2.13", + IPv4Len: ipv4PrefixLen, + IPv6: "2001:db8::192:0:2:d", + IPv6Len: ipv6PrefixLen, + } + + atePort4 = attrs.Attributes{ + Name: "atePort4", + MAC: "02:00:01:01:01:04", + IPv4: "192.0.2.14", + IPv4Len: ipv4PrefixLen, + IPv6: "2001:db8::192:0:2:e", + IPv6Len: ipv6PrefixLen, + } ) func TestMain(m *testing.M) { @@ -209,6 +226,92 @@ func TestBasicStaticRouteSupport(t *testing.T) { } } +func TestStaticRouteAddRemove(t *testing.T) { + dut := ondatra.DUT(t, "dut") + configureDUT(t, dut) + + ate := ondatra.ATE(t, "ate") + top := gosnappi.NewConfig() + configureOTG(t, ate, top) + + ate.OTG().PushConfig(t, top) + ate.OTG().StartProtocols(t) + defer ate.OTG().StopProtocols(t) + otgutils.WaitForARP(t, ate.OTG(), top, "IPv4") + + prefix := ipAddr{address: v4Route, prefix: v4RoutePrefix} + b := &gnmi.SetBatch{} + sV4 := &cfgplugins.StaticRouteCfg{ + NetworkInstance: deviations.DefaultNetworkInstance(dut), + Prefix: prefix.cidr(t), + NextHops: map[string]oc.NetworkInstance_Protocol_Static_NextHop_NextHop_Union{ + "0": oc.UnionString(atePort2.IPv4), + "1": oc.UnionString(atePort3.IPv4), + }, + } + if _, err := cfgplugins.NewStaticRouteCfg(b, sV4, dut); err != nil { + t.Fatalf("Failed to configure IPv4 static route: %v", err) + } + b.Set(t, dut) + validateStaticRoute(t, dut, prefix.cidr(t), sV4) + + // add 2 new nextHops, one at 0 index and another at 3 index + b = &gnmi.SetBatch{} + sV4 = &cfgplugins.StaticRouteCfg{ + NetworkInstance: deviations.DefaultNetworkInstance(dut), + Prefix: prefix.cidr(t), + NextHops: map[string]oc.NetworkInstance_Protocol_Static_NextHop_NextHop_Union{ + "0": oc.UnionString(atePort1.IPv4), + "1": oc.UnionString(atePort2.IPv4), + "2": oc.UnionString(atePort3.IPv4), + "3": oc.UnionString(atePort4.IPv4), + }, + } + if _, err := cfgplugins.NewStaticRouteCfg(b, sV4, dut); err != nil { + t.Fatalf("Failed to configure IPv4 static route: %v", err) + } + b.Set(t, dut) + validateStaticRoute(t, dut, prefix.cidr(t), sV4) + + // remove previously added indexes + b = &gnmi.SetBatch{} + sV4 = &cfgplugins.StaticRouteCfg{ + NetworkInstance: deviations.DefaultNetworkInstance(dut), + Prefix: prefix.cidr(t), + NextHops: map[string]oc.NetworkInstance_Protocol_Static_NextHop_NextHop_Union{ + "0": oc.UnionString(atePort2.IPv4), + "1": oc.UnionString(atePort3.IPv4), + }, + } + if _, err := cfgplugins.NewStaticRouteCfg(b, sV4, dut); err != nil { + t.Fatalf("Failed to configure IPv4 static route: %v", err) + } + b.Set(t, dut) + validateStaticRoute(t, dut, prefix.cidr(t), sV4) +} + +func validateStaticRoute(t *testing.T, dut *ondatra.DUTDevice, prefix string, sV4 *cfgplugins.StaticRouteCfg) { + sp := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_STATIC, deviations.StaticProtocolName(dut)) + gnmi.Await(t, dut, sp.Static(prefix).Prefix().State(), 120*time.Second, prefix) + + if deviations.SkipStaticNexthopCheck(dut) { + nexthops := gnmi.LookupAll(t, dut, sp.Static(prefix).NextHopAny().NextHop().State()) + if got, want := len(nexthops), len(sV4.NextHops); got != want { + t.Errorf("Static route next hop count - %s: got: %v, want: %v", prefix, got, want) + } + } else { + // Validate both the routes i.e. ipv4-route-[a|b] are configured and reported + // correctly + gotStatic := gnmi.Get(t, dut, sp.Static(prefix).State()) + t.Logf("Static route %s: got: %v, want: %v", prefix, len(gotStatic.NextHop), len(sV4.NextHops)) + for index, nextHop := range gotStatic.NextHop { + if got, want := nextHop.GetNextHop(), sV4.NextHops[index]; got != want { + t.Errorf("Static route %s: got: %v, want: %v", prefix, got, want) + } + } + } +} + func TestDisableRecursiveNextHopResolution(t *testing.T) { dut := ondatra.DUT(t, "dut") if deviations.UnsupportedStaticRouteNextHopRecurse(dut) { @@ -1208,23 +1311,29 @@ func configureDUT(t *testing.T, dut *ondatra.DUTDevice) { p1 := dut.Port(t, "port1") p2 := dut.Port(t, "port2") p3 := dut.Port(t, "port3") + p4 := dut.Port(t, "port4") b := &gnmi.SetBatch{} i1 := dutPort1.NewOCInterface(p1.Name(), dut) i2 := dutPort2.NewOCInterface(p2.Name(), dut) i3 := dutPort3.NewOCInterface(p3.Name(), dut) + i4 := dutPort4.NewOCInterface(p4.Name(), dut) if deviations.IPv6StaticRouteWithIPv4NextHopRequiresStaticARP(dut) { i1.GetOrCreateSubinterface(0).GetOrCreateIpv6().GetOrCreateNeighbor(dummyV6).LinkLayerAddress = ygot.String(dummyMAC) i2.GetOrCreateSubinterface(0).GetOrCreateIpv6().GetOrCreateNeighbor(dummyV6).LinkLayerAddress = ygot.String(dummyMAC) + i3.GetOrCreateSubinterface(0).GetOrCreateIpv6().GetOrCreateNeighbor(dummyV6).LinkLayerAddress = ygot.String(dummyMAC) + i4.GetOrCreateSubinterface(0).GetOrCreateIpv6().GetOrCreateNeighbor(dummyV6).LinkLayerAddress = ygot.String(dummyMAC) } gnmi.BatchReplace(b, gnmi.OC().Interface(p1.Name()).Config(), i1) gnmi.BatchReplace(b, gnmi.OC().Interface(p2.Name()).Config(), i2) gnmi.BatchReplace(b, gnmi.OC().Interface(p3.Name()).Config(), i3) + gnmi.BatchReplace(b, gnmi.OC().Interface(p4.Name()).Config(), i4) b.Set(t, dut) if deviations.ExplicitPortSpeed(dut) { fptest.SetPortSpeed(t, p1) fptest.SetPortSpeed(t, p2) fptest.SetPortSpeed(t, p3) + fptest.SetPortSpeed(t, p4) } fptest.ConfigureDefaultNetworkInstance(t, dut) @@ -1233,6 +1342,7 @@ func configureDUT(t *testing.T, dut *ondatra.DUTDevice) { fptest.AssignToNetworkInstance(t, dut, p1.Name(), deviations.DefaultNetworkInstance(dut), 0) fptest.AssignToNetworkInstance(t, dut, p2.Name(), deviations.DefaultNetworkInstance(dut), 0) fptest.AssignToNetworkInstance(t, dut, p3.Name(), deviations.DefaultNetworkInstance(dut), 0) + fptest.AssignToNetworkInstance(t, dut, p4.Name(), deviations.DefaultNetworkInstance(dut), 0) } } @@ -1241,11 +1351,13 @@ func configureOTG(t *testing.T, ate *ondatra.ATEDevice, top gosnappi.Config) []g p1 := ate.Port(t, "port1") p2 := ate.Port(t, "port2") p3 := ate.Port(t, "port3") + p4 := ate.Port(t, "port4") d1 := atePort1.AddToOTG(top, p1, &dutPort1) d2 := atePort2.AddToOTG(top, p2, &dutPort2) d3 := atePort3.AddToOTG(top, p3, &dutPort3) - return []gosnappi.Device{d1, d2, d3} + d4 := atePort4.AddToOTG(top, p4, &dutPort4) + return []gosnappi.Device{d1, d2, d3, d4} } func (td *testData) advertiseRoutesWithISIS(t *testing.T) { diff --git a/feature/staticroute/otg_tests/basic_static_route_support_test/metadata.textproto b/feature/staticroute/otg_tests/basic_static_route_support_test/metadata.textproto index 34fb8af4eaf..af7f010bc52 100644 --- a/feature/staticroute/otg_tests/basic_static_route_support_test/metadata.textproto +++ b/feature/staticroute/otg_tests/basic_static_route_support_test/metadata.textproto @@ -36,7 +36,6 @@ platform_exceptions: { unsupported_static_route_next_hop_recurse: true static_route_with_explicit_metric: true interface_ref_config_unsupported: true - } } platform_exceptions: {