diff --git a/feature/aft/afts_summary/otg_tests/route_summary_counters_test/metadata.textproto b/feature/aft/afts_summary/otg_tests/route_summary_counters_test/metadata.textproto index 617ae227d00..bef6a660d74 100644 --- a/feature/aft/afts_summary/otg_tests/route_summary_counters_test/metadata.textproto +++ b/feature/aft/afts_summary/otg_tests/route_summary_counters_test/metadata.textproto @@ -49,7 +49,6 @@ platform_exceptions: { 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/metadata.textproto b/feature/aft/afts_summary/otg_tests/scale_aft_summary/metadata.textproto index d61d4590b2b..8fb1fdbbe4e 100644 --- a/feature/aft/afts_summary/otg_tests/scale_aft_summary/metadata.textproto +++ b/feature/aft/afts_summary/otg_tests/scale_aft_summary/metadata.textproto @@ -49,6 +49,5 @@ platform_exceptions: { default_network_instance: "default" isis_instance_enabled_required: true isis_interface_afi_unsupported: true - route_policy_under_afi_unsupported: true } } diff --git a/feature/bgp/addpath/otg_tests/route_propagation_test/metadata.textproto b/feature/bgp/addpath/otg_tests/route_propagation_test/metadata.textproto index db7e7b16a42..86a84f7be76 100644 --- a/feature/bgp/addpath/otg_tests/route_propagation_test/metadata.textproto +++ b/feature/bgp/addpath/otg_tests/route_propagation_test/metadata.textproto @@ -28,7 +28,6 @@ platform_exceptions: { vendor: ARISTA } deviations: { - route_policy_under_afi_unsupported: true omit_l2_mtu: true interface_enabled: true default_network_instance: "default" diff --git a/feature/bgp/admin_distance/otg_tests/admin_distance_test/metadata.textproto b/feature/bgp/admin_distance/otg_tests/admin_distance_test/metadata.textproto index 42c8e91175e..c4c16ab351a 100644 --- a/feature/bgp/admin_distance/otg_tests/admin_distance_test/metadata.textproto +++ b/feature/bgp/admin_distance/otg_tests/admin_distance_test/metadata.textproto @@ -16,9 +16,6 @@ platform_exceptions: { interface_enabled: true default_network_instance: "default" isis_interface_afi_unsupported: true - skip_isis_set_level: true - skip_set_rp_match_set_options: true - skip_setting_disable_metric_propagation: true skip_setting_statement_for_policy: true } } diff --git a/feature/bgp/ate_tests/bgp_long_lived_graceful_restart/metadata.textproto b/feature/bgp/ate_tests/bgp_long_lived_graceful_restart/metadata.textproto index 004e3e5a3e6..ca088902401 100644 --- a/feature/bgp/ate_tests/bgp_long_lived_graceful_restart/metadata.textproto +++ b/feature/bgp/ate_tests/bgp_long_lived_graceful_restart/metadata.textproto @@ -36,7 +36,6 @@ platform_exceptions: { vendor: ARISTA } deviations: { - route_policy_under_afi_unsupported: true omit_l2_mtu: true interface_config_vrf_before_address: true deprecated_vlan_id: true 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 a3769f0ac2c..42840934722 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 @@ -11,16 +11,11 @@ platform_exceptions: { } deviations: { isis_instance_enabled_required: true - route_policy_under_afi_unsupported: true omit_l2_mtu: true missing_value_for_defaults: true interface_enabled: true default_network_instance: "default" isis_interface_afi_unsupported: true - skip_isis_set_level: true - skip_isis_set_metric_style_type: true - skip_set_rp_match_set_options: true - skip_setting_disable_metric_propagation: true } } platform_exceptions: { diff --git a/feature/bgp/gracefulrestart/ate_tests/bgp_graceful_restart_test/metadata.textproto b/feature/bgp/gracefulrestart/ate_tests/bgp_graceful_restart_test/metadata.textproto index 6bb6b0f824b..193098ce145 100644 --- a/feature/bgp/gracefulrestart/ate_tests/bgp_graceful_restart_test/metadata.textproto +++ b/feature/bgp/gracefulrestart/ate_tests/bgp_graceful_restart_test/metadata.textproto @@ -28,7 +28,6 @@ platform_exceptions: { vendor: ARISTA } deviations: { - route_policy_under_afi_unsupported: true omit_l2_mtu: true interface_enabled: true default_network_instance: "default" diff --git a/feature/bgp/multipath/otg_tests/bgp_multipath_ecmp_test/metadata.textproto b/feature/bgp/multipath/otg_tests/bgp_multipath_ecmp_test/metadata.textproto index b696e86ea0b..6a3d6250365 100644 --- a/feature/bgp/multipath/otg_tests/bgp_multipath_ecmp_test/metadata.textproto +++ b/feature/bgp/multipath/otg_tests/bgp_multipath_ecmp_test/metadata.textproto @@ -39,7 +39,6 @@ platform_exceptions: { vendor: ARISTA } deviations: { - route_policy_under_afi_unsupported: true omit_l2_mtu: true interface_enabled: true default_network_instance: "default" diff --git a/feature/bgp/multipath/otg_tests/bgp_multipath_wecmp_lbw_community_test/metadata.textproto b/feature/bgp/multipath/otg_tests/bgp_multipath_wecmp_lbw_community_test/metadata.textproto index 1f758c5b4f5..aa6885aa842 100644 --- a/feature/bgp/multipath/otg_tests/bgp_multipath_wecmp_lbw_community_test/metadata.textproto +++ b/feature/bgp/multipath/otg_tests/bgp_multipath_wecmp_lbw_community_test/metadata.textproto @@ -39,7 +39,6 @@ platform_exceptions: { vendor: ARISTA } deviations: { - route_policy_under_afi_unsupported: true omit_l2_mtu: true interface_enabled: true default_network_instance: "default" diff --git a/feature/bgp/otg_tests/bgp_2byte_4byte_asn/metadata.textproto b/feature/bgp/otg_tests/bgp_2byte_4byte_asn/metadata.textproto index 18a90886ebd..e9806a57b2a 100644 --- a/feature/bgp/otg_tests/bgp_2byte_4byte_asn/metadata.textproto +++ b/feature/bgp/otg_tests/bgp_2byte_4byte_asn/metadata.textproto @@ -10,7 +10,6 @@ platform_exceptions: { vendor: ARISTA } deviations: { - route_policy_under_afi_unsupported: true omit_l2_mtu: true network_instance_table_deletion_required: true interface_enabled: true diff --git a/feature/bgp/otg_tests/bgp_2byte_4byte_asn_policy_test/metadata.textproto b/feature/bgp/otg_tests/bgp_2byte_4byte_asn_policy_test/metadata.textproto index 58e2412e7cb..d2e9240bb24 100644 --- a/feature/bgp/otg_tests/bgp_2byte_4byte_asn_policy_test/metadata.textproto +++ b/feature/bgp/otg_tests/bgp_2byte_4byte_asn_policy_test/metadata.textproto @@ -30,7 +30,6 @@ platform_exceptions: { vendor: ARISTA } deviations: { - route_policy_under_afi_unsupported: true omit_l2_mtu: true interface_enabled: true default_network_instance: "default" 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 13ed1cf127b..77d1a362bc5 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 @@ -62,6 +62,7 @@ const ( var ( dutPort1 = attrs.Attributes{ Desc: "DUT to ATE Port1", + Name: "port1", IPv4: "192.0.2.1", IPv6: "2001:db8::192:0:2:1", IPv4Len: plenIPv4, @@ -77,6 +78,7 @@ var ( } dutPort2 = attrs.Attributes{ Desc: "DUT to ATE Port2", + Name: "port2", IPv4: "192.0.2.5", IPv6: "2001:db8::192:0:2:5", IPv4Len: plenIPv4, @@ -111,12 +113,17 @@ func configureDUT(t *testing.T, dut *ondatra.DUTDevice) { i2 := dutPort2.NewOCInterface(dut.Port(t, "port2").Name(), dut) gnmi.Replace(t, dut, dc.Interface(i2.GetName()).Config(), i2) + if deviations.ExplicitInterfaceInDefaultVRF(dut) { + fptest.AssignToNetworkInstance(t, dut, i1.GetName(), deviations.DefaultNetworkInstance(dut), 0) + fptest.AssignToNetworkInstance(t, dut, i2.GetName(), deviations.DefaultNetworkInstance(dut), 0) + } } // verifyPortsUp asserts that each port on the device is operating. -func verifyPortsUp(t *testing.T, dev *ondatra.Device) { +func verifyPortsUp(t *testing.T, dev *ondatra.Device, portList []string) { t.Helper() - for _, p := range dev.Ports() { + for _, port := range portList { + p := dev.Port(t, port) status := gnmi.Get(t, dev, gnmi.OC().Interface(p.Name()).OperStatus().State()) if want := oc.Interface_OperStatus_UP; status != want { t.Errorf("%s Status: got %v, want %v", p, status, want) @@ -144,7 +151,11 @@ func bgpCreateNbr(t *testing.T, localAs, peerAs uint32, dut *ondatra.DUTDevice, pg2 := bgp.GetOrCreatePeerGroup(peerGrpName2) // V6 peer group pg2.PeerAs = ygot.Uint32(dutAS) pg2.PeerGroupName = ygot.String(peerGrpName2) - + if isV4Only { + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + } else { + global.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) + } for _, nbr := range nbrs { nv4 := bgp.GetOrCreateNeighbor(nbr.neighborip) nv4.PeerGroup = ygot.String(nbr.peerGrp) @@ -479,7 +490,8 @@ func TestAfiSafiOcDefaults(t *testing.T) { }) t.Run("Verify port status on DUT", func(t *testing.T) { - verifyPortsUp(t, dut.Device) + portList := []string{"port1", "port2"} + verifyPortsUp(t, dut.Device, portList) }) t.Run("Verify BGP telemetry", func(t *testing.T) { 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 070b871264d..f043a15764a 100644 --- a/feature/bgp/otg_tests/bgp_afi_safi_defaults/metadata.textproto +++ b/feature/bgp/otg_tests/bgp_afi_safi_defaults/metadata.textproto @@ -28,6 +28,9 @@ platform_exceptions: { vendor: NOKIA } deviations: { + skip_bgp_session_check_without_afisafi: true + explicit_interface_in_default_vrf: true + bgp_global_extended_next_hop_encoding_unsupported: true interface_enabled: true } } @@ -36,7 +39,6 @@ platform_exceptions: { vendor: ARISTA } deviations: { - route_policy_under_afi_unsupported: true omit_l2_mtu: true network_instance_table_deletion_required: true interface_enabled: true diff --git a/feature/bgp/otg_tests/bgp_always_compare_med/metadata.textproto b/feature/bgp/otg_tests/bgp_always_compare_med/metadata.textproto index ecf4c782d29..1aea5f11c14 100644 --- a/feature/bgp/otg_tests/bgp_always_compare_med/metadata.textproto +++ b/feature/bgp/otg_tests/bgp_always_compare_med/metadata.textproto @@ -19,7 +19,6 @@ platform_exceptions: { vendor: ARISTA } deviations: { - route_policy_under_afi_unsupported: true omit_l2_mtu: true interface_enabled: true default_network_instance: "default" 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 030f0d4fa88..7f574446d81 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 @@ -176,12 +176,10 @@ func configureOTG(t *testing.T, otg *otg.OTG) (gosnappi.BgpV4Peer, gosnappi.Devi iDut1Bgp4Peer := iDut1Bgp.Ipv4Interfaces().Add().SetIpv4Name(iDut1Ipv4.Name()).Peers().Add().SetName(otgPort1V4Peer) iDut1Bgp4Peer.SetPeerAddress(iDut1Ipv4.Gateway()).SetAsNumber(ateAS1).SetAsType(gosnappi.BgpV4PeerAsType.EBGP) - iDut1Bgp4Peer.Capability().SetIpv4UnicastAddPath(true).SetIpv6UnicastAddPath(true) iDut1Bgp4Peer.LearnedInformationFilter().SetUnicastIpv4Prefix(true).SetUnicastIpv6Prefix(true) iDut2Bgp4Peer := iDut2Bgp.Ipv4Interfaces().Add().SetIpv4Name(iDut2Ipv4.Name()).Peers().Add().SetName(otgPort2V4Peer) iDut2Bgp4Peer.SetPeerAddress(iDut2Ipv4.Gateway()).SetAsNumber(ateAS2).SetAsType(gosnappi.BgpV4PeerAsType.EBGP) - iDut2Bgp4Peer.Capability().SetIpv4UnicastAddPath(true).SetIpv6UnicastAddPath(true) iDut2Bgp4Peer.LearnedInformationFilter().SetUnicastIpv4Prefix(true).SetUnicastIpv6Prefix(true) t.Logf("Pushing config to OTG and starting protocols...") diff --git a/feature/bgp/otg_tests/bgp_override_as_path_split_horizon_test/metadata.textproto b/feature/bgp/otg_tests/bgp_override_as_path_split_horizon_test/metadata.textproto index b4b418d51e2..f1f229cf639 100644 --- a/feature/bgp/otg_tests/bgp_override_as_path_split_horizon_test/metadata.textproto +++ b/feature/bgp/otg_tests/bgp_override_as_path_split_horizon_test/metadata.textproto @@ -19,7 +19,6 @@ platform_exceptions: { vendor: ARISTA } deviations: { - route_policy_under_afi_unsupported: true omit_l2_mtu: true interface_enabled: true default_network_instance: "default" diff --git a/feature/bgp/policybase/otg_tests/actions_med_localpref_prepend_flow_control/metadata.textproto b/feature/bgp/policybase/otg_tests/actions_med_localpref_prepend_flow_control/metadata.textproto index c11bd3995b2..d5e98b570c4 100644 --- a/feature/bgp/policybase/otg_tests/actions_med_localpref_prepend_flow_control/metadata.textproto +++ b/feature/bgp/policybase/otg_tests/actions_med_localpref_prepend_flow_control/metadata.textproto @@ -42,7 +42,6 @@ platform_exceptions: { vendor: ARISTA } deviations: { - route_policy_under_afi_unsupported: true omit_l2_mtu: true interface_enabled: true default_network_instance: "default" diff --git a/feature/bgp/policybase/otg_tests/aspath_and_community_test/metadata.textproto b/feature/bgp/policybase/otg_tests/aspath_and_community_test/metadata.textproto index 6075ea0b951..ea6cc928d37 100644 --- a/feature/bgp/policybase/otg_tests/aspath_and_community_test/metadata.textproto +++ b/feature/bgp/policybase/otg_tests/aspath_and_community_test/metadata.textproto @@ -17,8 +17,6 @@ platform_exceptions: { missing_value_for_defaults: true interface_enabled: true default_network_instance: "default" - skip_set_rp_match_set_options: true - skip_setting_disable_metric_propagation: true } } diff --git a/feature/bgp/policybase/otg_tests/aspath_test/metadata.textproto b/feature/bgp/policybase/otg_tests/aspath_test/metadata.textproto index c59c7f78251..a8d477d1315 100644 --- a/feature/bgp/policybase/otg_tests/aspath_test/metadata.textproto +++ b/feature/bgp/policybase/otg_tests/aspath_test/metadata.textproto @@ -11,13 +11,10 @@ platform_exceptions: { vendor: ARISTA } deviations: { - route_policy_under_afi_unsupported: true omit_l2_mtu: true missing_value_for_defaults: true interface_enabled: true default_network_instance: "default" - skip_set_rp_match_set_options: true - skip_setting_disable_metric_propagation: true } } platform_exceptions: { diff --git a/feature/bgp/policybase/otg_tests/chained_policies_test/metadata.textproto b/feature/bgp/policybase/otg_tests/chained_policies_test/metadata.textproto index 6dc207736c3..91a502a1acd 100644 --- a/feature/bgp/policybase/otg_tests/chained_policies_test/metadata.textproto +++ b/feature/bgp/policybase/otg_tests/chained_policies_test/metadata.textproto @@ -14,7 +14,6 @@ platform_exceptions: { interface_enabled: true default_network_instance: "default" missing_value_for_defaults: true - skip_set_rp_match_set_options: true default_import_export_policy_unsupported: false skip_setting_statement_for_policy: true } diff --git a/feature/bgp/policybase/otg_tests/community_test/metadata.textproto b/feature/bgp/policybase/otg_tests/community_test/metadata.textproto index 68da71ad8f8..c1ec937eca4 100644 --- a/feature/bgp/policybase/otg_tests/community_test/metadata.textproto +++ b/feature/bgp/policybase/otg_tests/community_test/metadata.textproto @@ -11,13 +11,10 @@ platform_exceptions: { vendor: ARISTA } deviations: { - route_policy_under_afi_unsupported: true omit_l2_mtu: true missing_value_for_defaults: true interface_enabled: true default_network_instance: "default" - skip_set_rp_match_set_options: true - skip_setting_disable_metric_propagation: true } } platform_exceptions: { diff --git a/feature/bgp/policybase/otg_tests/default_policies_test/metadata.textproto b/feature/bgp/policybase/otg_tests/default_policies_test/metadata.textproto index 21a048a2b80..c668c4dd4d3 100644 --- a/feature/bgp/policybase/otg_tests/default_policies_test/metadata.textproto +++ b/feature/bgp/policybase/otg_tests/default_policies_test/metadata.textproto @@ -24,7 +24,6 @@ platform_exceptions: { missing_isis_interface_afi_safi_enable: true isis_interface_afi_unsupported: true isis_instance_enabled_required: true - default_import_export_policy_unsupported: true bgp_default_policy_unsupported: true } } diff --git a/feature/bgp/policybase/otg_tests/import_export_multi_test/metadata.textproto b/feature/bgp/policybase/otg_tests/import_export_multi_test/metadata.textproto index 98502cb3188..959c157bc9e 100644 --- a/feature/bgp/policybase/otg_tests/import_export_multi_test/metadata.textproto +++ b/feature/bgp/policybase/otg_tests/import_export_multi_test/metadata.textproto @@ -16,10 +16,7 @@ platform_exceptions: { interface_enabled: true default_network_instance: "default" missing_value_for_defaults: true - skip_set_rp_match_set_options: true - bgp_community_set_refs_unsupported: true bgp_community_member_is_a_string: true - skip_bgp_send_community_type: true } } platform_exceptions: { diff --git a/feature/bgp/policybase/otg_tests/link_bandwidth_test/metadata.textproto b/feature/bgp/policybase/otg_tests/link_bandwidth_test/metadata.textproto index e5e9757204d..f0c47372b81 100644 --- a/feature/bgp/policybase/otg_tests/link_bandwidth_test/metadata.textproto +++ b/feature/bgp/policybase/otg_tests/link_bandwidth_test/metadata.textproto @@ -10,13 +10,10 @@ platform_exceptions: { vendor: ARISTA } deviations: { - route_policy_under_afi_unsupported: true omit_l2_mtu: true missing_value_for_defaults: true interface_enabled: true default_network_instance: "default" - skip_set_rp_match_set_options: true - skip_setting_disable_metric_propagation: true bgp_extended_community_index_unsupported: true } } diff --git a/feature/bgp/policybase/otg_tests/nested_policies/metadata.textproto b/feature/bgp/policybase/otg_tests/nested_policies/metadata.textproto index beed0cdd3fd..dce970ff455 100644 --- a/feature/bgp/policybase/otg_tests/nested_policies/metadata.textproto +++ b/feature/bgp/policybase/otg_tests/nested_policies/metadata.textproto @@ -14,7 +14,6 @@ platform_exceptions: { interface_enabled: true default_network_instance: "default" missing_value_for_defaults: true - skip_set_rp_match_set_options: true routing_policy_chaining_unsupported: true } } diff --git a/feature/bgp/policybase/otg_tests/prefix_set_test/metadata.textproto b/feature/bgp/policybase/otg_tests/prefix_set_test/metadata.textproto index 159d68be6a0..53a20acb188 100644 --- a/feature/bgp/policybase/otg_tests/prefix_set_test/metadata.textproto +++ b/feature/bgp/policybase/otg_tests/prefix_set_test/metadata.textproto @@ -27,7 +27,6 @@ platform_exceptions: { default_network_instance: "default" missing_value_for_defaults: true skip_set_rp_match_set_options: true - default_import_export_policy_unsupported: true } } platform_exceptions: { diff --git a/feature/bgp/policybase/otg_tests/route_installation_test/metadata.textproto b/feature/bgp/policybase/otg_tests/route_installation_test/metadata.textproto index eed0f9af8a2..389f5463bd3 100644 --- a/feature/bgp/policybase/otg_tests/route_installation_test/metadata.textproto +++ b/feature/bgp/policybase/otg_tests/route_installation_test/metadata.textproto @@ -29,7 +29,6 @@ platform_exceptions: { vendor: ARISTA } deviations: { - route_policy_under_afi_unsupported: true omit_l2_mtu: true interface_enabled: true default_network_instance: "default" diff --git a/feature/bgp/prefixlimit/otg_tests/bgp_prefix_limit_test/metadata.textproto b/feature/bgp/prefixlimit/otg_tests/bgp_prefix_limit_test/metadata.textproto index 3ffa1ab9deb..5dfec262b82 100644 --- a/feature/bgp/prefixlimit/otg_tests/bgp_prefix_limit_test/metadata.textproto +++ b/feature/bgp/prefixlimit/otg_tests/bgp_prefix_limit_test/metadata.textproto @@ -38,7 +38,6 @@ platform_exceptions: { vendor: ARISTA } deviations: { - route_policy_under_afi_unsupported: true omit_l2_mtu: true interface_enabled: true default_network_instance: "default" diff --git a/feature/bgp/static_route_bgp_redistribution/otg_tests/static_route_bgp_redistribution_test/metadata.textproto b/feature/bgp/static_route_bgp_redistribution/otg_tests/static_route_bgp_redistribution_test/metadata.textproto index 03580ac4f2c..4a1d861f80a 100644 --- a/feature/bgp/static_route_bgp_redistribution/otg_tests/static_route_bgp_redistribution_test/metadata.textproto +++ b/feature/bgp/static_route_bgp_redistribution/otg_tests/static_route_bgp_redistribution_test/metadata.textproto @@ -18,7 +18,6 @@ platform_exceptions: { skip_set_rp_match_set_options: true skip_prefix_set_mode: true table_connections_unsupported: true - use_vendor_native_tag_set_config: true skip_bgp_send_community_type: true } } @@ -31,10 +30,7 @@ platform_exceptions: { default_network_instance: "default" interface_enabled: true static_protocol_name: "STATIC" - skip_bgp_send_community_type: true - skip_setting_disable_metric_propagation: true same_policy_attached_to_all_afis: true - set_metric_as_preference: true } } platform_exceptions: { diff --git a/feature/bgp/tests/local_bgp_test/metadata.textproto b/feature/bgp/tests/local_bgp_test/metadata.textproto index b64b1439ba4..9c6cd72851e 100644 --- a/feature/bgp/tests/local_bgp_test/metadata.textproto +++ b/feature/bgp/tests/local_bgp_test/metadata.textproto @@ -32,7 +32,6 @@ platform_exceptions: { } deviations: { connect_retry: true - route_policy_under_afi_unsupported: true omit_l2_mtu: true network_instance_table_deletion_required: true missing_value_for_defaults: true diff --git a/feature/bgp/timers/otg_tests/bgp_keepalive_and_holdtimer_configuration_test/metadata.textproto b/feature/bgp/timers/otg_tests/bgp_keepalive_and_holdtimer_configuration_test/metadata.textproto index d9df992f174..279a2bc5dd5 100644 --- a/feature/bgp/timers/otg_tests/bgp_keepalive_and_holdtimer_configuration_test/metadata.textproto +++ b/feature/bgp/timers/otg_tests/bgp_keepalive_and_holdtimer_configuration_test/metadata.textproto @@ -29,7 +29,6 @@ platform_exceptions: { vendor: ARISTA } deviations: { - route_policy_under_afi_unsupported: true omit_l2_mtu: true interface_enabled: true default_network_instance: "default" diff --git a/feature/gnoi/packet_link_qualification/tests/packet_link_qualification_test/README.md b/feature/gnoi/packet_link_qualification/tests/packet_link_qualification_test/README.md index 01e4aca9b19..fa4005ee36c 100644 --- a/feature/gnoi/packet_link_qualification/tests/packet_link_qualification_test/README.md +++ b/feature/gnoi/packet_link_qualification/tests/packet_link_qualification_test/README.md @@ -7,7 +7,7 @@ between 2 DUTs. ## Topology -* dut1:port1 <--> port1:dut2 +* dut1:port1 <--> port1:dut2 (port1 as singleton and memberlink) ## Procedure diff --git a/feature/gnoi/packet_link_qualification/tests/packet_link_qualification_test/packet_link_qualification_test.go b/feature/gnoi/packet_link_qualification/tests/packet_link_qualification_test/packet_link_qualification_test.go index 3da68cc1db0..e18eb3daade 100644 --- a/feature/gnoi/packet_link_qualification/tests/packet_link_qualification_test/packet_link_qualification_test.go +++ b/feature/gnoi/packet_link_qualification/tests/packet_link_qualification_test/packet_link_qualification_test.go @@ -16,6 +16,7 @@ package packet_link_qualification_test import ( "context" + "fmt" "math" "testing" "time" @@ -27,6 +28,7 @@ import ( "github.com/openconfig/ondatra" "github.com/openconfig/ondatra/gnmi" "github.com/openconfig/ondatra/gnmi/oc" + "github.com/openconfig/ondatra/netutil" "github.com/openconfig/ygot/ygot" "google.golang.org/protobuf/types/known/durationpb" ) @@ -36,7 +38,7 @@ func TestMain(m *testing.M) { } // Topology: -// dut1:port1 <--> port1:dut2 +// dut1:port1 <--> port1:dut2 (port1 as singleton and memberlink) // // Test notes: // @@ -44,9 +46,28 @@ func TestMain(m *testing.M) { // https://github.com/fullstorydev/grpcurl // +type aggPortData struct { + dut1IPv4 string + dut2IPv4 string + ateAggName string + aggPortIDDUT1 uint32 + aggPortIDDUT2 uint32 +} + +const ( + ipv4PLen = 30 +) + var ( minRequiredGeneratorMTU = uint64(8184) minRequiredGeneratorPPS = uint64(1e8) + agg1 = &aggPortData{ + dut1IPv4: "192.0.2.1", + dut2IPv4: "192.0.2.2", + ateAggName: "lag3", + aggPortIDDUT1: 10, + aggPortIDDUT2: 11, + } ) func TestCapabilitiesResponse(t *testing.T) { @@ -224,26 +245,81 @@ func configInterfaceMTU(i *oc.Interface, dut *ondatra.DUTDevice) *oc.Interface { return i } -func TestLinkQualification(t *testing.T) { - dut1 := ondatra.DUT(t, "dut1") - dut2 := ondatra.DUT(t, "dut2") - - dp1 := dut1.Port(t, "port1") - dp2 := dut2.Port(t, "port1") - t.Logf("dut1: %v, dut2: %v", dut1.Name(), dut2.Name()) - t.Logf("dut1 dp1 name: %v, dut2 dp2 name : %v", dp1.Name(), dp2.Name()) +// configures DUT1 lagID <-----> lagID DUT2 with 1 member link. +func configureDUTAggregate(t *testing.T, dut1 *ondatra.DUTDevice, dut2 *ondatra.DUTDevice) { + t.Helper() + fptest.ConfigureDefaultNetworkInstance(t, dut1) + fptest.ConfigureDefaultNetworkInstance(t, dut2) + var aggIdDut1 string + var aggIdDut2 string for _, dut := range []*ondatra.DUTDevice{dut1, dut2} { - d := gnmi.OC() - p := dut.Port(t, "port1") - i := &oc.Interface{Name: ygot.String(p.Name())} - gnmi.Replace(t, dut, d.Interface(p.Name()).Config(), configInterfaceMTU(i, dut)) - if deviations.ExplicitPortSpeed(dut) { - fptest.SetPortSpeed(t, p) + b := &gnmi.SetBatch{} + d := &oc.Root{} + aggID := netutil.NextAggregateInterface(t, dut) + + agg := d.GetOrCreateInterface(aggID) + agg.GetOrCreateAggregation().LagType = oc.IfAggregate_AggregationType_STATIC + agg.Type = oc.IETFInterfaces_InterfaceType_ieee8023adLag + agg.Description = ygot.String(agg1.ateAggName) + if !deviations.OmitL2MTU(dut) { + agg.Mtu = ygot.Uint16(9000) + } + if deviations.InterfaceEnabled(dut) { + agg.Enabled = ygot.Bool(true) + } + + s := agg.GetOrCreateSubinterface(0) + s4 := s.GetOrCreateIpv4() + if deviations.InterfaceEnabled(dut) { + s4.Enabled = ygot.Bool(true) + } + var a4 *oc.Interface_Subinterface_Ipv4_Address + if dut == dut1 { + a4 = s4.GetOrCreateAddress(agg1.dut1IPv4) + aggIdDut1 = aggID + } else { + a4 = s4.GetOrCreateAddress(agg1.dut2IPv4) + aggIdDut2 = aggID + } + a4.PrefixLength = ygot.Uint8(ipv4PLen) + + gnmi.BatchDelete(b, gnmi.OC().Interface(aggID).Aggregation().MinLinks().Config()) + gnmi.BatchReplace(b, gnmi.OC().Interface(aggID).Config(), agg) + + p1 := dut.Port(t, "port1") + for _, port := range []*ondatra.Port{p1} { + gnmi.BatchDelete(b, gnmi.OC().Interface(port.Name()).Ethernet().AggregateId().Config()) + i := d.GetOrCreateInterface(port.Name()) + if dut == dut1 { + i.Id = ygot.Uint32(agg1.aggPortIDDUT1) + } else { + i.Id = ygot.Uint32(agg1.aggPortIDDUT2) + } + i.Description = ygot.String(fmt.Sprintf("LAG - Member -%s", port.Name())) + e := i.GetOrCreateEthernet() + e.AggregateId = ygot.String(aggID) + i.Type = oc.IETFInterfaces_InterfaceType_ethernetCsmacd + + if deviations.InterfaceEnabled(dut) { + i.Enabled = ygot.Bool(true) + } + gnmi.BatchReplace(b, gnmi.OC().Interface(port.Name()).Config(), i) + } + + b.Set(t, dut) + + if deviations.ExplicitInterfaceInDefaultVRF(dut) { + fptest.AssignToNetworkInstance(t, dut, aggID, deviations.DefaultNetworkInstance(dut), 0) } } + // Wait for LAG interfaces to be UP + gnmi.Await(t, dut1, gnmi.OC().Interface(aggIdDut1).OperStatus().State(), 60*time.Second, oc.Interface_OperStatus_UP) + + gnmi.Await(t, dut2, gnmi.OC().Interface(aggIdDut2).OperStatus().State(), 60*time.Second, oc.Interface_OperStatus_UP) +} - plqID := dut1.Name() + ":" + dp1.Name() + "<->" + dut2.Name() + ":" + dp2.Name() +func testLinkQualification(t *testing.T, dut1 *ondatra.DUTDevice, dut2 *ondatra.DUTDevice, dp1 *ondatra.Port, dp2 *ondatra.Port, plqID string) { if deviations.PLQGeneratorCapabilitiesMaxMTU(dut1) != 0 { minRequiredGeneratorMTU = uint64(deviations.PLQGeneratorCapabilitiesMaxMTU(dut1)) @@ -452,3 +528,49 @@ func TestLinkQualification(t *testing.T) { } } } + +func TestLinkQualification(t *testing.T) { + dut1 := ondatra.DUT(t, "dut1") + dut2 := ondatra.DUT(t, "dut2") + + dp1 := dut1.Port(t, "port1") + dp2 := dut2.Port(t, "port1") + t.Logf("dut1: %v, dut2: %v", dut1.Name(), dut2.Name()) + t.Logf("dut1 dp1 name: %v, dut2 dp2 name : %v", dp1.Name(), dp2.Name()) + + for _, dut := range []*ondatra.DUTDevice{dut1, dut2} { + d := gnmi.OC() + p := dut.Port(t, "port1") + i := &oc.Interface{Name: ygot.String(p.Name())} + gnmi.Replace(t, dut, d.Interface(p.Name()).Config(), configInterfaceMTU(i, dut)) + if deviations.ExplicitPortSpeed(dut) { + fptest.SetPortSpeed(t, p) + } + } + + cases := []struct { + desc string + plqID string + testFunc func(t *testing.T, dut1 *ondatra.DUTDevice, dut2 *ondatra.DUTDevice, dp1 *ondatra.Port, dp2 *ondatra.Port, plqID string) + aggregate bool + }{{ + desc: "Singleton Interface LinkQualification", + plqID: dut1.Name() + ":" + dp1.Name() + "<->" + dut2.Name() + ":" + dp2.Name() + ":singleton", + testFunc: testLinkQualification, + aggregate: false, + }, { + desc: "Member Link LinkQualification", + plqID: dut1.Name() + ":" + dp1.Name() + "<->" + dut2.Name() + ":" + dp2.Name() + ":memberlink", + testFunc: testLinkQualification, + aggregate: true, + }} + + for _, tc := range cases { + t.Run(tc.desc, func(t *testing.T) { + if tc.aggregate { + configureDUTAggregate(t, dut1, dut2) + } + tc.testFunc(t, dut1, dut2, dp1, dp2, tc.plqID) + }) + } +} diff --git a/feature/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/metadata.textproto b/feature/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/metadata.textproto index 179ddbcc314..d14c3475525 100644 --- a/feature/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/metadata.textproto +++ b/feature/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/metadata.textproto @@ -36,7 +36,6 @@ platform_exceptions: { vendor: ARISTA } deviations: { - route_policy_under_afi_unsupported: true omit_l2_mtu: true interface_enabled: true default_network_instance: "default" diff --git a/feature/gribi/otg_tests/gribi_route_test/metadata.textproto b/feature/gribi/otg_tests/gribi_route_test/metadata.textproto index 333a3e00ed4..23b4d0caa8f 100644 --- a/feature/gribi/otg_tests/gribi_route_test/metadata.textproto +++ b/feature/gribi/otg_tests/gribi_route_test/metadata.textproto @@ -45,7 +45,6 @@ platform_exceptions: { isis_interface_afi_unsupported: true missing_isis_interface_afi_safi_enable: true isis_require_same_l1_metric_with_l2_metric: true - route_policy_under_afi_unsupported: true static_protocol_name: "STATIC" aggregate_atomic_update: true missing_value_for_defaults: true diff --git a/feature/gribi/otg_tests/gribigo_compliance_test/gribigo_compliance_test.go b/feature/gribi/otg_tests/gribigo_compliance_test/gribigo_compliance_test.go index 1792e620550..04300fb8eaf 100644 --- a/feature/gribi/otg_tests/gribigo_compliance_test/gribigo_compliance_test.go +++ b/feature/gribi/otg_tests/gribigo_compliance_test/gribigo_compliance_test.go @@ -224,6 +224,14 @@ func testAdditionalCompliance(tcArgs *testArgs, t *testing.T) { fn: addNHGReferencingToDownPort, }, } + + defer func() { + // Flush all entries after test. + if err := gribi.FlushAll(tcArgs.client); err != nil { + t.Error(err) + } + }() + for _, tt := range tests { t.Run(tt.desc, func(t *testing.T) { if err := gribi.FlushAll(tcArgs.client); err != nil { diff --git a/feature/interface/aggregate/otg_tests/aggregate_all_not_viable_test/metadata.textproto b/feature/interface/aggregate/otg_tests/aggregate_all_not_viable_test/metadata.textproto index aedbceb764b..35428c812c4 100644 --- a/feature/interface/aggregate/otg_tests/aggregate_all_not_viable_test/metadata.textproto +++ b/feature/interface/aggregate/otg_tests/aggregate_all_not_viable_test/metadata.textproto @@ -45,7 +45,6 @@ platform_exceptions: { isis_interface_afi_unsupported: true missing_isis_interface_afi_safi_enable: true isis_require_same_l1_metric_with_l2_metric: true - route_policy_under_afi_unsupported: true static_protocol_name: "STATIC" aggregate_atomic_update: true missing_value_for_defaults: true diff --git a/feature/isis/otg_tests/graceful_restart_helper/metadata.textproto b/feature/isis/otg_tests/graceful_restart_helper/metadata.textproto index bd3ca85f0ae..0c495e60d7a 100644 --- a/feature/isis/otg_tests/graceful_restart_helper/metadata.textproto +++ b/feature/isis/otg_tests/graceful_restart_helper/metadata.textproto @@ -16,6 +16,5 @@ platform_exceptions: { isis_interface_afi_unsupported: true isis_instance_enabled_required: true missing_value_for_defaults: true - skip_isis_set_level: true } } \ No newline at end of file diff --git a/feature/isis/otg_tests/graceful_restart_restarting/metadata.textproto b/feature/isis/otg_tests/graceful_restart_restarting/metadata.textproto index 7adf6d82d19..330cb133b91 100644 --- a/feature/isis/otg_tests/graceful_restart_restarting/metadata.textproto +++ b/feature/isis/otg_tests/graceful_restart_restarting/metadata.textproto @@ -16,6 +16,5 @@ platform_exceptions: { isis_interface_afi_unsupported: true isis_instance_enabled_required: true missing_value_for_defaults: true - skip_isis_set_level: true } } \ No newline at end of file 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 2e9a824e2c1..ce30ef694e5 100644 --- a/feature/isis/otg_tests/static_route_isis_redistribution/metadata.textproto +++ b/feature/isis/otg_tests/static_route_isis_redistribution/metadata.textproto @@ -26,12 +26,7 @@ platform_exceptions: { isis_interface_afi_unsupported: true isis_instance_enabled_required: true missing_value_for_defaults: true - skip_isis_set_level: true - skip_setting_disable_metric_propagation: true - ipv6_static_route_with_ipv4_next_hop_requires_static_arp: true - routing_policy_tag_set_embedded: true same_policy_attached_to_all_afis: true - match_tag_set_condition_unsupported: true } } platform_exceptions: { diff --git a/feature/isis/otg_tests/weighted_ecmp_test/metadata.textproto b/feature/isis/otg_tests/weighted_ecmp_test/metadata.textproto index 947afd21cf8..8c66bd70839 100644 --- a/feature/isis/otg_tests/weighted_ecmp_test/metadata.textproto +++ b/feature/isis/otg_tests/weighted_ecmp_test/metadata.textproto @@ -17,7 +17,6 @@ platform_exceptions: { isis_interface_afi_unsupported: true missing_isis_interface_afi_safi_enable: true isis_require_same_l1_metric_with_l2_metric: true - route_policy_under_afi_unsupported: true static_protocol_name: "STATIC" rib_wecmp: true explicit_port_speed: true diff --git a/feature/platform/fabric/otg_tests/fabric_redundancy_test/README.md b/feature/platform/fabric/otg_tests/fabric_redundancy_test/README.md index fa4726e255b..7abcb725bab 100644 --- a/feature/platform/fabric/otg_tests/fabric_redundancy_test/README.md +++ b/feature/platform/fabric/otg_tests/fabric_redundancy_test/README.md @@ -1,4 +1,4 @@ -# gNMI-1.16 Fabric redundnacy test +# gNMI-1.16: Fabric redundnacy test ## Summary - collect inventory data for each fabric card @@ -41,26 +41,49 @@ * Wait * get last-reboot-time and compare with "PREVIOUS_REBOOT_TIME". The "PREVIOUS_REBOOT_TIME" must be smaller (earlier) then recently collected last-reboot-time +## OpenConfig Path and RPC Coverage -## Config Parameter coverage +```yaml +paths: + ## Config Parameter coverage -* /components/component/fabric/config/power-admin-state + /components/component/fabric/config/power-admin-state: + platform_type: [ "FABRIC" ] -## Telemetry Parameter coverage + ## Telemetry Parameter coverage -* /components/component/fabric/state/power-admin-state -* /components/component/state/description -* /components/component/state/hardware-version -* /components/component/state/id -* /components/component/state/mfg-name -* /components/component/state/name -* /components/component/state/oper-status -* /components/component/state/parent -* /components/component/state/part-no -* /components/component/state/serial-no -* /components/component/state/type -* /components/component/state/location -* /components/component/state/last-reboot-time + /components/component/fabric/state/power-admin-state: + platform_type: [ "FABRIC" ] + /components/component/state/description: + platform_type: [ "FABRIC" ] + /components/component/state/hardware-version: + platform_type: [ "FABRIC" ] + /components/component/state/id: + platform_type: [ "FABRIC" ] + /components/component/state/mfg-name: + platform_type: [ "FABRIC" ] + /components/component/state/name: + platform_type: [ "FABRIC" ] + /components/component/state/oper-status: + platform_type: [ "FABRIC" ] + /components/component/state/parent: + platform_type: [ "FABRIC" ] + /components/component/state/part-no: + platform_type: [ "FABRIC" ] + /components/component/state/serial-no: + platform_type: [ "FABRIC" ] + /components/component/state/type: + platform_type: [ "FABRIC" ] + /components/component/state/location: + platform_type: [ "FABRIC" ] + /components/component/state/last-reboot-time: + platform_type: [ "FABRIC" ] + +rpcs: + gnmi: + gNMI.Set: + gNMI.Subscribe: +``` ## Minimum DUT platform requirement * MFF diff --git a/feature/platform/fabric/otg_tests/fabric_redundancy_test/fabric_redundancy_test.go b/feature/platform/fabric/otg_tests/fabric_redundancy_test/fabric_redundancy_test.go new file mode 100644 index 00000000000..f4c3cbe8dd1 --- /dev/null +++ b/feature/platform/fabric/otg_tests/fabric_redundancy_test/fabric_redundancy_test.go @@ -0,0 +1,549 @@ +// Copyright 2023 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 +// +// hfdp://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 fabric_redundancy_test + +import ( + "fmt" + "math/rand" + "reflect" + "strings" + "testing" + "time" + + "github.com/open-traffic-generator/snappi/gosnappi" + "github.com/openconfig/featureprofiles/internal/attrs" + "github.com/openconfig/featureprofiles/internal/components" + "github.com/openconfig/featureprofiles/internal/deviations" + "github.com/openconfig/featureprofiles/internal/fptest" + "github.com/openconfig/featureprofiles/internal/otgutils" + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" + "github.com/openconfig/ondatra/gnmi/oc" + "github.com/openconfig/ondatra/otg" + "github.com/openconfig/ygot/ygot" +) + +const ( + fabricType = oc.PlatformTypes_OPENCONFIG_HARDWARE_COMPONENT_FABRIC + ipv6 = "IPv6" + ipv4PrefixLen = 30 + ipv6PrefixLen = 126 + mtu = 4000 + trafficStopWaitDuration = 10 * time.Second + acceptablePacketSizeDelta = 0.5 + acceptableLossPercent = 0.001 + subInterfaceIndex = 0 + ppsRate = 100000 + packetsToSend = 16000000 +) + +var ( + fabricLeafOrValuePresent = make(map[string][]any) + fabricLeafOrValueNotPresent = make(map[string]string) + dutSrc = &attrs.Attributes{ + Name: "dutSrc", + MAC: "00:12:01:01:01:01", + IPv4: "192.0.2.1", + IPv6: "2001:db8::1", + IPv4Len: ipv4PrefixLen, + IPv6Len: ipv6PrefixLen, + MTU: mtu, + } + + dutDst = &attrs.Attributes{ + Name: "dutDst", + MAC: "00:12:02:01:01:01", + IPv4: "192.0.2.5", + IPv6: "2001:db8::5", + IPv4Len: ipv4PrefixLen, + IPv6Len: ipv6PrefixLen, + MTU: mtu, + } + + ateSrc = &attrs.Attributes{ + Name: "ateSrc", + MAC: "02:00:01:01:01:01", + IPv4: "192.0.2.2", + IPv6: "2001:db8::2", + IPv4Len: ipv4PrefixLen, + IPv6Len: ipv6PrefixLen, + MTU: mtu, + } + + ateDst = &attrs.Attributes{ + Name: "ateDst", + MAC: "02:00:02:01:01:01", + IPv4: "192.0.2.6", + IPv6: "2001:db8::6", + IPv4Len: ipv4PrefixLen, + IPv6Len: ipv6PrefixLen, + MTU: mtu, + } + dutPorts = map[string]*attrs.Attributes{ + "port1": dutSrc, + "port2": dutDst, + } + + atePorts = map[string]*attrs.Attributes{ + "port1": ateSrc, + "port2": ateDst, + } + + fd = flowDefinition{ + name: "flow_size_4000", + desc: "4000 byte flow", + flowSize: 4000, + } +) + +type flowDefinition struct { + name string + desc string + flowSize uint32 +} + +type otgData struct { + flowProto string + otg *otg.OTG + otgConfig gosnappi.Config +} + +func TestMain(m *testing.M) { + fptest.RunTests(m) +} + +func (d *otgData) waitInterface(t *testing.T) { + otgutils.WaitForARP(t, d.otg, d.otgConfig, d.flowProto) +} + +func createFlow(flowName string, flowSize uint32, ipv6 string) gosnappi.Flow { + flow := gosnappi.NewFlow().SetName(flowName) + flow.Metrics().SetEnable(true) + flow.Size().SetFixed(flowSize) + flow.Rate().SetPps(ppsRate) + flow.Duration().FixedPackets().SetPackets(packetsToSend) + flow.TxRx().Device(). + SetTxNames([]string{fmt.Sprintf("%s.%s", ateSrc.Name, ipv6)}). + SetRxNames([]string{fmt.Sprintf("%s.%s", ateDst.Name, ipv6)}) + ethHdr := flow.Packet().Add().Ethernet() + ethHdr.Src().SetValue(ateSrc.MAC) + flow.SetSize(gosnappi.NewFlowSize().SetFixed(flowSize)) + + v6 := flow.Packet().Add().Ipv6() + v6.Src().SetValue(ateSrc.IPv6) + v6.Dst().SetValue(ateDst.IPv6) + + flow.EgressPacket().Add().Ethernet() + + return flow +} + +func configureDUTPort( + t *testing.T, + dut *ondatra.DUTDevice, + port *ondatra.Port, + portAttrs *attrs.Attributes, +) { + gnmi.Replace( + t, + dut, + gnmi.OC().Interface(port.Name()).Config(), + portAttrs.NewOCInterface(port.Name(), dut), + ) + + if deviations.ExplicitPortSpeed(dut) { + fptest.SetPortSpeed(t, port) + } + + if deviations.ExplicitInterfaceInDefaultVRF(dut) { + fptest.AssignToNetworkInstance(t, dut, port.Name(), deviations.DefaultNetworkInstance(dut), subInterfaceIndex) + } +} + +func configureDUT(t *testing.T, dut *ondatra.DUTDevice) { + for portName, portAfdrs := range dutPorts { + port := dut.Port(t, portName) + configureDUTPort(t, dut, port, portAfdrs) + verifyDUTPort(t, dut, port.Name()) + } +} + +func verifyDUTPort(t *testing.T, dut *ondatra.DUTDevice, portName string) { + switch { + case deviations.OmitL2MTU(dut): + configuredIpv6SubInterfaceMtu := gnmi.Get(t, dut, gnmi.OC().Interface(portName).Subinterface(subInterfaceIndex).Ipv6().Mtu().State()) + expectedSubInterfaceMtu := mtu + + if int(configuredIpv6SubInterfaceMtu) != expectedSubInterfaceMtu { + t.Errorf( + "dut %s configured mtu is incorrect, got: %d, want: %d", + dut.Name(), configuredIpv6SubInterfaceMtu, expectedSubInterfaceMtu, + ) + } + default: + configuredInterfaceMtu := gnmi.Get(t, dut, gnmi.OC().Interface(portName).Mtu().State()) + expectedInterfaceMtu := mtu + 14 + + if int(configuredInterfaceMtu) != expectedInterfaceMtu { + t.Errorf( + "dut %s configured mtu is incorrect, got: %d, want: %d", + dut.Name(), configuredInterfaceMtu, expectedInterfaceMtu, + ) + } + } +} + +func configureATE(t *testing.T, ate *ondatra.ATEDevice) gosnappi.Config { + otgConfig := gosnappi.NewConfig() + + for portName, portAfdrs := range atePorts { + port := ate.Port(t, portName) + dutPort := dutPorts[portName] + portAfdrs.AddToOTG(otgConfig, port, dutPort) + } + + return otgConfig +} + +func testFabricInventory(t *testing.T, dut *ondatra.DUTDevice, fabrics []string, od otgData) { + for _, fabric := range fabrics { + t.Logf("\n\n VALIDATE %s: \n\n", fabric) + description := gnmi.OC().Component(fabric).Description() + hardwareVersion := gnmi.OC().Component(fabric).HardwareVersion() + id := gnmi.OC().Component(fabric).Id() + mfgName := gnmi.OC().Component(fabric).MfgName() + name := gnmi.OC().Component(fabric).Name() + operStatus := gnmi.OC().Component(fabric).OperStatus() + parent := gnmi.OC().Component(fabric).Parent() + partNo := gnmi.OC().Component(fabric).PartNo() + serialNo := gnmi.OC().Component(fabric).SerialNo() + typeVal := gnmi.OC().Component(fabric).Type() + location := gnmi.OC().Component(fabric).Location() + lastReboofdime := gnmi.OC().Component(fabric).LastRebootTime() + powerAdminState := gnmi.OC().Component(fabric).Fabric().PowerAdminState() + + descriptionKey := strings.Join([]string{fabric, "description"}, ":") + hardwareVersionKey := strings.Join([]string{fabric, "hardware-version"}, ":") + idKey := strings.Join([]string{fabric, "id"}, ":") + mfgNameKey := strings.Join([]string{fabric, "mfg-name"}, ":") + nameKey := strings.Join([]string{fabric, "name"}, ":") + operStatusKey := strings.Join([]string{fabric, "oper-status"}, ":") + parentKey := strings.Join([]string{fabric, "parent"}, ":") + partNoKey := strings.Join([]string{fabric, "part-no"}, ":") + serialNoKey := strings.Join([]string{fabric, "serial-no"}, ":") + typeValKey := strings.Join([]string{fabric, "type"}, ":") + locationKey := strings.Join([]string{fabric, "location"}, ":") + lastReboofdimeKey := strings.Join([]string{fabric, "last-reboot-time"}, ":") + powerAdminStateConfigKey := strings.Join([]string{fabric, "config/power-admin-state"}, ":") + powerAdminStateStateKey := strings.Join([]string{fabric, "state/power-admin-state"}, ":") + + /* fabricLeafOrValuePresent: Key: fabric:leaf, Value: []any{isLeafPresent, leafValue} */ + fabricLeafOrValuePresent[descriptionKey] = []any{gnmi.Lookup(t, dut, description.State()).IsPresent()} + fabricLeafOrValuePresent[hardwareVersionKey] = []any{gnmi.Lookup(t, dut, hardwareVersion.State()).IsPresent()} + fabricLeafOrValuePresent[idKey] = []any{gnmi.Lookup(t, dut, id.State()).IsPresent()} + fabricLeafOrValuePresent[mfgNameKey] = []any{gnmi.Lookup(t, dut, mfgName.State()).IsPresent()} + fabricLeafOrValuePresent[nameKey] = []any{gnmi.Lookup(t, dut, name.State()).IsPresent()} + fabricLeafOrValuePresent[operStatusKey] = []any{gnmi.Lookup(t, dut, operStatus.State()).IsPresent()} + fabricLeafOrValuePresent[parentKey] = []any{gnmi.Lookup(t, dut, parent.State()).IsPresent()} + fabricLeafOrValuePresent[partNoKey] = []any{gnmi.Lookup(t, dut, partNo.State()).IsPresent()} + fabricLeafOrValuePresent[serialNoKey] = []any{gnmi.Lookup(t, dut, serialNo.State()).IsPresent()} + fabricLeafOrValuePresent[typeValKey] = []any{gnmi.Lookup(t, dut, typeVal.State()).IsPresent()} + fabricLeafOrValuePresent[locationKey] = []any{gnmi.Lookup(t, dut, location.State()).IsPresent()} + fabricLeafOrValuePresent[lastReboofdimeKey] = []any{gnmi.Lookup(t, dut, lastReboofdime.State()).IsPresent()} + fabricLeafOrValuePresent[powerAdminStateConfigKey] = []any{gnmi.Lookup(t, dut, powerAdminState.Config()).IsPresent()} + fabricLeafOrValuePresent[powerAdminStateStateKey] = []any{gnmi.Lookup(t, dut, powerAdminState.State()).IsPresent()} + + for leaf, value := range fabricLeafOrValuePresent { + if value[0].(bool) && strings.Contains(leaf, fabric) { + switch leaf { + case descriptionKey: + fabricLeafOrValuePresent[leaf] = append(fabricLeafOrValuePresent[leaf], gnmi.Get(t, dut, description.State())) + case hardwareVersionKey: + fabricLeafOrValuePresent[leaf] = append(fabricLeafOrValuePresent[leaf], gnmi.Get(t, dut, hardwareVersion.State())) + case idKey: + fabricLeafOrValuePresent[leaf] = append(fabricLeafOrValuePresent[leaf], gnmi.Get(t, dut, id.State())) + case mfgNameKey: + fabricLeafOrValuePresent[leaf] = append(fabricLeafOrValuePresent[leaf], gnmi.Get(t, dut, mfgName.State())) + case nameKey: + fabricLeafOrValuePresent[leaf] = append(fabricLeafOrValuePresent[leaf], gnmi.Get(t, dut, name.State())) + case operStatusKey: + fabricLeafOrValuePresent[leaf] = append(fabricLeafOrValuePresent[leaf], gnmi.Get(t, dut, operStatus.State())) + case parentKey: + fabricLeafOrValuePresent[leaf] = append(fabricLeafOrValuePresent[leaf], gnmi.Get(t, dut, parent.State())) + case partNoKey: + fabricLeafOrValuePresent[leaf] = append(fabricLeafOrValuePresent[leaf], gnmi.Get(t, dut, partNo.State())) + case serialNoKey: + fabricLeafOrValuePresent[leaf] = append(fabricLeafOrValuePresent[leaf], gnmi.Get(t, dut, serialNo.State())) + case typeValKey: + fabricLeafOrValuePresent[leaf] = append(fabricLeafOrValuePresent[leaf], gnmi.Get(t, dut, typeVal.State())) + case locationKey: + fabricLeafOrValuePresent[leaf] = append(fabricLeafOrValuePresent[leaf], gnmi.Get(t, dut, location.State())) + case lastReboofdimeKey: + fabricLeafOrValuePresent[leaf] = append(fabricLeafOrValuePresent[leaf], gnmi.Get(t, dut, lastReboofdime.State())) + case powerAdminStateConfigKey: + fabricLeafOrValuePresent[leaf] = append(fabricLeafOrValuePresent[leaf], gnmi.Get(t, dut, powerAdminState.Config())) + case powerAdminStateStateKey: + fabricLeafOrValuePresent[leaf] = append(fabricLeafOrValuePresent[leaf], gnmi.Get(t, dut, powerAdminState.State())) + } + + // Check if the leaf value is present or not. nil, '', 0 or empty slice is considered as not present. + if fabricLeafOrValuePresent[leaf][1] == nil || reflect.ValueOf(fabricLeafOrValuePresent[leaf][1]).IsZero() || (reflect.ValueOf(fabricLeafOrValuePresent[leaf][1]).Kind() == reflect.Slice && reflect.ValueOf(fabricLeafOrValuePresent[leaf][1]).Len() == 0) { + fabricLeafOrValueNotPresent[leaf] = fmt.Sprintf("value: '%v' is not as expected", fabricLeafOrValuePresent[leaf][1]) + } else { + t.Logf("PASSED: leaf: '%v' value: '%v' is as expected", leaf, fabricLeafOrValuePresent[leaf][1]) + } + } else if !value[0].(bool) && strings.Contains(leaf, fabric) { + fabricLeafOrValueNotPresent[leaf] = "is not present" + } + } + } + + t.Logf("\n\n") + for leaf, value := range fabricLeafOrValueNotPresent { + t.Errorf("[FAILED]: leaf: '%v' %v", leaf, value) + } +} + +func testFabricLastRebootTime(t *testing.T, dut *ondatra.DUTDevice, fabrics []string, od otgData) { + // Create a new random source with a specific seed + source := rand.NewSource(time.Now().UnixNano()) + random := rand.New(source) + + // Generate a random index within the range of the slice + randomIndex := random.Intn(len(fabrics)) + + // Access the fabric at the random index + fabric := fabrics[randomIndex] + + t.Logf("\n\n VALIDATE %s: \n\n", fabric) + lastReboofdime := gnmi.OC().Component(fabric).LastRebootTime() + lastReboofdimeBefore := gnmi.Get(t, dut, lastReboofdime.State()) + + gnmi.Replace(t, dut, gnmi.OC().Component(fabric).Fabric().PowerAdminState().Config(), oc.Platform_ComponentPowerType_POWER_DISABLED) + gnmi.Await(t, dut, gnmi.OC().Component(fabric).Fabric().PowerAdminState().State(), time.Minute, oc.Platform_ComponentPowerType_POWER_DISABLED) + + t.Logf("Waiting for 90s after power disable...") + time.Sleep(90 * time.Second) + + gnmi.Replace(t, dut, gnmi.OC().Component(fabric).Fabric().PowerAdminState().Config(), oc.Platform_ComponentPowerType_POWER_ENABLED) + + if deviations.MissingValueForDefaults(dut) { + time.Sleep(time.Minute) + } else { + if power, ok := gnmi.Await(t, dut, gnmi.OC().Component(fabric).Fabric().PowerAdminState().State(), time.Minute, oc.Platform_ComponentPowerType_POWER_ENABLED).Val(); !ok { + t.Errorf("Component %s, power-admin-state got: %v, want: %v", fabric, power, oc.Platform_ComponentPowerType_POWER_ENABLED) + } + } + if oper, ok := gnmi.Await(t, dut, gnmi.OC().Component(fabric).OperStatus().State(), 2*time.Minute, oc.PlatformTypes_COMPONENT_OPER_STATUS_ACTIVE).Val(); !ok { + t.Errorf("Component %s oper-status after POWER_ENABLED, got: %v, want: %v", fabric, oper, oc.PlatformTypes_COMPONENT_OPER_STATUS_ACTIVE) + } + + t.Logf("Waiting for 90s after power enable...") + time.Sleep(90 * time.Second) + + lastReboofdimeAfter := gnmi.Get(t, dut, lastReboofdime.State()) + + if lastReboofdimeBefore > lastReboofdimeAfter { + t.Errorf("Component %s, last-reboot-time before power disable is same as after power enable", fabric) + } +} + +func testFabricRedundancy(t *testing.T, dut *ondatra.DUTDevice, fabrics []string, od otgData) { + t.Logf("Name: %s, Description: %s", fd.name, fd.desc) + + flowParams := createFlow(fd.name, fd.flowSize, od.flowProto) + od.otgConfig.Flows().Clear() + od.otgConfig.Flows().Append(flowParams) + od.otg.PushConfig(t, od.otgConfig) + time.Sleep(time.Second * 30) + + disabledFabric := "" + // Create a new random source with a specific seed + source := rand.NewSource(time.Now().UnixNano()) + random := rand.New(source) + + // Generate a random index within the range of the slice + randomIndex := random.Intn(len(fabrics)) + + // Access the fabric at the random index + disabledFabric = fabrics[randomIndex] + + gnmi.Replace(t, dut, gnmi.OC().Component(disabledFabric).Fabric().PowerAdminState().Config(), oc.Platform_ComponentPowerType_POWER_DISABLED) + gnmi.Await(t, dut, gnmi.OC().Component(disabledFabric).Fabric().PowerAdminState().State(), time.Minute, oc.Platform_ComponentPowerType_POWER_DISABLED) + + t.Logf("Waiting for 90s after power disable...") + time.Sleep(90 * time.Second) + + od.otg.StartProtocols(t) + od.waitInterface(t) + + sleepTime := time.Duration(packetsToSend/uint32(ppsRate)) + 5 + od.otg.StartTraffic(t) + time.Sleep(sleepTime * time.Second) + + od.otg.StopTraffic(t) + time.Sleep(trafficStopWaitDuration) + + otgutils.LogFlowMetrics(t, od.otg, od.otgConfig) + + flow := gnmi.OTG().Flow(fd.name) + flowCounters := flow.Counters() + + outPkts := gnmi.Get(t, od.otg, flowCounters.OutPkts().State()) + inPkts := gnmi.Get(t, od.otg, flowCounters.InPkts().State()) + inOctets := gnmi.Get(t, od.otg, flowCounters.InOctets().State()) + + if outPkts == 0 || inPkts == 0 { + t.Error("flow did not send or receive any packets, this should not happen") + } + + lossPercent := (float32(outPkts-inPkts) / float32(outPkts)) * 100 + + if lossPercent > acceptableLossPercent { + t.Errorf( + "flow sent '%d' packets and received '%d' packets, resulting in a "+ + "loss percent of '%.2f'. max acceptable loss percent is '%.2f'", + outPkts, inPkts, lossPercent, acceptableLossPercent, + ) + } + + avgPacketSize := uint32(inOctets / inPkts) + packetSizeDelta := float32(avgPacketSize-fd.flowSize) / (float32(avgPacketSize+fd.flowSize) / 2) * 100 + + if packetSizeDelta > acceptablePacketSizeDelta { + t.Errorf( + "flow sent '%d' packets and received '%d' packets, resulting in "+ + "averagepacket size of '%d' and a packet size delta of '%.2f' percent. "+ + "packet size delta should not exceed '%.2f'", + outPkts, inPkts, avgPacketSize, packetSizeDelta, acceptablePacketSizeDelta, + ) + } + + gnmi.Replace(t, dut, gnmi.OC().Component(disabledFabric).Fabric().PowerAdminState().Config(), oc.Platform_ComponentPowerType_POWER_ENABLED) + if deviations.MissingValueForDefaults(dut) { + time.Sleep(time.Minute) + } else { + if power, ok := gnmi.Await(t, dut, gnmi.OC().Component(disabledFabric).Fabric().PowerAdminState().State(), time.Minute, oc.Platform_ComponentPowerType_POWER_ENABLED).Val(); !ok { + t.Errorf("Component %s, power-admin-state got: %v, want: %v", disabledFabric, power, oc.Platform_ComponentPowerType_POWER_ENABLED) + } + } + if oper, ok := gnmi.Await(t, dut, gnmi.OC().Component(disabledFabric).OperStatus().State(), 2*time.Minute, oc.PlatformTypes_COMPONENT_OPER_STATUS_ACTIVE).Val(); !ok { + t.Errorf("Component %s oper-status after POWER_ENABLED, got: %v, want: %v", disabledFabric, oper, oc.PlatformTypes_COMPONENT_OPER_STATUS_ACTIVE) + } + + t.Logf("Waiting for 90s after power enable...") + time.Sleep(90 * time.Second) + +} + +func TestFabricRedundancy(t *testing.T) { + dut := ondatra.DUT(t, "dut") + + // Get fabric list that are inserted in the DUT. + fabrics := components.FindComponentsByType(t, dut, fabricType) + t.Logf("Found fabric list: %v", fabrics) + index := 0 + for _, fabric := range fabrics { + empty, ok := gnmi.Lookup(t, dut, gnmi.OC().Component(fabric).Empty().State()).Val() + if !(ok && empty) { + fabrics[index] = fabric + index++ + } else { + t.Logf("Fabric Component %s is empty, hence skipping", fabric) + } + } + fabrics = fabrics[:index] + t.Logf("Found non-empty fabric list: %v", fabrics) + + // Validate that there are at least 2 non-empty fabrics in the DUT. + if len(fabrics) < 2 { + t.Fatalf("No of Fabrics on DUT (%q): got %v, want => 2", dut.Model(), len(fabrics)) + } + + /* configure the ATE device to send/receive 16 millions of packets + at 100kpps rate and using 4000B packets (with 10E-6 tolerance). */ + ate := ondatra.ATE(t, "ate") + otg := ate.OTG() + configureDUT(t, dut) + otgConfig := configureATE(t, ate) + od := otgData{ + flowProto: ipv6, + otg: otg, + otgConfig: otgConfig, + } + + // Cleanup the DUT config. + t.Cleanup(func() { + deleteBatch := &gnmi.SetBatch{} + if deviations.ExplicitInterfaceInDefaultVRF(dut) { + netInst := &oc.NetworkInstance{Name: ygot.String(deviations.DefaultNetworkInstance(dut))} + + for portName := range dutPorts { + gnmi.BatchDelete( + deleteBatch, + gnmi.OC(). + NetworkInstance(*netInst.Name). + Interface(fmt.Sprintf("%s.%d", dut.Port(t, portName).Name(), subInterfaceIndex)). + Config(), + ) + } + } + + for portName := range dutPorts { + gnmi.BatchDelete( + deleteBatch, + gnmi.OC(). + Interface(dut.Port(t, portName).Name()). + Subinterface(subInterfaceIndex). + Config(), + ) + gnmi.BatchDelete(deleteBatch, gnmi.OC().Interface(dut.Port(t, portName).Name()).Mtu().Config()) + } + deleteBatch.Set(t, dut) + }) + + // Test cases. + type testCase struct { + name string + fabrics []string + testFunc func(t *testing.T, dut *ondatra.DUTDevice, fabrics []string, od otgData) + } + + testCases := []testCase{ + { + name: "TEST 1: Fabric inventory", + fabrics: fabrics, + testFunc: testFabricInventory, + }, + { + name: "TEST 2: Fabric redundancy", + fabrics: fabrics, + testFunc: testFabricRedundancy, + }, + { + name: "TEST 3: Fabric last reboot time", + fabrics: fabrics, + testFunc: testFabricLastRebootTime, + }, + } + + // Run the test cases. + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + t.Logf("Description: %s", tc.name) + tc.testFunc(t, dut, tc.fabrics, od) + }) + } +} diff --git a/feature/platform/fabric/otg_tests/fabric_redundancy_test/metadata.textproto b/feature/platform/fabric/otg_tests/fabric_redundancy_test/metadata.textproto index 6bda502dc25..4281f41ad3d 100644 --- a/feature/platform/fabric/otg_tests/fabric_redundancy_test/metadata.textproto +++ b/feature/platform/fabric/otg_tests/fabric_redundancy_test/metadata.textproto @@ -3,5 +3,24 @@ uuid: "261d317f-9bcc-43f9-a412-295ae6c008cf" plan_id: "gNMI-1.16" -description: "fabric redundancy test" +description: "Fabric redundnacy test" testbed: TESTBED_DUT_ATE_2LINKS +platform_exceptions: { + platform: { + vendor: NOKIA + } + deviations: { + explicit_port_speed: true + explicit_interface_in_default_vrf: true + missing_value_for_defaults: true + } +} +platform_exceptions: { + platform: { + vendor: ARISTA + } + deviations: { + missing_value_for_defaults: true + default_network_instance: "default" + } +} diff --git a/feature/platform/integrated_circuit/otg_tests/utilization_test/metadata.textproto b/feature/platform/integrated_circuit/otg_tests/utilization_test/metadata.textproto index 45d28a4dcdf..176b048af2b 100644 --- a/feature/platform/integrated_circuit/otg_tests/utilization_test/metadata.textproto +++ b/feature/platform/integrated_circuit/otg_tests/utilization_test/metadata.textproto @@ -10,7 +10,6 @@ platform_exceptions: { vendor: ARISTA } deviations: { - route_policy_under_afi_unsupported: true interface_enabled: true default_network_instance: "default" mismatched_hardware_resource_name_in_component: true diff --git a/feature/platform/transceiver/chromatic_dispersion/tests/zrp_cd_test/README.md b/feature/platform/transceiver/chromatic_dispersion/tests/zrp_cd_test/README.md index 38d2a7baa9c..34a200dd80c 100644 --- a/feature/platform/transceiver/chromatic_dispersion/tests/zrp_cd_test/README.md +++ b/feature/platform/transceiver/chromatic_dispersion/tests/zrp_cd_test/README.md @@ -1,4 +1,4 @@ -# TRANSCEIVER-1: Telemetry: 400ZR_PLUS Chromatic Dispersion(CD) telemetry values streaming +# TRANSCEIVER-1 (400ZR_PLUS): Telemetry: 400ZR_PLUS Chromatic Dispersion(CD) telemetry values streaming ## Summary diff --git a/feature/platform/transceiver/chromatic_dispersion/tests/zrp_cd_test/metadata.textproto b/feature/platform/transceiver/chromatic_dispersion/tests/zrp_cd_test/metadata.textproto new file mode 100644 index 00000000000..cca50bb884c --- /dev/null +++ b/feature/platform/transceiver/chromatic_dispersion/tests/zrp_cd_test/metadata.textproto @@ -0,0 +1,15 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata +uuid: "6ee614f9-efa6-4d1c-bdea-b15332feedc7" +plan_id: "TRANSCEIVER-1 (400ZR_PLUS)" +description: "Telemetry: 400ZR_PLUS Chromatic Dispersion(CD) telemetry values streaming" +testbed: TESTBED_DUT_400ZR_PLUS +platform_exceptions: { + platform: { + vendor: ARISTA + } + deviations: { + default_network_instance: "default" + missing_port_to_optical_channel_component_mapping: true + } +} diff --git a/feature/platform/transceiver/chromatic_dispersion/tests/zrp_cd_test/zrp_cd_test.go b/feature/platform/transceiver/chromatic_dispersion/tests/zrp_cd_test/zrp_cd_test.go new file mode 100644 index 00000000000..e093b1675ab --- /dev/null +++ b/feature/platform/transceiver/chromatic_dispersion/tests/zrp_cd_test/zrp_cd_test.go @@ -0,0 +1,172 @@ +package zrp_cd_test + +import ( + "flag" + "reflect" + "testing" + "time" + + "github.com/openconfig/featureprofiles/internal/cfgplugins" + "github.com/openconfig/featureprofiles/internal/components" + "github.com/openconfig/featureprofiles/internal/fptest" + "github.com/openconfig/featureprofiles/internal/samplestream" + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" + "github.com/openconfig/ondatra/gnmi/oc" +) + +const ( + samplingInterval = 10 * time.Second + minCDValue = -200 + maxCDValue = 2400 + inActiveCDValue = 0.0 + timeout = 10 * time.Minute + flapInterval = 30 * time.Second +) + +var ( + frequencies = []uint64{191400000, 196100000} + targetOutputPowers = []float64{-7, 0} + operationalModeFlag = flag.Int("operational_mode", 5, "vendor-specific operational-mode for the channel") + operationalMode uint16 +) + +func TestMain(m *testing.M) { + fptest.RunTests(m) +} + +func verifyCDValue(t *testing.T, dut1 *ondatra.DUTDevice, pStream *samplestream.SampleStream[float64], sensorName string, operStatus oc.E_Interface_OperStatus) float64 { + cdSampleNexts := pStream.Nexts(2) + cdSample := cdSampleNexts[1] + t.Logf("CDSampleNexts %v", cdSampleNexts) + if cdSample == nil { + t.Fatalf("CD telemetry %s was not streamed in the most recent subscription interval", sensorName) + } + cdVal, ok := cdSample.Val() + if !ok { + t.Fatalf("CD %q telemetry is not present", cdSample) + } + if reflect.TypeOf(cdVal).Kind() != reflect.Float64 { + t.Fatalf("CD value is not type float64") + } + // Check CD return value of correct type + switch operStatus { + case oc.Interface_OperStatus_DOWN: + if cdVal != inActiveCDValue { + t.Fatalf("The inactive CD is %v, expected %v", cdVal, inActiveCDValue) + } + case oc.Interface_OperStatus_UP: + if cdVal < minCDValue || cdVal > maxCDValue { + t.Fatalf("The variable CD is %v, expected range (%v, %v)", cdVal, minCDValue, maxCDValue) + } + default: + t.Fatalf("Invalid status %v", operStatus) + } + // Get current time + now := time.Now() + // Format the time string + formattedTime := now.Format("2006-01-02 15:04:05") + t.Logf("%s Device %v CD %s value at status %v: %v", formattedTime, dut1.Name(), sensorName, operStatus, cdVal) + + return cdVal +} + +// TODO: Avg and Instant value checks are not available. Need to align their sample streaming windows. +func verifyAllCDValues(t *testing.T, dut1 *ondatra.DUTDevice, p1StreamInstant, p1StreamMax, p1StreamMin, p1StreamAvg *samplestream.SampleStream[float64], operStatus oc.E_Interface_OperStatus) { + tests := []struct { + desc string + stream *samplestream.SampleStream[float64] + streamType string + operStatus oc.E_Interface_OperStatus + }{ + { + desc: "Instant", + stream: p1StreamInstant, + operStatus: operStatus, + }, + { + desc: "Max", + stream: p1StreamMax, + operStatus: operStatus, + }, + { + desc: "Min", + stream: p1StreamMin, + operStatus: operStatus, + }, + { + desc: "Avg", + stream: p1StreamAvg, + operStatus: operStatus, + }, + } + + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + verifyCDValue(t, dut1, tt.stream, tt.desc, tt.operStatus) + }) + } +} + +func TestCDValue(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) + + dp1 := dut.Port(t, "port1") + dp2 := dut.Port(t, "port2") + + och1 := components.OpticalChannelComponentFromPort(t, dut, dp1) + och2 := components.OpticalChannelComponentFromPort(t, dut, dp2) + + component1 := gnmi.OC().Component(och1) + for _, frequency := range frequencies { + for _, targetOutputPower := range targetOutputPowers { + cfgplugins.ConfigOpticalChannel(t, dut, och1, frequency, targetOutputPower, operationalMode) + cfgplugins.ConfigOpticalChannel(t, dut, och2, frequency, targetOutputPower, operationalMode) + + // Wait for channels to be up. + gnmi.Await(t, dut, gnmi.OC().Interface(dp1.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_UP) + gnmi.Await(t, dut, gnmi.OC().Interface(dp2.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_UP) + + p1StreamInstant := samplestream.New(t, dut, component1.OpticalChannel().ChromaticDispersion().Instant().State(), samplingInterval) + p1StreamMin := samplestream.New(t, dut, component1.OpticalChannel().ChromaticDispersion().Min().State(), samplingInterval) + p1StreamMax := samplestream.New(t, dut, component1.OpticalChannel().ChromaticDispersion().Max().State(), samplingInterval) + p1StreamAvg := samplestream.New(t, dut, component1.OpticalChannel().ChromaticDispersion().Avg().State(), samplingInterval) + + defer p1StreamInstant.Close() + defer p1StreamMin.Close() + defer p1StreamMax.Close() + defer p1StreamAvg.Close() + + verifyAllCDValues(t, dut, p1StreamInstant, p1StreamMax, p1StreamMin, p1StreamAvg, oc.Interface_OperStatus_UP) + + // Disable interface. + for _, p := range dut.Ports() { + cfgplugins.ToggleInterface(t, dut, p.Name(), false) + } + // Wait for channels to be down. + gnmi.Await(t, dut, gnmi.OC().Interface(dp1.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_DOWN) + gnmi.Await(t, dut, gnmi.OC().Interface(dp2.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_DOWN) + t.Logf("Interfaces are down: %v, %v", dp1.Name(), dp2.Name()) + verifyAllCDValues(t, dut, p1StreamInstant, p1StreamMax, p1StreamMin, p1StreamAvg, oc.Interface_OperStatus_DOWN) + + time.Sleep(flapInterval) + + // Enable interface. + for _, p := range dut.Ports() { + cfgplugins.ToggleInterface(t, dut, p.Name(), true) + } + // Wait for channels to be up. + gnmi.Await(t, dut, gnmi.OC().Interface(dp1.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_UP) + gnmi.Await(t, dut, gnmi.OC().Interface(dp2.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_UP) + t.Logf("Interfaces are up: %v, %v", dp1.Name(), dp2.Name()) + verifyAllCDValues(t, dut, p1StreamInstant, p1StreamMax, p1StreamMin, p1StreamAvg, oc.Interface_OperStatus_UP) + + } + } +} diff --git a/feature/platform/transceiver/fec_uncorrectable_frames/tests/zrp_fec_uncorrectable_frames_test/README.md b/feature/platform/transceiver/fec_uncorrectable_frames/tests/zrp_fec_uncorrectable_frames_test/README.md index 9a36062a6b1..756bc623d6b 100644 --- a/feature/platform/transceiver/fec_uncorrectable_frames/tests/zrp_fec_uncorrectable_frames_test/README.md +++ b/feature/platform/transceiver/fec_uncorrectable_frames/tests/zrp_fec_uncorrectable_frames_test/README.md @@ -1,4 +1,4 @@ -# TRANSCEIVER-10: Telemetry: 400ZR_PLUS Optics FEC(Forward Error Correction) Uncorrectable Frames Streaming. +# TRANSCEIVER-10 (400ZR_PLUS): Telemetry: 400ZR_PLUS Optics FEC(Forward Error Correction) Uncorrectable Frames Streaming. ## Summary diff --git a/feature/platform/transceiver/fec_uncorrectable_frames/tests/zrp_fec_uncorrectable_frames_test/metadata.textproto b/feature/platform/transceiver/fec_uncorrectable_frames/tests/zrp_fec_uncorrectable_frames_test/metadata.textproto new file mode 100644 index 00000000000..4d15d622908 --- /dev/null +++ b/feature/platform/transceiver/fec_uncorrectable_frames/tests/zrp_fec_uncorrectable_frames_test/metadata.textproto @@ -0,0 +1,28 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata + +uuid: "387c1f76-7811-4a04-99e3-f690fba1e98e" +plan_id: "TRANSCEIVER-10 (400ZR_PLUS)" +description: "Telemetry: 400ZR_PLUS Optics FEC(Forward Error Correction) Uncorrectable Frames Streaming." +testbed: TESTBED_DUT_400ZR_PLUS +platform_exceptions: { + platform: { + vendor: ARISTA + } + deviations: { + interface_enabled: true + default_network_instance: "default" + missing_port_to_optical_channel_component_mapping: true + channel_assignment_rate_class_parameters_unsupported: true + } +} +platform_exceptions: { + platform: { + vendor: CISCO + } + deviations: { + otn_channel_trib_unsupported: true + eth_channel_ingress_parameters_unsupported: true + eth_channel_assignment_cisco_numbering: true + } +} diff --git a/feature/platform/transceiver/fec_uncorrectable_frames/tests/zrp_fec_uncorrectable_frames_test/zrp_fec_uncorrectable_frames_test.go b/feature/platform/transceiver/fec_uncorrectable_frames/tests/zrp_fec_uncorrectable_frames_test/zrp_fec_uncorrectable_frames_test.go new file mode 100644 index 00000000000..829376d5560 --- /dev/null +++ b/feature/platform/transceiver/fec_uncorrectable_frames/tests/zrp_fec_uncorrectable_frames_test/zrp_fec_uncorrectable_frames_test.go @@ -0,0 +1,116 @@ +// 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 zrp_fec_uncorrectable_frames_test + +import ( + "flag" + "fmt" + "reflect" + "testing" + "time" + + "github.com/openconfig/featureprofiles/internal/cfgplugins" + "github.com/openconfig/featureprofiles/internal/components" + "github.com/openconfig/featureprofiles/internal/fptest" + "github.com/openconfig/featureprofiles/internal/samplestream" + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" + "github.com/openconfig/ondatra/gnmi/oc" +) + +const ( + sampleInterval = 10 * time.Second + intUpdateTime = 5 * time.Minute + otnIndexBase = uint32(4000) + ethIndexBase = uint32(40000) + targetOutputPower = -3 + frequency = 193100000 +) + +var ( + operationalModeFlag = flag.Int("operational_mode", 5, "vendor-specific operational-mode for the channel") + operationalMode uint16 +) + +func TestMain(m *testing.M) { + fptest.RunTests(m) +} + +func validateFecUncorrectableBlocks(t *testing.T, stream *samplestream.SampleStream[uint64]) { + fecStream := stream.Next() + if fecStream == nil { + t.Fatalf("Fec Uncorrectable Blocks was not streamed in the most recent subscription interval") + } + fec, ok := fecStream.Val() + if !ok { + t.Fatalf("Error capturing streaming Fec value") + } + if reflect.TypeOf(fec).Kind() != reflect.Uint64 { + t.Fatalf("fec value is not type uint64") + } + if fec != 0 { + t.Fatalf("Got FecUncorrectableBlocks got %d, want 0", fec) + } +} + +func TestZrUncorrectableFrames(t *testing.T) { + if operationalModeFlag != nil { + operationalMode = uint16(*operationalModeFlag) + } else { + t.Fatalf("Please specify the vendor-specific operational-mode flag") + } + dut := ondatra.DUT(t, "dut") + + var ( + // trs = make(map[string]string) + // ochs = make(map[string]string) + otnIndexes = make(map[string]uint32) + ethIndexes = make(map[string]uint32) + ) + + ports := []string{"port1", "port2"} + + for i, port := range ports { + p := dut.Port(t, port) + och := components.OpticalChannelComponentFromPort(t, dut, p) + otnIndexes[p.Name()] = otnIndexBase + uint32(i) + ethIndexes[p.Name()] = ethIndexBase + uint32(i) + cfgplugins.ConfigOpticalChannel(t, dut, och, frequency, targetOutputPower, operationalMode) + cfgplugins.ConfigOTNChannel(t, dut, och, otnIndexes[p.Name()], ethIndexes[p.Name()]) + cfgplugins.ConfigETHChannel(t, dut, p.Name(), och, otnIndexes[p.Name()], ethIndexes[p.Name()]) + } + + for _, port := range ports { + t.Run(fmt.Sprintf("Port:%s", port), func(t *testing.T) { + p := dut.Port(t, port) + gnmi.Await(t, dut, gnmi.OC().Interface(p.Name()).OperStatus().State(), intUpdateTime, oc.Interface_OperStatus_UP) + streamFecOtn := samplestream.New(t, dut, gnmi.OC().TerminalDevice().Channel(otnIndexes[p.Name()]).Otn().FecUncorrectableBlocks().State(), sampleInterval) + defer streamFecOtn.Close() + validateFecUncorrectableBlocks(t, streamFecOtn) + + // Disable interface + cfgplugins.ToggleInterface(t, dut, p.Name(), false) + // Wait for the cooling-off period + gnmi.Await(t, dut, gnmi.OC().Interface(p.Name()).OperStatus().State(), intUpdateTime, oc.Interface_OperStatus_DOWN) + + // Enable interface + cfgplugins.ToggleInterface(t, dut, p.Name(), true) + // Wait for the cooling-off period + gnmi.Await(t, dut, gnmi.OC().Interface(p.Name()).OperStatus().State(), intUpdateTime, oc.Interface_OperStatus_UP) + + validateFecUncorrectableBlocks(t, streamFecOtn) + }) + } +} diff --git a/feature/platform/transceiver/logical_channels/tests/zrp_logical_channels_test/README.md b/feature/platform/transceiver/logical_channels/tests/zrp_logical_channels_test/README.md index d79558ddcb4..19b7daed9b7 100644 --- a/feature/platform/transceiver/logical_channels/tests/zrp_logical_channels_test/README.md +++ b/feature/platform/transceiver/logical_channels/tests/zrp_logical_channels_test/README.md @@ -1,4 +1,4 @@ -# TRANSCEIVER-11: Telemetry: 400ZR_PLUS Optics logical channels provisioning and related telemetry. +# TRANSCEIVER-11 (400ZR_PLUS): Telemetry: 400ZR_PLUS Optics logical channels provisioning and related telemetry. ## Summary diff --git a/feature/platform/transceiver/logical_channels/tests/zrp_logical_channels_test/metadata.textproto b/feature/platform/transceiver/logical_channels/tests/zrp_logical_channels_test/metadata.textproto new file mode 100644 index 00000000000..ce84a00ccfc --- /dev/null +++ b/feature/platform/transceiver/logical_channels/tests/zrp_logical_channels_test/metadata.textproto @@ -0,0 +1,28 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata +uuid: "e5b469c9-f765-4f95-b3dc-af4c926309f5" +plan_id: "TRANSCEIVER-11 (400ZR_PLUS)" +description: "Telemetry: 400ZR_PLUS Optics logical channels provisioning and related telemetry." +testbed: TESTBED_DUT_400ZR_PLUS +platform_exceptions: { + platform: { + vendor: ARISTA + } + deviations: { + interface_enabled: true + default_network_instance: "default" + missing_port_to_optical_channel_component_mapping: true + channel_assignment_rate_class_parameters_unsupported: 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 + } +} diff --git a/feature/platform/transceiver/logical_channels/tests/zrp_logical_channels_test/zrp_logical_channels_test.go b/feature/platform/transceiver/logical_channels/tests/zrp_logical_channels_test/zrp_logical_channels_test.go new file mode 100644 index 00000000000..d0253fa0c24 --- /dev/null +++ b/feature/platform/transceiver/logical_channels/tests/zrp_logical_channels_test/zrp_logical_channels_test.go @@ -0,0 +1,280 @@ +package zrp_logical_channels_test + +import ( + "flag" + "strings" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "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" + "github.com/openconfig/ondatra/gnmi" + "github.com/openconfig/ondatra/gnmi/oc" +) + +const ( + targetOutputPower = -3 + frequency = 193100000 + samplingInterval = 10 * time.Second + timeout = 10 * time.Minute + otnIndex1 = uint32(4001) + otnIndex2 = uint32(4002) + ethernetIndex1 = uint32(40001) + ethernetIndex2 = uint32(40002) +) + +var ( + dutPort1 = attrs.Attributes{ + Desc: "dutPort1", + IPv4: "192.0.2.1", + IPv4Len: 30, + } + dutPort2 = attrs.Attributes{ + Desc: "dutPort2", + IPv4: "192.0.2.5", + IPv4Len: 30, + } + operationalModeFlag = flag.Int("operational_mode", 5, "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") + + fptest.ConfigureDefaultNetworkInstance(t, dut) + + 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)) + + oc1 := components.OpticalChannelComponentFromPort(t, dut, p1) + oc2 := components.OpticalChannelComponentFromPort(t, dut, p2) + 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, operationalMode) + cfgplugins.ConfigOTNChannel(t, dut, oc1, otnIndex1, ethernetIndex1) + cfgplugins.ConfigETHChannel(t, dut, p1.Name(), tr1, otnIndex1, ethernetIndex1) + cfgplugins.ConfigOpticalChannel(t, dut, oc2, frequency, targetOutputPower, operationalMode) + cfgplugins.ConfigOTNChannel(t, dut, oc2, otnIndex2, ethernetIndex2) + cfgplugins.ConfigETHChannel(t, dut, p2.Name(), tr2, otnIndex2, ethernetIndex2) + + ethChan1 := samplestream.New(t, dut, gnmi.OC().TerminalDevice().Channel(ethernetIndex1).State(), samplingInterval) + defer ethChan1.Close() + ethChan2 := samplestream.New(t, dut, gnmi.OC().TerminalDevice().Channel(ethernetIndex2).State(), samplingInterval) + defer ethChan2.Close() + otnChan1 := samplestream.New(t, dut, gnmi.OC().TerminalDevice().Channel(otnIndex1).State(), samplingInterval) + defer otnChan1.Close() + otnChan2 := samplestream.New(t, dut, gnmi.OC().TerminalDevice().Channel(otnIndex2).State(), samplingInterval) + defer otnChan2.Close() + + 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, 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, 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") + } + ec, ok := val.Val() + if !ok { + t.Fatalf("Ethernet Channel telemetry stream empty in last 10 seconds") + } + tcs := []testcase{ + { + desc: "Index", + got: ec.GetIndex(), + want: ethernetChIdx, + }, + { + desc: "Description", + got: ec.GetDescription(), + want: "ETH Logical Channel", + }, + { + desc: "Logical Channel Type", + got: ec.GetLogicalChannelType().String(), + want: oc.TransportTypes_LOGICAL_ELEMENT_PROTOCOL_TYPE_PROT_ETHERNET.String(), + }, + { + desc: "Trib Protocol", + got: ec.GetTribProtocol().String(), + want: oc.TransportTypes_TRIBUTARY_PROTOCOL_TYPE_PROT_400GE.String(), + }, + } + var assignmentIndexTestcases []testcase + + index := 0 + if deviations.EthChannelAssignmentCiscoNumbering(dut) { + index = 1 + } + + assignment := ec.GetAssignment(uint32(index)) + assignmentIndexTestcases = []testcase{ + { + desc: "Assignment: Index", + got: assignment.GetIndex(), + want: uint32(index), + }, + { + desc: "Assignment: Logical Channel", + got: assignment.GetLogicalChannel(), + want: otnChIdx, + }, + { + desc: "Assignment: Description", + got: assignment.GetDescription(), + want: "ETH to OTN", + }, + { + desc: "Assignment: Allocation", + got: assignment.GetAllocation(), + want: float64(400), + }, + { + desc: "Assignment: Type", + got: assignment.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 != "" { + t.Errorf("Ethernet Logical Channel: %s, diff (-got +want):\n%s", tc.desc, diff) + } + }) + } +} + +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") + } + cc, ok := val.Val() + if !ok { + t.Fatalf("OTN Channel telemetry stream empty in last 10 seconds") + } + tcs := []testcase{ + { + desc: "Description", + got: cc.GetDescription(), + want: "OTN Logical Channel", + }, + { + desc: "Index", + got: cc.GetIndex(), + want: otnChIdx, + }, + { + desc: "Logical Channel Type", + got: cc.GetLogicalChannelType().String(), + want: oc.TransportTypes_LOGICAL_ELEMENT_PROTOCOL_TYPE_PROT_OTN.String(), + }, + } + var opticalChannelAssignmentIndexTestcases []testcase + + index := 0 + if deviations.OTNChannelAssignmentCiscoNumbering(dut) { + opticalChannel = strings.ReplaceAll(opticalChannel, "/", "_") // Ex: ciscoOpticalChannelFormat is OpticalChannel0_0_0_18 + index = 1 + } + + assignment := cc.GetAssignment(uint32(index)) + opticalChannelAssignmentIndexTestcases = []testcase{ + { + desc: "Assignment: Index", + got: assignment.GetIndex(), + want: uint32(index), + }, + { + desc: "Optical Channel Assignment: Optical Channel", + got: assignment.GetOpticalChannel(), + want: opticalChannel, + }, + { + desc: "Optical Channel Assignment: Description", + got: assignment.GetDescription(), + want: "OTN to Optical Channel", + }, + { + desc: "Optical Channel Assignment: Allocation", + got: assignment.GetAllocation(), + want: float64(400), + }, + { + desc: "Optical Channel Assignment: Type", + got: assignment.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 { + t.Run(tc.desc, func(t *testing.T) { + if diff := cmp.Diff(tc.got, tc.want); diff != "" { + t.Errorf("OTN Logical Channel: %s, diff (-got +want):\n%s", tc.desc, diff) + } + }) + } +} diff --git a/feature/platform/transceiver/tunable_parameters/tests/zrp_tunable_parameters_test/README.md b/feature/platform/transceiver/tunable_parameters/tests/zrp_tunable_parameters_test/README.md index 567a834ff8d..3ea934270db 100644 --- a/feature/platform/transceiver/tunable_parameters/tests/zrp_tunable_parameters_test/README.md +++ b/feature/platform/transceiver/tunable_parameters/tests/zrp_tunable_parameters_test/README.md @@ -1,4 +1,4 @@ -# TRANSCEIVER-5: Configuration: 400ZR_PLUS channel frequency, output TX launch power and operational mode setting. +# TRANSCEIVER-5 (400ZR_PLUS): Configuration: 400ZR_PLUS channel frequency, output TX launch power and operational mode setting. ## Summary diff --git a/feature/platform/transceiver/tunable_parameters/tests/zrp_tunable_parameters_test/metadata.textproto b/feature/platform/transceiver/tunable_parameters/tests/zrp_tunable_parameters_test/metadata.textproto new file mode 100644 index 00000000000..547fb7e066a --- /dev/null +++ b/feature/platform/transceiver/tunable_parameters/tests/zrp_tunable_parameters_test/metadata.textproto @@ -0,0 +1,24 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata +uuid: "0ff18ddb-5333-4fc3-a2fb-5ac6d372a88f" +plan_id: "TRANSCEIVER-5 (400ZR_PLUS)" +description: "Configuration: 400ZR_PLUS channel frequency, output TX launch power and operational mode setting." +testbed: TESTBED_DUT_400ZR_PLUS +platform_exceptions: { + platform: { + vendor: ARISTA + } + deviations: { + interface_enabled: true + default_network_instance: "default" + missing_zr_optical_channel_tunable_parameters_telemetry: true + } +} +platform_exceptions: { + platform: { + vendor: JUNIPER + } + deviations: { + operational_mode_unsupported: true + } +} diff --git a/feature/platform/transceiver/tunable_parameters/tests/zrp_tunable_parameters_test/zrp_tunable_parameters_test.go b/feature/platform/transceiver/tunable_parameters/tests/zrp_tunable_parameters_test/zrp_tunable_parameters_test.go new file mode 100644 index 00000000000..6c2ca0872f6 --- /dev/null +++ b/feature/platform/transceiver/tunable_parameters/tests/zrp_tunable_parameters_test/zrp_tunable_parameters_test.go @@ -0,0 +1,305 @@ +package zrp_tunable_parameters_test + +import ( + "flag" + "fmt" + "math" + "reflect" + "testing" + "time" + + "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" + "github.com/openconfig/ondatra/gnmi" + "github.com/openconfig/ondatra/gnmi/oc" +) + +const ( + samplingInterval = 10 * time.Second + frequencyTolerance = 1800 + timeout = 10 * time.Minute +) + +var ( + dutPort1 = attrs.Attributes{ + Desc: "dutPort1", + IPv4: "192.0.2.1", + IPv4Len: 30, + } + dutPort2 = attrs.Attributes{ + Desc: "dutPort2", + IPv4: "192.0.2.5", + IPv4Len: 30, + } + operationalModeFlag = flag.Int("operational_mode", 5, "vendor-specific operational-mode for the channel") + operationalMode uint16 +) + +func TestMain(m *testing.M) { + fptest.RunTests(m) +} + +func Test400ZRPlusTunableFrequency(t *testing.T) { + if operationalModeFlag != nil { + operationalMode = uint16(*operationalModeFlag) + } else { + t.Fatalf("Please specify the vendor-specific operational-mode flag") + } + dut := ondatra.DUT(t, "dut") + p1 := dut.Port(t, "port1") + p2 := dut.Port(t, "port2") + fptest.ConfigureDefaultNetworkInstance(t, dut) + 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)) + oc1 := components.OpticalChannelComponentFromPort(t, dut, p1) + oc2 := components.OpticalChannelComponentFromPort(t, dut, p2) + streamOC1 := samplestream.New(t, dut, gnmi.OC().Component(oc1).State(), samplingInterval) + defer streamOC1.Close() + streamOC2 := samplestream.New(t, dut, gnmi.OC().Component(oc2).State(), samplingInterval) + defer streamOC2.Close() + tests := []struct { + description string + startFreq uint64 + endFreq uint64 + freqStep uint64 + targetOutputPower float64 + }{ + { + // Validate setting 400ZR++ optics module tunable laser center frequency + // across frequency range 196.100 - 191.375 THz for 75GHz grid. + description: "75GHz grid", + startFreq: 191375000, + endFreq: 196100000, + freqStep: 75000 * 6, + targetOutputPower: -3, + }, + } + for _, tc := range tests { + t.Run(tc.description, func(t *testing.T) { + for freq := tc.startFreq; freq <= tc.endFreq; freq += tc.freqStep { + t.Run(fmt.Sprintf("Freq: %v", freq), func(t *testing.T) { + if deviations.OperationalModeUnsupported(dut) { + operationalMode = 0 + } + cfgplugins.ConfigOpticalChannel(t, dut, oc1, freq, tc.targetOutputPower, operationalMode) + cfgplugins.ConfigOpticalChannel(t, dut, oc2, freq, tc.targetOutputPower, operationalMode) + 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) + validateOpticsTelemetry(t, []*samplestream.SampleStream[*oc.Component]{streamOC1, streamOC2}, freq, tc.targetOutputPower, oc.Interface_OperStatus_UP) + }) + } + }) + } + +} +func Test400ZRPlusTunableOutputPower(t *testing.T) { + if operationalModeFlag != nil { + operationalMode = uint16(*operationalModeFlag) + } else { + t.Fatalf("Please specify the vendor-specific operational-mode flag") + } + dut := ondatra.DUT(t, "dut") + p1 := dut.Port(t, "port1") + p2 := dut.Port(t, "port2") + fptest.ConfigureDefaultNetworkInstance(t, dut) + 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)) + oc1 := components.OpticalChannelComponentFromPort(t, dut, p1) + oc2 := components.OpticalChannelComponentFromPort(t, dut, p2) + streamOC1 := samplestream.New(t, dut, gnmi.OC().Component(oc1).State(), samplingInterval) + defer streamOC1.Close() + streamOC2 := samplestream.New(t, dut, gnmi.OC().Component(oc2).State(), samplingInterval) + defer streamOC2.Close() + tests := []struct { + description string + frequency uint64 + startTargetOutputPower float64 + endTargetOutputPower float64 + targetOutputPowerStep float64 + }{ + { + // Validate adjustable range of transmit output power across -7 to 0 dBm + // range in steps of 1dB. So the module’s output power will be set to -7, + // -6,-5, -4, -3, -2, -1, 0 dBm in each step. + description: "adjustable range of transmit output power across -7 to 0 dBm range in steps of 1dB", + frequency: 193100000, + startTargetOutputPower: -7, + endTargetOutputPower: 0, + targetOutputPowerStep: 1, + }, + } + for _, tc := range tests { + for top := tc.startTargetOutputPower; top <= tc.endTargetOutputPower; top += tc.targetOutputPowerStep { + t.Run(fmt.Sprintf("Target Power: %v", top), func(t *testing.T) { + if deviations.OperationalModeUnsupported(dut) { + operationalMode = 0 + } + + cfgplugins.ConfigOpticalChannel(t, dut, oc1, tc.frequency, top, operationalMode) + cfgplugins.ConfigOpticalChannel(t, dut, oc2, tc.frequency, top, operationalMode) + 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) + validateOpticsTelemetry(t, []*samplestream.SampleStream[*oc.Component]{streamOC1, streamOC2}, tc.frequency, top, oc.Interface_OperStatus_UP) + }) + } + } +} + +func Test400ZRPlusInterfaceFlap(t *testing.T) { + if operationalModeFlag != nil { + operationalMode = uint16(*operationalModeFlag) + } else { + t.Fatalf("Please specify the vendor-specific operational-mode flag") + } + dut := ondatra.DUT(t, "dut") + p1 := dut.Port(t, "port1") + p2 := dut.Port(t, "port2") + fptest.ConfigureDefaultNetworkInstance(t, dut) + 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)) + oc1 := components.OpticalChannelComponentFromPort(t, dut, p1) + oc2 := components.OpticalChannelComponentFromPort(t, dut, p2) + streamOC1 := samplestream.New(t, dut, gnmi.OC().Component(oc1).State(), samplingInterval) + defer streamOC1.Close() + streamOC2 := samplestream.New(t, dut, gnmi.OC().Component(oc2).State(), samplingInterval) + defer streamOC2.Close() + targetPower := float64(-3) + frequency := uint64(193100000) + + if deviations.OperationalModeUnsupported(dut) { + operationalMode = 0 + } + + cfgplugins.ConfigOpticalChannel(t, dut, oc1, frequency, targetPower, operationalMode) + cfgplugins.ConfigOpticalChannel(t, dut, oc2, frequency, targetPower, operationalMode) + 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) + t.Run("Telemetry before flap", func(t *testing.T) { + validateOpticsTelemetry(t, []*samplestream.SampleStream[*oc.Component]{streamOC1, streamOC2}, frequency, targetPower, oc.Interface_OperStatus_UP) + }) + // Disable or shut down the interface on the DUT. + cfgplugins.ToggleInterface(t, dut, p1.Name(), false) + cfgplugins.ToggleInterface(t, dut, p2.Name(), false) + gnmi.Await(t, dut, gnmi.OC().Interface(p1.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_DOWN) + gnmi.Await(t, dut, gnmi.OC().Interface(p2.Name()).OperStatus().State(), timeout, oc.Interface_OperStatus_DOWN) + + // Verify with interfaces in down state both optics are still streaming + // configured value for frequency. + // Verify for the TX output power with interface in down state a decimal64 + // value of -40 dB is streamed. + t.Run("Telemetry during interface disabled", func(t *testing.T) { + validateOpticsTelemetry(t, []*samplestream.SampleStream[*oc.Component]{streamOC1, streamOC2}, frequency, -40, oc.Interface_OperStatus_DOWN) + }) + // Re-enable the interfaces on the DUT. + cfgplugins.ToggleInterface(t, dut, p1.Name(), true) + cfgplugins.ToggleInterface(t, dut, p2.Name(), true) + 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) + // Verify the ZR optics tune back to the correct frequency and TX output + // power as per the configuration and related telemetry values are updated + // to the value in the normal range again. + t.Run("Telemetry after flap", func(t *testing.T) { + validateOpticsTelemetry(t, []*samplestream.SampleStream[*oc.Component]{streamOC1, streamOC2}, frequency, targetPower, oc.Interface_OperStatus_UP) + }) +} + +func validateOpticsTelemetry(t *testing.T, streams []*samplestream.SampleStream[*oc.Component], frequency uint64, outputPower float64, operStatus oc.E_Interface_OperStatus) { + dut := ondatra.DUT(t, "dut") + var ocs []*oc.Component_OpticalChannel + for _, s := range streams { + val := s.Next() + if val == nil { + t.Fatal("Optical channel streaming telemetry not received") + } + v, ok := val.Val() + if !ok { + t.Fatal("Optical channel streaming telemetry empty") + } + ocs = append(ocs, v.GetOpticalChannel()) + } + + for _, _oc := range ocs { + opm := _oc.GetOperationalMode() + inst := _oc.GetCarrierFrequencyOffset().GetInstant() + avg := _oc.GetCarrierFrequencyOffset().GetAvg() + min := _oc.GetCarrierFrequencyOffset().GetMin() + max := _oc.GetCarrierFrequencyOffset().GetMax() + if got, want := opm, uint16(operationalMode); got != want && !deviations.OperationalModeUnsupported(dut) { + t.Errorf("Optical-Channel: operational-mode: got %v, want %v", got, want) + } + // Laser frequency offset should not be more than +/- 1.8 GHz max from the + // configured centre frequency. + if inst < -1*frequencyTolerance || inst > frequencyTolerance { + t.Errorf("Optical-Channel: carrier-frequency-offset not in tolerable range, got: %v, want: (+/-)%v", inst, frequencyTolerance) + } + for _, ele := range []any{inst, min, max, avg} { + if reflect.TypeOf(ele).Kind() != reflect.Float64 { + t.Fatalf("Value %v is not type float64", ele) + } + } + if deviations.MissingZROpticalChannelTunableParametersTelemetry(dut) { + t.Log("Skipping Min/Max/Avg Tunable Parameters Telemetry validation. Deviation MissingZROpticalChannelTunableParametersTelemetry enabled.") + } else { + // For reported data check for validity: min <= avg/instant <= max + if min > math.Round(inst) { + t.Errorf("Optical-Channel: carrier-frequency-offset min: %v greater than carrier-frequency-offset instant: %v", min, inst) + } + if max < math.Round(inst) { + t.Errorf("Optical-Channel: carrier-frequency-offset max: %v less than carrier-frequency-offset instant: %v", max, inst) + } + if min > math.Round(avg) { + t.Errorf("Optical-Channel: carrier-frequency-offset min: %v greater than carrier-frequency-offset avg: %v", min, avg) + } + if max < math.Round(avg) { + t.Errorf("Optical-Channel: carrier-frequency-offset max: %v less than carrier-frequency-offset avg: %v", max, avg) + } + } + inst = _oc.GetOutputPower().GetInstant() + avg = _oc.GetOutputPower().GetAvg() + min = _oc.GetOutputPower().GetMin() + max = _oc.GetOutputPower().GetMax() + // When set to a specific target output power, transmit power control + // absolute accuracy should be within +/- 1 dBm of the target configured + // output power. + switch operStatus { + case oc.Interface_OperStatus_UP: + if inst < outputPower-1 || inst > outputPower+1 { + t.Errorf("Optical-Channel: output-power not in tolerable range, got: %v, want: %v", inst, outputPower) + } + case oc.Interface_OperStatus_DOWN: + if inst != -40 { + t.Errorf("Optical-Channel: output-power not in tolerable range, got: %v, want: %v", inst, -40) + } + } + for _, ele := range []any{inst, min, max, avg} { + if reflect.TypeOf(ele).Kind() != reflect.Float64 { + t.Fatalf("Value %v is not type float64", ele) + } + } + if deviations.MissingZROpticalChannelTunableParametersTelemetry(dut) { + t.Log("Skipping Min/Max/Avg Tunable Parameters Telemetry validation. Deviation MissingZROpticalChannelTunableParametersTelemetry enabled.") + } else { + // For reported data check for validity: min <= avg/instant <= max + if min > math.Round(inst) { + t.Errorf("Optical-Channel: output-power min: %v greater than output-power instant: %v", min, inst) + } + if max < math.Round(inst) { + t.Errorf("Optical-Channel: output-power max: %v less than output-power instant: %v", max, inst) + } + if min > math.Round(avg) { + t.Errorf("Optical-Channel: output-power min: %v greater than output-power avg: %v", min, avg) + } + if max < math.Round(avg) { + t.Errorf("Optical-Channel: output-power max: %v less than output-power avg: %v", max, avg) + } + } + if got, want := _oc.GetFrequency(), frequency; got != want { + t.Errorf("Optical-Channel: frequency: %v, want: %v", got, want) + } + } +} diff --git a/feature/qos/ecn/otg_tests/dscp_transparency_test/dscp_transparency_test.go b/feature/qos/ecn/otg_tests/dscp_transparency_test/dscp_transparency_test.go index 921451ad2bb..adabdd526dc 100644 --- a/feature/qos/ecn/otg_tests/dscp_transparency_test/dscp_transparency_test.go +++ b/feature/qos/ecn/otg_tests/dscp_transparency_test/dscp_transparency_test.go @@ -115,7 +115,7 @@ var ( "port3": atePort3, } - allQueueNames = []entname.QoSQueue{ + allQueueNames = []entname.QoSClass{ entname.QoSNC1, entname.QoSAF4, entname.QoSAF3, @@ -128,7 +128,7 @@ var ( testCases = []struct { name string createFlowsF func(otgConfig gosnappi.Config, protocol string, atePortSpeed int) - validateFlowsF func(t *testing.T, dut *ondatra.DUTDevice, ate *ondatra.ATEDevice, atePortSpeed int, startingCounters map[entname.QoSQueue]*queueCounters) + validateFlowsF func(t *testing.T, dut *ondatra.DUTDevice, ate *ondatra.ATEDevice, atePortSpeed int, startingCounters map[entname.QoSClass]*queueCounters) }{ { name: "TestNoCongestion", @@ -444,10 +444,10 @@ func createFlow(otgConfig gosnappi.Config, protocol string, targetTotalFlowRate return flow } -func getQueueCounters(t *testing.T, dut *ondatra.DUTDevice) map[entname.QoSQueue]*queueCounters { +func getQueueCounters(t *testing.T, dut *ondatra.DUTDevice) map[entname.QoSClass]*queueCounters { t.Helper() ep := dut.Port(t, dutEgressPort) - qc := map[entname.QoSQueue]*queueCounters{} + qc := map[entname.QoSClass]*queueCounters{} for _, egressQueueName := range allQueueNames { qc[egressQueueName] = &queueCounters{ @@ -460,7 +460,7 @@ func getQueueCounters(t *testing.T, dut *ondatra.DUTDevice) map[entname.QoSQueue return qc } -func logAndGetResolvedQueueCounters(t *testing.T, egressQueueName entname.QoSQueue, egressQueueStartingCounters, egressQueueEndingCounters *queueCounters) (uint64, uint64, uint64) { +func logAndGetResolvedQueueCounters(t *testing.T, egressQueueName entname.QoSClass, egressQueueStartingCounters, egressQueueEndingCounters *queueCounters) (uint64, uint64, uint64) { queueDroppedPackets := egressQueueEndingCounters.droppedPackets - egressQueueStartingCounters.droppedPackets queueTransmitPackets := egressQueueEndingCounters.transmitPackets - egressQueueStartingCounters.transmitPackets queueTransmitOctets := egressQueueEndingCounters.transmitOctets - egressQueueStartingCounters.transmitOctets @@ -517,7 +517,7 @@ func testNoCongestionCreateFlows(otgConfig gosnappi.Config, protocol string, dut } } -func testNoCongestionValidateFlows(t *testing.T, dut *ondatra.DUTDevice, ate *ondatra.ATEDevice, dutPortSpeed int, startingCounters map[entname.QoSQueue]*queueCounters) { +func testNoCongestionValidateFlows(t *testing.T, dut *ondatra.DUTDevice, ate *ondatra.ATEDevice, dutPortSpeed int, startingCounters map[entname.QoSClass]*queueCounters) { maxAllowedZeroPackets, _ := getZeroIshThresholds(dutPortSpeed) endingCounters := getQueueCounters(t, dut) @@ -607,7 +607,7 @@ func testCongestionCreateFlows(otgConfig gosnappi.Config, protocol string, dutPo } } -func testCongestionValidateFlows(t *testing.T, dut *ondatra.DUTDevice, ate *ondatra.ATEDevice, dutPortSpeed int, startingCounters map[entname.QoSQueue]*queueCounters) { +func testCongestionValidateFlows(t *testing.T, dut *ondatra.DUTDevice, ate *ondatra.ATEDevice, dutPortSpeed int, startingCounters map[entname.QoSClass]*queueCounters) { maxAllowedZeroPackets, _ := getZeroIshThresholds(dutPortSpeed) endingCounters := getQueueCounters(t, dut) @@ -741,7 +741,7 @@ func testNC1CongestionCreateFlows(otgConfig gosnappi.Config, protocol string, du } } -func testNC1CongestionValidateFlows(t *testing.T, dut *ondatra.DUTDevice, ate *ondatra.ATEDevice, dutPortSpeed int, startingCounters map[entname.QoSQueue]*queueCounters) { +func testNC1CongestionValidateFlows(t *testing.T, dut *ondatra.DUTDevice, ate *ondatra.ATEDevice, dutPortSpeed int, startingCounters map[entname.QoSClass]*queueCounters) { maxAllowedZeroPackets, maxAllowedZeroOctets := getZeroIshThresholds(dutPortSpeed) endingCounters := getQueueCounters(t, dut) diff --git a/feature/staticroute/otg_tests/basic_static_route_support_test/metadata.textproto b/feature/staticroute/otg_tests/basic_static_route_support_test/metadata.textproto index af7f010bc52..ccac5af9ab0 100644 --- a/feature/staticroute/otg_tests/basic_static_route_support_test/metadata.textproto +++ b/feature/staticroute/otg_tests/basic_static_route_support_test/metadata.textproto @@ -18,11 +18,6 @@ platform_exceptions: { isis_interface_afi_unsupported: true missing_isis_interface_afi_safi_enable: true isis_require_same_l1_metric_with_l2_metric: true - ipv6_static_route_with_ipv4_next_hop_requires_static_arp: true - set_metric_as_preference: true - missing_static_route_next_hop_metric_telemetry: true - unsupported_static_route_next_hop_recurse: true - missing_static_route_drop_next_hop_telemetry: true } } platform_exceptions: { diff --git a/feature/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/metadata.textproto b/feature/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/metadata.textproto index e6104d7837a..36badab880d 100644 --- a/feature/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/metadata.textproto +++ b/feature/system/gnmi/benchmarking/otg_tests/drained_configuration_convergence_time/metadata.textproto @@ -31,7 +31,6 @@ platform_exceptions: { vendor: ARISTA } deviations: { - route_policy_under_afi_unsupported: true interface_enabled: true default_network_instance: "default" missing_isis_interface_afi_safi_enable: true diff --git a/feature/system/gnmi/benchmarking/tests/full_configuration_replace_test/metadata.textproto b/feature/system/gnmi/benchmarking/tests/full_configuration_replace_test/metadata.textproto index 64eed0547a0..7d9bb480d71 100644 --- a/feature/system/gnmi/benchmarking/tests/full_configuration_replace_test/metadata.textproto +++ b/feature/system/gnmi/benchmarking/tests/full_configuration_replace_test/metadata.textproto @@ -31,7 +31,6 @@ platform_exceptions: { vendor: ARISTA } deviations: { - route_policy_under_afi_unsupported: true interface_enabled: true missing_isis_interface_afi_safi_enable: true isis_interface_afi_unsupported: true diff --git a/feature/system/management/otg_tests/management_ha_test/metadata.textproto b/feature/system/management/otg_tests/management_ha_test/metadata.textproto index bbc70c53bc1..ed33d7b530c 100644 --- a/feature/system/management/otg_tests/management_ha_test/metadata.textproto +++ b/feature/system/management/otg_tests/management_ha_test/metadata.textproto @@ -10,13 +10,10 @@ platform_exceptions: { vendor: ARISTA } deviations: { - route_policy_under_afi_unsupported: true omit_l2_mtu: true static_protocol_name: "STATIC" interface_enabled: true default_network_instance: "default" - skip_set_rp_match_set_options: true - skip_setting_disable_metric_propagation: true set_no_peer_group: true explicit_enable_bgp_on_default_vrf: true } diff --git a/go.mod b/go.mod index 269c599baa8..278de33bcf2 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/kr/pretty v0.3.1 github.com/open-traffic-generator/snappi/gosnappi v1.3.0 github.com/openconfig/containerz v0.0.0-20250119143156-ea1f112cd31c - github.com/openconfig/entity-naming v0.0.0-20230912181021-7ac806551a31 + github.com/openconfig/entity-naming v0.0.0-20250108173956-784f643e8b64 github.com/openconfig/gnmi v0.11.0 github.com/openconfig/gnoi v0.6.0 github.com/openconfig/gnoigo v0.0.0-20240320202954-ebd033e3542c diff --git a/go.sum b/go.sum index 09c4333466f..c34a20aa9ee 100644 --- a/go.sum +++ b/go.sum @@ -1658,6 +1658,8 @@ github.com/openconfig/containerz v0.0.0-20250119143156-ea1f112cd31c h1:4WtTr8Iv2 github.com/openconfig/containerz v0.0.0-20250119143156-ea1f112cd31c/go.mod h1:VcT2W5ddds98x7CS2r7q1tnUICgflBQ3Wv9rmRkb5TQ= github.com/openconfig/entity-naming v0.0.0-20230912181021-7ac806551a31 h1:K/9O+J20+liIof8WjquMydnebD0N1U9ItjhJYF6H4hg= github.com/openconfig/entity-naming v0.0.0-20230912181021-7ac806551a31/go.mod h1:ZRUrfwYYY+pLaOoWPad3p/8J4LLQcSqtXhBCkD2pXJc= +github.com/openconfig/entity-naming v0.0.0-20250108173956-784f643e8b64 h1:pS4NcCl49ker3FYRkvY+erNUw1CgL/lB8gnDQbax6Yk= +github.com/openconfig/entity-naming v0.0.0-20250108173956-784f643e8b64/go.mod h1:FDF5sbP9BbP2IM6EUopcAWfGJ5OPZ4VV2EYQ9vvqLjA= github.com/openconfig/gnmi v0.0.0-20200414194230-1597cc0f2600/go.mod h1:M/EcuapNQgvzxo1DDXHK4tx3QpYM/uG4l591v33jG2A= github.com/openconfig/gnmi v0.0.0-20200508230933-d19cebf5e7be/go.mod h1:M/EcuapNQgvzxo1DDXHK4tx3QpYM/uG4l591v33jG2A= github.com/openconfig/gnmi v0.10.0/go.mod h1:Y9os75GmSkhHw2wX8sMsxfI7qRGAEcDh8NTa5a8vj6E= diff --git a/internal/encap_frr/base.go b/internal/encap_frr/base.go deleted file mode 100644 index 30a0203e072..00000000000 --- a/internal/encap_frr/base.go +++ /dev/null @@ -1,578 +0,0 @@ -// 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 base contains utility functions for encap frr using repair VRF. -package base - -import ( - "context" - "strconv" - "testing" - "time" - - "github.com/openconfig/featureprofiles/internal/attrs" - "github.com/openconfig/featureprofiles/internal/deviations" - "github.com/openconfig/gribigo/chk" - "github.com/openconfig/gribigo/constants" - "github.com/openconfig/gribigo/fluent" - "github.com/openconfig/ondatra" - "github.com/openconfig/ondatra/gnmi" - "github.com/openconfig/ondatra/gnmi/oc" - "github.com/openconfig/ygot/ygot" -) - -const ( - plenIPv4 = 30 - magicIP = "192.168.1.1" - magicMAC = "02:00:00:00:00:01" - maskLen24 = "24" - maskLen32 = "32" - niEncapTeVrfA = "ENCAP_TE_VRF_A" - niTEVRF111 = "TE_VRF_111" - niTEVRF222 = "TE_VRF_222" - niRepairVrf = "REPAIR_VRF" - ipv4OuterSrc111Addr = "198.51.100.111" - ipv4OuterSrc222Addr = "198.51.100.222" - gribiIPv4EntryDefVRF1 = "192.0.2.101" - gribiIPv4EntryDefVRF2 = "192.0.2.102" - gribiIPv4EntryDefVRF3 = "192.0.2.103" - gribiIPv4EntryDefVRF4 = "192.0.2.104" - gribiIPv4EntryDefVRF5 = "192.0.2.105" - gribiIPv4EntryVRF1111 = "203.0.113.1" - gribiIPv4EntryVRF1112 = "203.0.113.2" - gribiIPv4EntryVRF2221 = "203.0.113.100" - gribiIPv4EntryVRF2222 = "203.0.113.101" - gribiIPv4EntryEncapVRF = "138.0.11.0" - noMatchEncapDest = "20.0.0.1" -) - -var ( - dutPort2DummyIP = attrs.Attributes{ - Desc: "dutPort2", - IPv4Sec: "192.0.2.33", - IPv4LenSec: plenIPv4, - } - - otgPort2DummyIP = attrs.Attributes{ - Desc: "otgPort2", - IPv4: "192.0.2.34", - IPv4Len: plenIPv4, - } - - dutPort3DummyIP = attrs.Attributes{ - Desc: "dutPort3", - IPv4Sec: "192.0.2.37", - IPv4LenSec: plenIPv4, - } - - otgPort3DummyIP = attrs.Attributes{ - Desc: "otgPort3", - IPv4: "192.0.2.38", - IPv4Len: plenIPv4, - } - - dutPort4DummyIP = attrs.Attributes{ - Desc: "dutPort4", - IPv4Sec: "192.0.2.41", - IPv4LenSec: plenIPv4, - } - - otgPort4DummyIP = attrs.Attributes{ - Desc: "otgPort4", - IPv4: "192.0.2.42", - IPv4Len: plenIPv4, - } - - dutPort5DummyIP = attrs.Attributes{ - Desc: "dutPort5", - IPv4Sec: "192.0.2.45", - IPv4LenSec: plenIPv4, - } - - otgPort5DummyIP = attrs.Attributes{ - Desc: "otgPort5", - IPv4: "192.0.2.46", - IPv4Len: plenIPv4, - } - dutPort6DummyIP = attrs.Attributes{ - Desc: "dutPort5", - IPv4Sec: "192.0.2.49", - IPv4LenSec: plenIPv4, - } - - otgPort6DummyIP = attrs.Attributes{ - Desc: "otgPort5", - IPv4: "192.0.2.50", - IPv4Len: plenIPv4, - } - dutPort7DummyIP = attrs.Attributes{ - Desc: "dutPort5", - IPv4Sec: "192.0.2.53", - IPv4LenSec: plenIPv4, - } - - otgPort7DummyIP = attrs.Attributes{ - Desc: "otgPort5", - IPv4: "192.0.2.54", - IPv4Len: plenIPv4, - } -) - -func programAftWithDummyIP(t *testing.T, dut *ondatra.DUTDevice, client *fluent.GRIBIClient) { - client.Modify().AddEntry(t, - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(11).WithMacAddress(magicMAC).WithInterfaceRef(dut.Port(t, "port2").Name()). - WithIPAddress(otgPort2DummyIP.IPv4), - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(12).WithMacAddress(magicMAC).WithInterfaceRef(dut.Port(t, "port3").Name()). - WithIPAddress(otgPort3DummyIP.IPv4), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(11).AddNextHop(11, 1).AddNextHop(12, 3), - fluent.IPv4Entry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithPrefix(gribiIPv4EntryDefVRF1+"/"+maskLen32).WithNextHopGroup(11), - - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(13).WithMacAddress(magicMAC).WithInterfaceRef(dut.Port(t, "port4").Name()). - WithIPAddress(otgPort4DummyIP.IPv4), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(12).AddNextHop(13, 2), - fluent.IPv4Entry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithPrefix(gribiIPv4EntryDefVRF2+"/"+maskLen32).WithNextHopGroup(12), - - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(14).WithMacAddress(magicMAC).WithInterfaceRef(dut.Port(t, "port5").Name()). - WithIPAddress(otgPort5DummyIP.IPv4), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(13).AddNextHop(14, 1), - fluent.IPv4Entry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithPrefix(gribiIPv4EntryDefVRF3+"/"+maskLen32).WithNextHopGroup(13), - - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(15).WithMacAddress(magicMAC).WithInterfaceRef(dut.Port(t, "port6").Name()). - WithIPAddress(otgPort6DummyIP.IPv4), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(14).AddNextHop(15, 1), - fluent.IPv4Entry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithPrefix(gribiIPv4EntryDefVRF4+"/"+maskLen32).WithNextHopGroup(14), - - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(16).WithMacAddress(magicMAC).WithInterfaceRef(dut.Port(t, "port7").Name()). - WithIPAddress(otgPort7DummyIP.IPv4), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(15).AddNextHop(16, 1), - fluent.IPv4Entry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithPrefix(gribiIPv4EntryDefVRF5+"/"+maskLen32).WithNextHopGroup(15), - ) -} - -// configStaticArp configures static arp entries -func configStaticArp(p string, ipv4addr string, macAddr string) *oc.Interface { - i := &oc.Interface{Name: ygot.String(p)} - i.Type = oc.IETFInterfaces_InterfaceType_ethernetCsmacd - s := i.GetOrCreateSubinterface(0) - s4 := s.GetOrCreateIpv4() - n4 := s4.GetOrCreateNeighbor(ipv4addr) - n4.LinkLayerAddress = ygot.String(macAddr) - return i -} - -// StaticARPWithSpecificIP configures secondary IPs and static ARP. -func StaticARPWithSpecificIP(t *testing.T, dut *ondatra.DUTDevice) { - t.Helper() - p2 := dut.Port(t, "port2") - p3 := dut.Port(t, "port3") - p4 := dut.Port(t, "port4") - p5 := dut.Port(t, "port5") - p6 := dut.Port(t, "port6") - p7 := dut.Port(t, "port7") - gnmi.Update(t, dut, gnmi.OC().Interface(p2.Name()).Config(), dutPort2DummyIP.NewOCInterface(p2.Name(), dut)) - gnmi.Update(t, dut, gnmi.OC().Interface(p3.Name()).Config(), dutPort3DummyIP.NewOCInterface(p3.Name(), dut)) - gnmi.Update(t, dut, gnmi.OC().Interface(p4.Name()).Config(), dutPort4DummyIP.NewOCInterface(p4.Name(), dut)) - gnmi.Update(t, dut, gnmi.OC().Interface(p5.Name()).Config(), dutPort5DummyIP.NewOCInterface(p5.Name(), dut)) - gnmi.Update(t, dut, gnmi.OC().Interface(p6.Name()).Config(), dutPort6DummyIP.NewOCInterface(p6.Name(), dut)) - gnmi.Update(t, dut, gnmi.OC().Interface(p7.Name()).Config(), dutPort7DummyIP.NewOCInterface(p7.Name(), dut)) - gnmi.Update(t, dut, gnmi.OC().Interface(p2.Name()).Config(), configStaticArp(p2.Name(), otgPort2DummyIP.IPv4, magicMAC)) - gnmi.Update(t, dut, gnmi.OC().Interface(p3.Name()).Config(), configStaticArp(p3.Name(), otgPort3DummyIP.IPv4, magicMAC)) - gnmi.Update(t, dut, gnmi.OC().Interface(p4.Name()).Config(), configStaticArp(p4.Name(), otgPort4DummyIP.IPv4, magicMAC)) - gnmi.Update(t, dut, gnmi.OC().Interface(p5.Name()).Config(), configStaticArp(p5.Name(), otgPort5DummyIP.IPv4, magicMAC)) - gnmi.Update(t, dut, gnmi.OC().Interface(p6.Name()).Config(), configStaticArp(p6.Name(), otgPort6DummyIP.IPv4, magicMAC)) - gnmi.Update(t, dut, gnmi.OC().Interface(p7.Name()).Config(), configStaticArp(p7.Name(), otgPort7DummyIP.IPv4, magicMAC)) -} - -// StaticARPWithMagicUniversalIP programs the static ARP with magic universal IP -func StaticARPWithMagicUniversalIP(t *testing.T, dut *ondatra.DUTDevice) { - t.Helper() - sb := &gnmi.SetBatch{} - p2 := dut.Port(t, "port2") - p3 := dut.Port(t, "port3") - p4 := dut.Port(t, "port4") - p5 := dut.Port(t, "port5") - p6 := dut.Port(t, "port6") - p7 := dut.Port(t, "port7") - portList := []*ondatra.Port{p2, p3, p4, p5, p6, p7} - for idx, p := range portList { - s := &oc.NetworkInstance_Protocol_Static{ - Prefix: ygot.String(magicIP + "/32"), - NextHop: map[string]*oc.NetworkInstance_Protocol_Static_NextHop{ - strconv.Itoa(idx): { - Index: ygot.String(strconv.Itoa(idx)), - InterfaceRef: &oc.NetworkInstance_Protocol_Static_NextHop_InterfaceRef{ - Interface: ygot.String(p.Name()), - }, - }, - }, - } - sp := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_STATIC, deviations.StaticProtocolName(dut)) - gnmi.BatchUpdate(sb, sp.Static(magicIP+"/32").Config(), s) - gnmi.BatchUpdate(sb, gnmi.OC().Interface(p.Name()).Config(), configStaticArp(p.Name(), magicIP, magicMAC)) - } - sb.Set(t, dut) -} - -// ConfigureBaseGribiRoutes programs the base gribi routes for encap FRR using repair VRF -func ConfigureBaseGribiRoutes(ctx context.Context, t *testing.T, dut *ondatra.DUTDevice, client *fluent.GRIBIClient) { - t.Helper() - - // Programming AFT entries for prefixes in DEFAULT VRF - if deviations.GRIBIMACOverrideStaticARPStaticRoute(dut) { - client.Modify().AddEntry(t, - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(11).WithMacAddress(magicMAC).WithInterfaceRef(dut.Port(t, "port2").Name()).WithIPAddress(magicIP), - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(12).WithMacAddress(magicMAC).WithInterfaceRef(dut.Port(t, "port3").Name()).WithIPAddress(magicIP), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(11).AddNextHop(11, 1).AddNextHop(12, 3), - - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(13).WithMacAddress(magicMAC).WithInterfaceRef(dut.Port(t, "port4").Name()).WithIPAddress(magicIP), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(12).AddNextHop(13, 2), - - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(14).WithMacAddress(magicMAC).WithInterfaceRef(dut.Port(t, "port5").Name()).WithIPAddress(magicIP), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(13).AddNextHop(14, 1), - - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(15).WithMacAddress(magicMAC).WithInterfaceRef(dut.Port(t, "port6").Name()).WithIPAddress(magicIP), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(14).AddNextHop(15, 1), - - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(16).WithMacAddress(magicMAC).WithInterfaceRef(dut.Port(t, "port7").Name()).WithIPAddress(magicIP), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(15).AddNextHop(16, 1), - ) - } else if deviations.GRIBIMACOverrideWithStaticARP(dut) { - programAftWithDummyIP(t, dut, client) - } else { - client.Modify().AddEntry(t, - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(11).WithMacAddress(magicMAC).WithInterfaceRef(dut.Port(t, "port2").Name()), - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(12).WithMacAddress(magicMAC).WithInterfaceRef(dut.Port(t, "port3").Name()), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(11).AddNextHop(11, 1).AddNextHop(12, 3), - - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(13).WithMacAddress(magicMAC).WithInterfaceRef(dut.Port(t, "port4").Name()), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(12).AddNextHop(13, 2), - - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(14).WithMacAddress(magicMAC).WithInterfaceRef(dut.Port(t, "port5").Name()), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(13).AddNextHop(14, 1), - - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(15).WithMacAddress(magicMAC).WithInterfaceRef(dut.Port(t, "port6").Name()), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(14).AddNextHop(15, 1), - - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(16).WithMacAddress(magicMAC).WithInterfaceRef(dut.Port(t, "port7").Name()), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(15).AddNextHop(16, 1), - ) - } - if err := awaitTimeout(ctx, t, client, time.Minute); err != nil { - t.Logf("Could not program entries via client, got err, check error codes: %v", err) - } - - client.Modify().AddEntry(t, - fluent.IPv4Entry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithPrefix(gribiIPv4EntryDefVRF1+"/"+maskLen32).WithNextHopGroup(11), - fluent.IPv4Entry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithPrefix(gribiIPv4EntryDefVRF2+"/"+maskLen32).WithNextHopGroup(12), - fluent.IPv4Entry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithPrefix(gribiIPv4EntryDefVRF3+"/"+maskLen32).WithNextHopGroup(13), - fluent.IPv4Entry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithPrefix(gribiIPv4EntryDefVRF4+"/"+maskLen32).WithNextHopGroup(14), - fluent.IPv4Entry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithPrefix(gribiIPv4EntryDefVRF5+"/"+maskLen32).WithNextHopGroup(15), - ) - if err := awaitTimeout(ctx, t, client, time.Minute); err != nil { - t.Logf("Could not program entries via client, got err, check error codes: %v", err) - } - - defaultVRFIPList := []string{gribiIPv4EntryDefVRF1, gribiIPv4EntryDefVRF2, gribiIPv4EntryDefVRF3, gribiIPv4EntryDefVRF4, gribiIPv4EntryDefVRF5} - for ip := range defaultVRFIPList { - chk.HasResult(t, client.Results(t), - fluent.OperationResult(). - WithIPv4Operation(defaultVRFIPList[ip]+"/32"). - WithOperationType(constants.Add). - WithProgrammingResult(fluent.InstalledInFIB). - AsResult(), - chk.IgnoreOperationID(), - ) - } - - // Programming AFT entries for backup NHG - client.Modify().AddEntry(t, - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(2000).WithDecapsulateHeader(fluent.IPinIP).WithNextHopNetworkInstance(deviations.DefaultNetworkInstance(dut)), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(2000).AddNextHop(2000, 1), - ) - if err := awaitTimeout(ctx, t, client, time.Minute); err != nil { - t.Logf("Could not program entries via client, got err, check error codes: %v", err) - } - - // Programming AFT entries for prefixes in TE_VRF_222 - client.Modify().AddEntry(t, - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(3).WithIPAddress(gribiIPv4EntryDefVRF3), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(2).AddNextHop(3, 1).WithBackupNHG(2000), - fluent.IPv4Entry().WithNetworkInstance(niTEVRF222).WithNextHopGroupNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithPrefix(gribiIPv4EntryVRF2221+"/"+maskLen32).WithNextHopGroup(2), - - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(5).WithIPAddress(gribiIPv4EntryDefVRF5), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(4).AddNextHop(5, 1).WithBackupNHG(2000), - fluent.IPv4Entry().WithNetworkInstance(niTEVRF222).WithNextHopGroupNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithPrefix(gribiIPv4EntryVRF2222+"/"+maskLen32).WithNextHopGroup(4), - ) - if err := awaitTimeout(ctx, t, client, time.Minute); err != nil { - t.Logf("Could not program entries via client, got err, check error codes: %v", err) - } - - teVRF222IPList := []string{gribiIPv4EntryVRF2221, gribiIPv4EntryVRF2222} - for ip := range teVRF222IPList { - chk.HasResult(t, client.Results(t), - fluent.OperationResult(). - WithIPv4Operation(teVRF222IPList[ip]+"/32"). - WithOperationType(constants.Add). - WithProgrammingResult(fluent.InstalledInFIB). - AsResult(), - chk.IgnoreOperationID(), - ) - } - - // Programming AFT entries for backup NHG - client.Modify().AddEntry(t, - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(1000).WithDecapsulateHeader(fluent.IPinIP).WithEncapsulateHeader(fluent.IPinIP). - WithIPinIP(ipv4OuterSrc222Addr, gribiIPv4EntryVRF2221). - WithNextHopNetworkInstance(niTEVRF222), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(1000).AddNextHop(1000, 1).WithBackupNHG(2000), - - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(1001).WithDecapsulateHeader(fluent.IPinIP).WithEncapsulateHeader(fluent.IPinIP). - WithIPinIP(ipv4OuterSrc222Addr, gribiIPv4EntryVRF2222). - WithNextHopNetworkInstance(niTEVRF222), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(1001).AddNextHop(1001, 1).WithBackupNHG(2000), - - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(3000).WithNextHopNetworkInstance(niRepairVrf), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(3000).AddNextHop(3000, 1), - ) - if err := awaitTimeout(ctx, t, client, time.Minute); err != nil { - t.Logf("Could not program entries via client, got err, check error codes: %v", err) - } - - // Programming AFT entries for prefixes in TE_VRF_111 - client.Modify().AddEntry(t, - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(1).WithIPAddress(gribiIPv4EntryDefVRF1), - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(2).WithIPAddress(gribiIPv4EntryDefVRF2), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(1).AddNextHop(1, 1).AddNextHop(2, 3).WithBackupNHG(3000), - fluent.IPv4Entry().WithNetworkInstance(niTEVRF111).WithNextHopGroupNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithPrefix(gribiIPv4EntryVRF1111+"/"+maskLen32).WithNextHopGroup(1), - - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(4).WithIPAddress(gribiIPv4EntryDefVRF4), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(3).AddNextHop(4, 1).WithBackupNHG(3000), - fluent.IPv4Entry().WithNetworkInstance(niTEVRF111).WithNextHopGroupNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithPrefix(gribiIPv4EntryVRF1112+"/"+maskLen32).WithNextHopGroup(3), - - fluent.IPv4Entry().WithNetworkInstance(niRepairVrf).WithNextHopGroupNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithPrefix(gribiIPv4EntryVRF1111+"/"+maskLen32).WithNextHopGroup(1000), - fluent.IPv4Entry().WithNetworkInstance(niRepairVrf).WithNextHopGroupNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithPrefix(gribiIPv4EntryVRF1112+"/"+maskLen32).WithNextHopGroup(1001), - ) - if err := awaitTimeout(ctx, t, client, time.Minute); err != nil { - t.Logf("Could not program entries via client, got err, check error codes: %v", err) - } - - teVRF111IPList := []string{gribiIPv4EntryVRF1111, gribiIPv4EntryVRF1112} - for ip := range teVRF111IPList { - chk.HasResult(t, client.Results(t), - fluent.OperationResult(). - WithIPv4Operation(teVRF111IPList[ip]+"/32"). - WithOperationType(constants.Add). - WithProgrammingResult(fluent.InstalledInFIB). - AsResult(), - chk.IgnoreOperationID(), - ) - } - - // Programming AFT entries for backup NHG - client.Modify().AddEntry(t, - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(2001).WithNextHopNetworkInstance(deviations.DefaultNetworkInstance(dut)), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(2001).AddNextHop(2001, 1), - ) - if err := awaitTimeout(ctx, t, client, time.Minute); err != nil { - t.Logf("Could not program entries via client, got err, check error codes: %v", err) - } - - // Programming AFT entries for prefixes in ENCAP_TE_VRF_A - client.Modify().AddEntry(t, - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(101).WithEncapsulateHeader(fluent.IPinIP). - WithIPinIP(ipv4OuterSrc111Addr, gribiIPv4EntryVRF1111). - WithNextHopNetworkInstance(niTEVRF111), - fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithIndex(102).WithEncapsulateHeader(fluent.IPinIP). - WithIPinIP(ipv4OuterSrc111Addr, gribiIPv4EntryVRF1112). - WithNextHopNetworkInstance(niTEVRF111), - fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithID(101).AddNextHop(101, 1).AddNextHop(102, 3).WithBackupNHG(2001), - fluent.IPv4Entry().WithNetworkInstance(niEncapTeVrfA).WithNextHopGroupNetworkInstance(deviations.DefaultNetworkInstance(dut)). - WithPrefix(gribiIPv4EntryEncapVRF+"/"+maskLen24).WithNextHopGroup(101), - ) - if err := awaitTimeout(ctx, t, client, time.Minute); err != nil { - t.Logf("Could not program entries via client, got err, check error codes: %v", err) - } - - chk.HasResult(t, client.Results(t), - fluent.OperationResult(). - WithIPv4Operation(gribiIPv4EntryEncapVRF+"/24"). - WithOperationType(constants.Add). - WithProgrammingResult(fluent.InstalledInFIB). - AsResult(), - chk.IgnoreOperationID(), - ) -} - -// TestCase is a struct to hold the parameters for FRR test cases. -type TestCase struct { - Desc string - DownPortList []string - CapturePortList []string - EncapHeaderOuterIPList []string - EncapHeaderInnerIPList []string - TrafficDestIP string - LoadBalancePercent []float64 - TestID string -} - -// TestCases returns a list of base test cases for FRR tests. -func TestCases(atePortNamelist []string, ipv4InnerDst string) []*TestCase { - cases := []*TestCase{ - { - Desc: "Test-1: primary encap unviable but backup encap viable for single tunnel", - DownPortList: []string{"port2", "port3", "port4"}, - CapturePortList: []string{atePortNamelist[4], atePortNamelist[5]}, - EncapHeaderOuterIPList: []string{gribiIPv4EntryVRF2221, gribiIPv4EntryVRF1112}, - EncapHeaderInnerIPList: []string{ipv4InnerDst, ipv4InnerDst}, - TrafficDestIP: ipv4InnerDst, - LoadBalancePercent: []float64{0, 0, 0, 0.25, 0.75, 0, 0}, - TestID: "primarySingle", - }, { - Desc: "Test-2: primary and backup encap unviable for single tunnel", - DownPortList: []string{"port2", "port3", "port4", "port5"}, - CapturePortList: []string{atePortNamelist[5], atePortNamelist[7]}, - EncapHeaderOuterIPList: []string{gribiIPv4EntryVRF1112}, - EncapHeaderInnerIPList: []string{ipv4InnerDst}, - TrafficDestIP: ipv4InnerDst, - LoadBalancePercent: []float64{0, 0, 0, 0, 0.75, 0, 0.25}, - TestID: "primaryBackupSingle", - }, { - Desc: "Test-3: primary encap unviable with backup to routing for single tunnel", - DownPortList: []string{"port2", "port3", "port4"}, - CapturePortList: []string{atePortNamelist[5], atePortNamelist[7]}, - EncapHeaderOuterIPList: []string{gribiIPv4EntryVRF1112}, - EncapHeaderInnerIPList: []string{ipv4InnerDst}, - TrafficDestIP: ipv4InnerDst, - LoadBalancePercent: []float64{0, 0, 0, 0, 0.75, 0, 0.25}, - TestID: "primaryBackupRoutingSingle", - }, { - Desc: "Test-4: primary encap unviable but backup encap viable for all tunnels", - DownPortList: []string{"port2", "port3", "port4", "port6"}, - CapturePortList: []string{atePortNamelist[4], atePortNamelist[6]}, - EncapHeaderOuterIPList: []string{gribiIPv4EntryVRF2221, gribiIPv4EntryVRF2222}, - EncapHeaderInnerIPList: []string{ipv4InnerDst, ipv4InnerDst}, - TrafficDestIP: ipv4InnerDst, - LoadBalancePercent: []float64{0, 0, 0, 0.25, 0, 0.75, 0}, - TestID: "primaryAll", - }, { - Desc: "Test-5: primary and backup encap unviable for all tunnels", - DownPortList: []string{"port2", "port3", "port4", "port5", "port6", "port7"}, - CapturePortList: []string{atePortNamelist[7]}, - EncapHeaderOuterIPList: []string{}, - EncapHeaderInnerIPList: []string{ipv4InnerDst}, - TrafficDestIP: ipv4InnerDst, - LoadBalancePercent: []float64{0, 0, 0, 0, 0, 0, 1}, - TestID: "primaryBackupAll", - }, { - Desc: "Test-6: primary encap unviable with backup to routing for all tunnels", - DownPortList: []string{"port2", "port3", "port4", "port6"}, - CapturePortList: []string{atePortNamelist[7]}, - EncapHeaderOuterIPList: []string{}, - EncapHeaderInnerIPList: []string{ipv4InnerDst}, - TrafficDestIP: ipv4InnerDst, - LoadBalancePercent: []float64{0, 0, 0, 0, 0, 0, 1}, - TestID: "primaryBackupRoutingAll", - }, { - Desc: "Test-7: no match in encap VRF", - DownPortList: []string{}, - CapturePortList: []string{atePortNamelist[7]}, - EncapHeaderOuterIPList: []string{}, - EncapHeaderInnerIPList: []string{noMatchEncapDest}, - TrafficDestIP: noMatchEncapDest, - LoadBalancePercent: []float64{0, 0, 0, 0, 0, 0, 1}, - TestID: "encapNoMatch", - }, - } - - return cases -} - -// awaitTimeout calls a fluent client Await, adding a timeout to the context. -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) -}