diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index df375ba3436..82423e81a15 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -12,7 +12,7 @@ # /feature folders each have owners who are auto requested for review and may merge PR's /feature/acl/ @alokmtri-g -/feature/aft/ @sudhinj +/feature/aft/ @sudhinj @yunjie-lu /feature/bgp/ @dplore /feature/dhcp/ @alokmtri-g /feature/ethernet/ @ram-mac diff --git a/feature/aft/aft_base/otg_tests/afts_base/README.md b/feature/aft/aft_base/otg_tests/afts_base/README.md new file mode 100644 index 00000000000..b2e0d5a2792 --- /dev/null +++ b/feature/aft/aft_base/otg_tests/afts_base/README.md @@ -0,0 +1,177 @@ +# AFT-1.1: AFTs Base + +## Summary + +IPv4/IPv6 unicast routes next hop group and next hop. + +## Testbed + +* atedut_4.testbed + +## Test Setup + +### Generate DUT and ATE Configuration + +Configure DUT:port1,port2,port3 for IS-IS session with ATE:port1,port2,port3 +* IS-IS must be level 2 only with wide metric. +* IS-IS must be point to point. +* Send 1000 ipv4 and 1000 ipv6 IS-IS prefixes from ATE:port3 to DUT:port3. + + +Establish eBGP sessions between ATE:port1,port2 and DUT:port1,port2 and another between ATE:port3 and DUT:port3. +* Configure eBGP over the interface ip. +* eBGP must be multipath. +* Advertise 1000 ipv4,ipv6 prefixes from ATE port1,port2 observe received prefixes at DUT. +* Validate total number of entries of AFT for IPv4 and IPv6. +* Each prefix must have 2 next hops pointing to ATE port1,port2. +* Advertise 100 ipv4,ipv6 from ATE port3 observe received prefixes at DUT. + +Establish RSVP Sessions between ATE:port3 and SUT:port3. +* Configure mpls and rsvp sessions. +* Configure 2 ingress TE tunnels from DUT:port3 to ATE:port3. +* Tunnel destination is interface ip of ATE:port3. +* Configure explicit null and ipv6 tunneling. +* BGP advertised routes from ATE:port3 must be pointing to the 2 tunnels in the DUT. + +### Procedure + +* Use gNMI.Set with REPLACE option to push the Test Setup configuration to the DUT. +* ATE configuration must be pushed. + +### Verifications + +* BGP route advertised from ATE:port1,port2 must have 2 nexthops. +* IS-IS route advertised from ATE:port3 must have one next hop. +* BGP route advertised from ATE:port3 must have 2 next hops pointing to tunnels. +* Use gnmi Subscribe with ON_CHANGE option to /network-instances/network-instance/afts. +* For verifying prefix, nexthop groups, next hop use the leaves mentioed in the path section. +* Verify afts prefix advertised by BGP,ISIS. +* Verify its next hop group, number of next hop and its interfaces. +* Verify the number of next hop is same as expected. +* Verify all other leaves mentioned in the path section. + + +## AFT-1.1.1: AFT Base Link Down scenario 1 + +### Procedure + +Bring down the link between ATE:port2 and DUT:port2 using OTG api. + +### Verifications + +* BGP routes advertised from ATE:port1,port2 must have 1 nexthop. +* IS-IS routes advertised from ATE:port3 must have one next hop. +* BGP routes advertised from ATE:port3 must have 2 next hops pointing to tunnels. +* For verifying prefix, nexthop groups, next hop use the leaves mentioed in the path section. +* Verify afts prefix advertised by BGP,ISIS. +* Verify its next hop group, number of next hop and its interfaces. +* Verify the number of next hop is same as expected. + +## AFT-1.1.2: AFT Base Link Down scenario 2 + +### Procedure + +Bring down both links between ATE:port1,port2 and DUT:port1,port2 using OTG api. + +### Verifications + +* BGP routes advertised from ATE:port1,port2 must be removed from RIB,FIB of the DUT, query results nil. +* IS-IS routes advertised from ATE:port3 must have one next hop. +* BGP routes advertised from ATE:port3 must have 2 next hops pointing to tunnels. +* For verifying prefix, nexthop groups, next hop use the leaves mentioed in the path section. +* Verify afts prefix advertised by BGP,ISIS. +* Verify its next hop group, number of next hop and its interfaces. +* Verify the number of next hop is same as expected. + +## AFT-1.1.3: AFT Base Link Up scenario 1 + +### Procedure + +Bring up link between ATE:port1 and DUT:port1 using OTG api. + +### Verifications + +* BGP routes advertised from ATE:port1,port2 must have one next hop. +* IS-IS routes advertised from ATE:port3 must have one next hop. +* BGP routes advertised from ATE:port3 must have 2 next hops pointing to tunnels. +* Verify afts prefix advertised by BGP,ISIS. +* For verifying prefix, nexthop groups, next hop use the leaves mentioed in the path section. +* Verify its next hop group, number of next hop and its interfaces. +* Verify the number of next hop is same as expected. + +## AFT-1.1.4: AFT Base Link Up scenario 2 + +### Procedure + +Bring up both link between ATE:port1,port2 and DUT:port1,port2 using OTG api. + +### Verifications + +* BGP routes advertised from ATE:port1,port2 must have 2 next hops. +* IS-IS routes advertised from ATE:port3 must have one next hop. +* BGP routes advertised from ATE:port3 must have 2 next hops pointing to tunnels. +* For verifying prefix, nexthop groups, next hop use the leaves mentioed in the path section. +* Verify afts prefix advertised by BGP,ISIS. +* Verify its next hop group, number of next hop and its interfaces. +* Verify the number of next hop is same as expected. + +## 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. + +```yaml +paths: + ## Config Paths ## + + + ## State Paths ## + + /network-instances/network-instance/afts/ethernet/mac-entry/state/next-hop-group: + /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/next-hop-group: + /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/origin-protocol: + /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/prefix: + /network-instances/network-instance/afts/ipv6-unicast/ipv6-entry/state/next-hop-group: + /network-instances/network-instance/afts/ipv6-unicast/ipv6-entry/state/origin-protocol: + /network-instances/network-instance/afts/ipv6-unicast/ipv6-entry/state/prefix: + /network-instances/network-instance/afts/aft-summaries/ipv4-unicast/protocols/protocol/state/origin-protocol: + /network-instances/network-instance/afts/aft-summaries/ipv6-unicast/protocols/protocol/state/origin-protocol: + /network-instances/network-instance/afts/next-hop-groups/next-hop-group/id: + /network-instances/network-instance/afts/next-hop-groups/next-hop-group/next-hops/next-hop/index: + /network-instances/network-instance/afts/next-hop-groups/next-hop-group/next-hops/next-hop/state/index: + /network-instances/network-instance/afts/next-hop-groups/next-hop-group/next-hops/next-hop/state/weight: + /network-instances/network-instance/afts/next-hop-groups/next-hop-group/state/backup-next-hop-group: + /network-instances/network-instance/afts/next-hop-groups/next-hop-group/state/id: + /network-instances/network-instance/afts/next-hops/next-hop/index: + /network-instances/network-instance/afts/next-hops/next-hop/interface-ref/state/interface: + /network-instances/network-instance/afts/next-hops/next-hop/interface-ref/state/subinterface: + /network-instances/network-instance/afts/next-hops/next-hop/state/encapsulate-header: + /network-instances/network-instance/afts/next-hops/next-hop/state/index: + /network-instances/network-instance/afts/next-hops/next-hop/state/ip-address: + /network-instances/network-instance/afts/next-hops/next-hop/state/mac-address: + /network-instances/network-instance/afts/next-hops/next-hop/state/origin-protocol: + /network-instances/network-instance/afts/state-synced/state/ipv4-unicast: + /network-instances/network-instance/afts/state-synced/state/ipv6-unicast: + /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/entry-metadata: + /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/next-hop-group-network-instance: + /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/origin-network-instance: + /network-instances/network-instance/afts/ipv6-unicast/ipv6-entry/state/entry-metadata: + /network-instances/network-instance/afts/ipv6-unicast/ipv6-entry/state/next-hop-group-network-instance: + /network-instances/network-instance/afts/ipv6-unicast/ipv6-entry/state/origin-network-instance: + /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/prefix: + /network-instances/network-instance/afts/ipv6-unicast/ipv6-entry/prefix: + +rpcs: + gnmi: + gNMI.Subscribe: +``` + +## Control Protocol Coverage + +BGP +IS-IS +RSVP +MPLS + +## Minimum DUT Platform Requirement + +vRX diff --git a/feature/aft/aft_base/otg_tests/afts_prefix_counters/README.md b/feature/aft/aft_base/otg_tests/afts_prefix_counters/README.md new file mode 100644 index 00000000000..9fce154e4a1 --- /dev/null +++ b/feature/aft/aft_base/otg_tests/afts_prefix_counters/README.md @@ -0,0 +1,178 @@ +# AFT-2.1: AFTs Prefix Counters + +## Summary + +IPv4/IPv6 prefix counters + +## Testbed + +* atedut_2.testbed + +## Test Setup + +### Generate DUT and ATE Configuration + +Configure DUT:port1 for IS-IS session with ATE:port1 +* IS-IS must be level 2 only with wide metric. +* IS-IS must be point to point. +* Send 1000 ipv4 and 1000 ipv6 IS-IS prefixes from ATE:port1 to DUT:port1. + +Establish eBGP sessions between ATE:port1 and DUT:port1. +* Configure eBGP over the interface ip. +* Advertise 1000 ipv4,ipv6 prefixes from ATE port1 observe received prefixes at DUT. + +### Procedure + +* Gnmi set with REPLACE option to push the configuration DUT. +* ATE configuration must be pushed. + +### verifications + +* BGP routes advertised from ATE:port1 must have 1 nexthop. +* IS-IS routes advertised from ATE:port1 must have one next hop. +* Use gnmi Subscribe with ON_CHANGE option to /network-instances/network-instance/afts. +* Verify afts prefix entries using the following paths with in a timeout of 30s. + +/network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/prefix, +/network-instances/network-instance/afts/ipv6-unicast/ipv6-entry/state/prefix + + + +## AFT-2.1.1: AFT Prefix Counters ipv4 packets forwarded, ipv4 octets forwarded IS-IS route. + +### Procedure + +From ATE:port2 send 10000 packets to one of the ipv4 prefix advertise by IS-IS. + +### Verifications + +* Before the traffic measure the initial counter value. +* After the traffic measure the final counter value. +* The difference between final and initial value must match with the counter value in ATE then the test is marked as passed. +* Verify afts ipv4 forwarded packets and ipv4 forwarded octets counter entries using the path mentioned in the paths section of this test plan. + +## AFT-2.1.2: AFT Prefix Counters ipv4 packets forwarded, ipv4 octets forwarded BGP route. + +### Procedure + +From ATE:port2 send 10000 packets to one of the ipv4 prefix advertise by BGP. + +### Verifications + +* Before the traffic measure the initial counter value. +* After the traffic measure the final counter value. +* The difference between final and initial value must match with the counter value in ATE, then the test is marked as passed. +* Verify afts ipv4 forwarded packets and ipv4 forwarded octets counter entries using the path mentioned in the paths section of this test plan. + + +## AFT-2.1.3: AFT Prefix Counters ipv6 packets forwarded, ipv6 octets forwarded IS-IS route. + +### Procedure + +From ATE:port2 send 10000 packets to one of the ipv6 prefix advertise by IS-IS. + +### Verifications + +* Before the traffic measure the initial counter value. +* After the traffic measure the final counter value. +* The difference between final and initial value must match with the counter value in ATE, then the test is marked as passed. +* Verify afts ipv6 forwarded packets and ipv6 forwarded octets counter entries using the path mentioned in the paths section of this test plan. + +## AFT-2.1.4: AFT Prefix Counters ipv6 packets forwarded, ipv6 octets forwarded BGP route. + +### Procedure + +From ATE:port2 send 10000 packets to one of the ipv6 prefix advertise by BGP. + +### Verifications + +* Before the traffic measure the initial counter value. +* After the traffic measure the final counter value. +* The difference between final and initial value must match with the counter value in ATE, then the test is marked as passed. +* Verify afts ipv6 forwarded packets and ipv6 forwarded octets counter entries using the path mentioned in the paths section of this test plan. + +## AFT-2.1.5: AFT Prefix Counters withdraw the ipv4 prefix. + +### Procedure + +* From ATE:port1 withdraw some prefixes of BGP and IS-IS. +* Send 10000 packets from ATE:port2 to DUT:port2 for one of the withdrawn ipv4 prefix. +* The traffic must blackhole. + +### Verifications + +* The counters must not send incremental value as the prefix is not present in RIB/FIB. The test fails if the counter shows incremental values. +* Verify afts ipv4 forwarded packet counter entries using the path mentioned in the paths section of this test plan. + +## AFT-2.1.6: AFT Prefix Counters add the ipv4 prefix back. + +### Procedure + +* From ATE:port1 add the prefixes of BGP and IS-IS back. +* Send 10000 packets from ATE:port2 to DUT:port2 for one of the added ipv4 prefix. +* The traffic must flow end to end. + +### Verifications + +* Before the traffic measure the initial counter value. +* After the traffic measure the final counter value. +* The difference between final and initial value must match with the counter value in ATE, then the test is marked as passed. +* Verify afts counter entries using the path mentioned in the paths section of this test plan. + +## AFT-2.1.7: AFT Prefix Counters withdraw the ipv6 prefix. + +### Procedure + +* From ATE:port1 withdraw some prefixes of BGP and IS-IS. +* Send 10000 packets from ATE:port2 to DUT:port2 for one of the withdrawn ipv6 prefix. +* The traffic must blackhole. + +### Verifications + +* The counters must not send incremental value as the prefix is not present in RIB/FIB. The test fails if the counter shows incremental values. +* Verify afts counter entries using the path mentioned in the paths section of this test plan. + +## AFT-2.1.8: AFT Prefix Counters add the ipv6 prefix back. + +### Procedure + +* From ATE:port1 add the prefixes of BGP and IS-IS back. +* Send 10000 packets from ATE:port2 to DUT:port2 for one of the added ipv6 prefix. +* The traffic must flow end to end. + +### Verifications + +* Before the traffic measure the initial counter value. +* After the traffic measure the final counter value. +* The difference between final and initial value must match with the counter value in ATE, then the test is marked as passed. +* Verify afts counter entries using the path mentioned in the paths section of this test plan. + +## 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. + +```yaml +paths: + ## Config Paths ## + + ## State Paths ## + + /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/counters/octets-forwarded: + /network-instances/network-instance/afts/ipv4-unicast/ipv4-entry/state/counters/packets-forwarded: + /network-instances/network-instance/afts/ipv6-unicast/ipv6-entry/state/counters/octets-forwarded: + /network-instances/network-instance/afts/ipv6-unicast/ipv6-entry/state/counters/packets-forwarded: + + +rpcs: + gnmi: + gNMI.Subscribe: +``` + +## Control Protocol Coverage + +BGP +IS-IS + +## Minimum DUT Platform Requirement + +vRX \ No newline at end of file diff --git a/feature/aft/aft_summary/otg_tests/route_summary_counters_test/README.md b/feature/aft/afts_summary/otg_tests/route_summary_counters_test/README.md similarity index 100% rename from feature/aft/aft_summary/otg_tests/route_summary_counters_test/README.md rename to feature/aft/afts_summary/otg_tests/route_summary_counters_test/README.md diff --git a/feature/aft/aft_summary/otg_tests/route_summary_counters_test/metadata.textproto b/feature/aft/afts_summary/otg_tests/route_summary_counters_test/metadata.textproto similarity index 100% rename from feature/aft/aft_summary/otg_tests/route_summary_counters_test/metadata.textproto rename to feature/aft/afts_summary/otg_tests/route_summary_counters_test/metadata.textproto diff --git a/feature/aft/aft_summary/otg_tests/route_summary_counters_test/route_summary_counters_test.go b/feature/aft/afts_summary/otg_tests/route_summary_counters_test/route_summary_counters_test.go similarity index 100% rename from feature/aft/aft_summary/otg_tests/route_summary_counters_test/route_summary_counters_test.go rename to feature/aft/afts_summary/otg_tests/route_summary_counters_test/route_summary_counters_test.go diff --git a/feature/aft/afts_summary/otg_tests/scale_aft_summary/README.md b/feature/aft/afts_summary/otg_tests/scale_aft_summary/README.md new file mode 100644 index 00000000000..e7e416b40e7 --- /dev/null +++ b/feature/aft/afts_summary/otg_tests/scale_aft_summary/README.md @@ -0,0 +1,39 @@ +# RT-4.11: AFTs Route Summary + +## Summary + +IPv4/IPv6 scale unicast AFTs route summary for ISIS and BGP protocol + +## Procedure + +* Configure DUT:port1 for an IS-IS session with ATE:port1 +* Establish eBGP sessions between ATE:port1 and DUT:port1 and another between ATE:port2 and DUT:port2 +* Configure Route-policy under BGP peer-group address-family +* Advertise scale prefixes from ATE port-1, port-2 observe received prefixes at DUT for IPv4 and IPv6 +* Validate total number of entries of AFT for IPv4 and IPv6 + +## 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. + +```yaml +paths: + ## Config Paths ## + + ## State Paths ## + /network-instances/network-instance/afts/aft-summaries/ipv4-unicast/protocols/protocol/state/counters/aft-entries: + /network-instances/network-instance/afts/aft-summaries/ipv6-unicast/protocols/protocol/state/counters/aft-entries: + +rpcs: + gnmi: + gNMI.Subscribe: +``` + +## Control Protocol Coverage + +BGP +IS-IS + +## Minimum DUT Platform Requirement + +vRX diff --git a/feature/aft/afts_summary/otg_tests/scale_aft_summary/metadata.textproto b/feature/aft/afts_summary/otg_tests/scale_aft_summary/metadata.textproto new file mode 100644 index 00000000000..d61d4590b2b --- /dev/null +++ b/feature/aft/afts_summary/otg_tests/scale_aft_summary/metadata.textproto @@ -0,0 +1,54 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata + +uuid: "89da0b4c-9a16-44f8-9757-d98ccdd6aaf4" +plan_id: "RT-4.11" +description: "AFTs Route Summary" +testbed: TESTBED_DUT_ATE_2LINKS +platform_exceptions: { + platform: { + vendor: NOKIA + } + deviations: { + isis_multi_topology_unsupported: true + isis_interface_level1_disable_required: true + missing_isis_interface_afi_safi_enable: true + isis_restart_suppress_unsupported: true + explicit_port_speed: true + explicit_interface_in_default_vrf: true + missing_value_for_defaults: true + interface_enabled: true + } +} +platform_exceptions: { + platform: { + vendor: CISCO + } + deviations: { + ipv4_missing_enabled: true + isis_interface_level1_disable_required: true + isis_single_topology_required: true + } +} +platform_exceptions: { + platform: { + vendor: JUNIPER + } + deviations: { + isis_level_enabled: true + } +} +platform_exceptions: { + platform: { + vendor: ARISTA + } + deviations: { + omit_l2_mtu: true + missing_value_for_defaults: true + interface_enabled: true + default_network_instance: "default" + isis_instance_enabled_required: true + isis_interface_afi_unsupported: true + route_policy_under_afi_unsupported: true + } +} diff --git a/feature/aft/afts_summary/otg_tests/scale_aft_summary/route_test.go b/feature/aft/afts_summary/otg_tests/scale_aft_summary/route_test.go new file mode 100644 index 00000000000..e283663711e --- /dev/null +++ b/feature/aft/afts_summary/otg_tests/scale_aft_summary/route_test.go @@ -0,0 +1,566 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package route_test + +import ( + "testing" + "time" + + "github.com/open-traffic-generator/snappi/gosnappi" + "github.com/openconfig/featureprofiles/internal/attrs" + "github.com/openconfig/featureprofiles/internal/deviations" + "github.com/openconfig/featureprofiles/internal/fptest" + "github.com/openconfig/featureprofiles/internal/isissession" + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" + "github.com/openconfig/ondatra/gnmi/oc" + "github.com/openconfig/ygnmi/ygnmi" + "github.com/openconfig/ygot/ygot" +) + +func TestMain(m *testing.M) { + fptest.RunTests(m) +} + +// The testbed consists of ate:port1 -> dut:port1 and +// dut:port2 -> ate:port2. The first pair is called the "source" +// pair, and the second the "destination" pair. +// +// * Source: ate:port1 -> dut:port1 subnet 192.0.2.0/30 2001:db8::192:0:2:0/126 +// * Destination: dut:port2 -> ate:port2 subnet 192.0.2.4/30 2001:db8::192:0:2:4/126 +// +// Note that the first (.0, .3) and last (.4, .7) IPv4 addresses are +// reserved from the subnet for broadcast, so a /30 leaves exactly 2 +// usable addresses. This does not apply to IPv6 which allows /127 +// for point to point links, but we use /126 so the numbering is +// consistent with IPv4. + +const ( + advertisedRoutesv4Prefix = 32 + advertisedRoutesv6Prefix = 128 + dutAS = 65501 + ate1AS = 64501 + ate2AS = 200 + plenIPv4 = 30 + plenIPv6 = 126 + rplType = oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE + rplName = "ALLOW" + peerGrpNamev4 = "BGP-PEER-GROUP-V4" + peerGrpNamev6 = "BGP-PEER-GROUP-V6" + peerGrpNamev4P1 = "BGP-PEER-GROUP-V4-P1" + peerGrpNamev6P1 = "BGP-PEER-GROUP-V6-P1" + peerGrpNamev4P2 = "BGP-PEER-GROUP-V4-P2" + peerGrpNamev6P2 = "BGP-PEER-GROUP-V6-P2" + isisRoute = "199.0.0.1" + bgpRoute = "203.0.113.0" + isisRoutev6 = "2001:db8::203:0:113:1" + bgpRoutev6 = "2001:DB8:2::1" + RouteCount = uint32(1000) +) + +var ( + dutP1 = attrs.Attributes{ + Desc: "DUT to ATE source", + IPv4: "192.0.2.1", + IPv6: "2001:db8::1", + IPv4Len: plenIPv4, + IPv6Len: plenIPv6, + } + ateP1 = attrs.Attributes{ + Name: "ateP1", + MAC: "02:00:01:01:01:01", + IPv4: "192.0.2.2", + IPv6: "2001:db8::2", + IPv4Len: plenIPv4, + IPv6Len: plenIPv6, + } + + dutP2 = attrs.Attributes{ + Desc: "DUT to ATE destination", + IPv4: "192.0.2.5", + IPv6: "2001:db8::5", + IPv4Len: plenIPv4, + IPv6Len: plenIPv6, + } + + ateP2 = attrs.Attributes{ + Name: "ateP2", + MAC: "02:00:02:01:01:01", + IPv4: "192.0.2.6", + IPv6: "2001:db8::6", + IPv4Len: plenIPv4, + IPv6Len: plenIPv6, + } +) + +// configureDUT configures all the interfaces and BGP on the DUT. +func configureDUT(t *testing.T, dut *ondatra.DUTDevice) { + dc := gnmi.OC() + p1 := dut.Port(t, "port1").Name() + i1 := dutP1.NewOCInterface(p1, dut) + gnmi.Replace(t, dut, dc.Interface(p1).Config(), i1) + + p2 := dut.Port(t, "port2").Name() + i2 := dutP2.NewOCInterface(p2, dut) + gnmi.Replace(t, dut, dc.Interface(p2).Config(), i2) + + // Configure Network instance type on DUT + t.Log("Configure/update Network Instance") + fptest.ConfigureDefaultNetworkInstance(t, dut) + + if deviations.ExplicitPortSpeed(dut) { + fptest.SetPortSpeed(t, dut.Port(t, "port1")) + fptest.SetPortSpeed(t, dut.Port(t, "port2")) + } + if deviations.ExplicitInterfaceInDefaultVRF(dut) { + fptest.AssignToNetworkInstance(t, dut, p1, deviations.DefaultNetworkInstance(dut), 0) + fptest.AssignToNetworkInstance(t, dut, p2, deviations.DefaultNetworkInstance(dut), 0) + } + configureRoutePolicy(t, dut, rplName, rplType) + + dutConfPath := dc.NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP") + dutConf := createBGPNeighborP1(dutAS, ate1AS, dut) + gnmi.Replace(t, dut, dutConfPath.Config(), dutConf) + dutConf = createBGPNeighborP2(dutAS, ate2AS, dut) + gnmi.Update(t, dut, dutConfPath.Config(), dutConf) + ts := isissession.MustNew(t).WithISIS() + ts.ConfigISIS(func(isis *oc.NetworkInstance_Protocol_Isis) { + global := isis.GetOrCreateGlobal() + global.HelloPadding = oc.Isis_HelloPaddingType_DISABLE + + if deviations.ISISSingleTopologyRequired(ts.DUT) { + afv6 := global.GetOrCreateAf(oc.IsisTypes_AFI_TYPE_IPV6, oc.IsisTypes_SAFI_TYPE_UNICAST) + afv6.GetOrCreateMultiTopology().SetAfiName(oc.IsisTypes_AFI_TYPE_IPV4) + afv6.GetOrCreateMultiTopology().SetSafiName(oc.IsisTypes_SAFI_TYPE_UNICAST) + } + }) + ts.ATEIntf1.Isis().Advanced().SetEnableHelloPadding(false) + ts.PushAndStart(t) +} + +type BGPNeighbor struct { + as uint32 + neighborip string + isV4 bool +} + +func createBGPNeighborP1(localAs, peerAs uint32, dut *ondatra.DUTDevice) *oc.NetworkInstance_Protocol { + nbrs := []*BGPNeighbor{ + {as: peerAs, neighborip: ateP1.IPv4, isV4: true}, + {as: peerAs, neighborip: ateP1.IPv6, isV4: false}, + } + + d := &oc.Root{} + ni1 := d.GetOrCreateNetworkInstance(deviations.DefaultNetworkInstance(dut)) + niProto := ni1.GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP") + bgp := niProto.GetOrCreateBgp() + + global := bgp.GetOrCreateGlobal() + global.As = ygot.Uint32(localAs) + global.RouterId = ygot.String(dutP1.IPv4) + + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) + + // Note: we have to define the peer group even if we aren't setting any policy because it's + // invalid OC for the neighbor to be part of a peer group that doesn't exist. + pgv4 := bgp.GetOrCreatePeerGroup(peerGrpNamev4P1) + pgv4.PeerAs = ygot.Uint32(peerAs) + pgv4.PeerGroupName = ygot.String(peerGrpNamev4P1) + pgv6 := bgp.GetOrCreatePeerGroup(peerGrpNamev6P1) + pgv6.PeerAs = ygot.Uint32(peerAs) + pgv6.PeerGroupName = ygot.String(peerGrpNamev6P1) + + for _, nbr := range nbrs { + if nbr.isV4 { + nv4 := bgp.GetOrCreateNeighbor(nbr.neighborip) + nv4.PeerAs = ygot.Uint32(nbr.as) + nv4.Enabled = ygot.Bool(true) + nv4.PeerGroup = ygot.String(peerGrpNamev4P1) + afisafi := nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST) + afisafi.Enabled = ygot.Bool(true) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(false) + if deviations.RoutePolicyUnderAFIUnsupported(dut) { + rpl := pgv4.GetOrCreateApplyPolicy() + rpl.ImportPolicy = []string{rplName} + rpl.ExportPolicy = []string{rplName} + } else { + pgafv4 := pgv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST) + pgafv4.Enabled = ygot.Bool(true) + rpl := pgafv4.GetOrCreateApplyPolicy() + rpl.ImportPolicy = []string{rplName} + rpl.ExportPolicy = []string{rplName} + } + } else { + nv6 := bgp.GetOrCreateNeighbor(nbr.neighborip) + nv6.PeerAs = ygot.Uint32(nbr.as) + nv6.Enabled = ygot.Bool(true) + nv6.PeerGroup = ygot.String(peerGrpNamev6P1) + afisafi6 := nv6.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST) + afisafi6.Enabled = ygot.Bool(true) + nv6.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(false) + if deviations.RoutePolicyUnderAFIUnsupported(dut) { + rpl := pgv6.GetOrCreateApplyPolicy() + rpl.ImportPolicy = []string{rplName} + rpl.ExportPolicy = []string{rplName} + } else { + pgafv6 := pgv6.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST) + pgafv6.Enabled = ygot.Bool(true) + rpl := pgafv6.GetOrCreateApplyPolicy() + rpl.ImportPolicy = []string{rplName} + rpl.ExportPolicy = []string{rplName} + + } + } + } + return niProto +} + +func createBGPNeighborP2(localAs, peerAs uint32, dut *ondatra.DUTDevice) *oc.NetworkInstance_Protocol { + nbrs := []*BGPNeighbor{ + {as: peerAs, neighborip: ateP2.IPv4, isV4: true}, + {as: peerAs, neighborip: ateP2.IPv6, isV4: false}, + } + + d := &oc.Root{} + ni1 := d.GetOrCreateNetworkInstance(deviations.DefaultNetworkInstance(dut)) + niProto := ni1.GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP") + bgp := niProto.GetOrCreateBgp() + + global := bgp.GetOrCreateGlobal() + global.As = ygot.Uint32(localAs) + global.RouterId = ygot.String(dutP1.IPv4) + + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) + + // Note: we have to define the peer group even if we aren't setting any policy because it's + // invalid OC for the neighbor to be part of a peer group that doesn't exist. + pgv4 := bgp.GetOrCreatePeerGroup(peerGrpNamev4P2) + pgv4.PeerAs = ygot.Uint32(peerAs) + pgv4.PeerGroupName = ygot.String(peerGrpNamev4P2) + pgv6 := bgp.GetOrCreatePeerGroup(peerGrpNamev6P2) + pgv6.PeerAs = ygot.Uint32(peerAs) + pgv6.PeerGroupName = ygot.String(peerGrpNamev6P2) + + for _, nbr := range nbrs { + if nbr.isV4 { + nv4 := bgp.GetOrCreateNeighbor(nbr.neighborip) + nv4.PeerAs = ygot.Uint32(nbr.as) + nv4.Enabled = ygot.Bool(true) + nv4.PeerGroup = ygot.String(peerGrpNamev4P2) + afisafi := nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST) + afisafi.Enabled = ygot.Bool(true) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(false) + if deviations.RoutePolicyUnderAFIUnsupported(dut) { + rpl := pgv4.GetOrCreateApplyPolicy() + rpl.ImportPolicy = []string{rplName} + rpl.ExportPolicy = []string{rplName} + } else { + pgafv4 := pgv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST) + pgafv4.Enabled = ygot.Bool(true) + rpl := pgafv4.GetOrCreateApplyPolicy() + rpl.ImportPolicy = []string{rplName} + rpl.ExportPolicy = []string{rplName} + } + } else { + nv6 := bgp.GetOrCreateNeighbor(nbr.neighborip) + nv6.PeerAs = ygot.Uint32(nbr.as) + nv6.Enabled = ygot.Bool(true) + nv6.PeerGroup = ygot.String(peerGrpNamev6P2) + afisafi6 := nv6.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST) + afisafi6.Enabled = ygot.Bool(true) + nv6.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(false) + if deviations.RoutePolicyUnderAFIUnsupported(dut) { + rpl := pgv6.GetOrCreateApplyPolicy() + rpl.ImportPolicy = []string{rplName} + rpl.ExportPolicy = []string{rplName} + } else { + pgafv6 := pgv6.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST) + pgafv6.Enabled = ygot.Bool(true) + rpl := pgafv6.GetOrCreateApplyPolicy() + rpl.ImportPolicy = []string{rplName} + rpl.ExportPolicy = []string{rplName} + + } + } + } + return niProto +} + +func configureRoutePolicy(t *testing.T, dut *ondatra.DUTDevice, name string, pr oc.E_RoutingPolicy_PolicyResultType) { + d := &oc.Root{} + rp := d.GetOrCreateRoutingPolicy() + pd := rp.GetOrCreatePolicyDefinition(name) + st, err := pd.AppendNewStatement("id-1") + if err != nil { + t.Fatal(err) + } + st.GetOrCreateActions().PolicyResult = pr + gnmi.Replace(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) +} + +func waitForBGPSession(t *testing.T, dut *ondatra.DUTDevice, wantEstablished bool) { + statePath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP").Bgp() + nbrPath := statePath.Neighbor(ateP2.IPv4) + nbrPathv6 := statePath.Neighbor(ateP2.IPv6) + compare := func(val *ygnmi.Value[oc.E_Bgp_Neighbor_SessionState]) bool { + state, ok := val.Val() + if ok { + if wantEstablished { + t.Logf("BGP session state: %s", state.String()) + return state == oc.Bgp_Neighbor_SessionState_ESTABLISHED + } + return state == oc.Bgp_Neighbor_SessionState_IDLE + } + return false + } + + _, ok := gnmi.Watch(t, dut, nbrPath.SessionState().State(), 2*time.Minute, compare).Await(t) + if !ok { + fptest.LogQuery(t, "BGP reported state", nbrPath.State(), gnmi.Get(t, dut, nbrPath.State())) + if wantEstablished { + t.Fatal("No BGP neighbor formed...") + } else { + t.Fatal("BGPv4 session didn't teardown.") + } + } + _, ok = gnmi.Watch(t, dut, nbrPathv6.SessionState().State(), 2*time.Minute, compare).Await(t) + if !ok { + fptest.LogQuery(t, "BGPv6 reported state", nbrPathv6.State(), gnmi.Get(t, dut, nbrPathv6.State())) + if wantEstablished { + t.Fatal("No BGPv6 neighbor formed...") + } else { + t.Fatal("BGPv6 session didn't teardown.") + } + } +} + +func verifyBGPTelemetry(t *testing.T, dut *ondatra.DUTDevice) { + t.Log("Waiting for BGPv4 neighbor to establish...") + waitForBGPSession(t, dut, true) + +} + +func configureATE(t *testing.T) gosnappi.Config { + ate := ondatra.ATE(t, "ate") + ap1 := ate.Port(t, "port1") + ap2 := ate.Port(t, "port2") + config := gosnappi.NewConfig() + // add ports + p1 := config.Ports().Add().SetName(ap1.ID()) + p2 := config.Ports().Add().SetName(ap2.ID()) + // add devices + d1 := config.Devices().Add().SetName("p1.d1") + d2 := config.Devices().Add().SetName("p2.d1") + // Configuration on port1. + d1Eth1 := d1.Ethernets(). + Add(). + SetName("p1.d1.eth1"). + SetMac("00:00:02:02:02:02"). + SetMtu(1500) + d1Eth1. + Connection(). + SetPortName(p1.Name()) + + d1ipv41 := d1Eth1. + Ipv4Addresses(). + Add(). + SetName("p1.d1.eth1.ipv4"). + SetAddress("192.0.2.2"). + SetGateway("192.0.2.1"). + SetPrefix(30) + + d1ipv61 := d1Eth1. + Ipv6Addresses(). + Add(). + SetName("p1.d1.eth1.ipv6"). + SetAddress("2001:db8::2"). + SetGateway("2001:db8::1"). + SetPrefix(126) + + // isis router + d1isis := d1.Isis(). + SetName("p1.d1.isis"). + SetSystemId("650000000001") + d1isis.Basic(). + SetIpv4TeRouterId(d1ipv41.Address()). + SetHostname("ixia-c-port1") + d1isis.Advanced().SetAreaAddresses([]string{"49"}) + d1isisint := d1isis.Interfaces(). + Add(). + SetName("p1.d1.isis.intf"). + SetEthName(d1Eth1.Name()). + SetNetworkType(gosnappi.IsisInterfaceNetworkType.POINT_TO_POINT). + SetLevelType(gosnappi.IsisInterfaceLevelType.LEVEL_2). + SetMetric(10) + d1isisint.TrafficEngineering().Add().PriorityBandwidths() + d1isisint.Advanced().SetAutoAdjustMtu(true).SetAutoAdjustArea(true).SetAutoAdjustSupportedProtocols(true) + + d1IsisRoute1 := d1isis.V4Routes().Add().SetName("p1.d1.isis.rr1") + d1IsisRoute1.Addresses(). + Add(). + SetAddress(isisRoute). + SetPrefix(32).SetCount(RouteCount) + + d1IsisRoute1v6 := d1isis.V6Routes().Add().SetName("p1.d1.isis.rr1.v6") + d1IsisRoute1v6.Addresses(). + Add(). + SetAddress(isisRoutev6). + SetPrefix(126).SetCount(RouteCount) + + configureBGPDev(d1, d1ipv41, d1ipv61, ate1AS) + + // configuration on port2 + d2Eth1 := d2.Ethernets(). + Add(). + SetName("p2.d1.eth1"). + SetMac("00:00:03:03:03:03"). + SetMtu(1500) + d2Eth1. + Connection(). + SetPortName(p2.Name()) + d2ipv41 := d2Eth1.Ipv4Addresses(). + Add(). + SetName("p2.d1.eth1.ipv4"). + SetAddress("192.0.2.6"). + SetGateway("192.0.2.5"). + SetPrefix(30) + + d2ipv61 := d2Eth1. + Ipv6Addresses(). + Add(). + SetName("p2.d1.eth1.ipv6"). + SetAddress("2001:db8::6"). + SetGateway("2001:db8::5"). + SetPrefix(126) + + // isis router + d2isis := d2.Isis(). + SetName("p2.d1.isis"). + SetSystemId("650000000001") + d2isis.Basic(). + SetIpv4TeRouterId(d2ipv41.Address()). + SetHostname("ixia-c-port2") + d2isis.Advanced().SetAreaAddresses([]string{"49"}) + d2isisint := d2isis.Interfaces(). + Add(). + SetName("p2.d1.isis.intf"). + SetEthName(d2Eth1.Name()). + SetNetworkType(gosnappi.IsisInterfaceNetworkType.POINT_TO_POINT). + SetLevelType(gosnappi.IsisInterfaceLevelType.LEVEL_2). + SetMetric(10) + d2isisint.TrafficEngineering().Add().PriorityBandwidths() + d2isisint.Advanced().SetAutoAdjustMtu(true).SetAutoAdjustArea(true).SetAutoAdjustSupportedProtocols(true) + + d2IsisRoute1 := d2isis.V4Routes().Add().SetName("p2.d1.isis.rr1") + d2IsisRoute1.Addresses(). + Add(). + SetAddress(isisRoute). + SetPrefix(32). + SetCount(RouteCount) + + d2IsisRoute1V6 := d2isis.V6Routes().Add().SetName("p2.d1.isis.rr1.v6") + d2IsisRoute1V6.Addresses(). + Add(). + SetAddress(isisRoutev6). + SetPrefix(126). + SetCount(RouteCount) + + configureBGPDev(d2, d2ipv41, d2ipv61, ate2AS) + + return config +} + +// configureBGPDev configures the BGP on the OTG dev +func configureBGPDev(dev gosnappi.Device, Ipv4 gosnappi.DeviceIpv4, Ipv6 gosnappi.DeviceIpv6, as int) { + + Bgp := dev.Bgp().SetRouterId(Ipv4.Address()) + Bgp4Peer := Bgp.Ipv4Interfaces().Add().SetIpv4Name(Ipv4.Name()).Peers().Add().SetName(dev.Name() + ".BGP4.peer") + Bgp4Peer.SetPeerAddress(Ipv4.Gateway()).SetAsNumber(uint32(as)).SetAsType(gosnappi.BgpV4PeerAsType.EBGP) + Bgp6Peer := Bgp.Ipv6Interfaces().Add().SetIpv6Name(Ipv6.Name()).Peers().Add().SetName(dev.Name() + ".BGP6.peer") + Bgp6Peer.SetPeerAddress(Ipv6.Gateway()).SetAsNumber(uint32(as)).SetAsType(gosnappi.BgpV6PeerAsType.EBGP) + + configureBGPv4Routes(Bgp4Peer, Ipv4.Address(), Bgp4Peer.Name()+"v4route", bgpRoute, RouteCount) + configureBGPv6Routes(Bgp6Peer, Ipv6.Address(), Bgp6Peer.Name()+"v6route", bgpRoutev6, RouteCount) + +} + +func configureBGPv4Routes(peer gosnappi.BgpV4Peer, ipv4 string, name string, prefix string, count uint32) { + routes := peer.V4Routes().Add().SetName(name) + routes.SetNextHopIpv4Address(ipv4). + SetNextHopAddressType(gosnappi.BgpV4RouteRangeNextHopAddressType.IPV4). + SetNextHopMode(gosnappi.BgpV4RouteRangeNextHopMode.MANUAL) + routes.Addresses().Add(). + SetAddress(prefix). + SetPrefix(advertisedRoutesv4Prefix). + SetCount(count) +} + +func configureBGPv6Routes(peer gosnappi.BgpV6Peer, ipv6 string, name string, prefix string, count uint32) { + routes := peer.V6Routes().Add().SetName(name) + routes.SetNextHopIpv6Address(ipv6). + SetNextHopAddressType(gosnappi.BgpV6RouteRangeNextHopAddressType.IPV6). + SetNextHopMode(gosnappi.BgpV6RouteRangeNextHopMode.MANUAL) + routes.Addresses().Add(). + SetAddress(prefix). + SetPrefix(advertisedRoutesv6Prefix). + SetCount(count) +} +func VerifyDUT(t *testing.T, dut *ondatra.DUTDevice) { + + dni := deviations.DefaultNetworkInstance(dut) + if got, ok := gnmi.Await(t, dut, gnmi.OC().NetworkInstance(dni).Afts().AftSummaries().Ipv4Unicast().Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP).Counters().AftEntries().State(), 1*time.Minute, uint64(RouteCount)).Val(); !ok { + t.Errorf("ipv4 BGP entries, got: %d, want: %d", got, RouteCount) + } else { + t.Logf("Test case Passed: ipv4 BGP entries, got: %d, want: %d", got, RouteCount) + } + if got, ok := gnmi.Await(t, dut, gnmi.OC().NetworkInstance(dni).Afts().AftSummaries().Ipv6Unicast().Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP).Counters().AftEntries().State(), 1*time.Minute, uint64(RouteCount)).Val(); !ok { + t.Errorf("ipv6 BGP entries, got: %d, want: %d", got, RouteCount) + } else { + t.Logf("Test case Passed:ipv6 BGP entries, got: %d, want: %d", got, RouteCount) + } + + if got, ok := gnmi.Await(t, dut, gnmi.OC().NetworkInstance(dni).Afts().AftSummaries().Ipv4Unicast().Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS).Counters().AftEntries().State(), 1*time.Minute, uint64(RouteCount)).Val(); !ok { + t.Errorf("ipv4 isis entries, got: %d, want: %d", got, RouteCount) + } else { + t.Logf("Test case Passed: ipv4 isis entries, got: %d, want: %d", got, RouteCount) + + } + + if got, ok := gnmi.Await(t, dut, gnmi.OC().NetworkInstance(dni).Afts().AftSummaries().Ipv6Unicast().Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS).Counters().AftEntries().State(), 1*time.Minute, uint64(RouteCount)).Val(); !ok { + t.Errorf("ipv6 isis entries, got: %d, want: %d", got, RouteCount) + } else { + t.Logf("Test case Passed: ipv6 isis entries, got: %d, want: %d", got, RouteCount) + } +} + +func TestBGP(t *testing.T) { + + dut := ondatra.DUT(t, "dut") + ate := ondatra.ATE(t, "ate") + // DUT Configuration + t.Log("Start DUT interface Config") + configureDUT(t, dut) + // ATE Configuration. + t.Log("Start ATE Config") + config := configureATE(t) + ate.OTG().PushConfig(t, config) + time.Sleep(time.Second * 20) + ate.OTG().StartProtocols(t) + time.Sleep(time.Second * 20) + verifyBGPTelemetry(t, dut) + VerifyDUT(t, dut) +} diff --git a/feature/bgp/bgp_isis_redistribution/otg_tests/bgp_isis_redistribution_test/bgp_isis_redistribution_test.go b/feature/bgp/bgp_isis_redistribution/otg_tests/bgp_isis_redistribution_test/bgp_isis_redistribution_test.go index c69b20cbe5e..083ce37ff44 100644 --- a/feature/bgp/bgp_isis_redistribution/otg_tests/bgp_isis_redistribution_test/bgp_isis_redistribution_test.go +++ b/feature/bgp/bgp_isis_redistribution/otg_tests/bgp_isis_redistribution_test/bgp_isis_redistribution_test.go @@ -193,6 +193,13 @@ func TestBGPToISISRedistribution(t *testing.T) { t.Run(tc.name, func(t *testing.T) { t.Logf("Description: %s", tc.desc) tc.applyPolicyFunc(t, ts.DUT) + if tc.ipv4 { + bgpISISRedistribution(t, ts.DUT, "set") + defer bgpISISRedistribution(t, ts.DUT, "delete") + } else { + bgpISISRedistributionV6(t, ts.DUT, "set") + defer bgpISISRedistributionV6(t, ts.DUT, "delete") + } tc.verifyTelemetryFunc(t, ts.DUT, ts.ATE) if tc.testTraffic { if tc.ipv4 { @@ -321,8 +328,6 @@ func nonMatchingPrefixRoutePolicy(t *testing.T, dut *ondatra.DUTDevice) { stmt.GetOrCreateConditions().GetOrCreateMatchPrefixSet().SetPrefixSet(v4PrefixSet) gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) - // enable bgp isis redistribution - bgpISISRedistribution(t, dut) } func matchingPrefixRoutePolicy(t *testing.T, dut *ondatra.DUTDevice) { @@ -330,7 +335,7 @@ func matchingPrefixRoutePolicy(t *testing.T, dut *ondatra.DUTDevice) { rp := root.GetOrCreateRoutingPolicy() prefixSet := rp.GetOrCreateDefinedSets().GetOrCreatePrefixSet(v4PrefixSet) prefixSet.GetOrCreatePrefix(advertisedIPv4.cidr(t), maskLenExact) - gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().DefinedSets().PrefixSet(v4PrefixSet).Config(), prefixSet) + gnmi.Replace(t, dut, gnmi.OC().RoutingPolicy().DefinedSets().PrefixSet(v4PrefixSet).Config(), prefixSet) } func nonMatchingCommunityRoutePolicy(t *testing.T, dut *ondatra.DUTDevice) { @@ -364,7 +369,15 @@ func nonMatchingCommunityRoutePolicy(t *testing.T, dut *ondatra.DUTDevice) { ref1.SetCommunitySet(v4CommunitySet) ref1.SetMatchSetOptions(oc.RoutingPolicy_MatchSetOptionsType_ANY) } - gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) + // Configure ALLOWAll policy + pdef = rp.GetOrCreatePolicyDefinition(allowAllPolicy) + stmt, err = pdef.AppendNewStatement("id-1") + if err != nil { + t.Fatalf("AppendNewStatement(%s) failed: %v", "id-1", err) + } + stmt.GetOrCreateActions().PolicyResult = oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE + + gnmi.Replace(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) } } @@ -377,7 +390,7 @@ func matchingCommunityRoutePolicy(t *testing.T, dut *ondatra.DUTDevice) { rp := root.GetOrCreateRoutingPolicy() communitySet := rp.GetOrCreateDefinedSets().GetOrCreateBgpDefinedSets().GetOrCreateCommunitySet(v4CommunitySet) communitySet.SetCommunityMember([]oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union{oc.UnionString(fmt.Sprintf("%d:%d", ateAS, 100))}) - gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().DefinedSets().BgpDefinedSets().CommunitySet(v4CommunitySet).Config(), communitySet) + gnmi.Replace(t, dut, gnmi.OC().RoutingPolicy().DefinedSets().BgpDefinedSets().CommunitySet(v4CommunitySet).Config(), communitySet) } } @@ -468,16 +481,11 @@ func verifyNonMatchingCommunityTelemetry(t *testing.T, dut *ondatra.DUTDevice, a if commSet == nil { t.Errorf("Community set is nil, want non-nil") } - if deviations.BgpCommunityMemberIsAString(dut) { - cm := nonMatchingCommunityVal - if commSetMember := commSet.GetCommunityMember(); len(commSetMember) == 0 || !containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionString(cm))) { - t.Errorf("Community set member: %v, want: %s", commSetMember, cm) - } - } else { - cm, _ := strconv.ParseInt(fmt.Sprintf("%04x%04x", dummyAS, 200), 16, 0) - if commSetMember := commSet.GetCommunityMember(); len(commSetMember) == 0 || !containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionUint32(cm))) { - t.Errorf("Community set member: %v, want: %d", commSetMember, cm) - } + + cm, _ := strconv.ParseInt(fmt.Sprintf("%04x%04x", dummyAS, 200), 16, 0) + + if commSetMember := commSet.GetCommunityMember(); len(commSetMember) == 0 || !(containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionString(nonMatchingCommunityVal))) || containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionUint32(cm)))) { + t.Errorf("Community set member: %v, want: %s or %d", commSetMember, nonMatchingCommunityVal, cm) } _, ok := gnmi.WatchAll(t, ate.OTG(), gnmi.OTG().IsisRouter("devIsis").LinkStateDatabase().LspsAny().Tlvs().ExtendedIpv4Reachability().Prefix(advertisedIPv4.address).State(), 30*time.Second, func(v *ygnmi.Value[*otgtelemetry.IsisRouter_LinkStateDatabase_Lsps_Tlvs_ExtendedIpv4Reachability_Prefix]) bool { @@ -494,16 +502,10 @@ func verifyMatchingCommunityTelemetry(t *testing.T, dut *ondatra.DUTDevice, ate if commSet == nil { t.Errorf("Community set is nil, want non-nil") } - if deviations.BgpCommunityMemberIsAString(dut) { - cm := matchingCommunityVal - if commSetMember := commSet.GetCommunityMember(); len(commSetMember) == 0 || !containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionString(cm))) { - t.Errorf("Community set member: %v, want: %v", commSetMember, cm) - } - } else { - cm, _ := strconv.ParseInt(fmt.Sprintf("%04x%04x", ateAS, 100), 16, 0) - if commSetMember := commSet.GetCommunityMember(); len(commSetMember) == 0 || !containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionUint32(cm))) { - t.Errorf("Community set member: %v, want: %v", commSetMember, cm) - } + + cm, _ := strconv.ParseInt(fmt.Sprintf("%04x%04x", ateAS, 100), 16, 0) + if commSetMember := commSet.GetCommunityMember(); len(commSetMember) == 0 || !(containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionString(matchingCommunityVal))) || containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionUint32(cm)))) { + t.Errorf("Community set member: %v, want: %s or %d", commSetMember, matchingCommunityVal, cm) } _, ok := gnmi.WatchAll(t, ate.OTG(), gnmi.OTG().IsisRouter("devIsis").LinkStateDatabase().LspsAny().Tlvs().ExtendedIpv4Reachability().Prefix(advertisedIPv4.address).State(), 30*time.Second, func(v *ygnmi.Value[*otgtelemetry.IsisRouter_LinkStateDatabase_Lsps_Tlvs_ExtendedIpv4Reachability_Prefix]) bool { @@ -542,9 +544,6 @@ func nonMatchingPrefixRoutePolicyV6(t *testing.T, dut *ondatra.DUTDevice) { } stmt.GetOrCreateConditions().GetOrCreateMatchPrefixSet().SetPrefixSet(v6PrefixSet) gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) - - // enable bgp isis redistribution - bgpISISRedistributionV6(t, dut) } func matchingPrefixRoutePolicyV6(t *testing.T, dut *ondatra.DUTDevice) { @@ -552,7 +551,7 @@ func matchingPrefixRoutePolicyV6(t *testing.T, dut *ondatra.DUTDevice) { rp := root.GetOrCreateRoutingPolicy() prefixSet := rp.GetOrCreateDefinedSets().GetOrCreatePrefixSet(v6PrefixSet) prefixSet.GetOrCreatePrefix(advertisedIPv6.cidr(t), maskLenExact) - gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().DefinedSets().PrefixSet(v6PrefixSet).Config(), prefixSet) + gnmi.Replace(t, dut, gnmi.OC().RoutingPolicy().DefinedSets().PrefixSet(v6PrefixSet).Config(), prefixSet) } func nonMatchingCommunityRoutePolicyV6(t *testing.T, dut *ondatra.DUTDevice) { @@ -579,14 +578,21 @@ func nonMatchingCommunityRoutePolicyV6(t *testing.T, dut *ondatra.DUTDevice) { communitySet.SetCommunityMember([]oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union{oc.UnionString(fmt.Sprintf("%d:%d", dummyAS, 200))}) if deviations.BGPConditionsMatchCommunitySetUnsupported(dut) { - communitySet.SetMatchSetOptions(oc.BgpPolicy_MatchSetOptionsType_ANY) stmt.GetOrCreateConditions().GetOrCreateBgpConditions().SetCommunitySet(v6CommunitySet) + communitySet.SetMatchSetOptions(oc.BgpPolicy_MatchSetOptionsType_ANY) } else { ref1 := stmt.GetOrCreateConditions().GetOrCreateBgpConditions().GetOrCreateMatchCommunitySet() ref1.SetCommunitySet(v6CommunitySet) ref1.SetMatchSetOptions(oc.RoutingPolicy_MatchSetOptionsType_ANY) } - gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) + // Configure ALLOWAll policy + pdef = rp.GetOrCreatePolicyDefinition(allowAllPolicy) + stmt, err = pdef.AppendNewStatement("id-1") + if err != nil { + t.Fatalf("AppendNewStatement(%s) failed: %v", "id-1", err) + } + stmt.GetOrCreateActions().PolicyResult = oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE + gnmi.Replace(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) } } @@ -599,7 +605,7 @@ func matchingCommunityRoutePolicyV6(t *testing.T, dut *ondatra.DUTDevice) { rp := root.GetOrCreateRoutingPolicy() communitySet := rp.GetOrCreateDefinedSets().GetOrCreateBgpDefinedSets().GetOrCreateCommunitySet(v6CommunitySet) communitySet.SetCommunityMember([]oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union{oc.UnionString(fmt.Sprintf("%d:%d", ateAS, 100))}) - gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().DefinedSets().BgpDefinedSets().CommunitySet(v6CommunitySet).Config(), communitySet) + gnmi.Replace(t, dut, gnmi.OC().RoutingPolicy().DefinedSets().BgpDefinedSets().CommunitySet(v6CommunitySet).Config(), communitySet) } } @@ -626,7 +632,6 @@ func verifyNonMatchingPrefixTelemetryV6(t *testing.T, dut *ondatra.DUTDevice, at if pName := prefixSet.GetName(); pName != v6PrefixSet { t.Errorf("Prefix set name: %s, want: %s", pName, v6PrefixSet) } - if !deviations.SkipPrefixSetMode(dut) { if pMode := prefixSet.GetMode(); pMode != oc.PrefixSet_Mode_IPV6 { t.Errorf("Prefix set mode: %s, want: %s", pMode, oc.PrefixSet_Mode_IPV6) @@ -691,16 +696,9 @@ func verifyNonMatchingCommunityTelemetryV6(t *testing.T, dut *ondatra.DUTDevice, if commSet == nil { t.Errorf("Community set is nil, want non-nil") } - if deviations.BgpCommunityMemberIsAString(dut) { - cm := nonMatchingCommunityVal - if commSetMember := commSet.GetCommunityMember(); len(commSetMember) == 0 || !containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionString(cm))) { - t.Errorf("Community set member: %v, want: %v", commSetMember, cm) - } - } else { - cm, _ := strconv.ParseInt(fmt.Sprintf("%04x%04x", dummyAS, 200), 16, 0) - if commSetMember := commSet.GetCommunityMember(); len(commSetMember) == 0 || !containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionUint32(cm))) { - t.Errorf("Community set member: %v, want: %d", commSetMember, cm) - } + cm, _ := strconv.ParseInt(fmt.Sprintf("%04x%04x", dummyAS, 200), 16, 0) + if commSetMember := commSet.GetCommunityMember(); len(commSetMember) == 0 || !(containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionString(nonMatchingCommunityVal))) || containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionUint32(cm)))) { + t.Errorf("Community set member: %v, want: %s or %d", commSetMember, nonMatchingCommunityVal, cm) } _, ok := gnmi.WatchAll(t, ate.OTG(), gnmi.OTG().IsisRouter("devIsis").LinkStateDatabase().LspsAny().Tlvs().Ipv6Reachability().Prefix(advertisedIPv6.address).State(), 60*time.Second, func(v *ygnmi.Value[*otgtelemetry.IsisRouter_LinkStateDatabase_Lsps_Tlvs_Ipv6Reachability_Prefix]) bool { @@ -717,16 +715,10 @@ func verifyMatchingCommunityTelemetryV6(t *testing.T, dut *ondatra.DUTDevice, at if commSet == nil { t.Errorf("Community set is nil, want non-nil") } - if deviations.BgpCommunityMemberIsAString(dut) { - cm := matchingCommunityVal - if commSetMember := commSet.GetCommunityMember(); len(commSetMember) == 0 || !containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionString(cm))) { - t.Errorf("Community set member: %v, want: %v", commSetMember, cm) - } - } else { - cm, _ := strconv.ParseInt(fmt.Sprintf("%04x%04x", ateAS, 100), 16, 0) - if commSetMember := commSet.GetCommunityMember(); len(commSetMember) == 0 || !containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionUint32(cm))) { - t.Errorf("Community set member: %v, want: %v", commSetMember, cm) - } + + cm, _ := strconv.ParseInt(fmt.Sprintf("%04x%04x", ateAS, 100), 16, 0) + if commSetMember := commSet.GetCommunityMember(); len(commSetMember) == 0 || !(containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionString(matchingCommunityVal))) || containsValue(commSetMember, oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union(oc.UnionUint32(cm)))) { + t.Errorf("Community set member: %v, want: %s or %d", commSetMember, matchingCommunityVal, cm) } _, ok := gnmi.WatchAll(t, ate.OTG(), gnmi.OTG().IsisRouter("devIsis").LinkStateDatabase().LspsAny().Tlvs().Ipv6Reachability().Prefix(advertisedIPv6.address).State(), 60*time.Second, func(v *ygnmi.Value[*otgtelemetry.IsisRouter_LinkStateDatabase_Lsps_Tlvs_Ipv6Reachability_Prefix]) bool { @@ -738,38 +730,48 @@ func verifyMatchingCommunityTelemetryV6(t *testing.T, dut *ondatra.DUTDevice, at } } -func bgpISISRedistribution(t *testing.T, dut *ondatra.DUTDevice) { +func bgpISISRedistribution(t *testing.T, dut *ondatra.DUTDevice, operation string) { dni := deviations.DefaultNetworkInstance(dut) root := &oc.Root{} - if deviations.EnableTableConnections(dut) { state := "enable" configEnableTbNative(t, dut, state) } - tableConn := root.GetOrCreateNetworkInstance(dni).GetOrCreateTableConnection(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, oc.Types_ADDRESS_FAMILY_IPV4) - if !deviations.SkipSettingDisableMetricPropagation(dut) { - tableConn.SetDisableMetricPropagation(false) - } - if !deviations.DefaultRoutePolicyUnsupported(dut) { - tableConn.SetDefaultImportPolicy(oc.RoutingPolicy_DefaultPolicyType_REJECT_ROUTE) + if operation == "set" { + if !deviations.SkipSettingDisableMetricPropagation(dut) { + tableConn.SetDisableMetricPropagation(false) + } + if !deviations.DefaultRoutePolicyUnsupported(dut) { + tableConn.SetDefaultImportPolicy(oc.RoutingPolicy_DefaultPolicyType_REJECT_ROUTE) + } + tableConn.SetImportPolicy([]string{v4RoutePolicy}) + gnmi.Update(t, dut, gnmi.OC().NetworkInstance(dni).TableConnection(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, oc.Types_ADDRESS_FAMILY_IPV4).Config(), tableConn) + } else if operation == "delete" { + gnmi.Delete(t, dut, gnmi.OC().NetworkInstance(dni).TableConnection(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, oc.Types_ADDRESS_FAMILY_IPV4).Config()) } - tableConn.SetImportPolicy([]string{v4RoutePolicy}) - gnmi.Update(t, dut, gnmi.OC().NetworkInstance(dni).TableConnection(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, oc.Types_ADDRESS_FAMILY_IPV4).Config(), tableConn) } -func bgpISISRedistributionV6(t *testing.T, dut *ondatra.DUTDevice) { +func bgpISISRedistributionV6(t *testing.T, dut *ondatra.DUTDevice, operation string) { dni := deviations.DefaultNetworkInstance(dut) root := &oc.Root{} - tableConn := root.GetOrCreateNetworkInstance(dni).GetOrCreateTableConnection(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, oc.Types_ADDRESS_FAMILY_IPV6) - if !deviations.SkipSettingDisableMetricPropagation(dut) { - tableConn.SetDisableMetricPropagation(false) + if deviations.EnableTableConnections(dut) { + state := "enable" + configEnableTbNative(t, dut, state) } - if !deviations.DefaultRoutePolicyUnsupported(dut) { - tableConn.SetDefaultImportPolicy(oc.RoutingPolicy_DefaultPolicyType_REJECT_ROUTE) + tableConn := root.GetOrCreateNetworkInstance(dni).GetOrCreateTableConnection(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, oc.Types_ADDRESS_FAMILY_IPV6) + if operation == "set" { + if !deviations.SkipSettingDisableMetricPropagation(dut) { + tableConn.SetDisableMetricPropagation(false) + } + if !deviations.DefaultRoutePolicyUnsupported(dut) { + tableConn.SetDefaultImportPolicy(oc.RoutingPolicy_DefaultPolicyType_REJECT_ROUTE) + } + tableConn.SetImportPolicy([]string{v6RoutePolicy}) + gnmi.Update(t, dut, gnmi.OC().NetworkInstance(dni).TableConnection(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, oc.Types_ADDRESS_FAMILY_IPV6).Config(), tableConn) + } else if operation == "delete" { + gnmi.Delete(t, dut, gnmi.OC().NetworkInstance(dni).TableConnection(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, oc.Types_ADDRESS_FAMILY_IPV6).Config()) } - tableConn.SetImportPolicy([]string{v6RoutePolicy}) - gnmi.Update(t, dut, gnmi.OC().NetworkInstance(dni).TableConnection(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, oc.Types_ADDRESS_FAMILY_IPV6).Config(), tableConn) } func bgpISISRedistributionWithRouteTagPolicy(t *testing.T, dut *ondatra.DUTDevice, afi oc.E_Types_ADDRESS_FAMILY) { dni := deviations.DefaultNetworkInstance(dut) @@ -792,11 +794,11 @@ func configureBGPTablePolicyWithSetTag(t *testing.T, prefixSetName, prefixSetAdd if err != nil { t.Fatalf("AppendNewStatement(%s) failed: %v", "routePolicyStatement", err) } - //Create prefix-set + // Create prefix-set prefixSet := rp.GetOrCreateDefinedSets().GetOrCreatePrefixSet(prefixSetName) prefixSet.GetOrCreatePrefix(prefixSetAddress, maskLenExact) gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().DefinedSets().PrefixSet(prefixSetName).Config(), prefixSet) - //Create community-set + // Create community-set communitySet := rp.GetOrCreateDefinedSets().GetOrCreateBgpDefinedSets().GetOrCreateCommunitySet(communitySetName) communitySet.SetCommunityMember([]oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union{oc.UnionString(fmt.Sprintf("%d:%d", commAS, commValue))}) communitySet.SetMatchSetOptions(oc.BgpPolicy_MatchSetOptionsType_ANY) @@ -807,12 +809,12 @@ func configureBGPTablePolicyWithSetTag(t *testing.T, prefixSetName, prefixSetAdd stmt1.GetOrCreateActions().GetOrCreateSetTag().GetOrCreateInline().SetTag([]oc.RoutingPolicy_PolicyDefinition_Statement_Actions_SetTag_Inline_Tag_Union{oc.UnionUint32(routeTagVal)}) stmt1.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE) - //Create tag-set with above route tag value + // Create tag-set with above route tag value tagSet := rp.GetOrCreateDefinedSets().GetOrCreateTagSet("RouteTagForRedistribution") tagSet.SetName("RouteTagForRedistribution") tagSet.SetTagValue([]oc.RoutingPolicy_DefinedSets_TagSet_TagValue_Union{oc.UnionUint32(routeTagVal)}) - //Route-policy to match tag and accept + // Route-policy to match tag and accept pdef2 := rp.GetOrCreatePolicyDefinition("MatchTagRedistributionPolicy") stmt2, err := pdef2.AppendNewStatement("matchTag") stmt2.GetOrCreateConditions().GetOrCreateMatchPrefixSet().SetPrefixSet(prefixSetName) @@ -834,47 +836,6 @@ func configureBGPTablePolicyWithSetTag(t *testing.T, prefixSetName, prefixSetAdd } } -func configEnableTbNative(t testing.TB, d *ondatra.DUTDevice, state string) { - t.Helper() - switch d.Vendor() { - case ondatra.NOKIA: - //value := state - adminEnable, err := json.Marshal(state) - if err != nil { - t.Fatalf("Error with json Marshal: %v", err) - } - - gpbSetRequest := &gpb.SetRequest{ - Prefix: &gpb.Path{ - Origin: "native", - }, - Update: []*gpb.Update{ - { - Path: &gpb.Path{ - Elem: []*gpb.PathElem{ - {Name: "network-instance", Key: map[string]string{"name": "DEFAULT"}}, - {Name: "table-connections"}, - {Name: "admin-state"}, - }, - }, - Val: &gpb.TypedValue{ - Value: &gpb.TypedValue_JsonIetfVal{ - JsonIetfVal: adminEnable, - }, - }, - }, - }, - } - - gnmiClient := d.RawAPIs().GNMI(t) - if _, err := gnmiClient.Set(context.Background(), gpbSetRequest); err != nil { - t.Fatalf("Unexpected error updating SRL static-route tag-set: %v", err) - } - default: - t.Fatalf("Unsupported vendor %s for deviation 'UseVendorNativeACLConfiguration'", d.Vendor()) - } -} - func configureRoutePolicyAllow(t *testing.T, dut *ondatra.DUTDevice, name string, pr oc.E_RoutingPolicy_PolicyResultType) { d := &oc.Root{} rp := d.GetOrCreateRoutingPolicy() @@ -967,3 +928,44 @@ func containsValue[T comparable](slice []T, val T) bool { } return found } + +func configEnableTbNative(t testing.TB, d *ondatra.DUTDevice, state string) { + t.Helper() + switch d.Vendor() { + case ondatra.NOKIA: + //value := state + adminEnable, err := json.Marshal(state) + if err != nil { + t.Fatalf("Error with json Marshal: %v", err) + } + + gpbSetRequest := &gpb.SetRequest{ + Prefix: &gpb.Path{ + Origin: "native", + }, + Update: []*gpb.Update{ + { + Path: &gpb.Path{ + Elem: []*gpb.PathElem{ + {Name: "network-instance", Key: map[string]string{"name": "DEFAULT"}}, + {Name: "table-connections"}, + {Name: "admin-state"}, + }, + }, + Val: &gpb.TypedValue{ + Value: &gpb.TypedValue_JsonIetfVal{ + JsonIetfVal: adminEnable, + }, + }, + }, + }, + } + + gnmiClient := d.RawAPIs().GNMI(t) + if _, err := gnmiClient.Set(context.Background(), gpbSetRequest); err != nil { + t.Fatalf("Unexpected error updating SRL static-route tag-set: %v", err) + } + default: + t.Fatalf("Unsupported vendor %s for deviation 'EnableTableConnections'", d.Vendor()) + } +} diff --git a/feature/bgp/bgp_isis_redistribution/otg_tests/bgp_isis_redistribution_test/metadata.textproto b/feature/bgp/bgp_isis_redistribution/otg_tests/bgp_isis_redistribution_test/metadata.textproto index 5ead442c232..5f8e014ea50 100644 --- a/feature/bgp/bgp_isis_redistribution/otg_tests/bgp_isis_redistribution_test/metadata.textproto +++ b/feature/bgp/bgp_isis_redistribution/otg_tests/bgp_isis_redistribution_test/metadata.textproto @@ -54,6 +54,5 @@ platform_exceptions: { interface_enabled: true skip_prefix_set_mode: true enable_table_connections: true - bgp_community_member_is_a_string: true - } + } } diff --git a/feature/bgp/otg_tests/bgp_afi_safi_defaults/README.md b/feature/bgp/otg_tests/bgp_afi_safi_defaults/README.md index 68fe918d23c..10037d7171c 100644 --- a/feature/bgp/otg_tests/bgp_afi_safi_defaults/README.md +++ b/feature/bgp/otg_tests/bgp_afi_safi_defaults/README.md @@ -10,6 +10,7 @@ BGP AFI SAFI OC DEFAULTS TEST defines as the defaults i.e, * For BGP, there are no defaults for AFI-SAFI at the neighbor and peer-group levels. However at the global level the default is "false" +* For BGP neighbor level extended-next-hop encoding to be configured and validated too * This test currently only verifies the defaults for ipv4-unicast and ipv6-unicast families. However, this test can be extended further to cover for other AFI-SAFIs as well in future. * The test will check for default implementations under the neighbor and peer-group hierarchies and @@ -32,6 +33,8 @@ BGP AFI SAFI OC DEFAULTS TEST * Ensure that there are no AFI-SAFI configurations at the global and peer-group levels. * On the ATE side ensure that IPv4-unicast and IPv6-unicast AFI-SAFI are enabled==true for IPv4 and IPv6 neighbors. + * Ensure that there is extended-next-hop encoding feature is configured via OC path and the + default value of this should be set to false * Verification: * For IPv4 neighbor, ensure that the IPv4 neighborship is up and IPv6-unicast capability is @@ -95,6 +98,7 @@ paths: /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/config/peer-as: /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/config/enabled: /network-instances/network-instance/protocols/protocol/bgp/global/afi-safis/afi-safi/config/enabled: + /network-instances/network-instance/protocols/protocol/bgp/global/afi-safis/afi-safi/ipv4-unicast/config/extended-next-hop-encoding: ## Telemetry Parameter coverage @@ -105,6 +109,7 @@ paths: /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/state/peer-type: /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/state/peer-as: /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/state/local-as: + /network-instances/network-instance/protocols/protocol/bgp/global/afi-safis/afi-safi/ipv4-unicast/state/extended-next-hop-encoding: rpcs: gnmi: @@ -114,4 +119,4 @@ rpcs: ``` ## Minimum DUT Required -vRX - Virtual Router Device \ No newline at end of file +vRX - Virtual Router Device diff --git a/feature/bgp/otg_tests/bgp_afi_safi_defaults/bgp_afi_safi_defaults_test.go b/feature/bgp/otg_tests/bgp_afi_safi_defaults/bgp_afi_safi_defaults_test.go index 899d897e164..0898f0285e2 100644 --- a/feature/bgp/otg_tests/bgp_afi_safi_defaults/bgp_afi_safi_defaults_test.go +++ b/feature/bgp/otg_tests/bgp_afi_safi_defaults/bgp_afi_safi_defaults_test.go @@ -155,43 +155,59 @@ func bgpCreateNbr(t *testing.T, localAs, peerAs uint32, dut *ondatra.DUTDevice, switch afiSafiLevel { case globalLevel: - global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) - global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) - if !isV4Only { - extNh := global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).GetOrCreateIpv4Unicast() - extNh.ExtendedNextHopEncoding = ygot.Bool(true) + pg1.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(false) + pg1.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(false) + pg2.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(false) + pg2.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(false) + if isV4Only { + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(false) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(false) + } else { + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(false) + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(false) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) } if deviations.BGPGlobalExtendedNextHopEncodingUnsupported(dut) { global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Ipv4Unicast = nil } case nbrLevel: - if nbr.isV4 == true { - af4 := nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST) - af4.Enabled = ygot.Bool(true) + if isV4Only { + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(false) + extNh := nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).GetOrCreateIpv4Unicast() + if !deviations.BgpExtendedNextHopEncodingLeafUnsupported(dut) { + extNh.ExtendedNextHopEncoding = ygot.Bool(true) + } } else { - af6 := nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST) - af6.Enabled = ygot.Bool(true) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(false) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) + } + if deviations.BGPGlobalExtendedNextHopEncodingUnsupported(dut) { + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Ipv4Unicast = nil } case peerGrpLevel: - pg1af4 := pg1.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST) - pg1af4.Enabled = ygot.Bool(true) - pg1af6 := pg1.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST) - pg1af6.Enabled = ygot.Bool(true) - - pg2af4 := pg2.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST) - pg2af4.Enabled = ygot.Bool(true) - ext2Nh := pg2af4.GetOrCreateIpv4Unicast() - ext2Nh.ExtendedNextHopEncoding = ygot.Bool(true) - pg2af6 := pg2.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST) - pg2af6.Enabled = ygot.Bool(true) + if isV4Only { + pg1.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + pg1.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(false) + pg2.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + pg2.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(false) + } else { + pg1.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(false) + pg1.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) + pg2.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(false) + pg2.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) + } case afiSafiSetToFalse: t.Log("AFI-SAFI is set to false") - if nbr.isV4 { - af4 := nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST) - af4.Enabled = ygot.Bool(false) + if isV4Only { + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(false) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(false) } else { - af6 := nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST) - af6.Enabled = ygot.Bool(false) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(false) + nv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(false) } } } @@ -244,8 +260,11 @@ func verifyBgpSession(t *testing.T, dut *ondatra.DUTDevice, nbrsList []*bgpNeigh for _, nbr := range nbrsList { nbrPath := bgpPath.Neighbor(nbr.neighborip) state := gnmi.Get(t, dut, nbrPath.SessionState().State()) + t.Logf("BGP adjacency for %s: %v", nbr.neighborip, state) if state == oc.Bgp_Neighbor_SessionState_ESTABLISHED { t.Errorf("BGP peer %s status got %d, want other than ESTABLISHED", nbr.neighborip, state) + } else { + t.Logf("BGP peer %s status got %d, want other than ESTABLISHED", nbr.neighborip, state) } } } @@ -313,7 +332,7 @@ func configureOTG(t *testing.T, otg *otg.OTG, otgPeerList []string) gosnappi.Con } // verifyBGPCapabilities is used to Verify BGP capabilities like route refresh as32 and mpbgp. -func verifyBgpCapabilities(t *testing.T, dut *ondatra.DUTDevice, afiSafiLevel string, nbrs []*bgpNeighbor) { +func verifyBgpCapabilities(t *testing.T, dut *ondatra.DUTDevice, afiSafiLevel string, nbrs []*bgpNeighbor, isV4Only bool) { t.Helper() t.Log("Verifying BGP AFI-SAFI capabilities.") @@ -327,11 +346,32 @@ func verifyBgpCapabilities(t *testing.T, dut *ondatra.DUTDevice, afiSafiLevel st oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST: false, oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST: false, } - - for _, cap := range gnmi.GetAll(t, dut, nbrPath.State()) { - capabilities[cap.GetAfiSafiName()] = cap.GetActive() + if deviations.BgpAfiSafiWildcardNotSupported(dut) { + t.Logf("AFI-SAFI wildcard/getall not supported") + afiSafiType := []oc.E_BgpTypes_AFI_SAFI_TYPE{oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST, oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST} + afiSafiList := []*oc.NetworkInstance_Protocol_Bgp_Neighbor_AfiSafi{} + for _, afiSafi := range afiSafiType { + if nbr.isV4 && afiSafi == oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST { + continue + } + if !nbr.isV4 && afiSafi == oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST { + continue + } + t.Logf("AFI-SAFI state: %v", gnmi.Get(t, dut, statePath.Neighbor(nbr.neighborip).AfiSafi(afiSafi).State())) + afiSafiList = append(afiSafiList, gnmi.Get(t, dut, statePath.Neighbor(nbr.neighborip).AfiSafi(afiSafi).State())) + t.Logf("AFI-SAFI list: %v", afiSafiList) + } + for _, cap := range afiSafiList { + capabilities[cap.GetAfiSafiName()] = cap.GetActive() + } + t.Logf("Capabilities for peer %v are %v", nbr.neighborip, capabilities) + } else { + gnmi.GetAll(t, dut, nbrPath.State()) + for _, cap := range gnmi.GetAll(t, dut, nbrPath.State()) { + capabilities[cap.GetAfiSafiName()] = cap.GetActive() + } + t.Logf("Capabilities for peer %v are %v", nbr.neighborip, capabilities) } - switch afiSafiLevel { case nbrLevel: if nbr.isV4 && capabilities[oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST] { @@ -342,20 +382,25 @@ func verifyBgpCapabilities(t *testing.T, dut *ondatra.DUTDevice, afiSafiLevel st } t.Logf("Capabilities for peer %v are %v", nbr.neighborip, capabilities) case peerGrpLevel: - if capabilities[oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST] == true && - capabilities[oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST] == true { + if isV4Only && capabilities[oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST] == true { + t.Logf("Both V4 and V6 AFI-SAFI are inherited from peer-group level for peer: %v, %v", nbr.neighborip, capabilities) + } else if !isV4Only && capabilities[oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST] == true { t.Logf("Both V4 and V6 AFI-SAFI are inherited from peer-group level for peer: %v, %v", nbr.neighborip, capabilities) } else { t.Errorf("Both V4 and V6 AFI-SAFI are not inherited from peer-group level for peer: %v, %v", nbr.neighborip, capabilities) } + t.Logf("Capabilities for peer %v are %v", nbr.neighborip, capabilities) case globalLevel: - if capabilities[oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST] == true && - capabilities[oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST] == true { + if isV4Only && capabilities[oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST] == true { + t.Logf("Both V4 and V6 AFI-SAFI are inherited from global level for peer: %v, %v", nbr.neighborip, capabilities) + } else if !isV4Only && capabilities[oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST] == true { t.Logf("Both V4 and V6 AFI-SAFI are inherited from global level for peer: %v, %v", nbr.neighborip, capabilities) } else { t.Errorf("Both V4 and V6 AFI-SAFI are not inherited from global level for peer: %v, %v", nbr.neighborip, capabilities) } + t.Logf("Capabilities for peer %v are %v", nbr.neighborip, capabilities) case afiSafiSetToFalse: + t.Logf("afiSafiSetToFalse capabilities: %v, v4 -> %v, v6 ->%v", isV4Only, capabilities[oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST], capabilities[oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST]) if nbr.isV4 && capabilities[oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST] == true { t.Errorf("AFI-SAFI are Active after disabling: %v, %v", capabilities, nbr.neighborip) } @@ -430,7 +475,7 @@ func TestAfiSafiOcDefaults(t *testing.T) { desc: "Validate AFI-SAFI OC defaults at peer group level for BGPv4 peers", afiSafiLevel: peerGrpLevel, nbrs: []*bgpNeighbor{nbr1, nbr3}, - isV4Only: false, + isV4Only: true, otgPeerList: []string{otgPort1V4Peer, otgPort2V4Peer}, }, { desc: "Validate AFI-SAFI OC defaults at global level for V4 peers", @@ -480,7 +525,7 @@ func TestAfiSafiOcDefaults(t *testing.T) { t.Run("Verify BGP telemetry", func(t *testing.T) { verifyBgpTelemetry(t, dut, tc.nbrs) verifyOtgBgpTelemetry(t, otg, otgConfig, tc.otgPeerList, "ESTABLISHED") - verifyBgpCapabilities(t, dut, tc.afiSafiLevel, tc.nbrs) + verifyBgpCapabilities(t, dut, tc.afiSafiLevel, tc.nbrs, tc.isV4Only) }) }) } @@ -540,10 +585,14 @@ func TestAfiSafiSetToFalse(t *testing.T) { t.Run("Configure OTG", func(t *testing.T) { configureOTG(t, otg, tc.otgPeerList) }) + t.Logf("Verify BGP session on DUT") + time.Sleep(60 * time.Second) - t.Run("Verify BGP telemetry", func(t *testing.T) { + t.Run("Verify BGP session", func(t *testing.T) { verifyBgpSession(t, dut, tc.nbrs) - verifyBgpCapabilities(t, dut, tc.afiSafiLevel, tc.nbrs) + }) + t.Run("Verify BGP capabilities", func(t *testing.T) { + verifyBgpCapabilities(t, dut, tc.afiSafiLevel, tc.nbrs, tc.isV4Only) }) }) } diff --git a/feature/bgp/otg_tests/bgp_afi_safi_defaults/metadata.textproto b/feature/bgp/otg_tests/bgp_afi_safi_defaults/metadata.textproto index c2e44e3e549..070b871264d 100644 --- a/feature/bgp/otg_tests/bgp_afi_safi_defaults/metadata.textproto +++ b/feature/bgp/otg_tests/bgp_afi_safi_defaults/metadata.textproto @@ -11,6 +11,8 @@ platform_exceptions: { } deviations: { ipv4_missing_enabled: true + bgp_extended_next_hop_encoding_leaf_unsupported: true + bgp_afi_safi_wildcard_not_supported: true } } platform_exceptions: { diff --git a/feature/bgp/otg_tests/bgp_override_as_path_split_horizon_test/bgp_override_as_path_split_horizon_test.go b/feature/bgp/otg_tests/bgp_override_as_path_split_horizon_test/bgp_override_as_path_split_horizon_test.go index d40b62036ec..bdecdb40c3b 100644 --- a/feature/bgp/otg_tests/bgp_override_as_path_split_horizon_test/bgp_override_as_path_split_horizon_test.go +++ b/feature/bgp/otg_tests/bgp_override_as_path_split_horizon_test/bgp_override_as_path_split_horizon_test.go @@ -112,6 +112,8 @@ func bgpCreateNbr(t *testing.T, dut *ondatra.DUTDevice) *oc.NetworkInstance_Prot global := bgp.GetOrCreateGlobal() global.RouterId = ygot.String(dutPort2.IPv4) global.As = ygot.Uint32(dutGlobalAS) + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) // Note: we have to define the peer group even if we aren't setting any policy because it's // invalid OC for the neighbor to be part of a peer group that doesn't exist. @@ -122,6 +124,7 @@ func bgpCreateNbr(t *testing.T, dut *ondatra.DUTDevice) *oc.NetworkInstance_Prot pg.PeerAs = ygot.Uint32(nbr.PeerAS) pg.LocalAs = ygot.Uint32(nbr.LocalAS) pg.PeerGroupName = ygot.String(nbr.PeerGrp) + pg.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) nv4 := bgp.GetOrCreateNeighbor(nbr.Neighborip) nv4.PeerGroup = ygot.String(nbr.PeerGrp) @@ -218,6 +221,7 @@ func advBGPRouteFromOTG(t *testing.T, args *otgTestArgs, asSeg []uint32) { // sent and received IPv4 prefixes. func verifyPrefixesTelemetry(t *testing.T, dut *ondatra.DUTDevice, nbr string, wantInstalled, wantSent uint32) { t.Helper() + time.Sleep(15 * time.Second) statePath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP").Bgp() prefixesv4 := statePath.Neighbor(nbr).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Prefixes() if gotInstalled := gnmi.Get(t, dut, prefixesv4.Installed().State()); gotInstalled != wantInstalled { @@ -232,15 +236,15 @@ func verifyPrefixesTelemetry(t *testing.T, dut *ondatra.DUTDevice, nbr string, w func configureRoutePolicy(t *testing.T, dut *ondatra.DUTDevice, name string, pr oc.E_RoutingPolicy_PolicyResultType) { d := &oc.Root{} rp := d.GetOrCreateRoutingPolicy() - pd := rp.GetOrCreatePolicyDefinition(name) - st, err := pd.AppendNewStatement("id-1") + pdef := rp.GetOrCreatePolicyDefinition(name) + stmt, err := pdef.AppendNewStatement(name) if err != nil { - t.Fatal(err) + t.Fatalf("AppendNewStatement(%s) failed: %v", name, err) } - stc := st.GetOrCreateConditions() - stc.InstallProtocolEq = oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP - st.GetOrCreateActions().PolicyResult = pr - gnmi.Replace(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) + stmt.GetOrCreateActions().PolicyResult = pr + // stmt.GetOrCreateConditions().InstallProtocolEq = oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP + gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) + } // verifyOTGPrefixTelemetry is to Validate prefix received on OTG por2. @@ -325,7 +329,6 @@ func testSplitHorizonAllowOwnAs3(t *testing.T, args *otgTestArgs) { t.Log("Validate session state and capabilities received on DUT using telemetry.") cfgplugins.VerifyDUTBGPEstablished(t, args.dut) cfgplugins.VerifyBGPCapabilities(t, args.dut, []*cfgplugins.BgpNeighbor{nbr1, nbr2}) - t.Log("Verify that the DUT accepts the route.") verifyPrefixesTelemetry(t, args.dut, nbr1.Neighborip, 1, 0) verifyPrefixesTelemetry(t, args.dut, nbr2.Neighborip, 0, 1) @@ -440,8 +443,7 @@ func TestBGPOverrideASPathSplitHorizon(t *testing.T) { }) t.Run("Configure DEFAULT network instance", func(t *testing.T) { - dutConfNIPath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)) - gnmi.Replace(t, dut, dutConfNIPath.Type().Config(), oc.NetworkInstanceTypes_NETWORK_INSTANCE_TYPE_DEFAULT_INSTANCE) + fptest.ConfigureDefaultNetworkInstance(t, dut) }) dutConfPath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP") diff --git a/feature/bgp/policybase/otg_tests/link_bandwidth_test/link_bandwidth_test.go b/feature/bgp/policybase/otg_tests/link_bandwidth_test/link_bandwidth_test.go index c7031776efc..a1205cfa0c0 100644 --- a/feature/bgp/policybase/otg_tests/link_bandwidth_test/link_bandwidth_test.go +++ b/feature/bgp/policybase/otg_tests/link_bandwidth_test/link_bandwidth_test.go @@ -123,7 +123,7 @@ var ( "linkbw_any": "^.*:.*$", } - CommunitySet = map[string]string{ + communitySet = map[string]string{ "regex_match_comm100": "^100:.*$", } ) @@ -182,35 +182,65 @@ func TestBGPLinkBandwidth(t *testing.T) { } baseSetupConfigAndVerification(t, td) configureExtCommunityRoutingPolicy(t, dut) - if deviations.BgpExplicitExtendedCommunityEnable(dut) { - enableExtCommunityCLIConfig(t, dut) - } + enableExtCommunityCLIConfig(t, dut) + testCases := []testCase{ { - name: "Policy set not_match_100_set_linkbw_1M", + name: "ImportPolicy set not_match_100_set_linkbw_1M", policyName: "not_match_100_set_linkbw_1M", - applyPolicy: applyPolicyDut, - validate: validatPolicyDut, - routeCommunity: extCommunity{prefixSet1Comm: "none", prefixSet2Comm: "100:100", prefixSet3Comm: "link-bandwidth:23456:0"}, + applyPolicy: applyImportPolicyDut, + validate: validateImportPolicyDut, + routeCommunity: extCommunity{prefixSet1Comm: "link-bandwidth:23456:1000000", prefixSet2Comm: "100:100", prefixSet3Comm: "link-bandwidth:23456:1000000"}, localPerf: false, validateRouteCommunityV4: validateRouteCommunityV4, validateRouteCommunityV6: validateRouteCommunityV6, }, { - name: "Policy set match_100_set_linkbw_2G", + name: "ExportPolicy set not_match_100_set_linkbw_1M", + policyName: "not_match_100_set_linkbw_1M", + applyPolicy: applyExportPolicyDut, + validate: validateExportPolicyDut, + routeCommunity: extCommunity{prefixSet1Comm: "link-bandwidth:23456:1000000", prefixSet2Comm: "100:100", prefixSet3Comm: "link-bandwidth:23456:1000000"}, + localPerf: false, + validateRouteCommunityV4: validateRouteCommunityV4, + validateRouteCommunityV6: validateRouteCommunityV6, + }, + { + name: "ImportPolicy set match_100_set_linkbw_2G", policyName: "match_100_set_linkbw_2G", - applyPolicy: applyPolicyDut, - validate: validatPolicyDut, - routeCommunity: extCommunity{prefixSet1Comm: "none", prefixSet2Comm: "link-bandwidth:23456:2000000000", prefixSet3Comm: "link-bandwidth:23456:0"}, + applyPolicy: applyImportPolicyDut, + validate: validateImportPolicyDut, + routeCommunity: extCommunity{prefixSet1Comm: "none", prefixSet2Comm: "link-bandwidth:23456:2000000000", prefixSet3Comm: "link-bandwidth:23456:1000"}, localPerf: false, validateRouteCommunityV4: validateRouteCommunityV4, validateRouteCommunityV6: validateRouteCommunityV6, }, + { - name: "Policy set del_linkbw", + name: "ExportPolicy set match_100_set_linkbw_2G", + policyName: "match_100_set_linkbw_2G", + applyPolicy: applyExportPolicyDut, + validate: validateExportPolicyDut, + routeCommunity: extCommunity{prefixSet1Comm: "none", prefixSet2Comm: "link-bandwidth:23456:2000000000", prefixSet3Comm: "link-bandwidth:23456:1000"}, + localPerf: false, + validateRouteCommunityV4: validateRouteCommunityV4, + validateRouteCommunityV6: validateRouteCommunityV6, + }, + { + name: "ImportPolicy set del_linkbw", policyName: "del_linkbw", - applyPolicy: applyPolicyDut, - validate: validatPolicyDut, + applyPolicy: applyImportPolicyDut, + validate: validateImportPolicyDut, + routeCommunity: extCommunity{prefixSet1Comm: "none", prefixSet2Comm: "100:100", prefixSet3Comm: "none"}, + localPerf: false, + validateRouteCommunityV4: validateRouteCommunityV4, + validateRouteCommunityV6: validateRouteCommunityV6, + }, + { + name: "ExportPolicy set del_linkbw", + policyName: "del_linkbw", + applyPolicy: applyExportPolicyDut, + validate: validateExportPolicyDut, routeCommunity: extCommunity{prefixSet1Comm: "none", prefixSet2Comm: "100:100", prefixSet3Comm: "none"}, localPerf: false, validateRouteCommunityV4: validateRouteCommunityV4, @@ -229,25 +259,41 @@ func TestBGPLinkBandwidth(t *testing.T) { } func enableExtCommunityCLIConfig(t *testing.T, dut *ondatra.DUTDevice) { - var extCommunityEnableCLIConfig string - switch dut.Vendor() { - case ondatra.CISCO: - extCommunityEnableCLIConfig = fmt.Sprintf("router bgp %v instance BGP neighbor-group %v \n ebgp-recv-extcommunity-dmz \n ebgp-send-extcommunity-dmz\n", dutAS, cfgplugins.BGPPeerGroup1) - default: - t.Fatalf("Unsupported vendor %s for deviation 'BgpExplicitExtendedCommunityEnable'", dut.Vendor()) - } - helpers.GnmiCLIConfig(t, dut, extCommunityEnableCLIConfig) + if deviations.BgpExplicitExtendedCommunityEnable(dut) { + var extCommunityEnableCLIConfig string + switch dut.Vendor() { + case ondatra.CISCO: + extCommunityEnableCLIConfig = fmt.Sprintf("router bgp %v instance BGP neighbor-group %v \n ebgp-recv-extcommunity-dmz \n ebgp-send-extcommunity-dmz\n", dutAS, cfgplugins.BGPPeerGroup1) + default: + t.Fatalf("Unsupported vendor %s for deviation 'BgpExplicitExtendedCommunityEnable'", dut.Vendor()) + } + helpers.GnmiCLIConfig(t, dut, extCommunityEnableCLIConfig) + } } -func applyPolicyDut(t *testing.T, dut *ondatra.DUTDevice, policyName string) { - // Apply ipv4 policy to bgp neighbour. +func removeImportAndExportPolicy(t *testing.T, dut *ondatra.DUTDevice) { + dni := deviations.DefaultNetworkInstance(dut) + + bd := &gnmi.SetBatch{} + path1 := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort1.IPv4).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).ApplyPolicy() + path2 := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort2.IPv4).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).ApplyPolicy() + path3 := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort1.IPv6).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).ApplyPolicy() + path4 := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort2.IPv6).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).ApplyPolicy() + gnmi.BatchDelete(bd, path1.Config()) + gnmi.BatchDelete(bd, path2.Config()) + gnmi.BatchDelete(bd, path3.Config()) + gnmi.BatchDelete(bd, path4.Config()) + bd.Set(t, dut) +} + +func applyImportPolicyDut(t *testing.T, dut *ondatra.DUTDevice, policyName string) { root := &oc.Root{} dni := deviations.DefaultNetworkInstance(dut) - path := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName). - Bgp().Neighbor(atePort1.IPv4).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).ApplyPolicy() + removeImportAndExportPolicy(t, dut) - policy := root.GetOrCreateNetworkInstance(dni).GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName). - GetOrCreateBgp().GetOrCreateNeighbor(atePort1.IPv4).GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).GetOrCreateApplyPolicy() + // Apply ipv4 policy to bgp neighbour. + path := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort1.IPv4).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).ApplyPolicy() + policy := root.GetOrCreateNetworkInstance(dni).GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).GetOrCreateBgp().GetOrCreateNeighbor(atePort1.IPv4).GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).GetOrCreateApplyPolicy() policy.SetImportPolicy([]string{policyName}) gnmi.Replace(t, dut, path.Config(), policy) @@ -269,13 +315,70 @@ func applyPolicyDut(t *testing.T, dut *ondatra.DUTDevice, policyName string) { gnmi.Update(t, dut, gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP").Config(), niProto) } -func validatPolicyDut(t *testing.T, dut *ondatra.DUTDevice, policyName string) { +func applyExportPolicyDut(t *testing.T, dut *ondatra.DUTDevice, policyName string) { + root := &oc.Root{} + dni := deviations.DefaultNetworkInstance(dut) + removeImportAndExportPolicy(t, dut) + + // Apply ipv4 policy to bgp neighbour. + path := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort2.IPv4).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).ApplyPolicy() + policy := root.GetOrCreateNetworkInstance(dni).GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).GetOrCreateBgp().GetOrCreateNeighbor(atePort2.IPv4).GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).GetOrCreateApplyPolicy() + policy.SetExportPolicy([]string{policyName}) + gnmi.Replace(t, dut, path.Config(), policy) + + // Apply ipv6 policy to bgp neighbour. + path = gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort2.IPv6).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).ApplyPolicy() + policy = root.GetOrCreateNetworkInstance(dni).GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).GetOrCreateBgp().GetOrCreateNeighbor(atePort2.IPv6).GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).GetOrCreateApplyPolicy() + policy.SetExportPolicy([]string{policyName}) + gnmi.Replace(t, dut, path.Config(), policy) + + ni := root.GetOrCreateNetworkInstance(deviations.DefaultNetworkInstance(dut)) + niProto := ni.GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP") + bgp := niProto.GetOrCreateBgp() + bgp.GetOrCreatePeerGroup(cfgplugins.BGPPeerGroup1).GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + bgp.GetOrCreatePeerGroup(cfgplugins.BGPPeerGroup1).GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) + bgpNbrV4 := bgp.GetOrCreateNeighbor(atePort1.IPv4) + bgpNbrV4.PeerGroup = ygot.String(cfgplugins.BGPPeerGroup1) + bgpNbrV6 := bgp.GetOrCreateNeighbor(atePort1.IPv6) + bgpNbrV6.PeerGroup = ygot.String(cfgplugins.BGPPeerGroup1) + gnmi.Update(t, dut, gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP").Config(), niProto) +} + +func validateImportPolicyDut(t *testing.T, dut *ondatra.DUTDevice, policyName string) { dni := deviations.DefaultNetworkInstance(dut) path := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort1.IPv4).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).ApplyPolicy() - policy := gnmi.Get[*oc.NetworkInstance_Protocol_Bgp_Neighbor_AfiSafi_ApplyPolicy](t, dut, path.State()) - importPolicies := policy.GetImportPolicy() - if len(importPolicies) != 1 { - t.Fatalf("ImportPolicy Ipv4 got= %v, want %v", importPolicies, []string{policyName}) + _, ok := gnmi.Watch(t, dut, path.State(), 30*time.Second, func(v *ygnmi.Value[*oc.NetworkInstance_Protocol_Bgp_Neighbor_AfiSafi_ApplyPolicy]) bool { + value, ok := v.Val() + if !ok { + return false + } + importPolicies := value.GetImportPolicy() + if len(importPolicies) != 1 || importPolicies[0] != policyName { + return false + } + return true + }).Await(t) + if !ok { + t.Fatalf("invalid import policy") + } +} + +func validateExportPolicyDut(t *testing.T, dut *ondatra.DUTDevice, policyName string) { + dni := deviations.DefaultNetworkInstance(dut) + path := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort2.IPv4).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).ApplyPolicy() + _, ok := gnmi.Watch(t, dut, path.State(), 30*time.Second, func(v *ygnmi.Value[*oc.NetworkInstance_Protocol_Bgp_Neighbor_AfiSafi_ApplyPolicy]) bool { + value, ok := v.Val() + if !ok { + return false + } + exportPolicies := value.GetExportPolicy() + if len(exportPolicies) != 1 || exportPolicies[0] != policyName { + return false + } + return true + }).Await(t) + if !ok { + t.Fatalf("invalid export policy") } } @@ -325,20 +428,19 @@ func validateRouteCommunityV4Prefix(t *testing.T, td testData, community, v4Pref for _, ec := range bgpPrefix.ExtendedCommunity { lbSubType := ec.Structured.NonTransitive_2OctetAsType.LinkBandwidthSubtype listCommunity := strings.Split(community, ":") - Bandwidth := listCommunity[2] + bandwidth := listCommunity[2] if lbSubType.GetGlobal_2ByteAs() != 23456 && lbSubType.GetGlobal_2ByteAs() != 32002 && lbSubType.GetGlobal_2ByteAs() != 32001 { t.Errorf("ERROR AS number should be 23456 or %d got %d", ateAS, lbSubType.GetGlobal_2ByteAs()) return } - if Bandwidth == "0" { - if ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 0 { - t.Errorf("ERROR lb Bandwidth want 0, got:=%v", ygot.BinaryToFloat32(lbSubType.GetBandwidth())) - } - } else { - if ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 2.5e+08 && ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 2000000000 { - t.Errorf("ERROR lb Bandwidth want :2G, got=%v", ygot.BinaryToFloat32(lbSubType.GetBandwidth())) - } + if bandwidth == "1000" && ygot.BinaryToFloat32(lbSubType.GetBandwidth()) == 0 { + t.Errorf("ERROR lb Bandwidth want 1000, got:=%v", ygot.BinaryToFloat32(lbSubType.GetBandwidth())) + } else if bandwidth == "1000000" && ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 125000 && ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 1000000 { + t.Errorf("ERROR lb Bandwidth want :1M, got=%v", ygot.BinaryToFloat32(lbSubType.GetBandwidth())) + } else if bandwidth == "2000000000" && ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 2.5e+08 && ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 2000000000 { + t.Errorf("ERROR lb Bandwidth want :2G, got=%v", ygot.BinaryToFloat32(lbSubType.GetBandwidth())) } + if !deviations.BgpExtendedCommunityIndexUnsupported(td.dut) { verifyExtCommunityIndexV4(t, td, v4Prefix) } @@ -361,7 +463,6 @@ func validateRouteCommunityV6(t *testing.T, td testData, ec extCommunity) { } func validateRouteCommunityV6Prefix(t *testing.T, td testData, community, v6Prefix string) { - // This function to verify received route communities on ATE ports. _, ok := gnmi.WatchAll(t, td.ate.OTG(), @@ -396,19 +497,17 @@ func validateRouteCommunityV6Prefix(t *testing.T, td testData, community, v6Pref for _, ec := range bgpPrefix.ExtendedCommunity { lbSubType := ec.Structured.NonTransitive_2OctetAsType.LinkBandwidthSubtype listCommunity := strings.Split(community, ":") - Bandwidth := listCommunity[2] + bandwidth := listCommunity[2] if lbSubType.GetGlobal_2ByteAs() != 23456 && lbSubType.GetGlobal_2ByteAs() != 32002 && lbSubType.GetGlobal_2ByteAs() != 32001 { t.Errorf("ERROR AS number should be 23456 or %d got %d", ateAS, lbSubType.GetGlobal_2ByteAs()) return } - if Bandwidth == "0" { - if ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 0 { - t.Errorf("ERROR lb Bandwidth want 0, got:=%v", ygot.BinaryToFloat32(lbSubType.GetBandwidth())) - } - } else { - if ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 2.5e+08 && ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 2000000000 { - t.Errorf("ERROR lb Bandwidth want :2G, got=%v", ygot.BinaryToFloat32(lbSubType.GetBandwidth())) - } + if bandwidth == "1000" && ygot.BinaryToFloat32(lbSubType.GetBandwidth()) == 0 { + t.Errorf("ERROR lb Bandwidth want 1000, got:=%v", ygot.BinaryToFloat32(lbSubType.GetBandwidth())) + } else if bandwidth == "1000000" && ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 125000 && ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 1000000 { + t.Errorf("ERROR lb Bandwidth want :1M, got=%v", ygot.BinaryToFloat32(lbSubType.GetBandwidth())) + } else if bandwidth == "2000000000" && ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 2.5e+08 && ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 2000000000 { + t.Errorf("ERROR lb Bandwidth want :2G, got=%v", ygot.BinaryToFloat32(lbSubType.GetBandwidth())) } if !deviations.BgpExtendedCommunityIndexUnsupported(td.dut) { verifyExtCommunityIndexV6(t, td, v6Prefix) @@ -419,6 +518,7 @@ func validateRouteCommunityV6Prefix(t *testing.T, td testData, community, v6Pref } } } + func configureImportRoutingPolicyAllowAll(t *testing.T, dut *ondatra.DUTDevice) { root := &oc.Root{} rp := root.GetOrCreateRoutingPolicy() @@ -509,26 +609,10 @@ func configureExtCommunityRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice) { root := &oc.Root{} var communitySetCLIConfig string var extCommunitySetCLIConfig string - switch dut.Vendor() { - case ondatra.CISCO: - extCommunitySet = extCommunitySetCisco - default: - t.Logf("extCommunitySet = %v", extCommunitySet) - } - if !deviations.BgpExtendedCommunitySetUnsupported(dut) { - for name, community := range extCommunitySet { - rp := root.GetOrCreateRoutingPolicy() - pdef := rp.GetOrCreateDefinedSets().GetOrCreateBgpDefinedSets() - stmt, err := pdef.NewExtCommunitySet(name) - if err != nil { - t.Fatalf("NewExtCommunitySet failed: %v", err) - } - stmt.SetExtCommunityMember([]string{community}) - gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) - } - } else { + if deviations.BgpExtendedCommunitySetUnsupported(dut) { switch dut.Vendor() { case ondatra.CISCO: + extCommunitySet = extCommunitySetCisco for name, community := range extCommunitySet { if name == "linkbw_any" && deviations.CommunityMemberRegexUnsupported(dut) { communitySetCLIConfig = fmt.Sprintf("community-set %v \n dfa-regex '%v' \n end-set", name, community) @@ -541,45 +625,55 @@ func configureExtCommunityRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice) { default: t.Fatalf("Unsupported vendor %s for native command support for deviation 'BgpExtendedCommunitySetUnsupported'", dut.Vendor()) } - } - - if !(deviations.CommunityMemberRegexUnsupported(dut)) { - for name, community := range CommunitySet { + } else { + for name, community := range extCommunitySet { rp := root.GetOrCreateRoutingPolicy() pdef := rp.GetOrCreateDefinedSets().GetOrCreateBgpDefinedSets() - stmt, err := pdef.NewCommunitySet(name) + stmt, err := pdef.NewExtCommunitySet(name) if err != nil { - t.Fatalf("NewCommunitySet failed: %v", err) + t.Fatalf("NewExtCommunitySet failed: %v", err) } - cs := []oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union{} - cs = append(cs, oc.UnionString(community)) - stmt.SetCommunityMember(cs) + stmt.SetExtCommunityMember([]string{community}) gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) } - } else { + } + + if deviations.CommunityMemberRegexUnsupported(dut) { switch dut.Vendor() { case ondatra.CISCO: - for name, community := range CommunitySet { + for name, community := range communitySet { communitySetCLIConfig = fmt.Sprintf("community-set %v\n dfa-regex '%v' \n end-set", name, community) helpers.GnmiCLIConfig(t, dut, communitySetCLIConfig) } default: t.Fatalf("Unsupported vendor %s for native cmd support for deviation 'CommunityMemberRegexUnsupported'", dut.Vendor()) } + } else { + for name, community := range communitySet { + rp := root.GetOrCreateRoutingPolicy() + pdef := rp.GetOrCreateDefinedSets().GetOrCreateBgpDefinedSets() + stmt, err := pdef.NewCommunitySet(name) + if err != nil { + t.Fatalf("NewCommunitySet failed: %v", err) + } + cs := []oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union{} + cs = append(cs, oc.UnionString(community)) + stmt.SetCommunityMember(cs) + gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) + } } // Configure routing Policy not_match_100_set_linkbw_1M. rpNotMatch := root.GetOrCreateRoutingPolicy() pdef2 := rpNotMatch.GetOrCreatePolicyDefinition("not_match_100_set_linkbw_1M") - pdef2Stmt1, err := pdef2.AppendNewStatement("1-megabit-match") + pdef2Stmt1, err := pdef2.AppendNewStatement("regex_match_comm100_rm_lbw") if err != nil { - t.Fatalf("AppendNewStatement 1-megabit-match failed: %v", err) + t.Fatalf("AppendNewStatement regex_match_comm100_rm_lbw failed: %v", err) } - if !deviations.BgpSetExtCommunitySetRefsUnsupported(dut) { ref := pdef2Stmt1.GetOrCreateActions().GetOrCreateBgpActions().GetOrCreateSetExtCommunity() - ref.GetOrCreateReference().SetExtCommunitySetRefs([]string{"linkbw_1M"}) - ref.SetOptions(oc.BgpPolicy_BgpSetCommunityOptionType_ADD) + ref.GetOrCreateReference().SetExtCommunitySetRefs([]string{"linkbw_any"}) + ref.SetOptions(oc.BgpPolicy_BgpSetCommunityOptionType_REMOVE) ref.SetMethod(oc.SetCommunity_Method_REFERENCE) } if deviations.BGPConditionsMatchCommunitySetUnsupported(dut) { @@ -608,25 +702,51 @@ func configureExtCommunityRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice) { if !deviations.SkipSettingStatementForPolicy(dut) { pdef2Stmt1.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_NEXT_STATEMENT) } - pdef2Stmt2, err := pdef2.AppendNewStatement("accept_all_routes") + + pdef2Stmt2, err := pdef2.AppendNewStatement("regex_match_comm100_add_lbw") if err != nil { - t.Fatalf("AppendNewStatement accept_all_routes failed: %v", err) + t.Fatalf("AppendNewStatement regex_match_comm100_add_lbw failed: %v", err) } - pdef2Stmt2.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE) - if !deviations.BgpSetExtCommunitySetRefsUnsupported(dut) { - gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rpNotMatch) + ref := pdef2Stmt2.GetOrCreateActions().GetOrCreateBgpActions().GetOrCreateSetExtCommunity() + ref.GetOrCreateReference().SetExtCommunitySetRefs([]string{"linkbw_1M"}) + ref.SetOptions(oc.BgpPolicy_BgpSetCommunityOptionType_ADD) + ref.SetMethod(oc.SetCommunity_Method_REFERENCE) + } + if deviations.BGPConditionsMatchCommunitySetUnsupported(dut) { + switch dut.Vendor() { + case ondatra.ARISTA: + ref1 := pdef2Stmt2.GetOrCreateConditions().GetOrCreateBgpConditions() + ref1.SetCommunitySet("regex_match_comm100_deviation1") + } } else { + ref1 := pdef2Stmt2.GetOrCreateConditions().GetOrCreateBgpConditions().GetOrCreateMatchCommunitySet() + ref1.SetCommunitySet("regex_match_comm100") + ref1.SetMatchSetOptions(oc.RoutingPolicy_MatchSetOptionsType_INVERT) + } + if !deviations.SkipSettingStatementForPolicy(dut) { + pdef2Stmt2.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_NEXT_STATEMENT) + } + + pdef2Stmt3, err := pdef2.AppendNewStatement("accept_all_routes") + if err != nil { + t.Fatalf("AppendNewStatement accept_all_routes failed: %v", err) + } + pdef2Stmt3.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE) + + if deviations.BgpSetExtCommunitySetRefsUnsupported(dut) { switch dut.Vendor() { case ondatra.CISCO: var communityCLIConfig string - communityCLIConfig = fmt.Sprintf("community-set %v\n dfa-regex '%v', \n match invert \n end-set", "regex_match_comm100", CommunitySet["regex_match_comm100"]) + communityCLIConfig = fmt.Sprintf("community-set %v\n dfa-regex '%v', \n match invert \n end-set", "regex_match_comm100", communitySet["regex_match_comm100"]) policySetCLIConfig := fmt.Sprintf("route-policy %v \n #statement-1 1-megabit-match \n if community is-empty then \n pass \n elseif community in %v then \n set extcommunity bandwidth %v \n endif \n pass \n #statement-2 accept_all_routes \n done \n end-policy", "not_match_100_set_linkbw_1M", "regex_match_comm100", "linkbw_1M") helpers.GnmiCLIConfig(t, dut, communityCLIConfig) helpers.GnmiCLIConfig(t, dut, policySetCLIConfig) default: t.Fatalf("Unsupported vendor %s for native cmd support for deviation 'BgpSetExtCommunitySetRefsUnsupported'", dut.Vendor()) } + } else { + gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rpNotMatch) } // Configure routing policy match_100_set_linkbw_2G. @@ -661,7 +781,7 @@ func configureExtCommunityRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice) { ref1.SetCommunitySet("regex_match_comm100_deviation2") } } else { - ref1 := pdef3Stmt1.GetOrCreateConditions().GetOrCreateBgpConditions().GetMatchCommunitySet() + ref1 := pdef3Stmt1.GetOrCreateConditions().GetOrCreateBgpConditions().GetOrCreateMatchCommunitySet() ref1.SetCommunitySet("regex_match_comm100") ref1.SetMatchSetOptions(oc.RoutingPolicy_MatchSetOptionsType_ANY) } @@ -673,18 +793,18 @@ func configureExtCommunityRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice) { t.Fatalf("AppendNewStatement accept_all_routes failed: %v", err) } pdef3Stmt2.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE) - if !deviations.BgpSetExtCommunitySetRefsUnsupported(dut) { - gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rpMatch) - } else { + if deviations.BgpSetExtCommunitySetRefsUnsupported(dut) { switch dut.Vendor() { case ondatra.CISCO: - communitySetCLIConfig = fmt.Sprintf("community-set %v\n dfa-regex '%v', \n match any \n end-set", "regex_match_any_comm100", CommunitySet["regex_match_comm100"]) + communitySetCLIConfig = fmt.Sprintf("community-set %v\n dfa-regex '%v', \n match any \n end-set", "regex_match_any_comm100", communitySet["regex_match_comm100"]) helpers.GnmiCLIConfig(t, dut, communitySetCLIConfig) communitySetCLIConfig = fmt.Sprintf("route-policy %v \n #statement-1 2-gigabit-match \n if community in %v then \n set extcommunity bandwidth %v \n endif \n pass \n #statement-2 accept_all_routes \n done \n end-policy", "match_100_set_linkbw_2G", "regex_match_any_comm100", "linkbw_2G") helpers.GnmiCLIConfig(t, dut, communitySetCLIConfig) default: t.Fatalf("Unsupported vendor %s for native cmd support for deviation 'BgpSetExtCommunitySetRefsUnsupported' and 'BGPConditionsMatchCommunitySetUnsupported' and 'SkipSettingStatementForPolicy'", dut.Vendor()) } + } else { + gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rpMatch) } // Configure routing policy del_linkbw. @@ -708,9 +828,7 @@ func configureExtCommunityRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice) { t.Fatalf("AppendNewStatement accept_all_routes failed: %v", err) } pdef4Stmt2.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE) - if !deviations.BgpDeleteLinkBandwidthUnsupported(dut) { - gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rpDelLinkbw) - } else { + if deviations.BgpDeleteLinkBandwidthUnsupported(dut) { var delLinkbwCLIConfig string switch dut.Vendor() { case ondatra.CISCO: @@ -719,7 +837,11 @@ func configureExtCommunityRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice) { t.Fatalf("Unsupported vendor %s for native cmd support for deviation 'BgpDeleteLinkBandwidthUnsupported'", dut.Vendor()) } helpers.GnmiCLIConfig(t, dut, delLinkbwCLIConfig) + } else { + gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rpDelLinkbw) } + + fptest.LogQuery(t, "", gnmi.OC().RoutingPolicy().Config(), root) } func createFlow(t *testing.T, td testData, fc flowConfig) { @@ -801,7 +923,7 @@ func (td *testData) advertiseRoutesWithEBGP(t *testing.T) { nV42 := bgp.GetOrCreateNeighbor(atePort2.IPv4) nV42.SetPeerAs(dutAS) if !deviations.SkipBgpSendCommunityType(td.dut) { - nV42.SetSendCommunityType([]oc.E_Bgp_CommunityType{oc.Bgp_CommunityType_BOTH}) + nV42.SetSendCommunityType([]oc.E_Bgp_CommunityType{oc.Bgp_CommunityType_STANDARD, oc.Bgp_CommunityType_EXTENDED}) } nV42.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) nV61 := bgp.GetOrCreateNeighbor(atePort1.IPv6) @@ -810,7 +932,7 @@ func (td *testData) advertiseRoutesWithEBGP(t *testing.T) { nV62 := bgp.GetOrCreateNeighbor(atePort2.IPv6) nV62.SetPeerAs(dutAS) if !deviations.SkipBgpSendCommunityType(td.dut) { - nV62.SetSendCommunityType([]oc.E_Bgp_CommunityType{oc.Bgp_CommunityType_BOTH}) + nV62.SetSendCommunityType([]oc.E_Bgp_CommunityType{oc.Bgp_CommunityType_STANDARD, oc.Bgp_CommunityType_EXTENDED}) } nV62.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) gnmi.Update(t, td.dut, gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(td.dut)).Config(), ni) @@ -849,12 +971,12 @@ func (td *testData) advertiseRoutesWithEBGP(t *testing.T) { netv43.Addresses().Add().SetAddress(advertisedIPv43.address).SetPrefix(advertisedIPv43.prefix) extcommv4 := netv43.ExtendedCommunities().Add().NonTransitive2OctetAsType().LinkBandwidthSubtype() extcommv4.SetGlobal2ByteAs(23456) - extcommv4.SetBandwidth(0) + extcommv4.SetBandwidth(1000) netv63 := bgp6Peer1.V6Routes().Add().SetName("v6-bgpNet-dev3") netv63.Addresses().Add().SetAddress(advertisedIPv63.address).SetPrefix(advertisedIPv63.prefix) extcommv6 := netv63.ExtendedCommunities().Add().NonTransitive2OctetAsType().LinkBandwidthSubtype() extcommv6.SetGlobal2ByteAs(23456) - extcommv6.SetBandwidth(0) + extcommv6.SetBandwidth(1000) // Configure iBGP on OTG port2. ipv42 := td.otgP2.Ethernets().Items()[0].Ipv4Addresses().Items()[0] diff --git a/feature/gribi/otg_tests/basic_encap_test/basic_encap_test.go b/feature/gribi/otg_tests/basic_encap_test/basic_encap_test.go index d5109eef5f1..a864237ba74 100644 --- a/feature/gribi/otg_tests/basic_encap_test/basic_encap_test.go +++ b/feature/gribi/otg_tests/basic_encap_test/basic_encap_test.go @@ -578,8 +578,6 @@ func getPbrRules(dut *ondatra.DUTDevice, clusterFacing bool) []pbrRule { pbrRules = append(pbrRules, encapRules...) } - pbrRules = append(pbrRules, splitDefaultClassRules...) - if deviations.PfRequireMatchDefaultRule(dut) { pbrRules = append(pbrRules, splitDefaultClassRules...) } else { @@ -803,6 +801,13 @@ func configureDUT(t *testing.T, dut *ondatra.DUTDevice) { // configure base PBF policies and network-instances configureBaseconfig(t, dut) + if deviations.ExplicitInterfaceInDefaultVRF(dut) { + 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) + fptest.AssignToNetworkInstance(t, dut, p5.Name(), deviations.DefaultNetworkInstance(dut), 0) + } // apply PBF to src interface. applyForwardingPolicy(t, dut, p1.Name()) if deviations.GRIBIMACOverrideWithStaticARP(dut) { diff --git a/feature/gribi/otg_tests/basic_encap_test/metadata.textproto b/feature/gribi/otg_tests/basic_encap_test/metadata.textproto index 29fb9f8def3..26ca7986368 100644 --- a/feature/gribi/otg_tests/basic_encap_test/metadata.textproto +++ b/feature/gribi/otg_tests/basic_encap_test/metadata.textproto @@ -38,4 +38,15 @@ platform_exceptions: { omit_l2_mtu: true } } +platform_exceptions: { + platform: { + vendor: NOKIA + } + deviations: { + interface_enabled: true + explicit_interface_in_default_vrf: true + static_protocol_name: "static" + ttl_copy_unsupported: true + } +} tags: TAGS_DATACENTER_EDGE diff --git a/feature/gribi/otg_tests/encap_decap_scale/README.md b/feature/gribi/otg_tests/encap_decap_scale/README.md index 050b8bae94a..def619ebb79 100644 --- a/feature/gribi/otg_tests/encap_decap_scale/README.md +++ b/feature/gribi/otg_tests/encap_decap_scale/README.md @@ -326,7 +326,7 @@ network-instances { * Add 1 VRF for decapsulation, `DECAP_TE_VRF`. * Add 2 Tunnel VRFs, `TE_VRF_111` and `TE_VRF_222`. * Inject 5000 IPv4Entry-ies and 5000 IPv6Entry-ies to each of the 4 encap VRFs. - * The entries in the encap VRFs should point to NextHopGroups in the `DEFAULT` VRF. Inject 200 such NextHopGroups in the DEFAULT VRF. + * The entries in the encap VRFs should point to NextHopGroups in the `DEFAULT` VRF. Inject 800 such NextHopGroups in the DEFAULT VRF. * Each NextHopGroup should have 8 NextHops where each NextHop points to a tunnel in the `TE_VRF_111`. In addition, the weights specified in the NextHopGroup should be co-prime and the sum of the weights should be 16. * Inject `48` entries in the DECAP_TE_VRF where the entries have a mix of prefix lengths /22, /24, /26, and /28. @@ -395,7 +395,7 @@ network-instances { * outer_src: `ipv4_outer_src_111` * outer_dst: `ipv4_outer_decap_match` * dscp: `dscp_encap_d` - * proto: `41` + * proto: `41` ``` 3. Send traffic to DUT-1, covering all the installed v4 and v6 entries in the decap and encap VRFs. Validate that all traffic are all decapped per the DECAP VRFs and then encapsulated per the ENCAP VRFs and received as encapsulated packet by ATE. diff --git a/feature/gribi/otg_tests/encap_decap_scale/encap_decap_scale_test.go b/feature/gribi/otg_tests/encap_decap_scale/encap_decap_scale_test.go index 22b731e0879..886a2554e2e 100644 --- a/feature/gribi/otg_tests/encap_decap_scale/encap_decap_scale_test.go +++ b/feature/gribi/otg_tests/encap_decap_scale/encap_decap_scale_test.go @@ -107,7 +107,7 @@ const ( teVrf111TunnelCount = 1600 teVrf222TunnelCount = 1600 encapNhCount = 1600 - encapNhgcount = 200 + encapNhgcount = 800 encapIPv4Count = 5000 encapIPv6Count = 5000 decapIPv4Count = 48 @@ -368,7 +368,7 @@ func createIPv6Entries(startIP string, count uint64) []string { // pushEncapEntries pushes IP entries in a specified Encap VRFs and tunnel VRFs. // The entries in the encap VRFs should point to NextHopGroups in the DEFAULT VRF. -// Inject 200 such NextHopGroups in the DEFAULT VRF. Each NextHopGroup should have +// Inject 800 such NextHopGroups in the DEFAULT VRF. Each NextHopGroup should have // 8 NextHops where each NextHop points to a tunnel in the TE_VRF_111. // In addition, the weights specified in the NextHopGroup should be co-prime and the // sum of the weights should be 16. diff --git a/feature/gribi/otg_tests/gribi_static_route_on_lemmings_test/README.md b/feature/gribi/otg_tests/gribi_static_route_on_lemmings_test/README.md new file mode 100644 index 00000000000..2dbfbd4334a --- /dev/null +++ b/feature/gribi/otg_tests/gribi_static_route_on_lemmings_test/README.md @@ -0,0 +1,48 @@ +# RT: GRIBI Static Route On Lemmings Test + +## Summary + +Ensure the GRIBI injecting the route entry on lemmings (Control plane), which is brought up in KNE topology + +## Topology + +ATE port-1 <------> port-1 DUT +DUT port-2 <------> port-2 ATE + + +## Baseline + +``` +### Install the following gRIBI AFTs. + +- IPv4Entry {198.50.100.64/32 (DEFAULT)} -> NHG#2 (DEFAULT VRF) -> { + {NH#2, DEFAULT VRF, weight:1}, interface-ref:dut-port-2-interface, + } + +``` + +## Procedure + +The DUT should be reset to the baseline after each of the following tests. + +Test-1, Configure the route entry on lemmings in KNE topology + +``` +1. Configure the DUT and OTG. +2. Configure Nh, NHG and IPv4 entry through gRIBI route injection. +3. Validate the acknowledgement for FIB installation success. + +``` + +## OpenConfig Path and RPC Coverage +```yaml +rpcs: + gnmi: + gNMI.Get: + gNMI.Set: + gNMI.Subscribe: + gribi: + gRIBI.Get: + gRIBI.Modify: + gRIBI.Flush: +``` diff --git a/feature/gribi/otg_tests/gribi_static_route_on_lemmings_test/gribi_static_route_on_lemmings_test.go b/feature/gribi/otg_tests/gribi_static_route_on_lemmings_test/gribi_static_route_on_lemmings_test.go new file mode 100644 index 00000000000..548713278da --- /dev/null +++ b/feature/gribi/otg_tests/gribi_static_route_on_lemmings_test/gribi_static_route_on_lemmings_test.go @@ -0,0 +1,185 @@ +package gribi_static_route_on_lemmings_test + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/open-traffic-generator/snappi/gosnappi" + "github.com/openconfig/featureprofiles/internal/attrs" + "github.com/openconfig/featureprofiles/internal/deviations" + "github.com/openconfig/featureprofiles/internal/fptest" + "github.com/openconfig/featureprofiles/internal/gribi" + "github.com/openconfig/gribigo/chk" + "github.com/openconfig/gribigo/constants" + "github.com/openconfig/gribigo/fluent" + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" +) + +const ( + niTransitTeVrf = "DEFAULT" + ipv4OuterDst111 = "198.50.100.64" +) + +var ( + dutPort1 = attrs.Attributes{ + Desc: "DUT Port 1", + IPv4: "192.0.2.1", + IPv4Len: 30, + } + dutPort2 = attrs.Attributes{ + Desc: "DUT Port 2", + IPv4: "192.0.2.5", + IPv4Len: 30, + } + + atePort1 = attrs.Attributes{ + Name: "port1", + MAC: "02:00:01:01:01:01", + Desc: "ATE Port 1", + IPv4: "192.0.2.2", + IPv4Len: 30, + } + atePort2 = attrs.Attributes{ + Name: "port2", + MAC: "02:00:02:01:01:01", + Desc: "ATE Port 2", + IPv4: "192.0.2.6", + IPv4Len: 30, + } +) + +// testArgs holds the objects needed by a test case. +type testArgs struct { + dut *ondatra.DUTDevice + ctx context.Context + client *fluent.GRIBIClient +} + +func TestMain(m *testing.M) { + fptest.RunTests(m) +} + +func TestGRIBI(t *testing.T) { + dut := ondatra.DUT(t, "dut") + configureDUT(t, dut) + configureOTG(t, dut) + configureGribiRoute(t, dut) + + // TODO: Don't have a support to validate the gRIBI route in AFT for Lemmings, implementation request should be raised. + // gnmi.Get(t, dut, gnmi.OC().NetworkInstance(networkInstance).Afts().Ipv4Entry(ipv4OuterDst111+"/"+mask).State()) + + aft := gnmi.Get(t, dut, gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Afts().State()) + t.Logf("dut1 system: %v", aft) + + afts := gnmi.LookupAll(t, dut, gnmi.OC().NetworkInstanceAny().Afts().State()) + t.Logf("dut1 system: %v", afts) + + fibt := gnmi.LookupAll(t, dut, gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).ProtocolAny().State()) + t.Logf("dut1 system: %v", fibt) +} + +func configureDUT(t *testing.T, dut *ondatra.DUTDevice) { + fptest.ConfigureDefaultNetworkInstance(t, dut) + t.Logf("configureDUT") + p1 := dut.Port(t, "port1") + p2 := dut.Port(t, "port2") + + gnmi.Replace(t, dut, gnmi.OC().Interface(p1.Name()).Config(), dutPort1.NewOCInterface(p1.Name(), dut)) + gnmi.Replace(t, dut, gnmi.OC().Interface(p2.Name()).Config(), dutPort2.NewOCInterface(p2.Name(), dut)) + + if deviations.ExplicitPortSpeed(dut) { + fptest.SetPortSpeed(t, p1) + fptest.SetPortSpeed(t, p2) + } + if deviations.ExplicitInterfaceInDefaultVRF(dut) { + fptest.AssignToNetworkInstance(t, dut, p1.Name(), deviations.DefaultNetworkInstance(dut), 0) + fptest.AssignToNetworkInstance(t, dut, p2.Name(), deviations.DefaultNetworkInstance(dut), 0) + } +} + +func configureOTG(t *testing.T, dut *ondatra.DUTDevice) { + t.Logf("configure OTG") + ate := ondatra.ATE(t, "ate") + ap1 := ate.Port(t, "port1") + ap2 := ate.Port(t, "port2") + + cfg := gosnappi.NewConfig() + cfg.Ports().Add().SetName(ap1.ID()) + intf1 := cfg.Devices().Add().SetName("intf1") + eth1Name := fmt.Sprintf("%s.eth", intf1.Name()) + eth1 := intf1.Ethernets().Add().SetName(eth1Name).SetMac(atePort1.MAC) + eth1.Connection().SetPortName(ap1.ID()) + ip1Name := fmt.Sprintf("%s.ipv4", intf1.Name()) + eth1.Ipv4Addresses().Add(). + SetName(ip1Name). + SetAddress(atePort1.IPv4). + SetPrefix(30). + SetGateway(dutPort1.IPv4) + cfg.Ports().Add().SetName(ap2.ID()) + intf2 := cfg.Devices().Add().SetName("intf2") + eth2Name := fmt.Sprintf("%s.eth", intf2.Name()) + eth2 := intf2.Ethernets().Add().SetName(eth2Name).SetMac(atePort2.MAC) + eth2.Connection().SetPortName(ap2.ID()) + ip2Name := fmt.Sprintf("%s.ipv4", intf2.Name()) + eth2.Ipv4Addresses().Add(). + SetName(ip2Name). + SetAddress(atePort2.IPv4). + SetPrefix(30). + SetGateway(dutPort2.IPv4) + ate.OTG().PushConfig(t, cfg) + ate.OTG().StartProtocols(t) +} + +func configureGribiRoute(t *testing.T, dut *ondatra.DUTDevice) { + t.Log("Configure GRIBI") + t.Helper() + ctx := context.Background() + gribic := dut.RawAPIs().GRIBI(t) + client := fluent.NewClient() + client.Connection().WithStub(gribic).WithPersistence().WithInitialElectionID(12, 0). + WithRedundancyMode(fluent.ElectedPrimaryClient).WithFIBACK() + client.Start(ctx, t) + defer client.Stop(t) + gribi.FlushAll(client) + defer gribi.FlushAll(client) + client.StartSending(ctx, t) + gribi.BecomeLeader(t, client) + + tcArgs := &testArgs{ + ctx: ctx, + client: client, + dut: dut, + } + + tcArgs.client.Modify().AddEntry(t, + fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(tcArgs.dut)). + WithIndex(uint64(2)).WithIPAddress(atePort2.IPv4), + fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(tcArgs.dut)). + WithID(uint64(2)).AddNextHop(uint64(2), uint64(1)), + + fluent.IPv4Entry().WithNetworkInstance(niTransitTeVrf).WithNextHopGroupNetworkInstance(deviations.DefaultNetworkInstance(dut)). + WithPrefix(ipv4OuterDst111+"/32").WithNextHopGroup(uint64(2))) + + if err := awaitTimeout(tcArgs.ctx, t, tcArgs.client, 90*time.Second); err != nil { + t.Logf("Could not program entries via client, got err, check error codes: %v", err) + } + + chk.HasResult(t, tcArgs.client.Results(t), + fluent.OperationResult(). + WithIPv4Operation(ipv4OuterDst111+"/32"). + WithOperationType(constants.Add). + WithProgrammingResult(fluent.InstalledInFIB). + AsResult(), + chk.IgnoreOperationID(), + ) +} + +func awaitTimeout(ctx context.Context, t testing.TB, c *fluent.GRIBIClient, timeout time.Duration) error { + t.Helper() + subctx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + return c.Await(subctx, t) +} diff --git a/feature/gribi/otg_tests/gribi_static_route_on_lemmings_test/metadata.textproto b/feature/gribi/otg_tests/gribi_static_route_on_lemmings_test/metadata.textproto new file mode 100644 index 00000000000..ce41cb2f6e3 --- /dev/null +++ b/feature/gribi/otg_tests/gribi_static_route_on_lemmings_test/metadata.textproto @@ -0,0 +1,23 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata + +uuid: "12335133-aed1-463d-b9cd-76dbf8ef88cc" +plan_id: "RT" +description: "GRIBI Static Route On Lemmings Test" +testbed: TESTBED_DUT_ATE_2LINKS +platform_exceptions: { + platform: { + vendor: ARISTA + } + deviations: { + interface_enabled: true + default_network_instance: "default" + route_policy_under_afi_unsupported: true + static_protocol_name: "STATIC" + aggregate_atomic_update: true + missing_value_for_defaults: true + max_ecmp_paths: true + explicit_interface_in_default_vrf: false + } +} +tags: TAGS_DATACENTER_EDGE \ No newline at end of file diff --git a/feature/gribi/otg_tests/mpls_in_udp/README.md b/feature/gribi/otg_tests/mpls_in_udp/README.md index fde748ddc4d..b2f8fc44704 100644 --- a/feature/gribi/otg_tests/mpls_in_udp/README.md +++ b/feature/gribi/otg_tests/mpls_in_udp/README.md @@ -253,11 +253,6 @@ openconfig-network-instance: * Generate traffic from ATE port 1 * Validate ATE port 2 receives the innermost IPv4 traffic with correct VLAN and inner_decap_ipv6 -### TE-18.1.5 - Policy forwarding to encap and forward for BGP packets - -TODO: Specify a solution for ensuring BGP packets are matched, encapsulated -and forwarding to a specified destination using OC policy-forwarding terms. - ## OpenConfig Path and RPC Coverage ```yaml diff --git a/feature/isis/otg_tests/static_route_isis_redistribution/metadata.textproto b/feature/isis/otg_tests/static_route_isis_redistribution/metadata.textproto index bbced9e82ee..2e9a824e2c1 100644 --- a/feature/isis/otg_tests/static_route_isis_redistribution/metadata.textproto +++ b/feature/isis/otg_tests/static_route_isis_redistribution/metadata.textproto @@ -34,3 +34,15 @@ platform_exceptions: { match_tag_set_condition_unsupported: true } } +platform_exceptions: { + platform: { + vendor: NOKIA + } + deviations: { + explicit_interface_in_default_vrf: true + interface_enabled: true + static_protocol_name: "static" + skip_prefix_set_mode: true + enable_table_connections: true + } +} diff --git a/feature/isis/otg_tests/static_route_isis_redistribution/static_route_isis_redistribution_test.go b/feature/isis/otg_tests/static_route_isis_redistribution/static_route_isis_redistribution_test.go index 231b7b19aa5..9bbc947d8d3 100644 --- a/feature/isis/otg_tests/static_route_isis_redistribution/static_route_isis_redistribution_test.go +++ b/feature/isis/otg_tests/static_route_isis_redistribution/static_route_isis_redistribution_test.go @@ -63,7 +63,8 @@ const ( protoDst = oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS dummyV6 = "2001:db8::192:0:2:d" dummyMAC = "00:1A:11:00:0A:BC" - tagValue = 100 + V4tagValue = 40 + V6tagValue = 60 ) var ( @@ -113,7 +114,7 @@ func getAndVerifyIsisImportPolicy(t *testing.T, if err != nil { t.Fatalf("failed due to %v", err) } - t.Log(getResponse) + t.Log("Received parameters of table connections") t.Log("Verify Get outputs ") for _, notification := range getResponse.Notification { @@ -142,9 +143,9 @@ func getAndVerifyIsisImportPolicy(t *testing.T, t.Fatalf("import-policy is not set to %s as expected", RplName) } } - t.Logf("Table Connection Details:"+ + t.Logf("Table Connection Details:\n"+ "SRC PROTO GOT %v WANT STATIC\n"+ - "DST PRTO GOT %v WANT ISIS\n"+ + "DST PROTO GOT %v WANT ISIS\n"+ "ADDRESS FAMILY GOT %v WANT %v\n"+ "DISABLEMETRICPROPAGATION GOT %v WANT %v\n", config.SrcProtocol, config.DstProtocol, config.AddressFamily, addressFamily, @@ -171,6 +172,10 @@ func isisImportPolicyConfig(t *testing.T, dut *ondatra.DUTDevice, policyName str if !deviations.SkipSettingDisableMetricPropagation(dut) { tableConn.SetDisableMetricPropagation(metricPropagation) } + if deviations.EnableTableConnections(dut) { + state := "enable" + configEnableTbNative(t, dut, state) + } gnmi.BatchReplace(batchSet, gnmi.OC().NetworkInstance(dni).TableConnection(srcProto, dstProto, addfmly).Config(), tableConn) if deviations.SamePolicyAttachedToAllAfis(dut) { @@ -206,7 +211,9 @@ func configureRoutePolicy(dut *ondatra.DUTDevice, rplName string, statement stri v4Prefix := v4Route + "/" + strconv.FormatUint(uint64(v4RoutePrefix), 10) pset := rp.GetOrCreateDefinedSets().GetOrCreatePrefixSet(v4PrefixSet) pset.GetOrCreatePrefix(v4Prefix, prefixMatch) - pset.SetMode(oc.PrefixSet_Mode_IPV4) + if !deviations.SkipPrefixSetMode(dut) { + pset.SetMode(oc.PrefixSet_Mode_IPV4) + } stmt1.GetOrCreateConditions().GetOrCreateMatchPrefixSet().SetPrefixSet(v4PrefixSet) stmt1.GetOrCreateActions().SetPolicyResult(rplType) @@ -217,7 +224,9 @@ func configureRoutePolicy(dut *ondatra.DUTDevice, rplName string, statement stri v6Prefix := v6Route + "/" + strconv.FormatUint(uint64(v6RoutePrefix), 10) pset = rp.GetOrCreateDefinedSets().GetOrCreatePrefixSet(v6PrefixSet) pset.GetOrCreatePrefix(v6Prefix, prefixMatch) - pset.SetMode(oc.PrefixSet_Mode_IPV6) + if !deviations.SkipPrefixSetMode(dut) { + pset.SetMode(oc.PrefixSet_Mode_IPV6) + } stmt2.GetOrCreateConditions().GetOrCreateMatchPrefixSet().SetPrefixSet(v6PrefixSet) stmt2.GetOrCreateActions().SetPolicyResult(rplType) } else if tagSetCond { @@ -228,7 +237,7 @@ func configureRoutePolicy(dut *ondatra.DUTDevice, rplName string, statement stri } v4tagSet := getTagSetName(dut, rplName, v4Statement, "v4") tagSet1 := rp.GetOrCreateDefinedSets().GetOrCreateTagSet(v4tagSet) - tagSet1.SetTagValue([]oc.RoutingPolicy_DefinedSets_TagSet_TagValue_Union{oc.UnionUint32(tagValue)}) + tagSet1.SetTagValue([]oc.RoutingPolicy_DefinedSets_TagSet_TagValue_Union{oc.UnionUint32(V4tagValue)}) stmt1.GetOrCreateConditions().GetOrCreateMatchTagSet().SetTagSet(v4tagSet) stmt1.GetOrCreateActions().SetPolicyResult(rplType) @@ -238,7 +247,7 @@ func configureRoutePolicy(dut *ondatra.DUTDevice, rplName string, statement stri } v6tagSet := getTagSetName(dut, rplName, v6Statement, "v6") tagSet2 := rp.GetOrCreateDefinedSets().GetOrCreateTagSet(v6tagSet) - tagSet2.SetTagValue([]oc.RoutingPolicy_DefinedSets_TagSet_TagValue_Union{oc.UnionUint32(tagValue)}) + tagSet2.SetTagValue([]oc.RoutingPolicy_DefinedSets_TagSet_TagValue_Union{oc.UnionUint32(V6tagValue)}) stmt2.GetOrCreateConditions().GetOrCreateMatchTagSet().SetTagSet(v6tagSet) stmt2.GetOrCreateActions().SetPolicyResult(rplType) } else { @@ -366,6 +375,46 @@ func getTagSetName(dut *ondatra.DUTDevice, policyName, stmtName, afStr string) s return fmt.Sprintf("tag-set-%s", afStr) } +func configEnableTbNative(t testing.TB, d *ondatra.DUTDevice, state string) { + t.Helper() + switch d.Vendor() { + case ondatra.NOKIA: + adminEnable, err := json.Marshal(state) + if err != nil { + t.Fatalf("Error with json Marshal: %v", err) + } + + gpbSetRequest := &gpb.SetRequest{ + Prefix: &gpb.Path{ + Origin: "native", + }, + Update: []*gpb.Update{ + { + Path: &gpb.Path{ + Elem: []*gpb.PathElem{ + {Name: "network-instance", Key: map[string]string{"name": "DEFAULT"}}, + {Name: "table-connections"}, + {Name: "admin-state"}, + }, + }, + Val: &gpb.TypedValue{ + Value: &gpb.TypedValue_JsonIetfVal{ + JsonIetfVal: adminEnable, + }, + }, + }, + }, + } + + gnmiClient := d.RawAPIs().GNMI(t) + if _, err := gnmiClient.Set(context.Background(), gpbSetRequest); err != nil { + t.Fatalf("Unexpected error updating SRL static-route tag-set: %v", err) + } + default: + t.Fatalf("Unsupported vendor %s for deviation 'EnableTableConnections'", d.Vendor()) + } +} + func TestStaticToISISRedistribution(t *testing.T) { var ts *isissession.TestSession @@ -462,6 +511,7 @@ func TestStaticToISISRedistribution(t *testing.T) { desc: "RT-2.12.8: Redistribute IPv6 static route to IS-IS matching a prefix using a route-policy", protoAf: oc.Types_ADDRESS_FAMILY_IPV6, RplName: v6RoutePolicy, + metricPropogation: true, policyStmtType: oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE, verifyTrafficStats: true, trafficFlows: []string{v6Flow}, @@ -497,8 +547,8 @@ func TestStaticToISISRedistribution(t *testing.T) { if tc.TagSetCondition { t.Run("Verify Configuration for RPL TagSet", func(t *testing.T) { - verifyRplConfig(t, ts.DUT, getTagSetName(ts.DUT, tc.RplName, v4Statement, "v4"), oc.UnionUint32(tagValue)) - verifyRplConfig(t, ts.DUT, getTagSetName(ts.DUT, tc.RplName, v6Statement, "v6"), oc.UnionUint32(tagValue)) + verifyRplConfig(t, ts.DUT, getTagSetName(ts.DUT, tc.RplName, v4Statement, "v4"), oc.UnionUint32(V4tagValue)) + verifyRplConfig(t, ts.DUT, getTagSetName(ts.DUT, tc.RplName, v6Statement, "v6"), oc.UnionUint32(V6tagValue)) }) } diff --git a/feature/isis/otg_tests/weighted_ecmp_test/README.md b/feature/isis/otg_tests/weighted_ecmp_test/README.md index dee5ca53f52..8a5bdf8448a 100644 --- a/feature/isis/otg_tests/weighted_ecmp_test/README.md +++ b/feature/isis/otg_tests/weighted_ecmp_test/README.md @@ -29,23 +29,25 @@ G[DUT:LAG4] <-- IBGP+IS-IS --> H[LAG3:ATE2]; ## Procedure -In the topology above, - -* Configure 1xLAG interface between ATE1<->DUT and 3xLAG interfaces between - DUT and ATE2. Each LAG interface is expected to be of 2x100Gbps - -* Configure IPv4 and IPv6 L2 adjacencies between DUT and ATE LAG bundles. - Therefore, DUT will have 1xIS-IS adjacency with ATE1 i.e. - DUT:LAG1<->ATE1:LAG1, and 3xIS-IS adjacencies with ATE2 i.e. - DUT:LAG2<->ATE2:LAG1, DUT:LAG3<->ATE2:LAG2 and DUT:LAG4<->ATE2:LAG3 - - * /network-instances/network-instance/protocols/protocol/isis/global/afi-safi - - * /network-instances/network-instance/protocols/protocol/isis/global/config/level-capability, - set to LEVEL_2 - - * /network-instances/network-instance/protocols/protocol/isis/levels/level/config/metric-style - set to WIDE_METRIC +### Test environment setup + +* Configure 1 aggregate interface with 2 100GE ports between DUT and ATE1 +* Configure 3 aggregate interfaces, each with 2 100GE ports between DUT and ATE2. +* Configure IPv4 and IPv6 L2 adjacencies between DUT and ATE aggregate interfaces. + Therefore, DUT will have + * 1xIS-IS adjacency with ATE1 DUT:LAG1<->ATE1:LAG1, + * 3xIS-IS adjacencies between DUT and ATE2 + * DUT:LAG2<->ATE2:LAG1 + * DUT:LAG3<->ATE2:LAG2 + * DUT:LAG4<->ATE2:LAG3 + + * Set ISIS parameters as + * /network-instances/network-instance/protocols/protocol/isis/global/ + * afi-safi/af/config/afi-name: IPV4, IPV6 + * afi-safi/af/config/safi-name: UNICAST + * afi-safi/af/config/enabled: true + * config/level-capability = LEVEL_2 + * /network-instances/network-instance/protocols/protocol/isis/levels/level/config/metric-style = WIDE_METRIC * Configure IPv4 and IPv6 IBGP peering between both ATEs and the DUT using their loopback addresses for both IPv4 and IPv6 address families. @@ -74,7 +76,7 @@ In the topology above, * /network-instances/network-instance/protocols/protocol/isis/interfaces/interface/weighted-ecmp/config/load-balancing-weight set to Auto -## RT-9.1: Equal distribution of traffic +## RT-2.13.1: Equal distribution of traffic * Start 1024 flows from IPv4 addresses in 100.0.2.0/24 to 100.0.1.0/24 @@ -114,7 +116,7 @@ In the topology above, * /interfaces/interface/state/counters/in-pkts -## RT-9.2: Unequal distribution of traffic +## RT-2.13.2: Unequal distribution of traffic * Stop traffic from RT-9.1 and introduce a failure by disabling one of the member interfaces in ATE2:LAG1. @@ -142,17 +144,8 @@ In the topology above, * /interfaces/interface/state/counters/in-pkts -### Config paths - -### Telemetry Parameter Coverage - ## 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. - -TODO(OCPATH): Container path originally part of spec that needs to be separated -into leaves: /routing-policy/defined-sets/prefix-sets/prefix-set: - ```yaml paths: ## Config Paths ## diff --git a/feature/platform/transceiver/tests/zr_logical_channels_test/metadata.textproto b/feature/platform/transceiver/tests/zr_logical_channels_test/metadata.textproto index caa9410e80a..fb942581ff5 100644 --- a/feature/platform/transceiver/tests/zr_logical_channels_test/metadata.textproto +++ b/feature/platform/transceiver/tests/zr_logical_channels_test/metadata.textproto @@ -14,3 +14,14 @@ platform_exceptions: { missing_port_to_optical_channel_component_mapping: true } } +platform_exceptions: { + platform: { + vendor: CISCO + } + deviations: { + otn_channel_trib_unsupported: true + eth_channel_ingress_parameters_unsupported: true + eth_channel_assignment_cisco_numbering: true + otn_channel_assignment_cisco_numbering: true + } +} \ No newline at end of file diff --git a/feature/platform/transceiver/tests/zr_logical_channels_test/zr_logical_channels_test.go b/feature/platform/transceiver/tests/zr_logical_channels_test/zr_logical_channels_test.go index 06dca4f91ed..fdf5d9220e8 100644 --- a/feature/platform/transceiver/tests/zr_logical_channels_test/zr_logical_channels_test.go +++ b/feature/platform/transceiver/tests/zr_logical_channels_test/zr_logical_channels_test.go @@ -1,6 +1,8 @@ package zr_logical_channels_test import ( + "flag" + "strings" "testing" "time" @@ -8,6 +10,7 @@ import ( "github.com/openconfig/featureprofiles/internal/attrs" "github.com/openconfig/featureprofiles/internal/cfgplugins" "github.com/openconfig/featureprofiles/internal/components" + "github.com/openconfig/featureprofiles/internal/deviations" "github.com/openconfig/featureprofiles/internal/fptest" "github.com/openconfig/featureprofiles/internal/samplestream" "github.com/openconfig/ondatra" @@ -18,7 +21,6 @@ import ( const ( targetOutputPower = -9 frequency = 193100000 - dp16QAM = 1 samplingInterval = 10 * time.Second timeout = 10 * time.Minute otnIndex1 = uint32(4001) @@ -33,21 +35,32 @@ var ( IPv4: "192.0.2.1", IPv4Len: 30, } - dutPort2 = attrs.Attributes{ Desc: "dutPort2", IPv4: "192.0.2.5", IPv4Len: 30, } + operationalModeFlag = flag.Int("operational_mode", 1, "vendor-specific operational-mode for the channel") + operationalMode uint16 ) +type testcase struct { + desc string + got any + want any +} + func TestMain(m *testing.M) { fptest.RunTests(m) } func Test400ZRLogicalChannels(t *testing.T) { dut := ondatra.DUT(t, "dut") - + if operationalModeFlag != nil { + operationalMode = uint16(*operationalModeFlag) + } else { + t.Fatalf("Please specify the vendor-specific operational-mode flag") + } p1 := dut.Port(t, "port1") p2 := dut.Port(t, "port2") @@ -61,10 +74,10 @@ func Test400ZRLogicalChannels(t *testing.T) { tr1 := gnmi.Get(t, dut, gnmi.OC().Interface(p1.Name()).Transceiver().State()) tr2 := gnmi.Get(t, dut, gnmi.OC().Interface(p2.Name()).Transceiver().State()) - cfgplugins.ConfigOpticalChannel(t, dut, oc1, frequency, targetOutputPower, dp16QAM) + cfgplugins.ConfigOpticalChannel(t, dut, oc1, frequency, targetOutputPower, operationalMode) cfgplugins.ConfigOTNChannel(t, dut, oc1, otnIndex1, ethernetIndex1) cfgplugins.ConfigETHChannel(t, dut, p1.Name(), tr1, otnIndex1, ethernetIndex1) - cfgplugins.ConfigOpticalChannel(t, dut, oc2, frequency, targetOutputPower, dp16QAM) + cfgplugins.ConfigOpticalChannel(t, dut, oc2, frequency, targetOutputPower, operationalMode) cfgplugins.ConfigOTNChannel(t, dut, oc2, otnIndex2, ethernetIndex2) cfgplugins.ConfigETHChannel(t, dut, p2.Name(), tr2, otnIndex2, ethernetIndex2) @@ -80,13 +93,13 @@ func Test400ZRLogicalChannels(t *testing.T) { gnmi.Await(t, dut, gnmi.OC().Interface(p1.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_UP) gnmi.Await(t, dut, gnmi.OC().Interface(p2.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_UP) - validateEthernetChannelTelemetry(t, otnIndex1, ethernetIndex1, ethChan1) - validateEthernetChannelTelemetry(t, otnIndex2, ethernetIndex2, ethChan2) - validateOTNChannelTelemetry(t, otnIndex1, ethernetIndex1, oc1, otnChan1) - validateOTNChannelTelemetry(t, otnIndex2, ethernetIndex2, oc2, otnChan2) + validateEthernetChannelTelemetry(t, dut, otnIndex1, ethernetIndex1, ethChan1) + validateEthernetChannelTelemetry(t, dut, otnIndex2, ethernetIndex2, ethChan2) + validateOTNChannelTelemetry(t, dut, otnIndex1, ethernetIndex1, oc1, otnChan1) + validateOTNChannelTelemetry(t, dut, otnIndex2, ethernetIndex2, oc2, otnChan2) } -func validateEthernetChannelTelemetry(t *testing.T, otnChIdx, ethernetChIdx uint32, stream *samplestream.SampleStream[*oc.TerminalDevice_Channel]) { +func validateEthernetChannelTelemetry(t *testing.T, dut *ondatra.DUTDevice, otnChIdx, ethernetChIdx uint32, stream *samplestream.SampleStream[*oc.TerminalDevice_Channel]) { val := stream.Next() // value received in the gnmi subscription within 10 seconds if val == nil { t.Fatalf("Ethernet Channel telemetry stream not received in last 10 seconds") @@ -95,11 +108,7 @@ func validateEthernetChannelTelemetry(t *testing.T, otnChIdx, ethernetChIdx uint if !ok { t.Fatalf("Ethernet Channel telemetry stream empty in last 10 seconds") } - tcs := []struct { - desc string - got any - want any - }{ + tcs := []testcase{ { desc: "Index", got: ec.GetIndex(), @@ -120,32 +129,64 @@ func validateEthernetChannelTelemetry(t *testing.T, otnChIdx, ethernetChIdx uint got: ec.GetTribProtocol().String(), want: oc.TransportTypes_TRIBUTARY_PROTOCOL_TYPE_PROT_400GE.String(), }, - { - desc: "Assignment: Index", - got: ec.GetAssignment(0).GetIndex(), - want: uint32(0), - }, - { - desc: "Assignment: Logical Channel", - got: ec.GetAssignment(0).GetLogicalChannel(), - want: otnChIdx, - }, - { - desc: "Assignment: Description", - got: ec.GetAssignment(0).GetDescription(), - want: "ETH to OTN", - }, - { - desc: "Assignment: Allocation", - got: ec.GetAssignment(0).GetAllocation(), - want: float64(400), - }, - { - desc: "Assignment: Type", - got: ec.GetAssignment(0).GetAssignmentType().String(), - want: oc.Assignment_AssignmentType_LOGICAL_CHANNEL.String(), - }, } + var assignmentIndexTestcases []testcase + + if deviations.EthChannelAssignmentCiscoNumbering(dut) { + assignmentIndexTestcases = []testcase{ + { + desc: "Assignment: Index", + got: ec.GetAssignment(1).GetIndex(), + want: uint32(1)}, + { + desc: "Assignment: Logical Channel", + got: ec.GetAssignment(1).GetLogicalChannel(), + want: otnChIdx, + }, + { + desc: "Assignment: Description", + got: ec.GetAssignment(1).GetDescription(), + want: "ETH to OTN", + }, + { + desc: "Assignment: Allocation", + got: ec.GetAssignment(1).GetAllocation(), + want: float64(400), + }, + { + desc: "Assignment: Type", + got: ec.GetAssignment(1).GetAssignmentType().String(), + want: oc.Assignment_AssignmentType_LOGICAL_CHANNEL.String(), + }} + } else { + assignmentIndexTestcases = []testcase{ + { + desc: "Assignment: Index", + got: ec.GetAssignment(0).GetIndex(), + want: uint32(0), + }, + { + desc: "Assignment: Logical Channel", + got: ec.GetAssignment(0).GetLogicalChannel(), + want: otnChIdx, + }, + { + desc: "Assignment: Description", + got: ec.GetAssignment(0).GetDescription(), + want: "ETH to OTN", + }, + { + desc: "Assignment: Allocation", + got: ec.GetAssignment(0).GetAllocation(), + want: float64(400), + }, + { + desc: "Assignment: Type", + got: ec.GetAssignment(0).GetAssignmentType().String(), + want: oc.Assignment_AssignmentType_LOGICAL_CHANNEL.String(), + }} + } + tcs = append(tcs, assignmentIndexTestcases...) for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { if diff := cmp.Diff(tc.got, tc.want); diff != "" { @@ -155,7 +196,7 @@ func validateEthernetChannelTelemetry(t *testing.T, otnChIdx, ethernetChIdx uint } } -func validateOTNChannelTelemetry(t *testing.T, otnChIdx uint32, ethChIdx uint32, opticalChannel string, stream *samplestream.SampleStream[*oc.TerminalDevice_Channel]) { +func validateOTNChannelTelemetry(t *testing.T, dut *ondatra.DUTDevice, otnChIdx uint32, ethChIdx uint32, opticalChannel string, stream *samplestream.SampleStream[*oc.TerminalDevice_Channel]) { val := stream.Next() // value received in the gnmi subscription within 10 seconds if val == nil { t.Fatalf("OTN Channel telemetry stream not received in last 10 seconds") @@ -164,11 +205,7 @@ func validateOTNChannelTelemetry(t *testing.T, otnChIdx uint32, ethChIdx uint32, if !ok { t.Fatalf("OTN Channel telemetry stream empty in last 10 seconds") } - tcs := []struct { - desc string - got any - want any - }{ + tcs := []testcase{ { desc: "Description", got: cc.GetDescription(), @@ -184,56 +221,97 @@ func validateOTNChannelTelemetry(t *testing.T, otnChIdx uint32, ethChIdx uint32, got: cc.GetLogicalChannelType().String(), want: oc.TransportTypes_LOGICAL_ELEMENT_PROTOCOL_TYPE_PROT_OTN.String(), }, - { - desc: "Optical Channel Assignment: Index", - got: cc.GetAssignment(0).GetIndex(), - want: uint32(0), - }, - { - desc: "Optical Channel Assignment: Optical Channel", - got: cc.GetAssignment(0).GetOpticalChannel(), - want: opticalChannel, - }, - { - desc: "Optical Channel Assignment: Description", - got: cc.GetAssignment(0).GetDescription(), - want: "OTN to Optical Channel", - }, - { - desc: "Optical Channel Assignment: Allocation", - got: cc.GetAssignment(0).GetAllocation(), - want: float64(400), - }, - { - desc: "Optical Channel Assignment: Type", - got: cc.GetAssignment(0).GetAssignmentType().String(), - want: oc.Assignment_AssignmentType_OPTICAL_CHANNEL.String(), - }, - { - desc: "Ethernet Assignment: Index", - got: cc.GetAssignment(1).GetIndex(), - want: uint32(1), - }, - { - desc: "Ethernet Assignment: Logical Channel", - got: cc.GetAssignment(1).GetLogicalChannel(), - want: ethChIdx, - }, - { - desc: "Ethernet Assignment: Description", - got: cc.GetAssignment(1).GetDescription(), - want: "OTN to ETH", - }, - { - desc: "Ethernet Assignment: Allocation", - got: cc.GetAssignment(1).GetAllocation(), - want: float64(400), - }, - { - desc: "Ethernet Assignment: Type", - got: cc.GetAssignment(1).GetAssignmentType().String(), - want: oc.Assignment_AssignmentType_LOGICAL_CHANNEL.String(), - }, + } + var opticalChannelAssignmentIndexTestcases []testcase + + if deviations.OTNChannelAssignmentCiscoNumbering(dut) { + ciscoOpticalChannelFormat := strings.ReplaceAll(opticalChannel, "/", "_") // Ex: OpticalChannel0_0_0_18 + opticalChannelAssignmentIndexTestcases = []testcase{ + { + desc: "Assignment: Index", + got: cc.GetAssignment(1).GetIndex(), + want: uint32(1), + }, + { + desc: "Optical Channel Assignment: Optical Channel", + got: cc.GetAssignment(1).GetOpticalChannel(), + want: ciscoOpticalChannelFormat, + }, + { + desc: "Optical Channel Assignment: Description", + got: cc.GetAssignment(1).GetDescription(), + want: "OTN to Optical Channel", + }, + { + desc: "Optical Channel Assignment: Allocation", + got: cc.GetAssignment(1).GetAllocation(), + want: float64(400), + }, + { + desc: "Optical Channel Assignment: Type", + got: cc.GetAssignment(1).GetAssignmentType().String(), + want: oc.Assignment_AssignmentType_OPTICAL_CHANNEL.String(), + }, + } + } else { + opticalChannelAssignmentIndexTestcases = []testcase{ + { + desc: "Assignment: Index", + got: cc.GetAssignment(0).GetIndex(), + want: uint32(0)}, + { + desc: "Optical Channel Assignment: Optical Channel", + got: cc.GetAssignment(0).GetOpticalChannel(), + want: opticalChannel, + }, + { + desc: "Optical Channel Assignment: Description", + got: cc.GetAssignment(0).GetDescription(), + want: "OTN to Optical Channel", + }, + { + desc: "Optical Channel Assignment: Allocation", + got: cc.GetAssignment(0).GetAllocation(), + want: float64(400), + }, + { + desc: "Optical Channel Assignment: Type", + got: cc.GetAssignment(0).GetAssignmentType().String(), + want: oc.Assignment_AssignmentType_OPTICAL_CHANNEL.String(), + }, + } + } + tcs = append(tcs, opticalChannelAssignmentIndexTestcases...) + + if !deviations.OTNChannelTribUnsupported(dut) { + logicalChannelAssignmentTestcases := []testcase{ + { + desc: "Ethernet Assignment: Index", + got: cc.GetAssignment(1).GetIndex(), + want: uint32(1), + }, + { + desc: "Ethernet Assignment: Logical Channel", + got: cc.GetAssignment(1).GetLogicalChannel(), + want: ethChIdx, + }, + { + desc: "Ethernet Assignment: Description", + got: cc.GetAssignment(1).GetDescription(), + want: "OTN to ETH", + }, + { + desc: "Ethernet Assignment: Allocation", + got: cc.GetAssignment(1).GetAllocation(), + want: float64(400), + }, + { + desc: "Ethernet Assignment: Type", + got: cc.GetAssignment(1).GetAssignmentType().String(), + want: oc.Assignment_AssignmentType_LOGICAL_CHANNEL.String(), + }, + } + tcs = append(tcs, logicalChannelAssignmentTestcases...) } for _, tc := range tcs { diff --git a/feature/platform/transceiver/tests/zr_pm_test/metadata.textproto b/feature/platform/transceiver/tests/zr_pm_test/metadata.textproto index 91557f86ff6..e7ad71ae9dd 100644 --- a/feature/platform/transceiver/tests/zr_pm_test/metadata.textproto +++ b/feature/platform/transceiver/tests/zr_pm_test/metadata.textproto @@ -13,3 +13,14 @@ platform_exceptions: { default_network_instance: "default" } } +platform_exceptions: { + platform: { + vendor: CISCO + } + deviations: { + otn_channel_trib_unsupported: true + eth_channel_ingress_parameters_unsupported: true + eth_channel_assignment_cisco_numbering: true + cisco_pre_fec_ber_inactive_value: true + } + } \ No newline at end of file diff --git a/feature/platform/transceiver/tests/zr_pm_test/zr_pm_test.go b/feature/platform/transceiver/tests/zr_pm_test/zr_pm_test.go index 455bf38a6cf..4ffd98c8287 100644 --- a/feature/platform/transceiver/tests/zr_pm_test/zr_pm_test.go +++ b/feature/platform/transceiver/tests/zr_pm_test/zr_pm_test.go @@ -1,10 +1,12 @@ package zr_pm_test import ( + "flag" "testing" "time" "github.com/openconfig/featureprofiles/internal/cfgplugins" + "github.com/openconfig/featureprofiles/internal/deviations" "github.com/openconfig/featureprofiles/internal/fptest" "github.com/openconfig/featureprofiles/internal/samplestream" "github.com/openconfig/ondatra" @@ -14,7 +16,6 @@ import ( ) const ( - dp16QAM = uint16(1) samplingInterval = 10 * time.Second minAllowedQValue = 7.0 maxAllowedQValue = 14.0 @@ -26,7 +27,6 @@ const ( inactivePreFECBER = 0.0 inactiveESNR = 0.0 timeout = 10 * time.Minute - flapInterval = 30 * time.Second otnIndexBase = uint32(4000) ethernetIndexBase = uint32(40000) ) @@ -34,6 +34,8 @@ const ( var ( frequencies = []uint64{191400000, 196100000} targetOpticalPowers = []float64{-9, -13} + operationalModeFlag = flag.Int("operational_mode", 1, "vendor-specific operational-mode for the channel") + operationalMode uint16 ) func TestMain(m *testing.M) { @@ -42,7 +44,11 @@ func TestMain(m *testing.M) { func TestPM(t *testing.T) { dut := ondatra.DUT(t, "dut") - + if operationalModeFlag != nil { + operationalMode = uint16(*operationalModeFlag) + } else { + t.Fatalf("Please specify the vendor-specific operational-mode flag") + } fptest.ConfigureDefaultNetworkInstance(t, dut) var ( @@ -71,7 +77,7 @@ func TestPM(t *testing.T) { for _, targetOpticalPower := range targetOpticalPowers { // Configure OCH component and OTN and ETH logical channels. for _, p := range dut.Ports() { - cfgplugins.ConfigOpticalChannel(t, dut, ochs[p.Name()], frequency, targetOpticalPower, dp16QAM) + cfgplugins.ConfigOpticalChannel(t, dut, ochs[p.Name()], frequency, targetOpticalPower, operationalMode) cfgplugins.ConfigOTNChannel(t, dut, ochs[p.Name()], otnIndexes[p.Name()], ethIndexes[p.Name()]) cfgplugins.ConfigETHChannel(t, dut, p.Name(), trs[p.Name()], otnIndexes[p.Name()], ethIndexes[p.Name()]) } @@ -135,7 +141,7 @@ func validateAllSamples(t *testing.T, dut *ondatra.DUTDevice, isEnabled bool, in if valIndex >= len(otnStreams[p.Name()].All()) { break } - operStatus := validateSampleStream(t, interfaceStreams[p.Name()].All()[valIndex], otnStreams[p.Name()].All()[valIndex], p.Name()) + operStatus := validateSampleStream(t, dut, interfaceStreams[p.Name()].All()[valIndex], otnStreams[p.Name()].All()[valIndex], p.Name()) switch operStatus { case oc.Interface_OperStatus_UP: if !isEnabled { @@ -151,7 +157,7 @@ func validateAllSamples(t *testing.T, dut *ondatra.DUTDevice, isEnabled bool, in } // validateSampleStream validates the stream data. -func validateSampleStream(t *testing.T, interfaceData *ygnmi.Value[*oc.Interface], terminalDeviceData *ygnmi.Value[*oc.TerminalDevice_Channel], portName string) oc.E_Interface_OperStatus { +func validateSampleStream(t *testing.T, dut *ondatra.DUTDevice, interfaceData *ygnmi.Value[*oc.Interface], terminalDeviceData *ygnmi.Value[*oc.TerminalDevice_Channel], portName string) oc.E_Interface_OperStatus { if interfaceData == nil { t.Errorf("Data not received for port %v.", portName) return oc.Interface_OperStatus_UNSET @@ -179,7 +185,11 @@ func validateSampleStream(t *testing.T, interfaceData *ygnmi.Value[*oc.Interface if b := otn.GetPreFecBer(); b == nil { t.Errorf("PreFECBER data is empty for port %v", portName) } else { - validatePMValue(t, portName, "PreFECBER", b.GetInstant(), b.GetMin(), b.GetMax(), b.GetAvg(), minAllowedPreFECBER, maxAllowedPreFECBER, inactivePreFECBER, operStatus) + if deviations.CiscoPreFECBERInactiveValue(dut) { + validatePMValue(t, portName, "PreFECBER", b.GetInstant(), b.GetMin(), b.GetMax(), b.GetAvg(), minAllowedPreFECBER, maxAllowedPreFECBER, 0.5, operStatus) + } else { + validatePMValue(t, portName, "PreFECBER", b.GetInstant(), b.GetMin(), b.GetMax(), b.GetAvg(), minAllowedPreFECBER, maxAllowedPreFECBER, inactivePreFECBER, operStatus) + } } if e := otn.GetEsnr(); e == nil { t.Errorf("ESNR data is empty for port %v", portName) @@ -203,7 +213,7 @@ func validatePMValue(t *testing.T, portName, pm string, instant, min, max, avg, return } case oc.Interface_OperStatus_DOWN: - if instant != inactiveValue { + if instant > inactiveValue { t.Errorf("Invalid %v sample when %v is DOWN --> min : %v, max : %v, avg : %v, instant : %v", pm, portName, min, max, avg, instant) return } diff --git a/feature/system/gnmi/metadata/tests/large_set_consistency_test/README.md b/feature/system/gnmi/metadata/tests/large_set_consistency_test/README.md index 51ac7dab893..e0b5b2ba32b 100644 --- a/feature/system/gnmi/metadata/tests/large_set_consistency_test/README.md +++ b/feature/system/gnmi/metadata/tests/large_set_consistency_test/README.md @@ -40,3 +40,13 @@ dut.testbed ## Minimum DUT platform FFF + +## OpenConfig Path and RPC Coverage + +```yaml +rpcs: + gnmi: + gNMI.Get: + gNMI.Subscribe: + +``` \ No newline at end of file diff --git a/feature/system/gnmi/metadata/tests/large_set_consistency_test/large_set_consistency_test.go b/feature/system/gnmi/metadata/tests/large_set_consistency_test/large_set_consistency_test.go index 84b7e7af943..5dbc85b2572 100644 --- a/feature/system/gnmi/metadata/tests/large_set_consistency_test/large_set_consistency_test.go +++ b/feature/system/gnmi/metadata/tests/large_set_consistency_test/large_set_consistency_test.go @@ -49,57 +49,6 @@ func TestMain(m *testing.M) { fptest.RunTests(m) } -// getDeviceConfig gets a full config from a device but refurbishes it enough so it can be -// pushed out again -func getDeviceConfig(t testing.TB, dev gnmi.DeviceOrOpts) *oc.Root { - config := gnmi.Get[*oc.Root](t, dev, gnmi.OC().Config()) - fptest.WriteQuery(t, "Untouched", gnmi.OC().Config(), config) - - for cname, component := range config.Component { - // Keep the port components in order to preserve the breakout-mode config. - if component.GetPort() == nil { - delete(config.Component, cname) - continue - } - // Need to prune subcomponents that may have a leafref to a component that was - // pruned. - component.Subcomponent = nil - } - - for iname, iface := range config.Interface { - if iface.GetEthernet() == nil { - continue - } - // Ethernet config may not contain meaningful values if it wasn't explicitly - // configured, so use its current state for the config, but prune non-config leaves. - intf := gnmi.Get(t, dev, gnmi.OC().Interface(iname).State()) - breakout := config.GetComponent(intf.GetHardwarePort()).GetPort().GetBreakoutMode() - e := intf.GetEthernet() - // Set port speed to unknown for non breakout interfaces - if breakout.GetGroup(1) == nil && e != nil { - e.SetPortSpeed(oc.IfEthernet_ETHERNET_SPEED_SPEED_UNKNOWN) - } - ygot.PruneConfigFalse(oc.SchemaTree["Interface_Ethernet"], e) - if e.PortSpeed != 0 && e.PortSpeed != oc.IfEthernet_ETHERNET_SPEED_SPEED_UNKNOWN { - iface.Ethernet = e - } - } - - if config.Lldp != nil { - config.Lldp.ChassisId = nil - config.Lldp.ChassisIdType = oc.Lldp_ChassisIdType_UNSET - } - - config.Qos = nil - - for _, ni := range config.NetworkInstance { - ni.Fdb = nil - } - - fptest.WriteQuery(t, "Touched", gnmi.OC().Config(), config) - return config -} - // setEthernetFromBase merges the ethernet config from the interfaces in base config into // the destination config. func setEthernetFromBase(t testing.TB, config *oc.Root) { @@ -244,8 +193,7 @@ func checkMetadata1(t *testing.T, gnmiClient gpb.GNMIClient, dut *ondatra.DUTDev t.Helper() got, getRespTimeStamp := extractMetadataAnnotation(t, gnmiClient, dut) want := metadata1 - t.Logf("getResp: %v ", getRespTimeStamp) - if got != want && done.Load() == 0 { + if got != want && getRespTimeStamp < done.Load() { t.Errorf("extractMetadataAnnotation: got %v, want %v", got, want) } } @@ -268,13 +216,15 @@ func TestLargeSetConsistency(t *testing.T) { p1 := dut.Port(t, "port1") p2 := dut.Port(t, "port2") + fptest.ConfigureDefaultNetworkInstance(t, dut) + // Configuring basic interface and network instance as some devices only populate OC after configuration. gnmi.Replace(t, dut, gnmi.OC().Interface(p1.Name()).Config(), dutPort1.NewOCInterface(p1.Name(), dut)) gnmi.Replace(t, dut, gnmi.OC().Interface(p2.Name()).Config(), dutPort2.NewOCInterface(p2.Name(), dut)) gnmi.Replace(t, dut, gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Type().Config(), oc.NetworkInstanceTypes_NETWORK_INSTANCE_TYPE_DEFAULT_INSTANCE) - baselineConfig := getDeviceConfig(t, dut) + baselineConfig := fptest.GetDeviceConfig(t, dut) setEthernetFromBase(t, baselineConfig) gnmiClient := dut.RawAPIs().GNMI(t) diff --git a/feature/system/gnmi/metadata/tests/large_set_consistency_test/metadata.textproto b/feature/system/gnmi/metadata/tests/large_set_consistency_test/metadata.textproto index cae8c3c1a46..c346a8d5da2 100644 --- a/feature/system/gnmi/metadata/tests/large_set_consistency_test/metadata.textproto +++ b/feature/system/gnmi/metadata/tests/large_set_consistency_test/metadata.textproto @@ -13,4 +13,12 @@ platform_exceptions: { default_network_instance: "default" } } +platform_exceptions: { + platform: { + vendor: CISCO + } + deviations: { + skip_macaddress_check: true + } +} diff --git a/feature/system/gnmi/set/tests/gnmi_set_test/gnmi_set_test.go b/feature/system/gnmi/set/tests/gnmi_set_test/gnmi_set_test.go index 8152a803887..d169ecec2f9 100644 --- a/feature/system/gnmi/set/tests/gnmi_set_test/gnmi_set_test.go +++ b/feature/system/gnmi/set/tests/gnmi_set_test/gnmi_set_test.go @@ -45,22 +45,8 @@ var ( skipContainerOp = flag.Bool("skip_container_op", false, "Skip ContainerOp test cases.") skipItemOp = flag.Bool("skip_item_op", false, "Skip ItemOp test cases.") - // The following experimental flags fine-tune the RootOp and ContainerOp behavior. Some - // devices require the config to be pruned for these to work. We are still undecided - // whether they should be deviations; pending OpenConfig clarifications. - pruneComponents = flag.Bool("prune_components", true, "Prune components that are not ports. Use this to preserve the breakout-mode settings.") - pruneLLDP = flag.Bool("prune_lldp", true, "Prune LLDP config.") - setEthernetFromState = flag.Bool("set_ethernet_from_state", true, "Set interface/ethernet config from state, mostly to get the port-speed settings correct.") - - // This has no known effect except to reduce logspam while debugging. - pruneQoS = flag.Bool("prune_qos", true, "Prune QoS config.") - // Experimental flags that will likely become a deviation. - cannotDeleteVRF = flag.Bool("cannot_delete_vrf", true, "Device cannot delete VRF.") // See "Note about cannotDeleteVRF" below. - cannotConfigurePortSpeed = flag.Bool("cannot_config_port_speed", false, "Some devices depending on the type of line card may not allow changing port speed, while still supporting the port speed leaf.") - - // Flags to ensure test passes without any dependency to the device config - baseOCConfigIsPresent = flag.Bool("base_oc_config_is_present", false, "No OC config is loaded on router, so Get config on the root returns no data.") + cannotDeleteVRF = flag.Bool("cannot_delete_vrf", true, "Device cannot delete VRF.") // See "Note about cannotDeleteVRF" below. ) var ( @@ -236,10 +222,6 @@ func TestReuseIP(t *testing.T) { forEachPushOp(t, dut, func(t *testing.T, op pushOp, config *oc.Root) { t.Log("Initialize") - if deviations.SkipMacaddressCheck(dut) { - *setEthernetFromState = false - } - config.DeleteInterface(p1.Name()) config.DeleteInterface(agg1) configMember(config.GetOrCreateInterface(p1.Name()), agg1, dut) @@ -840,7 +822,7 @@ func forEachPushOp( f func(t *testing.T, op pushOp, config *oc.Root), ) { baselineConfigOnce.Do(func() { - baselineConfig = getDeviceConfig(t, dut) + baselineConfig = fptest.GetDeviceConfig(t, dut) }) for _, op := range []pushOp{ @@ -850,154 +832,12 @@ func forEachPushOp( if op.shouldSkip() { t.Skip() } - o, err := ygot.DeepCopy(baselineConfig) - if err != nil { - t.Fatalf("Cannot copy baseConfig: %v", err) - } - config := o.(*oc.Root) + config := fptest.CopyDeviceConfig(t, dut, baselineConfig) f(t, op, config) }) } } -// getDeviceConfig gets a full config from a device but refurbishes it enough so it can be -// pushed out again. Ideally, we should be able to push the config we get from the same -// device without modification, but this is not explicitly defined in OpenConfig. -func getDeviceConfig(t testing.TB, dev gnmi.DeviceOrOpts) *oc.Root { - t.Helper() - - // Gets all the config (read-write) paths from root, not the state (read-only) paths. - config := gnmi.Get[*oc.Root](t, dev, gnmi.OC().Config()) - fptest.WriteQuery(t, "Untouched", gnmi.OC().Config(), config) - - // load the base oc config from the device state when no oc config is loaded - if !*baseOCConfigIsPresent { - if ondatra.DUT(t, "dut").Vendor() == ondatra.CISCO { - intfsState := gnmi.GetAll(t, dev, gnmi.OC().InterfaceAny().State()) - for _, intf := range intfsState { - ygot.PruneConfigFalse(oc.SchemaTree["Interface"], intf) - config.DeleteInterface(intf.GetName()) - if intf.GetName() == "Loopback0" || intf.GetName() == "PTP0/RP1/CPU0/0" || intf.GetName() == "Null0" || intf.GetName() == "PTP0/RP0/CPU0/0" { - continue - } - intf.ForwardingViable = nil - intf.Mtu = nil - intf.HoldTime = nil - if intf.Subinterface != nil { - if intf.Subinterface[0].Ipv6 != nil { - intf.Subinterface[0].Ipv6.Autoconf = nil - } - } - config.AppendInterface(intf) - } - vrfsStates := gnmi.GetAll(t, dev, gnmi.OC().NetworkInstanceAny().State()) - for _, vrf := range vrfsStates { - // only needed for containerOp - if vrf.GetName() == "**iid" { - continue - } - if vrf.GetName() == "DEFAULT" { - config.NetworkInstance = nil - vrf.Interface = nil - for _, ni := range config.NetworkInstance { - ni.Mpls = nil - } - } - ygot.PruneConfigFalse(oc.SchemaTree["NetworkInstance"], vrf) - vrf.Table = nil - vrf.RouteLimit = nil - vrf.Mpls = nil - for _, intf := range vrf.Interface { - intf.AssociatedAddressFamilies = nil - } - for _, protocol := range vrf.Protocol { - for _, routes := range protocol.Static { - routes.Description = nil - } - } - config.AppendNetworkInstance(vrf) - } - } - } - - if *pruneComponents { - for cname, component := range config.Component { - // Keep the port components in order to preserve the breakout-mode config. - if component.GetPort() == nil { - delete(config.Component, cname) - continue - } - // Need to prune subcomponents that may have a leafref to a component that was - // pruned. - component.Subcomponent = nil - } - } - - if *setEthernetFromState { - for iname, iface := range config.Interface { - if iface.GetEthernet() == nil { - continue - } - // Ethernet config may not contain meaningful values if it wasn't explicitly - // configured, so use its current state for the config, but prune non-config leaves. - intf := gnmi.Get(t, dev, gnmi.OC().Interface(iname).State()) - e := intf.GetEthernet() - if len(intf.GetHardwarePort()) != 0 { - breakout := config.GetComponent(intf.GetHardwarePort()).GetPort().GetBreakoutMode() - e := intf.GetEthernet() - // Set port speed to unknown for non breakout interfaces - if breakout.GetGroup(1) == nil && e != nil { - e.SetPortSpeed(oc.IfEthernet_ETHERNET_SPEED_SPEED_UNKNOWN) - } - } - ygot.PruneConfigFalse(oc.SchemaTree["Interface_Ethernet"], e) - if e.PortSpeed != 0 && e.PortSpeed != oc.IfEthernet_ETHERNET_SPEED_SPEED_UNKNOWN { - iface.Ethernet = e - } - // need to set mac address for mgmt interface to nil - if intf.GetName() == "MgmtEth0/RP0/CPU0/0" || intf.GetName() == "MgmtEth0/RP1/CPU0/0" && deviations.SkipMacaddressCheck(ondatra.DUT(t, "dut")) { - e.MacAddress = nil - } - // need to set mac address for bundle interface to nil - if iface.Ethernet.AggregateId != nil && deviations.SkipMacaddressCheck(ondatra.DUT(t, "dut")) { - iface.Ethernet.MacAddress = nil - continue - } - } - } - - if !*cannotConfigurePortSpeed { - for _, iface := range config.Interface { - if iface.GetEthernet() == nil { - continue - } - iface.GetEthernet().PortSpeed = oc.IfEthernet_ETHERNET_SPEED_UNSET - iface.GetEthernet().DuplexMode = oc.Ethernet_DuplexMode_UNSET - iface.GetEthernet().EnableFlowControl = nil - } - } - - if *pruneLLDP && config.Lldp != nil { - config.Lldp.ChassisId = nil - config.Lldp.ChassisIdType = oc.Lldp_ChassisIdType_UNSET - } - - if *pruneQoS { - config.Qos = nil - } - - pruneUnsupportedPaths(config) - - fptest.WriteQuery(t, "Touched", gnmi.OC().Config(), config) - return config -} - -func pruneUnsupportedPaths(config *oc.Root) { - for _, ni := range config.NetworkInstance { - ni.Fdb = nil - } -} - // pushScope describe the config scope that the test case wants to modify. This is for // itemOp only; rootOp and containerOp ignore this. type pushScope struct { @@ -1012,23 +852,6 @@ type pushOp interface { push(t testing.TB, dev gnmi.DeviceOrOpts, config *oc.Root, scope *pushScope) } -// setEthernetFromBase merges the ethernet config from the interfaces in base config into -// the destination config. -func setEthernetFromBase(t testing.TB, base *oc.Root, config *oc.Root) { - t.Helper() - - for iname, iface := range config.Interface { - eb := base.GetInterface(iname).GetEthernet() - ec := iface.GetOrCreateEthernet() - if eb == nil || ec == nil { - continue - } - if err := ygot.MergeStructInto(ec, eb); err != nil { - t.Errorf("Cannot merge %s ethernet: %v", iname, err) - } - } -} - // rootOp pushes config using replace at root. type rootOp struct{ base *oc.Root } @@ -1037,9 +860,6 @@ func (rootOp) shouldSkip() bool { return *skipRootOp } func (op rootOp) push(t testing.TB, dev gnmi.DeviceOrOpts, config *oc.Root, _ *pushScope) { t.Helper() - if *setEthernetFromState { - setEthernetFromBase(t, op.base, config) - } fptest.WriteQuery(t, "RootOp", gnmi.OC().Config(), config) dut := ondatra.DUT(t, "dut") if deviations.AddMissingBaseConfigViaCli(dut) { @@ -1060,9 +880,6 @@ func (containerOp) shouldSkip() bool { return *skipContainerOp } func (op containerOp) push(t testing.TB, dev gnmi.DeviceOrOpts, config *oc.Root, _ *pushScope) { t.Helper() - if *setEthernetFromState { - setEthernetFromBase(t, op.base, config) - } fptest.WriteQuery(t, "ContainerOp", gnmi.OC().Config(), config) batch := &gnmi.SetBatch{} @@ -1095,9 +912,6 @@ func (itemOp) shouldSkip() bool { return *skipItemOp } func (op itemOp) push(t testing.TB, dev gnmi.DeviceOrOpts, config *oc.Root, scope *pushScope) { t.Helper() - if *setEthernetFromState { - setEthernetFromBase(t, op.base, config) - } fptest.WriteQuery(t, "ItemOp", gnmi.OC().Config(), config) batch := &gnmi.SetBatch{} diff --git a/internal/deviations/README.md b/internal/deviations/README.md index 670bdbe9226..a42d37cfd59 100644 --- a/internal/deviations/README.md +++ b/internal/deviations/README.md @@ -1,21 +1,57 @@ -## Guidelines to add deviations to FNT tests +# Guidelines to add deviations to FNT tests -### Adding Deviations +## When to use deviations -* Add the deviation to the `Deviations` message in the [proto/metadata.proto](https://github.com/openconfig/featureprofiles/blob/main/proto/metadata.proto) file. +1. Deviations may be created to use alternate OC or use CLI instead of OC to + achieve the operational intent described in the README. +2. Deviations should not be created which change the operational intent. See + below for guidance on changing operational intent. +3. Deviations may be created to change which OC path is used for telemetry or + use an implementation's native yang path.  Deviations for telemetry + should not introduce a depedency on CLI output. +4. As with any pull request (PR), the CODEOWNERs must review and approve (or + delegate if appropriate). +5. The CODEOWNERs must ensure the README and code reflects the agreed to + operational support goal.  This may be done via offline discussions or + directly via approvals in the github PR. - ``` +See [Deviation Examples](#deviation-examples) for more information. + +## When not to use a deviation + +Deviations should not be used to skip configuration or skip validations. If the +feature is not supported and there is no workaround to achieve +the functionality, then the test should fail for that platform. + +If the README is in error, the README can be updated and code can be changed +(without introducing deviation) with approval from the CODEOWNERs. + +If the intent of the README needs to be changed (not due to an error, but a +change in the feature request), the CODEOWNER must ensure all parties are +notified. The CODEOWNER must determine if the change is late or early in the +development cycle. If late (development is underway and/or nearly complete), it +is recommended to create a new test which represents the change. If early in +the feature request (development has not started or is very early stage), then +the existing README and code may be updated. + +## Adding Deviations + +* Add the deviation to the `Deviations` message in the + [proto/metadata.proto](https://github.com/openconfig/featureprofiles/blob/main/proto/metadata.proto) + file. + +```go message Deviations { ... // Device does not support fragmentation bit for traceroute. bool traceroute_fragmentation = 2; ... } - ``` +``` * Run `make proto/metadata_go_proto/metadata.pb.go` from your featureprofiles root directory to generate the Go code for the added proto fields. - ``` +```shell $ make proto/metadata_go_proto/metadata.pb.go mkdir -p proto/metadata_go_proto # Set directory to hold symlink @@ -30,36 +66,57 @@ go list -f '{{ .Dir }} protobuf-import/{{ .Path }}' -m github.com/openconfig/ondatra | xargs -L1 -- ln -s protoc -I='protobuf-import' --proto_path=proto --go_out=./ --go_opt=Mmetadata.proto=proto/metadata_go_proto metadata.proto goimports -w proto/metadata_go_proto/metadata.pb.go - ``` - -* Add the accessor function for this deviation to the [internal/deviations/deviations.go](https://github.com/openconfig/featureprofiles/blob/main/internal/deviations/deviations.go) file. This function will need to accept a parameter `dut` of type `*ondatra.DUTDevice` to lookup the deviation value for a specific dut. This accessor function must call `lookupDUTDeviations` and return the deviation value. Test code will use this function to access deviations. - * If the default value of the deviation is the same as the default value for the proto field, the accessor method can directly call the `Get*()` function for the deviation field. For example, the boolean `traceroute_fragmentation` deviation, which has a default value of `false`, will have an accessor method with the single line `return lookupDUTDeviations(dut).GetTracerouteFragmentation()`. - - ``` - // TraceRouteFragmentation returns if the device does not support fragmentation bit for traceroute. - // Default value is false. - func TraceRouteFragmentation(dut *ondatra.DUTDevice) bool { - return lookupDUTDeviations(dut).GetTracerouteFragmentation() - } - ``` - - * If the default value of deviation is not the same as the default value of the proto field, the accessor method can add a check and return the required default value. For example, the accessor method for the float `hierarchical_weight_resolution_tolerance` deviation, which has a default value of `0`, will call the `GetHierarchicalWeightResolutionTolerance()` to check the value set in `metadata.textproto` and return the default value `0.2` if applicable. - - ``` - // HierarchicalWeightResolutionTolerance returns the allowed tolerance for BGP traffic flow while comparing for pass or fail conditions. - // Default minimum value is 0.2. Anything less than 0.2 will be set to 0.2. - func HierarchicalWeightResolutionTolerance(dut *ondatra.DUTDevice) float64 { - hwrt := lookupDUTDeviations(dut).GetHierarchicalWeightResolutionTolerance() - if minHWRT := 0.2; hwrt < minHWRT { +``` + +* Add the accessor function for this deviation to the + [internal/deviations/deviations.go](https://github.com/openconfig/featureprofiles/blob/main/internal/deviations/deviations.go) + file. This function will need to accept a parameter `dut` of type + `*ondatra.DUTDevice` to lookup the deviation value for a specific dut. This + accessor function must call `lookupDUTDeviations` and return the deviation + value. Test code will use this function to access deviations. + * If the default value of the deviation is the same as the default value for + the proto field, the accessor method can directly call the `Get*()` function + for the deviation field. For example, the boolean `traceroute_fragmentation` + deviation, which has a default value of `false`, will have an accessor + method with the single line `return + lookupDUTDeviations(dut).GetTracerouteFragmentation()`. + + ```go + // TraceRouteFragmentation returns if the device does not support fragmentation bit for traceroute. + // Default value is false. + func TraceRouteFragmentation(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetTracerouteFragmentation() + } + ``` + + * If the default value of deviation is not the same as the default value of + the proto field, the accessor method can add a check and return the required + default value. For example, the accessor method for the float + `hierarchical_weight_resolution_tolerance` deviation, which has a default + value of `0`, will call the `GetHierarchicalWeightResolutionTolerance()` to + check the value set in `metadata.textproto` and return the default value + `0.2` if applicable. + + ```go + // HierarchicalWeightResolutionTolerance returns the allowed tolerance for BGP traffic flow while comparing for pass or fail conditions. + // Default minimum value is 0.2. Anything less than 0.2 will be set to 0.2. + func HierarchicalWeightResolutionTolerance(dut *ondatra.DUTDevice) float64 { + hwrt := lookupDUTDeviations(dut).GetHierarchicalWeightResolutionTolerance() + if minHWRT := 0.2; hwrt < minHWRT { return minHWRT - } - return hwrt - } - ``` - -* Set the deviation value in the `metadata.textproto` file in the same folder as the test. For example, the deviations used in the test `feature/gnoi/system/tests/traceroute_test/traceroute_test.go` will be set in the file `feature/gnoi/system/tests/traceroute_test/metadata.textproto`. List all the vendor and optionally also hardware model regex that this deviation is applicable for. - - ``` + } + return hwrt + } + ``` + +* Set the deviation value in the `metadata.textproto` file in the same folder as + the test. For example, the deviations used in the test + `feature/gnoi/system/tests/traceroute_test/traceroute_test.go` will be set in + the file `feature/gnoi/system/tests/traceroute_test/metadata.textproto`. List + all the vendor and optionally also hardware model regex that this deviation is + applicable for. + + ```go ... platform_exceptions: { platform: { @@ -73,30 +130,69 @@ ... ``` -* To access the deviation from the test call the accessor function for the deviation. Pass the dut to this accessor. +* To access the deviation from the test call the accessor function for the + deviation. Pass the dut to this accessor. - ``` + ```go if deviations.TraceRouteFragmentation(dut) { ... } ``` -* Example PRs - https://github.com/openconfig/featureprofiles/pull/1649 and - https://github.com/openconfig/featureprofiles/pull/1668 +* Example PRs - and + + +## Removing Deviations -### Removing Deviations +* Once a deviation is no longer required and removed from all tests, delete the + deviation by removing them from the following files: -* Once a deviation is no longer required and removed from all tests, delete the deviation by removing them from the following files: + * metadata.textproto - Remove the deviation field from all metadata.textproto + in all tests. - * metadata.textproto - Remove the deviation field from all metadata.textproto in all tests. + * Remove the accessor method from + [deviations.go](https://github.com/openconfig/featureprofiles/blob/main/internal/deviations/deviations.go) - * [deviations.go](https://github.com/openconfig/featureprofiles/blob/main/internal/deviations/deviations.go) - Remove the accessor method for this deviation. + * Remove the field number from + [metadata.proto](https://github.com/openconfig/featureprofiles/blob/main/proto/metadata.proto) + by adding the `reserved n` to the `Deviations` message. Ref: + - * [metadata.proto](https://github.com/openconfig/featureprofiles/blob/main/proto/metadata.proto) - Remove the deviation field from the `Deviations` message and reserve the deleted field number by adding the `reserved n` to the `Deviations` message. -Ref: https://protobuf.dev/programming-guides/proto3/#deleting +* Run `make proto/metadata_go_proto/metadata.pb.go` from your featureprofiles + root directory to update the Go code for the removed proto fields. -* Run `make proto/metadata_go_proto/metadata.pb.go` from your featureprofiles root directory to update the Go code for the removed proto fields. +## Deviation examples + +```go +conf := configureDUT(dut) // returns *oc.Root + +if deviations.AlternateOCEnabled(t, dut) { + switch dut.Vendor() { + case ondatra.VENDOR_X: + conf.SetAlternateOC(val) + } +} else { + conf.SetRequiredOC(val) +} +``` + +```go +conf := configureDUT(dut) // returns *oc.Root + +if deviations.RequiredOCNotSupported(t, dut) { + switch dut.Vendor() { + case ondatra.VENDOR_X: + configureDeviceUsingCli(t, dut, vendorXConfig) + } +} +``` ## Notes -* If you run into issues with the `make proto/metadata_go_proto/metadata.pb.go` you may need to check if the `protoc` module is installed in your environment. Also depending on your Go version you may need to update your PATH and GOPATH. -* After running the `make proto/metadata_go_proto/metadata.pb.go` script, a `protobuf-import/` folder will be added in your current directory. Keep an eye out for this in case you use `git add .` to add modified files since this folder should not be part of your PR. + +* If you run into issues with the `make proto/metadata_go_proto/metadata.pb.go` + you may need to check if the `protoc` module is installed in your environment. + Also depending on your Go version you may need to update your PATH and GOPATH. +* After running the `make proto/metadata_go_proto/metadata.pb.go` script, a + `protobuf-import/` folder will be added in your current directory. Keep an eye + out for this in case you use `git add .` to add modified files since this + folder should not be part of your PR. diff --git a/internal/deviations/deviations.go b/internal/deviations/deviations.go index 93ef505adb3..9c04c301319 100644 --- a/internal/deviations/deviations.go +++ b/internal/deviations/deviations.go @@ -1208,6 +1208,32 @@ func BgpAllowownasDiffDefaultValue(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetBgpAllowownasDiffDefaultValue() } +// OTNChannelAssignmentCiscoNumbering returns true if OTN channel assignment index starts from 1 instead of 0 +func OTNChannelAssignmentCiscoNumbering(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetOtnChannelAssignmentCiscoNumbering() +} + +// CiscoPreFECBERInactiveValue returns true if a non-zero pre-fec-ber value is to be used for Cisco +func CiscoPreFECBERInactiveValue(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetCiscoPreFecBerInactiveValue() +} + +// BgpExtendedNextHopEncodingLeafUnsupported return true if bgp extended next hop encoding leaf is unsupported +// Cisco supports the extended nexthop encoding set to true by default that is excercised in the Script where the extended-nexthop-encoding +// a bool value is set to true. +func BgpExtendedNextHopEncodingLeafUnsupported(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetBgpExtendedNextHopEncodingLeafUnsupported() +} + +// BgpAfiSafiWildcardNotSupported return true if bgp afi/safi wildcard query is not supported. +// For example, this yang path query includes the wildcard key `afi-safi-name=`: +// `/network-instances/network-instance[name=DEFAULT]/protocols/protocol[identifier=BGP][name=BGP]/bgp/neighbors/neighbor[neighbor-address=192.0.2.2]/afi-safis/afi-safi[afi-safi-name=]`. +// Use of this deviation is permitted if a query using an explicit key is supported (such as +// `oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST`). +func BgpAfiSafiWildcardNotSupported(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetBgpAfiSafiWildcardNotSupported() +} + // Admin Enable Table Connections in SRL native func EnableTableConnections(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetEnableTableConnections() diff --git a/internal/fptest/config.go b/internal/fptest/config.go new file mode 100644 index 00000000000..bb976eea456 --- /dev/null +++ b/internal/fptest/config.go @@ -0,0 +1,205 @@ +package fptest + +import ( + "flag" + "testing" + + "github.com/openconfig/featureprofiles/internal/deviations" + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" + "github.com/openconfig/ondatra/gnmi/oc" + "github.com/openconfig/ygot/ygot" +) + +var ( + // Some devices require the config to be pruned for these to work. We are still undecided + // whether they should be deviations; pending OpenConfig clarifications. + pruneComponents = flag.Bool("prune_components", true, "Prune components that are not ports. Use this to preserve the breakout-mode settings.") + pruneLLDP = flag.Bool("prune_lldp", true, "Prune LLDP config.") + setEthernetFromState = flag.Bool("set_ethernet_from_state", true, "Set interface/ethernet config from state, mostly to get the port-speed settings correct.") + + // This has no known effect except to reduce logspam while debugging. + pruneQoS = flag.Bool("prune_qos", true, "Prune QoS config.") + + // Experimental flags that will likely become a deviation. + cannotConfigurePortSpeed = flag.Bool("cannot_config_port_speed", false, "Some devices depending on the type of line card may not allow changing port speed, while still supporting the port speed leaf.") + + // Flags to ensure test passes without any dependency to the device config + baseOCConfigIsPresent = flag.Bool("base_oc_config_is_present", false, "No OC config is loaded on router, so Get config on the root returns no data.") +) + +// GetDeviceConfig gets a full config from a device but refurbishes it enough so it can be +// pushed out again. Ideally, we should be able to push the config we get from the same +// device without modification, but this is not explicitly defined in OpenConfig. +func GetDeviceConfig(t testing.TB, dev gnmi.DeviceOrOpts) *oc.Root { + t.Helper() + + // Gets all the config (read-write) paths from root, not the state (read-only) paths. + config := gnmi.Get[*oc.Root](t, dev, gnmi.OC().Config()) + WriteQuery(t, "Untouched", gnmi.OC().Config(), config) + + // load the base oc config from the device state when no oc config is loaded + if !*baseOCConfigIsPresent { + if ondatra.DUT(t, "dut").Vendor() == ondatra.CISCO { + intfsState := gnmi.GetAll(t, dev, gnmi.OC().InterfaceAny().State()) + for _, intf := range intfsState { + ygot.PruneConfigFalse(oc.SchemaTree["Interface"], intf) + config.DeleteInterface(intf.GetName()) + if intf.GetName() == "Loopback0" || intf.GetName() == "PTP0/RP1/CPU0/0" || intf.GetName() == "Null0" || intf.GetName() == "PTP0/RP0/CPU0/0" { + continue + } + intf.ForwardingViable = nil + intf.Mtu = nil + intf.HoldTime = nil + if intf.Subinterface != nil { + if intf.Subinterface[0].Ipv6 != nil { + intf.Subinterface[0].Ipv6.Autoconf = nil + } + } + config.AppendInterface(intf) + } + vrfsStates := gnmi.GetAll(t, dev, gnmi.OC().NetworkInstanceAny().State()) + for _, vrf := range vrfsStates { + // only needed for containerOp + if vrf.GetName() == "**iid" { + continue + } + if vrf.GetName() == "DEFAULT" { + config.NetworkInstance = nil + vrf.Interface = nil + for _, ni := range config.NetworkInstance { + ni.Mpls = nil + } + } + ygot.PruneConfigFalse(oc.SchemaTree["NetworkInstance"], vrf) + vrf.Table = nil + vrf.RouteLimit = nil + vrf.Mpls = nil + for _, intf := range vrf.Interface { + intf.AssociatedAddressFamilies = nil + } + for _, protocol := range vrf.Protocol { + for _, routes := range protocol.Static { + routes.Description = nil + } + } + config.AppendNetworkInstance(vrf) + } + } + } + + if *pruneComponents { + for cname, component := range config.Component { + // Keep the port components in order to preserve the breakout-mode config. + if component.GetPort() == nil { + delete(config.Component, cname) + continue + } + // Need to prune subcomponents that may have a leafref to a component that was + // pruned. + component.Subcomponent = nil + } + } + + if *setEthernetFromState { + for iname, iface := range config.Interface { + if iface.GetEthernet() == nil { + continue + } + // Ethernet config may not contain meaningful values if it wasn't explicitly + // configured, so use its current state for the config, but prune non-config leaves. + intf := gnmi.Get(t, dev, gnmi.OC().Interface(iname).State()) + e := intf.GetEthernet() + if len(intf.GetHardwarePort()) != 0 { + breakout := config.GetComponent(intf.GetHardwarePort()).GetPort().GetBreakoutMode() + e := intf.GetEthernet() + // Set port speed to unknown for non breakout interfaces + if breakout.GetGroup(1) == nil && e != nil { + e.SetPortSpeed(oc.IfEthernet_ETHERNET_SPEED_SPEED_UNKNOWN) + } + } + ygot.PruneConfigFalse(oc.SchemaTree["Interface_Ethernet"], e) + if e.PortSpeed != 0 && e.PortSpeed != oc.IfEthernet_ETHERNET_SPEED_SPEED_UNKNOWN { + iface.Ethernet = e + } + // need to set mac address for mgmt interface to nil + if intf.GetName() == "MgmtEth0/RP0/CPU0/0" || intf.GetName() == "MgmtEth0/RP1/CPU0/0" && deviations.SkipMacaddressCheck(ondatra.DUT(t, "dut")) { + e.MacAddress = nil + } + // need to set mac address for bundle interface to nil + if iface.Ethernet.AggregateId != nil && deviations.SkipMacaddressCheck(ondatra.DUT(t, "dut")) { + iface.Ethernet.MacAddress = nil + continue + } + } + } + + if !*cannotConfigurePortSpeed { + for _, iface := range config.Interface { + if iface.GetEthernet() == nil { + continue + } + iface.GetEthernet().PortSpeed = oc.IfEthernet_ETHERNET_SPEED_UNSET + iface.GetEthernet().DuplexMode = oc.Ethernet_DuplexMode_UNSET + iface.GetEthernet().EnableFlowControl = nil + } + } + + if *pruneLLDP && config.Lldp != nil { + config.Lldp.ChassisId = nil + config.Lldp.ChassisIdType = oc.Lldp_ChassisIdType_UNSET + } + + if *pruneQoS { + config.Qos = nil + } + + pruneUnsupportedPaths(config) + + WriteQuery(t, "Touched", gnmi.OC().Config(), config) + return config +} + +// CopyDeviceConfig returns a deep copy of a device config but refurbishes it enough so it can be +// pushed out again +func CopyDeviceConfig(t testing.TB, dut *ondatra.DUTDevice, config *oc.Root) *oc.Root { + if deviations.SkipMacaddressCheck(dut) { + *setEthernetFromState = false + } + + o, err := ygot.DeepCopy(config) + if err != nil { + t.Fatalf("Cannot copy baseConfig: %v", err) + } + + copy := o.(*oc.Root) + + if *setEthernetFromState { + setEthernetFromBase(t, config, copy) + } + + return copy +} + +func pruneUnsupportedPaths(config *oc.Root) { + for _, ni := range config.NetworkInstance { + ni.Fdb = nil + } +} + +// setEthernetFromBase merges the ethernet config from the interfaces in base config into +// the destination config. +func setEthernetFromBase(t testing.TB, base *oc.Root, config *oc.Root) { + t.Helper() + + for iname, iface := range config.Interface { + eb := base.GetInterface(iname).GetEthernet() + ec := iface.GetOrCreateEthernet() + if eb == nil || ec == nil { + continue + } + if err := ygot.MergeStructInto(ec, eb); err != nil { + t.Errorf("Cannot merge %s ethernet: %v", iname, err) + } + } +} diff --git a/internal/security/acctz/acctz.go b/internal/security/acctz/acctz.go index 6837c82f0bc..6f475e14e1e 100644 --- a/internal/security/acctz/acctz.go +++ b/internal/security/acctz/acctz.go @@ -27,8 +27,8 @@ import ( "testing" "time" - "github.com/openconfig/gnmi/proto/gnmi" - "github.com/openconfig/gnoi/system" + gnmipb "github.com/openconfig/gnmi/proto/gnmi" + systempb "github.com/openconfig/gnoi/system" acctzpb "github.com/openconfig/gnsi/acctz" authzpb "github.com/openconfig/gnsi/authz" cpb "github.com/openconfig/gnsi/credentialz" @@ -113,7 +113,7 @@ func setupUserPassword(t *testing.T, dut *ondatra.DUTDevice, username, password time.Sleep(time.Second) } -func nokiaFailCliRole(t *testing.T) *gnmi.SetRequest { +func nokiaFailCliRole(t *testing.T) *gnmipb.SetRequest { failRoleData, err := json.Marshal([]any{ map[string]any{ "services": []string{"cli"}, @@ -126,22 +126,22 @@ func nokiaFailCliRole(t *testing.T) *gnmi.SetRequest { t.Fatalf("Error with json marshal: %v", err) } - return &gnmi.SetRequest{ - Prefix: &gnmi.Path{ + return &gnmipb.SetRequest{ + Prefix: &gnmipb.Path{ Origin: "native", }, - Replace: []*gnmi.Update{ + Replace: []*gnmipb.Update{ { - Path: &gnmi.Path{ - Elem: []*gnmi.PathElem{ + Path: &gnmipb.Path{ + Elem: []*gnmipb.PathElem{ {Name: "system"}, {Name: "aaa"}, {Name: "authorization"}, {Name: "role", Key: map[string]string{"rolename": failRoleName}}, }, }, - Val: &gnmi.TypedValue{ - Value: &gnmi.TypedValue_JsonIetfVal{ + Val: &gnmipb.TypedValue{ + Value: &gnmipb.TypedValue_JsonIetfVal{ JsonIetfVal: failRoleData, }, }, @@ -157,7 +157,7 @@ func SetupUsers(t *testing.T, dut *ondatra.DUTDevice, configureFailCliRole bool) successUser.SetRole(oc.AaaTypes_SYSTEM_DEFINED_ROLES_SYSTEM_ROLE_ADMIN) failUser := auth.GetOrCreateUser(failUsername) if configureFailCliRole { - var SetRequest *gnmi.SetRequest + var SetRequest *gnmipb.SetRequest // Create failure cli role in native. switch dut.Vendor() { @@ -325,13 +325,13 @@ func SendGnmiRPCs(t *testing.T, dut *ondatra.DUTDevice) []*acctzpb.RecordRespons var records []*acctzpb.RecordResponse grpcConn := dialGrpc(t, target) - gnmiClient := gnmi.NewGNMIClient(grpcConn) + gnmiClient := gnmipb.NewGNMIClient(grpcConn) ctx := context.Background() ctx = metadata.AppendToOutgoingContext(ctx, "username", failUsername) ctx = metadata.AppendToOutgoingContext(ctx, "password", failPassword) // Send an unsuccessful gNMI capabilities request (bad creds in context). - _, err := gnmiClient.Capabilities(ctx, &gnmi.CapabilityRequest{}) + _, err := gnmiClient.Capabilities(ctx, &gnmipb.CapabilityRequest{}) if err != nil { t.Logf("Got expected error fetching capabilities with bad creds, error: %s", err) } else { @@ -364,7 +364,7 @@ func SendGnmiRPCs(t *testing.T, dut *ondatra.DUTDevice) []*acctzpb.RecordRespons ctx = context.Background() ctx = metadata.AppendToOutgoingContext(ctx, "username", successUsername) ctx = metadata.AppendToOutgoingContext(ctx, "password", successPassword) - req := &gnmi.CapabilityRequest{} + req := &gnmipb.CapabilityRequest{} payload, err := anypb.New(req) if err != nil { t.Fatal("Failed creating anypb payload.") @@ -422,14 +422,14 @@ func SendGnoiRPCs(t *testing.T, dut *ondatra.DUTDevice) []*acctzpb.RecordRespons var records []*acctzpb.RecordResponse grpcConn := dialGrpc(t, target) - gnoiSystemClient := system.NewSystemClient(grpcConn) + gnoiSystemClient := systempb.NewSystemClient(grpcConn) ctx := context.Background() ctx = metadata.AppendToOutgoingContext(ctx, "username", failUsername) ctx = metadata.AppendToOutgoingContext(ctx, "password", failPassword) // Send an unsuccessful gNOI system time request (bad creds in context), we don't // care about receiving on it, just want to make the request. - gnoiSystemPingClient, err := gnoiSystemClient.Ping(ctx, &system.PingRequest{ + gnoiSystemPingClient, err := gnoiSystemClient.Ping(ctx, &systempb.PingRequest{ Destination: "127.0.0.1", Count: 1, }) @@ -468,7 +468,7 @@ func SendGnoiRPCs(t *testing.T, dut *ondatra.DUTDevice) []*acctzpb.RecordRespons ctx = context.Background() ctx = metadata.AppendToOutgoingContext(ctx, "username", successUsername) ctx = metadata.AppendToOutgoingContext(ctx, "password", successPassword) - req := &system.PingRequest{ + req := &systempb.PingRequest{ Destination: "127.0.0.1", Count: 1, } diff --git a/proto/metadata.proto b/proto/metadata.proto index 82e022fcec7..617537009be 100644 --- a/proto/metadata.proto +++ b/proto/metadata.proto @@ -643,9 +643,18 @@ message Metadata { // Device have different default value for allow own as. // Juniper : b/373559004 bool bgp_allowownas_diff_default_value = 231; + // Cisco numbering for OTN channel assignment starts from 1 instead of 0 + bool otn_channel_assignment_cisco_numbering = 232; + // Cisco pre-fec-ber inactive value for CISCO-ACACIA vendors + bool cisco_pre_fec_ber_inactive_value = 233; + // Device does not support bgp extended next hop encoding leaf. + // Cisco: b/377433951 + bool bgp_extended_next_hop_encoding_leaf_unsupported = 234; + // Device does not support bgp afi safi wildcard. + // Cisco: b/379863985 + bool bgp_afi_safi_wildcard_not_supported = 235; // Nokia; b/304493065 comment#7 SRL native admin_enable for table-connections - bool enable_table_connections = 232; - + bool enable_table_connections = 236; // Reserved field numbers and identifiers. reserved 84, 9, 28, 20, 90, 97, 55, 89, 19, 36, 35, 40, 173; } @@ -675,4 +684,3 @@ message Metadata { // checks. bool path_presence_test = 7; } - diff --git a/proto/metadata_go_proto/metadata.pb.go b/proto/metadata_go_proto/metadata.pb.go index 5fdcccea5fb..5b5d3f4ba28 100644 --- a/proto/metadata_go_proto/metadata.pb.go +++ b/proto/metadata_go_proto/metadata.pb.go @@ -924,8 +924,18 @@ type Metadata_Deviations struct { // Device have different default value for allow own as. // Juniper : b/373559004 BgpAllowownasDiffDefaultValue bool `protobuf:"varint,231,opt,name=bgp_allowownas_diff_default_value,json=bgpAllowownasDiffDefaultValue,proto3" json:"bgp_allowownas_diff_default_value,omitempty"` + // Cisco numbering for OTN channel assignment starts from 1 instead of 0 + OtnChannelAssignmentCiscoNumbering bool `protobuf:"varint,232,opt,name=otn_channel_assignment_cisco_numbering,json=otnChannelAssignmentCiscoNumbering,proto3" json:"otn_channel_assignment_cisco_numbering,omitempty"` + // Cisco pre-fec-ber inactive value for CISCO-ACACIA vendors + CiscoPreFecBerInactiveValue bool `protobuf:"varint,233,opt,name=cisco_pre_fec_ber_inactive_value,json=ciscoPreFecBerInactiveValue,proto3" json:"cisco_pre_fec_ber_inactive_value,omitempty"` + // Device does not support bgp extended next hop encoding leaf. + // Cisco: b/377433951 + BgpExtendedNextHopEncodingLeafUnsupported bool `protobuf:"varint,234,opt,name=bgp_extended_next_hop_encoding_leaf_unsupported,json=bgpExtendedNextHopEncodingLeafUnsupported,proto3" json:"bgp_extended_next_hop_encoding_leaf_unsupported,omitempty"` + // Device does not support bgp afi safi wildcard. + // Cisco: b/379863985 + BgpAfiSafiWildcardNotSupported bool `protobuf:"varint,235,opt,name=bgp_afi_safi_wildcard_not_supported,json=bgpAfiSafiWildcardNotSupported,proto3" json:"bgp_afi_safi_wildcard_not_supported,omitempty"` // Nokia; b/304493065 comment#7 SRL native admin_enable for table-connections - EnableTableConnections bool `protobuf:"varint,232,opt,name=enable_table_connections,json=enableTableConnections,proto3" json:"enable_table_connections,omitempty"` + EnableTableConnections bool `protobuf:"varint,236,opt,name=enable_table_connections,json=enableTableConnections,proto3" json:"enable_table_connections,omitempty"` } func (x *Metadata_Deviations) Reset() { @@ -2430,6 +2440,34 @@ func (x *Metadata_Deviations) GetBgpAllowownasDiffDefaultValue() bool { return false } +func (x *Metadata_Deviations) GetOtnChannelAssignmentCiscoNumbering() bool { + if x != nil { + return x.OtnChannelAssignmentCiscoNumbering + } + return false +} + +func (x *Metadata_Deviations) GetCiscoPreFecBerInactiveValue() bool { + if x != nil { + return x.CiscoPreFecBerInactiveValue + } + return false +} + +func (x *Metadata_Deviations) GetBgpExtendedNextHopEncodingLeafUnsupported() bool { + if x != nil { + return x.BgpExtendedNextHopEncodingLeafUnsupported + } + return false +} + +func (x *Metadata_Deviations) GetBgpAfiSafiWildcardNotSupported() bool { + if x != nil { + return x.BgpAfiSafiWildcardNotSupported + } + return false +} + func (x *Metadata_Deviations) GetEnableTableConnections() bool { if x != nil { return x.EnableTableConnections @@ -2500,7 +2538,7 @@ var file_metadata_proto_rawDesc = []byte{ 0x74, 0x69, 0x6e, 0x67, 0x1a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x6f, 0x6e, 0x64, 0x61, 0x74, 0x72, 0x61, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x62, 0x65, - 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf5, 0x82, 0x01, 0x0a, 0x08, 0x4d, 0x65, 0x74, + 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc5, 0x85, 0x01, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x6c, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x61, 0x6e, @@ -2534,7 +2572,7 @@ var file_metadata_proto_rawDesc = []byte{ 0x65, 0x67, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x67, 0x65, 0x78, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x52, 0x0e, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, - 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x1a, 0xc8, 0x7a, 0x0a, 0x0a, 0x44, 0x65, 0x76, 0x69, 0x61, + 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x1a, 0x98, 0x7d, 0x0a, 0x0a, 0x44, 0x65, 0x76, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x69, 0x70, 0x76, 0x34, 0x5f, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x69, 0x70, 0x76, 0x34, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, @@ -3506,9 +3544,30 @@ var file_metadata_proto_rawDesc = []byte{ 0x66, 0x66, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0xe7, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1d, 0x62, 0x67, 0x70, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x77, 0x6e, 0x61, 0x73, 0x44, 0x69, 0x66, 0x66, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, - 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x39, 0x0a, 0x18, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x53, 0x0a, 0x26, 0x6f, 0x74, 0x6e, 0x5f, 0x63, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, + 0x5f, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x69, 0x6e, 0x67, + 0x18, 0xe8, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x22, 0x6f, 0x74, 0x6e, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x43, 0x69, 0x73, + 0x63, 0x6f, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x46, 0x0a, 0x20, 0x63, + 0x69, 0x73, 0x63, 0x6f, 0x5f, 0x70, 0x72, 0x65, 0x5f, 0x66, 0x65, 0x63, 0x5f, 0x62, 0x65, 0x72, + 0x5f, 0x69, 0x6e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0xe9, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x50, 0x72, 0x65, + 0x46, 0x65, 0x63, 0x42, 0x65, 0x72, 0x49, 0x6e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x12, 0x63, 0x0a, 0x2f, 0x62, 0x67, 0x70, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e, + 0x64, 0x65, 0x64, 0x5f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x68, 0x6f, 0x70, 0x5f, 0x65, 0x6e, 0x63, + 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x65, 0x61, 0x66, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, + 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xea, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x29, 0x62, + 0x67, 0x70, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x6f, + 0x70, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x61, 0x66, 0x55, 0x6e, 0x73, + 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x4c, 0x0a, 0x23, 0x62, 0x67, 0x70, 0x5f, + 0x61, 0x66, 0x69, 0x5f, 0x73, 0x61, 0x66, 0x69, 0x5f, 0x77, 0x69, 0x6c, 0x64, 0x63, 0x61, 0x72, + 0x64, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, + 0xeb, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1e, 0x62, 0x67, 0x70, 0x41, 0x66, 0x69, 0x53, 0x61, + 0x66, 0x69, 0x57, 0x69, 0x6c, 0x64, 0x63, 0x61, 0x72, 0x64, 0x4e, 0x6f, 0x74, 0x53, 0x75, 0x70, + 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x39, 0x0a, 0x18, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x18, 0xe8, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x65, 0x6e, 0x61, 0x62, 0x6c, + 0x6e, 0x73, 0x18, 0xec, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4a, 0x04, 0x08, 0x54, 0x10, 0x55, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x1c, 0x10, 0x1d, 0x4a, 0x04, 0x08, 0x14, 0x10, 0x15, 0x4a, 0x04, 0x08, 0x5a, 0x10, 0x5b, 0x4a, diff --git a/testregistry.textproto b/testregistry.textproto index f3da91c3cfe..412f0a93b7d 100644 --- a/testregistry.textproto +++ b/testregistry.textproto @@ -809,6 +809,13 @@ test: { readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/aft/aft_summary/otg_tests/route_summary_counters_test/README.md" exec: " " } +test: { + id: "RT-4.11" + description: " Scale AFTs Route Summary" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/aft/aft_summary/otg_tests/scale_aft_summary/README.md" + exec: " " +} + test: { id: "RT-5.1" description: "Singleton Interface" @@ -1224,7 +1231,8 @@ test: { exec: " " } test: { - id: "TE-9.1: Push MPLS Labels to MPLS payload" + id: "TE-9.1" + description: "Push MPLS Labels to MPLS payload" readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/gribi/otg_tests/mpls_compliance/README.md" } test: { @@ -1798,3 +1806,15 @@ test: { readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/container/networking/tests/container_connectivity/README.md" exec: " " } +test: { + id: "AFT-1.1" + description: "AFT Streaming" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/aft/aft_base/otg_tests/aft_base/README.md" + exec: " " +} +test: { + id: "AFT-2.1" + description: "AFT Streaming" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/aft/aft_base/otg_tests/aft_prefixcounters/README.md" + exec: " " +} \ No newline at end of file diff --git a/tools/nosimage/validate/validate.go b/tools/nosimage/validate/validate.go index a43203d4e4d..76115528626 100644 --- a/tools/nosimage/validate/validate.go +++ b/tools/nosimage/validate/validate.go @@ -91,7 +91,12 @@ func main() { if err := os.MkdirAll(config.DownloadPath, 0750); err != nil { fmt.Println(fmt.Errorf("cannot create download path directory: %v", config.DownloadPath)) } - publicPath, err := ocpaths.ClonePublicRepo(config.DownloadPath, "v"+profile.Ocpaths.GetVersion()) + + ocReleaseTag := "" + if profile.Ocpaths.GetVersion() != "" { + ocReleaseTag = "v" + profile.Ocpaths.GetVersion() + } + publicPath, err := ocpaths.ClonePublicRepo(config.DownloadPath, ocReleaseTag) if err != nil { fmt.Println(err) os.Exit(1)