From 5c53baecb19b1f796d7244d79d2e9e4a1fa8e81a Mon Sep 17 00:00:00 2001 From: sunilprgit Date: Thu, 30 May 2024 14:34:20 +0530 Subject: [PATCH 1/7] Adding missing otg verification and script fix (#3016) * adding missing otg verification and script fix * fix readme validation * fix readme validation --- .../otg_tests/link_bandwidth_test/README.md | 74 ++++--- .../link_bandwidth_test.go | 195 ++++++++++++------ 2 files changed, 163 insertions(+), 106 deletions(-) diff --git a/feature/experimental/bgp/otg_tests/link_bandwidth_test/README.md b/feature/experimental/bgp/otg_tests/link_bandwidth_test/README.md index 22ad233b580..5705fd88f82 100644 --- a/feature/experimental/bgp/otg_tests/link_bandwidth_test/README.md +++ b/feature/experimental/bgp/otg_tests/link_bandwidth_test/README.md @@ -143,45 +143,41 @@ bandwidth communities to routes based on a prefix match. * Other implementations consider value 0 invalid or not having link-bandwidth. These implementations create ECMP group with all routes including this one, and ignores link-bandwidth of all members - distribute traffic equally. * This policy intention is to overcome this implementation difference, by deprefering (LocPref) routes with link-bandwidth 0 (only this routes) to prevent them becoming part of multipath, and remove link-bandwidth community so route will not be treated with WCMP behavior. -## Config Parameter Coverage - -## Configuration to enable advertise communities to bgp peer - -* /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/config/send-community - -### Policy for community-set configuration - -* /routing-policy/defined-sets/bgp-defined-sets/ext-community-sets/ext-community-set/config/ext-community-set-name -* /routing-policy/defined-sets/bgp-defined-sets/ext-community-sets/ext-community-set/config/community-member - -### Policy action configuration - -* /routing-policy/policy-definitions/policy-definition/config/name -* /routing-policy/policy-definitions/policy-definition/statements/statement/config/name -* /routing-policy/policy-definitions/policy-definition/statements/statement/actions/config/policy-result -* /routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/set-ext-community/config/options -* /routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/set-community/config/method -* /routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/set-ext-community/reference/config/ext-community-set-refs -* /routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/config/set-local-pref - - -### Policy for community-set match configuration - -* /routing-policy/policy-definitions/policy-definition/statements/statement/conditions/bgp-conditions/match-ext-community-set/config/community-set -* /routing-policy/policy-definitions/policy-definition/statements/statement/conditions/bgp-conditions/match-ext-community-set/config/match-set-options - -### Policy attachment point configuration - -* /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/apply-policy/config/import-policy -* /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/apply-policy/config/export-policy -* /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/apply-policy/config/import-policy -* /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/apply-policy/config/export-policy - -## Telemetry Parameter Coverage - -* /network-instances/network-instance/protocols/protocol/bgp/rib/afi-safis/afi-safi/ipv4-unicast/neighbors/neighbor/adj-rib-in-post/routes/route/state/ext-community-index -* /network-instances/network-instance/protocols/protocol/bgp/rib/afi-safis/afi-safi/ipv6-unicast/neighbors/neighbor/adj-rib-in-post/routes/route/state/ext-community-index - +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths intended to be covered by this test. OC paths used for test setup are not listed here. + +```yaml +paths: + ## Config Parameter Coverage + ## Configuration to enable advertise communities to bgp peer + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/config/send-community: + ## Policy for community-set configuration + /routing-policy/defined-sets/bgp-defined-sets/ext-community-sets/ext-community-set/config/ext-community-set-name: + /routing-policy/defined-sets/bgp-defined-sets/ext-community-sets/ext-community-set/config/ext-community-member: + ## Policy action configuration + /routing-policy/policy-definitions/policy-definition/config/name: + /routing-policy/policy-definitions/policy-definition/statements/statement/config/name: + /routing-policy/policy-definitions/policy-definition/statements/statement/actions/config/policy-result: + /routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/set-ext-community/config/options: + /routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/set-community/config/method: + /routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/set-ext-community/reference/config/ext-community-set-refs: + /routing-policy/policy-definitions/policy-definition/statements/statement/actions/bgp-actions/config/set-local-pref: + ## Policy for community-set match configuration + /routing-policy/policy-definitions/policy-definition/statements/statement/conditions/bgp-conditions/match-ext-community-set/config/ext-community-set: + /routing-policy/policy-definitions/policy-definition/statements/statement/conditions/bgp-conditions/match-ext-community-set/config/match-set-options: + ## Policy attachment point configuration + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/apply-policy/config/import-policy: + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/apply-policy/config/export-policy: + /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/apply-policy/config/import-policy: + /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/apply-policy/config/export-policy: + ## Telemetry Parameter Coverage + /network-instances/network-instance/protocols/protocol/bgp/rib/afi-safis/afi-safi/ipv4-unicast/neighbors/neighbor/adj-rib-in-post/routes/route/state/ext-community-index: + /network-instances/network-instance/protocols/protocol/bgp/rib/afi-safis/afi-safi/ipv6-unicast/neighbors/neighbor/adj-rib-in-post/routes/route/state/ext-community-index: +rpcs: + gnmi: + gNMI.Subscribe: +``` ## Minimum DUT Required vRX - Virtual Router Device diff --git a/feature/experimental/bgp/otg_tests/link_bandwidth_test/link_bandwidth_test.go b/feature/experimental/bgp/otg_tests/link_bandwidth_test/link_bandwidth_test.go index a45aaefada9..dddf7f24868 100644 --- a/feature/experimental/bgp/otg_tests/link_bandwidth_test/link_bandwidth_test.go +++ b/feature/experimental/bgp/otg_tests/link_bandwidth_test/link_bandwidth_test.go @@ -15,6 +15,8 @@ package link_bandwidth_test import ( + "strconv" + "strings" "testing" "time" @@ -32,29 +34,36 @@ import ( ) const ( - ipv4PrefixLen = 30 - ipv6PrefixLen = 126 - v41Route = "203.0.113.0" - v41TrafficStart = "203.0.113.1" - v42Route = "203.0.114.0" - v42TrafficStart = "203.0.114.1" - v43Route = "203.0.115.0" - v43TrafficStart = "203.0.115.1" - v4RoutePrefix = uint32(24) - v61Route = "2001:db8:128:128::0" - v61TrafficStart = "2001:db8:128:128::1" - v62Route = "2001:db8:128:129::0" - v62TrafficStart = "2001:db8:128:129::1" - v63Route = "2001:db8:128:130::0" - v63TrafficStart = "2001:db8:128:130::1" - v6RoutePrefix = uint32(64) - dutAS = uint32(65656) - ateAS = uint32(65657) - bgpName = "BGP" - maskLenExact = "exact" - localPref = 200 - v4Flow = "flow-v4" - v6Flow = "flow-v6" + ipv4PrefixLen = 30 + ipv6PrefixLen = 126 + v41Route = "203.0.113.0" + v41TrafficStart = "203.0.113.1" + v42Route = "203.0.114.0" + v42TrafficStart = "203.0.114.1" + v43Route = "203.0.115.0" + v43TrafficStart = "203.0.115.1" + v4RoutePrefix = uint32(24) + v61Route = "2001:db8:128:128::0" + v61RouteOtg = "2001:db8:128:128::" + v61RouteAdvertise = "2001:db8:128:128::/64" + v61TrafficStart = "2001:db8:128:128::1" + v62Route = "2001:db8:128:129::0" + v62RouteAdvertise = "2001:db8:128:129::/64" + v62RouteOtg = "2001:db8:128:129::" + v62TrafficStart = "2001:db8:128:129::1" + v63Route = "2001:db8:128:130::0" + v63RouteAdvertise = "2001:db8:128:130::/64" + v63RouteOtg = "2001:db8:128:130::" + v63TrafficStart = "2001:db8:128:130::1" + v6RoutePrefix = uint32(64) + dutAS = uint32(65656) + ateAS = uint32(65657) + bgpName = "BGP" + maskLenExact = "exact" + localPref = 200 + v4Flow = "flow-v4" + v6Flow = "flow-v6" + localPerfCfg = 5 ) var ( @@ -99,12 +108,14 @@ var ( advertisedIPv62 = ipAddr{address: v62Route, prefix: v6RoutePrefix} advertisedIPv63 = ipAddr{address: v63Route, prefix: v6RoutePrefix} extCommunitySet = map[string]string{ - "linkbw_0": "link-bandwidth:100:0", - "linkbw_1M": "link-bandwidth:100:1M", - "inkbw_2G": "link-bandwidth:100:2G", + "linkbw_0": "link-bandwidth:100:0", + "linkbw_1M": "link-bandwidth:100:1M", + "linkbw_2G": "link-bandwidth:100:2G", + "linkbw_any": "^link-bandwidth:.*:.$", + "linkbw_any_0": "^link-bandwidth:.*:0$", + } + CommunitySet = map[string]string{ "regex_match_comm100": "^100:.*$", - "linkbw_any": "^link-bandwidth:.*:.$", - "linkbw_any_0": "^link-bandwidth:.*:0$", } ) @@ -282,19 +293,34 @@ func validateRouteCommunityV4Prefix(t *testing.T, td testData, community, v4Pref t.Logf("Prefix recevied on OTG is correct, got Address %s, want prefix %v", bgpPrefix.GetAddress(), v4Prefix) switch community { case "none": - if len(bgpPrefix.Community) != 0 { - t.Fatalf("community is not empty it should be none") + if len(bgpPrefix.Community) != 0 || len(bgpPrefix.ExtendedCommunity) != 0 { + t.Errorf("community and ext communituy are not empty it should be none") + } + if localPerf && bgpPrefix.GetLocalPreference() != localPerfCfg && bgpPrefix.GetAddress() == v43Route { + t.Errorf("local preference is not %d got %d", localPerfCfg, bgpPrefix.GetLocalPreference()) } case "100:100": for _, gotCommunity := range bgpPrefix.Community { t.Logf("community AS:%d val: %d", gotCommunity.GetCustomAsNumber(), gotCommunity.GetCustomAsValue()) - if gotCommunity.GetCustomAsNumber() != 100 && gotCommunity.GetCustomAsValue() != 100 { - t.Fatalf("community is not 100:100 got AS number:%d AS value:%d", gotCommunity.GetCustomAsNumber(), gotCommunity.GetCustomAsValue()) + if gotCommunity.GetCustomAsNumber() != 100 || gotCommunity.GetCustomAsValue() != 100 { + t.Errorf("community is not 100:100 got AS number:%d AS value:%d", gotCommunity.GetCustomAsNumber(), gotCommunity.GetCustomAsValue()) } } default: - // TODO Verification as OTG not supported for Extended community/ - t.Logf("TODO: https://github.com/open-traffic-generator/snappi/issues/220 Verification as OTG not supported for Extended community") + for _, ec := range bgpPrefix.ExtendedCommunity { + lbSubType := ec.Structured.NonTransitive_2OctetAsType.LinkBandwidthSubtype + listCommunity := strings.Split(community, ":") + Bandwidth := listCommunity[2] + if Bandwidth == "0" { + if lbSubType.GetGlobal_2ByteAs() != 100 || ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 0 { + t.Errorf("ERROR lb AS want 100, got :%d, Bandwidth want 0, got:=%v", lbSubType.GetGlobal_2ByteAs(), ygot.BinaryToFloat32(lbSubType.GetBandwidth())) + } + } else { + if lbSubType.GetGlobal_2ByteAs() != 100 || ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 2000000000 { + t.Errorf("ERROR lb AS want 100, got :%d, Bandwidth want :2G, got=%v", lbSubType.GetGlobal_2ByteAs(), ygot.BinaryToFloat32(lbSubType.GetBandwidth())) + } + } + } if deviations.BgpExtendedCommunityIndexUnsupported(td.dut) { verifyExtCommunityIndexV4(t, td, v4Prefix) } @@ -306,9 +332,9 @@ func validateRouteCommunityV4Prefix(t *testing.T, td testData, community, v4Pref func validateRouteCommunityV6(t *testing.T, td testData, ec extCommunity, localPerf bool) { prefixes := map[string]string{ - v61Route: ec.prefixSet1Comm, - v62Route: ec.prefixSet2Comm, - v63Route: ec.prefixSet3Comm, + v61RouteOtg: ec.prefixSet1Comm, + v62RouteOtg: ec.prefixSet2Comm, + v63RouteOtg: ec.prefixSet3Comm, } for prefix, community := range prefixes { validateRouteCommunityV6Prefix(t, td, community, prefix, localPerf) @@ -330,23 +356,37 @@ func validateRouteCommunityV6Prefix(t *testing.T, td testData, community, v6Pref bgpPrefixes := gnmi.GetAll(t, td.ate.OTG(), gnmi.OTG().BgpPeer(td.otgP2.Name()+".BGP6.peer").UnicastIpv6PrefixAny().State()) for _, bgpPrefix := range bgpPrefixes { if bgpPrefix.GetAddress() == v6Prefix { - t.Logf("Prefix recevied on OTG is correct, got prefix:%v , want prefix %v", bgpPrefix, v6Prefix) + t.Logf("Prefix recevied on OTG is correct, got prefix:%v , want prefix %v", bgpPrefix.GetAddress(), v6Prefix) switch community { case "none": - if len(bgpPrefix.Community) != 0 { - t.Fatalf("community is not empty it should be none") + if len(bgpPrefix.Community) != 0 || len(bgpPrefix.ExtendedCommunity) != 0 { + t.Errorf("community and ext community are not empty it should be none") + } + if localPerf && bgpPrefix.GetLocalPreference() != localPerfCfg { + t.Errorf("local preference is not %d got %d", localPerfCfg, bgpPrefix.GetLocalPreference()) } case "100:100": for _, gotCommunity := range bgpPrefix.Community { t.Logf("community AS:%d val: %d", gotCommunity.GetCustomAsNumber(), gotCommunity.GetCustomAsValue()) - if gotCommunity.GetCustomAsNumber() != 100 && gotCommunity.GetCustomAsValue() != 100 { - t.Fatalf("community is not 100:100 got AS number:%d AS value:%d", gotCommunity.GetCustomAsNumber(), gotCommunity.GetCustomAsValue()) + if gotCommunity.GetCustomAsNumber() != 100 || gotCommunity.GetCustomAsValue() != 100 { + t.Errorf("community is not 100:100 got AS number:%d AS value:%d", gotCommunity.GetCustomAsNumber(), gotCommunity.GetCustomAsValue()) } } default: - - // TODO Verification as OTG not supported for Extended community. - t.Logf("TODO: https://github.com/open-traffic-generator/snappi/issues/220 Verification as OTG not supported for Extended community") + for _, ec := range bgpPrefix.ExtendedCommunity { + lbSubType := ec.Structured.NonTransitive_2OctetAsType.LinkBandwidthSubtype + listCommunity := strings.Split(community, ":") + Bandwidth := listCommunity[2] + if Bandwidth == "0" { + if lbSubType.GetGlobal_2ByteAs() != 100 || ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 0 { + t.Errorf("ERROR lb AS want 100, got :%d, Bandwidth want 0, got:=%v", lbSubType.GetGlobal_2ByteAs(), ygot.BinaryToFloat32(lbSubType.GetBandwidth())) + } + } else { + if lbSubType.GetGlobal_2ByteAs() != 100 || ygot.BinaryToFloat32(lbSubType.GetBandwidth()) != 2000000000 { + t.Errorf("ERROR lb AS want 100, got :%d, Bandwidth want :2G, got=%v", lbSubType.GetGlobal_2ByteAs(), ygot.BinaryToFloat32(lbSubType.GetBandwidth())) + } + } + } if deviations.BgpExtendedCommunityIndexUnsupported(td.dut) { verifyExtCommunityIndexV6(t, td, v6Prefix) } @@ -400,12 +440,11 @@ func validateImportRoutingPolicyAllowAll(t *testing.T, dut *ondatra.DUTDevice, a bgpRIBPath := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Rib() locRib := gnmi.Get[*oc.NetworkInstance_Protocol_Bgp_Rib_AfiSafi_Ipv4Unicast_LocRib](t, dut, bgpRIBPath. AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Ipv4Unicast().LocRib().State()) - found := 0 expected := map[string]bool{ - advertisedIPv41.address: true, - advertisedIPv42.address: true, - advertisedIPv43.address: true, + advertisedIPv41.address + "/" + strconv.Itoa(int(advertisedIPv41.prefix)): true, + advertisedIPv42.address + "/" + strconv.Itoa(int(advertisedIPv42.prefix)): true, + advertisedIPv43.address + "/" + strconv.Itoa(int(advertisedIPv43.prefix)): true, } for route, prefix := range locRib.Route { if expected[prefix.GetPrefix()] { @@ -414,7 +453,7 @@ func validateImportRoutingPolicyAllowAll(t *testing.T, dut *ondatra.DUTDevice, a } } if found != len(expected) { - t.Errorf("Not all V4 routes found. expected:%d got:%d", len(expected), found) + t.Fatalf("Not all V4 routes found. expected:%d got:%d", len(expected), found) } // Verify ipv6 policy. @@ -428,9 +467,9 @@ func validateImportRoutingPolicyAllowAll(t *testing.T, dut *ondatra.DUTDevice, a locRibv6 := gnmi.Get[*oc.NetworkInstance_Protocol_Bgp_Rib_AfiSafi_Ipv6Unicast_LocRib](t, dut, bgpRIBPathV6.AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Ipv6Unicast().LocRib().State()) found = 0 expectedV6 := map[string]bool{ - advertisedIPv61.address: true, - advertisedIPv62.address: true, - advertisedIPv63.address: true, + v61RouteAdvertise: true, + v62RouteAdvertise: true, + v63RouteAdvertise: true, } for route, prefix := range locRibv6.Route { if expectedV6[prefix.GetPrefix()] { @@ -439,7 +478,7 @@ func validateImportRoutingPolicyAllowAll(t *testing.T, dut *ondatra.DUTDevice, a } } if found != len(expectedV6) { - t.Errorf("Not all v6 Routes found expected:%d got:%d", len(expectedV6), found) + t.Fatalf("Not all v6 Routes found expected: %d got: %d", len(expectedV6), found) } } @@ -455,6 +494,18 @@ func configureExtCommunityRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice) { stmt.SetExtCommunityMember([]string{community}) gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) } + for name, community := range CommunitySet { + rp := root.GetOrCreateRoutingPolicy() + pdef := rp.GetOrCreateDefinedSets().GetOrCreateBgpDefinedSets() + stmt, err := pdef.NewCommunitySet(name) + if err != nil { + t.Fatalf("NewCommunitySet failed: %v", err) + } + cs := []oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union{} + cs = append(cs, oc.UnionString(community)) + stmt.SetCommunityMember(cs) + gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) + } // Configure routing policy link bandwidth zero. rpSetLinkBwZero := root.GetOrCreateRoutingPolicy() @@ -464,7 +515,7 @@ func configureExtCommunityRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice) { t.Fatalf("AppendNewStatement zero_linkbw failed: %v", err) } ref := pdef1Stmt1.GetOrCreateActions().GetOrCreateBgpActions().GetOrCreateSetExtCommunity() - ref.GetOrCreateReference().SetExtCommunitySetRef("linkbw_0") + ref.GetOrCreateReference().SetExtCommunitySetRefs([]string{"linkbw_0"}) ref.SetOptions(oc.BgpPolicy_BgpSetCommunityOptionType_ADD) ref.SetMethod(oc.SetCommunity_Method_REFERENCE) pdef1Stmt1.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_NEXT_STATEMENT) @@ -483,11 +534,14 @@ func configureExtCommunityRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice) { t.Fatalf("AppendNewStatement 1-megabit-match failed: %v", err) } ref = pdef2Stmt1.GetOrCreateActions().GetOrCreateBgpActions().GetOrCreateSetExtCommunity() - ref.GetOrCreateReference().SetExtCommunitySetRef("linkbw_1M") + ref.GetOrCreateReference().SetExtCommunitySetRefs([]string{"linkbw_1M"}) ref.SetOptions(oc.BgpPolicy_BgpSetCommunityOptionType_ADD) - ref1 := pdef2Stmt1.GetOrCreateConditions().GetOrCreateBgpConditions().GetMatchExtCommunitySet() - ref1.SetExtCommunitySet("regex_match_comm100") - ref1.SetMatchSetOptions(oc.RoutingPolicy_MatchSetOptionsType_INVERT) + ref.SetMethod(oc.SetCommunity_Method_REFERENCE) + if !deviations.BGPConditionsMatchCommunitySetUnsupported(dut) { + ref1 := pdef2Stmt1.GetOrCreateConditions().GetOrCreateBgpConditions().GetOrCreateMatchCommunitySet() + ref1.SetCommunitySet("regex_match_comm100") + ref1.SetMatchSetOptions(oc.RoutingPolicy_MatchSetOptionsType_INVERT) + } pdef2Stmt1.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_NEXT_STATEMENT) pdef2Stmt2, err := pdef2.AppendNewStatement("accept_all_routes") if err != nil { @@ -504,11 +558,14 @@ func configureExtCommunityRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice) { t.Fatalf("AppendNewStatement match_100_set_linkbw_2G failed: %v", err) } ref = pdef3Stmt1.GetOrCreateActions().GetOrCreateBgpActions().GetOrCreateSetExtCommunity() - ref.GetOrCreateReference().SetExtCommunitySetRef("linkbw_2G") + ref.GetOrCreateReference().SetExtCommunitySetRefs([]string{"linkbw_2G"}) ref.SetOptions(oc.BgpPolicy_BgpSetCommunityOptionType_ADD) - ref1 = pdef3Stmt1.GetOrCreateConditions().GetOrCreateBgpConditions().GetMatchExtCommunitySet() - ref1.SetExtCommunitySet("regex_match_comm100") - ref1.SetMatchSetOptions(oc.RoutingPolicy_MatchSetOptionsType_ANY) + ref.SetMethod(oc.SetCommunity_Method_REFERENCE) + if !deviations.BGPConditionsMatchCommunitySetUnsupported(dut) { + ref1 := pdef3Stmt1.GetOrCreateConditions().GetOrCreateBgpConditions().GetMatchCommunitySet() + ref1.SetCommunitySet("regex_match_comm100") + ref1.SetMatchSetOptions(oc.RoutingPolicy_MatchSetOptionsType_ANY) + } pdef3Stmt1.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_NEXT_STATEMENT) pdef3Stmt2, err := pdef3.AppendNewStatement("accept_all_routes") if err != nil { @@ -525,7 +582,7 @@ func configureExtCommunityRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice) { t.Fatalf("AppendNewStatement del_linkbw failed: %v", err) } ref = pdef4Stmt1.GetOrCreateActions().GetOrCreateBgpActions().GetOrCreateSetExtCommunity() - ref.GetOrCreateReference().SetExtCommunitySetRef("linkbw_any") + ref.GetOrCreateReference().SetExtCommunitySetRefs([]string{"linkbw_any"}) ref.SetOptions(oc.BgpPolicy_BgpSetCommunityOptionType_REMOVE) ref.SetMethod(oc.SetCommunity_Method_REFERENCE) pdef4Stmt1.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_NEXT_STATEMENT) @@ -544,17 +601,20 @@ func configureExtCommunityRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice) { t.Fatalf("AppendNewStatement match_and_remove_linkbw_any_0 failed: %v", err) } ref = pdef5Stmt1.GetOrCreateActions().GetOrCreateBgpActions().GetOrCreateSetExtCommunity() - ref.GetOrCreateReference().SetExtCommunitySetRef("linkbw_any_0") + ref.GetOrCreateReference().SetExtCommunitySetRefs([]string{"linkbw_any_0"}) ref.SetOptions(oc.BgpPolicy_BgpSetCommunityOptionType_REMOVE) ref.SetMethod(oc.SetCommunity_Method_REFERENCE) - ref1 = pdef5Stmt1.GetOrCreateConditions().GetOrCreateBgpConditions().GetMatchExtCommunitySet() - ref1.SetExtCommunitySet("linkbw_any_0") + if !deviations.BGPConditionsMatchCommunitySetUnsupported(dut) { + ref1 := pdef5Stmt1.GetOrCreateConditions().GetOrCreateBgpConditions().GetMatchExtCommunitySet() + ref1.SetExtCommunitySet("linkbw_any_0") + } pdef5Stmt1.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_NEXT_STATEMENT) pdef5Stmt1.GetOrCreateActions().GetOrCreateBgpActions().SetLocalPref = ygot.Uint32(5) pdef5Stmt2, err := pdef5.AppendNewStatement("accept_all_routes") if err != nil { t.Fatalf("AppendNewStatement accept_all_routes failed: %v", err) } + pdef5Stmt2.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE) gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rpMatchLB0Perf5) } @@ -644,6 +704,7 @@ func (td *testData) advertiseRoutesWithEBGP(t *testing.T) { nV61.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) nV62 := bgp.GetOrCreateNeighbor(atePort2.IPv6) nV62.SetPeerAs(dutAS) + nV62.SetSendCommunity(oc.Bgp_CommunityType_BOTH) nV62.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) gnmi.Update(t, td.dut, gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(td.dut)).Config(), ni) From 0eed7ad5d1807173a2b16c682624f6e036440ecf Mon Sep 17 00:00:00 2001 From: anksaiki Date: Thu, 30 May 2024 12:44:48 -0400 Subject: [PATCH 2/7] Update zr tunable parameters test plan and fix test (#3038) * Update zr tunable parameters test plan and fix test * update readme * update readme * update readme * update readme * update readme * update readme * update readme --- .../zr_tunable_parameters_test/README.md | 200 ++++++++++-------- .../zr_tunable_parameters_test.go | 6 +- 2 files changed, 115 insertions(+), 91 deletions(-) diff --git a/feature/platform/transceiver/tests/zr_tunable_parameters_test/README.md b/feature/platform/transceiver/tests/zr_tunable_parameters_test/README.md index b396ae4612d..0e47ff590d9 100644 --- a/feature/platform/transceiver/tests/zr_tunable_parameters_test/README.md +++ b/feature/platform/transceiver/tests/zr_tunable_parameters_test/README.md @@ -1,76 +1,78 @@ -# TRANSCEIVER-5: Configuration: 400ZR channel frequency, output TX launch power and operational mode setting. +# TRANSCEIVER-5: Configuration: 400ZR channel frequency, output TX launch power and operational mode setting. ## Summary -Validate setting 400ZR tunable parameters channel frequency, output TX -launch power and operational mode and verify corresponding telemetry values. +Validate setting 400ZR tunable parameters channel frequency, output TX launch +power and operational mode and verify corresponding telemetry values. ### Goals -* Verify full C band frequency tunability for 100GHz line system grid. -* Verify full C band frequency tunability for 75GHz line system grid. -* Verify adjustable range of transmit output power across -13 to -9 dBm - in steps of 1 dB. -* Verify that the ZR module Host Interface ID and Media Interface ID - combination to ZR module AppSel mapping can be configured through the OC - `operational-mode`. `operational-mode` is a construct in OpenConfig that masks - features related to line port transmission. OC operational modes provides a - platform-defined summary of information such as symbol rate, modulation, - pulse shaping, etc. + +* Verify full C band frequency tunability for 100GHz line system grid. +* Verify full C band frequency tunability for 75GHz line system grid. +* Verify adjustable range of transmit output power across -13 to -9 dBm in + steps of 1 dB. +* Verify that the ZR module Host Interface ID and Media Interface ID + combination to ZR module AppSel mapping can be configured through the OC + `operational-mode`. `operational-mode` is a construct in OpenConfig that + masks features related to line port transmission. OC operational modes + provides a platform-defined summary of information such as symbol rate, + modulation, pulse shaping, etc. **Note** For standard ZR, OIF 400ZR with C-FEC is the default mode however as we move to 400ZR++ and 800ZR, optic AppSel code would need to be configured explicitly through OC operational mode. - ## TRANSCEIVER-5.1 -* Connect two ZR interfaces using a duplex LC fiber jumper such that TX - output power of one is the RX input power of the other module. Connection - between the modules should pass through an optical switch that can be - controlled through automation to simulate a fiber cut. +* Connect two ZR interfaces using a duplex LC fiber jumper such that TX output + power of one is the RX input power of the other module. Connection between + the modules should pass through an optical switch that can be controlled + through automation to simulate a fiber cut. * To establish a point to point ZR link ensure the following: - * Both transceivers states are enabled. - * Validate setting 400ZR optics module tunable laser center frequency + + * Both transceivers states are enabled. + * Validate setting 400ZR optics module tunable laser center frequency across frequency range 196.100 - 191.400 THz for 100GHz grid. - * Validate setting 400ZR optics module tunable laser center frequency - across frequency range 196.100 - 191.375 THz for 75GHz grid. - * Specific frequency details can be found in 400ZR implementation + * Validate setting 400ZR optics module tunable laser center frequency + across frequency range 196.100 - 191.375 THz for 75GHz grid. + * Specific frequency details can be found in 400ZR implementation agreement under sections 15.1 ad 15.2 Operating frequency channel definitions. Link to IA below, - * https://www.oiforum.com/wp-content/uploads/OIF-400ZR-01.0_reduced2.pdf - * Validate adjustable range of transmit output power across -13 to -9 dBm + * https://www.oiforum.com/wp-content/uploads/OIF-400ZR-01.0_reduced2.pdf + * Validate adjustable range of transmit output power across -13 to -9 dBm range in steps of 1dB. So the module’s output power will be set to -13, -12, -11, -10, -9 dBm in each step. As an example this can be validated - for the module's default frequency of 193.1 THz. + for the module's default frequency of 193.1 THz. * With the ZR link established as explained above, for each configured - frequency and TX output power value verify that the following ZR - transceiver telemetry paths exist and are streamed for both the ZR optics. - * Frequency + frequency and TX output power value verify that the following ZR transceiver + telemetry paths exist and are streamed for both the ZR optics. + + * Frequency * /components/component/optical-channel/state/frequency * /components/component/optical-channel/state/carrier-frequency-offset/instant * /components/component/optical-channel/state/carrier-frequency-offset/avg * /components/component/optical-channel/state/carrier-frequency-offset/min * /components/component/optical-channel/state/carrier-frequency-offset/max - * TX Output Power + * TX Output Power * /components/component/optical-channel/state/output-power/instant * /components/component/optical-channel/state/output-power/avg * /components/component/optical-channel/state/output-power/min * /components/component/optical-channel/state/output-power/max - * Operational Mode + * Operational Mode * /components/component/optical-channel/state/operational-mode -* With above streamed data verify - * For each center frequency, laser frequency offset should not be more than - +/- 1.8 GHz max. - * For each center frequency, streamed value should be in Mhz units. Test - should fail if the streamed value is in Hz or THz units. As an example - 193.1 THz would be 193100000 in MHz. - * When set to a specific target output power, transmit power control - absolute accuracy should be within +/- 1 dBm of the target value. - * For reported data check for validity: min <= avg/instant <= max - - +* With above streamed data verify + + * For each center frequency, laser frequency offset should not be more + than +/- 1.8 GHz max. + * For each center frequency, streamed value should be in Mhz units. Test + should fail if the streamed value is in Hz or THz units. As an example + 193.1 THz would be 193100000 in MHz. + * When set to a specific target output power, transmit power control + absolute accuracy should be within +/- 1 dBm of the target value. + * For reported data check for validity: min <= avg/instant <= max + ## TRANSCEIVER-5.2 * When the modules or the devices are still in a boot stage, they must not @@ -90,8 +92,8 @@ explicitly through OC operational mode. * Verify the ZR optics frequency and TX output power telemetry values are set in the normal range. * Disable or shut down the interface on the DUT. - * Verify with interfaces in down state both optics are streaming uint 0 - value for frequency. + * 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. * Re-enable the interfaces on the DUT. @@ -99,13 +101,14 @@ explicitly through OC operational mode. power as per the configuration and related telemetry values are updated to the value in the normal range again. -* With above test also verify - * Laser frequency offset should not be more than +/- 1.8 GHz max from the - configured centre frequency. - * When set to a specific target output power, transmit power control - absolute accuracy should be within +/- 1 dBm of the target configured - output power. - * For reported data check for validity: min <= avg/instant <= max +* With above test also verify + + * Laser frequency offset should not be more than +/- 1.8 GHz max from the + configured centre frequency. + * When set to a specific target output power, transmit power control + absolute accuracy should be within +/- 1 dBm of the target configured + output power. + * For reported data check for validity: min <= avg/instant <= max ## TRANSCEIVER-5.4 @@ -117,44 +120,65 @@ explicitly through OC operational mode. in the normal range. * Simulate a fiber cut using the optical switch that sits in-between the DUT ports. - * Verify with link in down state due to fiber cut both optics are streaming - uint64 for frequency and decimal64 for TX output power. + * Verify with link in down state due to fiber cut both optics are + streaming uint64 for frequency and decimal64 for TX output power. * Re-enable the optical switch connection to clear the fiber cut fault. * Verify the ZR optics is able to stay tuned to the correct frequency and TX output power as per the configuration. -* With above test also verify - * Laser frequency offset should not be more than +/- 1.8 GHz max from the - configured centre frequency. - * When set to a specific target output power, transmit power control - absolute accuracy should be within +/- 1 dBm of the target configured - output power. - * For reported data check for validity: min <= avg/instant <= max - -**Note:** For min, max, and avg values, 10 second sampling is preferred. If - 10 seconds is not supported, the sampling interval used must be - communicated. - -## Config Parameter coverage - -* /components/component/transceiver/config/enabled -* /components/component/optical-channel/config/frequency -* /components/component/optical-channel/config/target-output-power -* /components/component/optical-channel/config/operational-mode - -## Telemetry Parameter coverage - -* Frequency - * /components/component/optical-channel/state/frequency - * /components/component/optical-channel/state/carrier-frequency-offset/instant - * /components/component/optical-channel/state/carrier-frequency-offset/avg - * /components/component/optical-channel/state/carrier-frequency-offset/min - * /components/component/optical-channel/state/carrier-frequency-offset/max -* TX Output Power - * /components/component/optical-channel/state/output-power/instant - * /components/component/optical-channel/state/output-power/avg - * /components/component/optical-channel/state/output-power/min - * /components/component/optical-channel/state/output-power/max -* Operational Mode - * /components/component/optical-channel/config/operational-mode - * /components/component/optical-channel/state/operational-mode \ No newline at end of file +* With above test also verify + + * Laser frequency offset should not be more than +/- 1.8 GHz max from the + configured centre frequency. + * When set to a specific target output power, transmit power control + absolute accuracy should be within +/- 1 dBm of the target configured + output power. + * For reported data check for validity: min <= avg/instant <= max + +**Note:** For min, max, and avg values, 10 second sampling is preferred. If 10 +seconds is not supported, the sampling interval used must be communicated. + +## OpenConfig Path and RPC Coverage + +```yaml +paths: + /components/component/transceiver/config/enabled: + platform_type: ["TRANSCEIVER"] + /components/component/optical-channel/config/frequency: + platform_type: ["OPTICAL_CHANNEL"] + /components/component/optical-channel/config/target-output-power: + platform_type: ["OPTICAL_CHANNEL"] + /components/component/optical-channel/config/operational-mode: + platform_type: ["OPTICAL_CHANNEL"] + /components/component/optical-channel/state/frequency: + platform_type: ["OPTICAL_CHANNEL"] + /components/component/optical-channel/state/carrier-frequency-offset/instant: + platform_type: ["OPTICAL_CHANNEL"] + /components/component/optical-channel/state/carrier-frequency-offset/avg: + platform_type: ["OPTICAL_CHANNEL"] + /components/component/optical-channel/state/carrier-frequency-offset/min: + platform_type: ["OPTICAL_CHANNEL"] + /components/component/optical-channel/state/carrier-frequency-offset/max: + platform_type: ["OPTICAL_CHANNEL"] + /components/component/optical-channel/state/output-power/instant: + platform_type: ["OPTICAL_CHANNEL"] + /components/component/optical-channel/state/output-power/avg: + platform_type: ["OPTICAL_CHANNEL"] + /components/component/optical-channel/state/output-power/min: + platform_type: ["OPTICAL_CHANNEL"] + /components/component/optical-channel/state/output-power/max: + platform_type: ["OPTICAL_CHANNEL"] + /components/component/optical-channel/state/operational-mode: + platform_type: ["OPTICAL_CHANNEL"] + +rpcs: + gnmi: + gNMI.Set: + replace: true + gNMI.Subscribe: + on_change: true +``` + +## Required DUT platform + +FFF diff --git a/feature/platform/transceiver/tests/zr_tunable_parameters_test/zr_tunable_parameters_test.go b/feature/platform/transceiver/tests/zr_tunable_parameters_test/zr_tunable_parameters_test.go index 04c40b069f1..fe01013e2be 100644 --- a/feature/platform/transceiver/tests/zr_tunable_parameters_test/zr_tunable_parameters_test.go +++ b/feature/platform/transceiver/tests/zr_tunable_parameters_test/zr_tunable_parameters_test.go @@ -182,12 +182,12 @@ func Test400ZRInterfaceFlap(t *testing.T) { // Disable or shut down the interface on the DUT. gnmi.Replace(t, dut, gnmi.OC().Interface(p1.Name()).Enabled().Config(), false) gnmi.Replace(t, dut, gnmi.OC().Interface(p2.Name()).Enabled().Config(), false) - // Verify with interfaces in down state both optics are streaming uint 0 - // value for frequency. + // 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}, 0, -40) + validateOpticsTelemetry(t, []*samplestream.SampleStream[*oc.Component]{streamOC1, streamOC2}, frequency, -40) }) // Re-enable the interfaces on the DUT. gnmi.Replace(t, dut, gnmi.OC().Interface(p1.Name()).Enabled().Config(), true) From 3c6216896f6f134f6b4fa32333dbba903cbafec5 Mon Sep 17 00:00:00 2001 From: prinikasn <117314826+prinikasn@users.noreply.github.com> Date: Thu, 30 May 2024 10:53:06 -0700 Subject: [PATCH 3/7] update ZR tests (#3034) * update ZR tests * update README * update README * update readme * fix readme * update readme * update readme * fix readme * update * update * update * update * update * fix import * updatE * update * updatE * update --- .../README.md | 25 +++-- .../metadata.textproto | 10 ++ .../zr_fec_uncorrectable_frames_test.go | 41 +++++---- .../tests/zr_low_power_mode_test/README.md | 56 ++++++++---- .../zr_low_power_mode_test/metadata.textproto | 10 ++ .../zr_low_power_mode_test.go | 47 +++++----- .../tests/zr_supply_voltage_test/README.md | 40 ++++---- .../zr_supply_voltage_test/metadata.textproto | 10 ++ .../zr_supply_voltage_test.go | 58 +++--------- internal/cfgplugins/interface.go | 91 +++++++++++++++++++ 10 files changed, 251 insertions(+), 137 deletions(-) create mode 100644 internal/cfgplugins/interface.go diff --git a/feature/platform/transceiver/tests/zr_fec_uncorrectable_frames_test/README.md b/feature/platform/transceiver/tests/zr_fec_uncorrectable_frames_test/README.md index 751768fde32..49966402fd2 100644 --- a/feature/platform/transceiver/tests/zr_fec_uncorrectable_frames_test/README.md +++ b/feature/platform/transceiver/tests/zr_fec_uncorrectable_frames_test/README.md @@ -29,11 +29,20 @@ This is a post-FEC decoder error metric. verify relevant FEC uncorrectable frame count is streamed. If there are no errors a value of 0 should be streamed for no FEC uncorrectable frames. -## Config Parameter coverage - -* /components/component/transceiver/config/enabled -* /interfaces/interface/config/enabled - -## Telemetry Parameter coverage - -* /terminal-device/logical-channels/channel/otn/state/fec-uncorrectable-blocks +## OpenConfig Path and RPC Coverage + +```yaml +paths: + # Config Parameter coverage + /interfaces/interface/config/enabled: + /components/component/transceiver/config/enabled: + platform_type: ["OPTICAL_CHANNEL"] + # Telemetry Parameter coverage + /terminal-device/logical-channels/channel/otn/state/fec-uncorrectable-blocks: + +rpcs: + gnmi: + gNMI.Get: + gNMI.Set: + gNMI.Subscribe: +``` \ No newline at end of file diff --git a/feature/platform/transceiver/tests/zr_fec_uncorrectable_frames_test/metadata.textproto b/feature/platform/transceiver/tests/zr_fec_uncorrectable_frames_test/metadata.textproto index 5c9c9aea535..501d2cce28f 100644 --- a/feature/platform/transceiver/tests/zr_fec_uncorrectable_frames_test/metadata.textproto +++ b/feature/platform/transceiver/tests/zr_fec_uncorrectable_frames_test/metadata.textproto @@ -5,3 +5,13 @@ uuid: "6f9059c8-e49c-4ff6-8bd2-f474cd4fcfce" plan_id: "TRANSCEIVER-10" description: "Telemetry: 400ZR Optics FEC(Forward Error Correction) Uncorrectable Frames Streaming." testbed: TESTBED_DUT_400ZR +platform_exceptions: { + platform: { + vendor: ARISTA + } + deviations: { + interface_enabled: true + default_network_instance: "default" + missing_port_to_optical_channel_component_mapping: true + } +} diff --git a/feature/platform/transceiver/tests/zr_fec_uncorrectable_frames_test/zr_fec_uncorrectable_frames_test.go b/feature/platform/transceiver/tests/zr_fec_uncorrectable_frames_test/zr_fec_uncorrectable_frames_test.go index 2779d56a4d6..590fa814e86 100644 --- a/feature/platform/transceiver/tests/zr_fec_uncorrectable_frames_test/zr_fec_uncorrectable_frames_test.go +++ b/feature/platform/transceiver/tests/zr_fec_uncorrectable_frames_test/zr_fec_uncorrectable_frames_test.go @@ -20,18 +20,18 @@ import ( "testing" "time" + "github.com/openconfig/featureprofiles/internal/cfgplugins" "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" + "github.com/openconfig/ygot/ygot" ) const ( - sampleInterval = 10 * time.Second - targetOutputPowerdBm = -10 - targetFrequencyHz = 193100000 - intUpdateTime = 2 * time.Minute + sampleInterval = 10 * time.Second + intUpdateTime = 2 * time.Minute ) func TestMain(m *testing.M) { @@ -57,33 +57,34 @@ func validateFecUncorrectableBlocks(t *testing.T, stream *samplestream.SampleStr func TestZrUncorrectableFrames(t *testing.T) { dut := ondatra.DUT(t, "dut") + cfgplugins.InterfaceConfig(t, dut, dut.Port(t, "port1")) + cfgplugins.InterfaceConfig(t, dut, dut.Port(t, "port2")) for _, port := range []string{"port1", "port2"} { t.Run(fmt.Sprintf("Port:%s", port), func(t *testing.T) { dp := dut.Port(t, "port1") gnmi.Await(t, dut, gnmi.OC().Interface(dp.Name()).OperStatus().State(), intUpdateTime, oc.Interface_OperStatus_UP) - // Derive transceiver names from ports. - tr := gnmi.Get(t, dut, gnmi.OC().Interface(dp.Name()).Transceiver().State()) - component := gnmi.OC().Component(tr) - - outputPower := gnmi.Get(t, dut, component.OpticalChannel().TargetOutputPower().State()) - if outputPower != targetOutputPowerdBm { - t.Fatalf("Output power does not match target output power, got: %v want :%v", outputPower, targetOutputPowerdBm) - } - - frequency := gnmi.Get(t, dut, component.OpticalChannel().Frequency().State()) - if frequency != targetFrequencyHz { - t.Fatalf("Frequency does not match target frequency, got: %v want :%v", frequency, targetFrequencyHz) - } - streamFec := samplestream.New(t, dut, gnmi.OC().TerminalDevice().Channel(0).Otn().FecUncorrectableBlocks().State(), sampleInterval) defer streamFec.Close() validateFecUncorrectableBlocks(t, streamFec) // Toggle interface enabled - gnmi.Update(t, dut, gnmi.OC().Interface(dp.Name()).Enabled().Config(), bool(false)) - gnmi.Update(t, dut, gnmi.OC().Interface(dp.Name()).Enabled().Config(), bool(true)) + d := &oc.Root{} + i := d.GetOrCreateInterface(dp.Name()) + i.Type = oc.IETFInterfaces_InterfaceType_ethernetCsmacd + + // Disable interface + i.Enabled = ygot.Bool(false) + gnmi.Replace(t, dut, gnmi.OC().Interface(dp.Name()).Config(), i) + // Wait for the cooling off period + gnmi.Await(t, dut, gnmi.OC().Interface(dp.Name()).OperStatus().State(), intUpdateTime, oc.Interface_OperStatus_DOWN) + + // Enable interface + i.Enabled = ygot.Bool(true) + gnmi.Replace(t, dut, gnmi.OC().Interface(dp.Name()).Config(), i) + // Wait for the cooling off period + gnmi.Await(t, dut, gnmi.OC().Interface(dp.Name()).OperStatus().State(), intUpdateTime, oc.Interface_OperStatus_UP) validateFecUncorrectableBlocks(t, streamFec) }) diff --git a/feature/platform/transceiver/tests/zr_low_power_mode_test/README.md b/feature/platform/transceiver/tests/zr_low_power_mode_test/README.md index 912a137f5a2..c3403986887 100644 --- a/feature/platform/transceiver/tests/zr_low_power_mode_test/README.md +++ b/feature/platform/transceiver/tests/zr_low_power_mode_test/README.md @@ -94,21 +94,41 @@ Once the ZR link is estabished proceed with the following: stream any invalid string values like "nil" or "-inf" until valid values are available for streaming. -## Config Parameter coverage - -* /interfaces/interface/config/enabled - -## Telemetry Parameter coverage - -* /platform/components/component/state/serial-no -* /platform/components/component/state/part-no -* /platform/components/component/state/type -* /platform/components/component/state/description -* /platform/components/component/state/mfg-name -* /platform/components/component/state/mfg-date -* /platform/components/component/state/hardware-version -* /platform/components/component/state/firmware-version -* /components/component/optical-channel/state/output-power/instant -* /components/component/optical-channel/state/output-power/avg -* /components/component/optical-channel/state/output-power/min -* /components/component/optical-channel/state/output-power/max \ No newline at end of file +## OpenConfig Path and RPC Coverage + +```yaml +paths: + # Configure parameter + /interfaces/interface/config/enabled: + # Telemetry Parameter coverage + /components/component/state/serial-no: + platform_type: ["OPTICAL_CHANNEL"] + /components/component/state/part-no: + platform_type: ["OPTICAL_CHANNEL"] + /components/component/state/type: + platform_type: ["OPTICAL_CHANNEL"] + /components/component/state/description: + platform_type: ["OPTICAL_CHANNEL"] + /components/component/state/mfg-name: + platform_type: ["OPTICAL_CHANNEL"] + /components/component/state/mfg-date: + platform_type: ["OPTICAL_CHANNEL"] + /components/component/state/hardware-version: + platform_type: ["OPTICAL_CHANNEL"] + /components/component/state/firmware-version: + platform_type: ["OPTICAL_CHANNEL"] + /components/component/optical-channel/state/output-power/instant: + platform_type: ["OPTICAL_CHANNEL"] + /components/component/optical-channel/state/output-power/avg: + platform_type: ["OPTICAL_CHANNEL"] + /components/component/optical-channel/state/output-power/min: + platform_type: ["OPTICAL_CHANNEL"] + /components/component/optical-channel/state/output-power/max: + platform_type: ["OPTICAL_CHANNEL"] + +rpcs: + gnmi: + gNMI.Get: + gNMI.Set: + gNMI.Subscribe: +``` \ No newline at end of file diff --git a/feature/platform/transceiver/tests/zr_low_power_mode_test/metadata.textproto b/feature/platform/transceiver/tests/zr_low_power_mode_test/metadata.textproto index 8236fb587cf..011a0b7bb63 100644 --- a/feature/platform/transceiver/tests/zr_low_power_mode_test/metadata.textproto +++ b/feature/platform/transceiver/tests/zr_low_power_mode_test/metadata.textproto @@ -5,3 +5,13 @@ uuid: "92fbb383-47b3-40e6-ab33-77be99e450b3" plan_id: "TRANSCEIVER-13" description: "Configuration: 400ZR Transceiver Low Power Mode Setting." testbed: TESTBED_DUT_400ZR +platform_exceptions: { + platform: { + vendor: ARISTA + } + deviations: { + interface_enabled: true + default_network_instance: "default" + missing_port_to_optical_channel_component_mapping: true + } +} diff --git a/feature/platform/transceiver/tests/zr_low_power_mode_test/zr_low_power_mode_test.go b/feature/platform/transceiver/tests/zr_low_power_mode_test/zr_low_power_mode_test.go index 4d655bdd815..b8bdc687167 100644 --- a/feature/platform/transceiver/tests/zr_low_power_mode_test/zr_low_power_mode_test.go +++ b/feature/platform/transceiver/tests/zr_low_power_mode_test/zr_low_power_mode_test.go @@ -16,23 +16,22 @@ package zr_low_power_mode_test import ( "fmt" - "math" "reflect" "testing" "time" + "github.com/openconfig/featureprofiles/internal/cfgplugins" "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" + "github.com/openconfig/ygot/ygot" ) const ( - samplingInterval = 10 * time.Second - targetOutputPowerdBm = -10 - targetOutputPowerTolerancedBm = 1 - targetFrequencyHz = 193100000 - targetFrequencyToleranceHz = 100000 + samplingInterval = 10 * time.Second + intUpdateTime = 2 * time.Minute ) func TestMain(m *testing.M) { @@ -81,16 +80,16 @@ func validateOutputPower(t *testing.T, streams map[string]*samplestream.SampleSt func TestLowPowerMode(t *testing.T) { dut := ondatra.DUT(t, "dut") + cfgplugins.InterfaceConfig(t, dut, dut.Port(t, "port1")) + cfgplugins.InterfaceConfig(t, dut, dut.Port(t, "port2")) for _, port := range []string{"port1", "port2"} { t.Run(fmt.Sprintf("Port:%s", port), func(t *testing.T) { dp := dut.Port(t, port) - - gnmi.Update(t, dut, gnmi.OC().Interface(dp.Name()).Enabled().Config(), bool(false)) + gnmi.Await(t, dut, gnmi.OC().Interface(dp.Name()).OperStatus().State(), intUpdateTime, oc.Interface_OperStatus_UP) // Derive transceiver names from ports. tr := gnmi.Get(t, dut, gnmi.OC().Interface(dp.Name()).Transceiver().State()) - // Stream all inventory information. streamSerialNo := samplestream.New(t, dut, gnmi.OC().Component(tr).SerialNo().State(), samplingInterval) defer streamSerialNo.Close() @@ -120,6 +119,17 @@ func TestLowPowerMode(t *testing.T) { } validateStreamOutput(t, allStream) + d := &oc.Root{} + i := d.GetOrCreateInterface(dp.Name()) + i.Type = oc.IETFInterfaces_InterfaceType_ethernetCsmacd + // Disable interface + i.Enabled = ygot.Bool(false) + gnmi.Replace(t, dut, gnmi.OC().Interface(dp.Name()).Config(), i) + // Wait for interface to go down. + gnmi.Await(t, dut, gnmi.OC().Interface(dp.Name()).OperStatus().State(), intUpdateTime, oc.Interface_OperStatus_DOWN) + + validateStreamOutput(t, allStream) + opInst := samplestream.New(t, dut, gnmi.OC().Component(tr).OpticalChannel().OutputPower().Instant().State(), samplingInterval) defer opInst.Close() if opInstN := opInst.Next(); opInstN != nil { @@ -152,7 +162,10 @@ func TestLowPowerMode(t *testing.T) { } } - gnmi.Update(t, dut, gnmi.OC().Interface(dp.Name()).Enabled().Config(), bool(true)) + // Enable interface + i.Enabled = ygot.Bool(true) + gnmi.Replace(t, dut, gnmi.OC().Interface(dp.Name()).Config(), i) + gnmi.Await(t, dut, gnmi.OC().Interface(dp.Name()).OperStatus().State(), intUpdateTime, oc.Interface_OperStatus_UP) powerStreamMap := map[string]*samplestream.SampleStream[float64]{ "inst": opInst, @@ -162,19 +175,7 @@ func TestLowPowerMode(t *testing.T) { } validateOutputPower(t, powerStreamMap) - - // Derive transceiver names from ports. - component := gnmi.OC().Component(tr) - - outputPower := gnmi.Get(t, dut, component.OpticalChannel().TargetOutputPower().State()) - if math.Abs(float64(outputPower)-float64(targetOutputPowerdBm)) > targetOutputPowerTolerancedBm { - t.Fatalf("Output power is not within expected tolerance, got: %v want: %v tolerance: %v", outputPower, targetOutputPowerdBm, targetOutputPowerTolerancedBm) - } - - frequency := gnmi.Get(t, dut, component.OpticalChannel().Frequency().State()) - if math.Abs(float64(frequency)-float64(targetFrequencyHz)) > targetFrequencyToleranceHz { - t.Fatalf("Frequency is not within expected tolerance, got: %v want: %v tolerance: %v", frequency, targetFrequencyHz, targetFrequencyToleranceHz) - } + cfgplugins.ValidateInterfaceConfig(t, dut, dp) }) } } diff --git a/feature/platform/transceiver/tests/zr_supply_voltage_test/README.md b/feature/platform/transceiver/tests/zr_supply_voltage_test/README.md index 84092157f21..7624af5654c 100644 --- a/feature/platform/transceiver/tests/zr_supply_voltage_test/README.md +++ b/feature/platform/transceiver/tests/zr_supply_voltage_test/README.md @@ -24,28 +24,16 @@ https://www.oiforum.com/wp-content/uploads/CMIS5p0_Third_Party_Spec.pdf ports to a second DUT2. For most tests this setup should be sufficient. Ref: [Typical ATE<>DUT Test bed](https://github.com/openconfig/featureprofiles/blob/main/topologies/atedut_2.testbed) * A and Z ends of the link should have same 400ZR PMD. For this test a - single DUT ZR port connected to a single ZR ATE port is also sufficient. + single DUT ZR port connected to a single ZR ATE port is also sufficient. Once the ZR link is estabished proceed with the following: * verify that the following ZR transceiver telemetry paths exist and are streamed for both the ZR optics. * /components/component/transceiver/state/supply-voltage/instant - * /components/component/transceiver/state/supply-voltage/min - * /components/component/transceiver/state/supply-voltage/max - * /components/component/transceiver/state/supply-voltage/avg -* For reported data check for validity min <= avg/instant <= max * If the modules or the devices are in a boot stage, they must not stream any invalid string values like "nil" or "-inf". * Reported supply voltage value must always be of type decimal64. - - -**Note:** For min, max, and avg values, 10 second sampling is preferred. If the - min, max average values or the 10 seconds sampling is not supported, - the sampling interval used must be specified and this must be - captured by adding a deviation to the test. - - * Verify the module supply voltage is reported correctly with optics interface in disabled state. @@ -58,13 +46,19 @@ Once the ZR link is estabished proceed with the following: any invalid string values like "nil" or "-inf". * Reported supply voltage value must always be of type decimal64. -## Config Parameter coverage - -* /interfaces/interface/config/enabled - -## Telemetry Parameter coverage - - * /components/component/transceiver/state/supply-voltage/instant - * /components/component/transceiver/state/supply-voltage/min - * /components/component/transceiver/state/supply-voltage/max - * /components/component/transceiver/state/supply-voltage/avg \ No newline at end of file +## OpenConfig Path and RPC Coverage + +```yaml +paths: + # Config Parameter coverage + /interfaces/interface/config/enabled: + # Telemetry Parameter coverage + /components/component/transceiver/state/supply-voltage/instant: + platform_type: ["OPTICAL_CHANNEL"] + +rpcs: + gnmi: + gNMI.Get: + gNMI.Set: + gNMI.Subscribe: +``` \ No newline at end of file diff --git a/feature/platform/transceiver/tests/zr_supply_voltage_test/metadata.textproto b/feature/platform/transceiver/tests/zr_supply_voltage_test/metadata.textproto index c645ec9f682..ce02315ba93 100644 --- a/feature/platform/transceiver/tests/zr_supply_voltage_test/metadata.textproto +++ b/feature/platform/transceiver/tests/zr_supply_voltage_test/metadata.textproto @@ -5,3 +5,13 @@ uuid: "7e0251e4-8c5c-4dff-9683-8c21c817816c" plan_id: "TRANSCEIVER-12" description: "Telemetry: 400ZR Transceiver Supply Voltage streaming." testbed: TESTBED_DUT_400ZR +platform_exceptions: { + platform: { + vendor: ARISTA + } + deviations: { + interface_enabled: true + default_network_instance: "default" + missing_port_to_optical_channel_component_mapping: true + } +} diff --git a/feature/platform/transceiver/tests/zr_supply_voltage_test/zr_supply_voltage_test.go b/feature/platform/transceiver/tests/zr_supply_voltage_test/zr_supply_voltage_test.go index 39497170da3..ce9383143a7 100644 --- a/feature/platform/transceiver/tests/zr_supply_voltage_test/zr_supply_voltage_test.go +++ b/feature/platform/transceiver/tests/zr_supply_voltage_test/zr_supply_voltage_test.go @@ -20,18 +20,18 @@ import ( "testing" "time" + "github.com/openconfig/featureprofiles/internal/cfgplugins" "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" + "github.com/openconfig/ygot/ygot" ) const ( - samplingInterval = 10 * time.Second - targetOutputPowerdBm = -10 - targetFrequencyHz = 193100000 - intUpdateTime = 2 * time.Minute + samplingInterval = 10 * time.Second + intUpdateTime = 2 * time.Minute ) func TestMain(m *testing.M) { @@ -57,10 +57,13 @@ func verifyVoltageValue(t *testing.T, pStream *samplestream.SampleStream[float64 func TestZrSupplyVoltage(t *testing.T) { dut := ondatra.DUT(t, "dut") + cfgplugins.InterfaceConfig(t, dut, dut.Port(t, "port1")) + cfgplugins.InterfaceConfig(t, dut, dut.Port(t, "port2")) for _, port := range []string{"port1", "port2"} { t.Run(fmt.Sprintf("Port:%s", port), func(t *testing.T) { dp := dut.Port(t, port) + t.Logf("Port %s", dp.Name()) gnmi.Await(t, dut, gnmi.OC().Interface(dp.Name()).OperStatus().State(), intUpdateTime, oc.Interface_OperStatus_UP) @@ -68,58 +71,23 @@ func TestZrSupplyVoltage(t *testing.T) { tr := gnmi.Get(t, dut, gnmi.OC().Interface(dp.Name()).Transceiver().State()) component := gnmi.OC().Component(tr) - outputPower := gnmi.Get(t, dut, component.OpticalChannel().TargetOutputPower().State()) - if outputPower != targetOutputPowerdBm { - t.Fatalf("Output power does not match target output power, got: %v want :%v", outputPower, targetOutputPowerdBm) - } - - frequency := gnmi.Get(t, dut, component.OpticalChannel().Frequency().State()) - if frequency != targetFrequencyHz { - t.Fatalf("Frequency does not match target frequency, got: %v want :%v", frequency, targetFrequencyHz) - } - streamInst := samplestream.New(t, dut, component.Transceiver().SupplyVoltage().Instant().State(), samplingInterval) defer streamInst.Close() - streamAvg := samplestream.New(t, dut, component.Transceiver().SupplyVoltage().Avg().State(), samplingInterval) - defer streamAvg.Close() - streamMin := samplestream.New(t, dut, component.Transceiver().SupplyVoltage().Min().State(), samplingInterval) - defer streamMin.Close() - streamMax := samplestream.New(t, dut, component.Transceiver().SupplyVoltage().Max().State(), samplingInterval) - defer streamMax.Close() volInst := verifyVoltageValue(t, streamInst, "Instant") t.Logf("Port %s instant voltage: %v", dp.Name(), volInst) - volAvg := verifyVoltageValue(t, streamAvg, "Avg") - t.Logf("Port %s average voltage: %v", dp.Name(), volAvg) - volMin := verifyVoltageValue(t, streamMin, "Min") - t.Logf("Port %s minimum voltage: %v", dp.Name(), volMin) - volMax := verifyVoltageValue(t, streamMax, "Max") - t.Logf("Port %s maximum voltage: %v", dp.Name(), volMax) - - if volAvg >= volMin && volAvg <= volMax { - t.Logf("The average is between the maximum and minimum values") - } else { - t.Fatalf("The average is not between the maximum and minimum values, Avg:%v Max:%v Min:%v", volAvg, volMax, volMin) - } + d := &oc.Root{} + i := d.GetOrCreateInterface(dp.Name()) + i.Type = oc.IETFInterfaces_InterfaceType_ethernetCsmacd + // Disable interface + i.Enabled = ygot.Bool(false) + gnmi.Replace(t, dut, gnmi.OC().Interface(dp.Name()).Config(), i) // Wait for the cooling off period gnmi.Await(t, dut, gnmi.OC().Interface(dp.Name()).OperStatus().State(), intUpdateTime, oc.Interface_OperStatus_DOWN) volInstNew := verifyVoltageValue(t, streamInst, "Instant") t.Logf("Port %s instant voltage after port down: %v", dp.Name(), volInstNew) - volAvgNew := verifyVoltageValue(t, streamAvg, "Avg") - t.Logf("Port %s average voltage after port down: %v", dp.Name(), volAvgNew) - volMinNew := verifyVoltageValue(t, streamMin, "Min") - t.Logf("Port %s minimum voltage after port down: %v", dp.Name(), volMinNew) - volMaxNew := verifyVoltageValue(t, streamMax, "Max") - t.Logf("Port %s maximum voltage after port down: %v", dp.Name(), volMaxNew) - - if volAvgNew >= volMinNew && volAvgNew <= volMaxNew { - t.Logf("The average voltage after port down is between the maximum and minimum values") - } else { - t.Fatalf("The average voltage after port down is not between the maximum and minimum values, Avg:%v Max:%v Min:%v", volAvgNew, volMaxNew, volMinNew) - } }) } - } diff --git a/internal/cfgplugins/interface.go b/internal/cfgplugins/interface.go new file mode 100644 index 00000000000..7567518c89e --- /dev/null +++ b/internal/cfgplugins/interface.go @@ -0,0 +1,91 @@ +// 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 cfgplugins + +import ( + "fmt" + "math" + "testing" + + "github.com/openconfig/featureprofiles/internal/deviations" + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" + "github.com/openconfig/ondatra/gnmi/oc" + "github.com/openconfig/ygot/ygot" +) + +const ( + targetOutputPowerdBm = -10 + targetOutputPowerTolerancedBm = 1 + targetFrequencyMHz = 193100000 + targetFrequencyToleranceMHz = 100000 +) + +// opticalChannelComponentFromPort returns the name of the optical channel component for the given +// port. +func opticalChannelComponentFromPort(t *testing.T, dut *ondatra.DUTDevice, p *ondatra.Port) string { + t.Helper() + if deviations.MissingPortToOpticalChannelMapping(dut) { + transceiverName := gnmi.Get(t, dut, gnmi.OC().Interface(p.Name()).Transceiver().State()) + return fmt.Sprintf("%s-Optical0", transceiverName) + } + compName := gnmi.Get(t, dut, gnmi.OC().Interface(p.Name()).HardwarePort().State()) + for { + comp, ok := gnmi.Lookup(t, dut, gnmi.OC().Component(compName).State()).Val() + if !ok { + t.Fatalf("Recursive optical channel lookup failed for port: %s, component %s not found.", p.Name(), compName) + } + if comp.GetType() == oc.PlatformTypes_OPENCONFIG_HARDWARE_COMPONENT_OPTICAL_CHANNEL { + return compName + } + if comp.GetParent() == "" { + t.Fatalf("Recursive optical channel lookup failed for port: %s, parent of component %s not found.", p.Name(), compName) + } + compName = comp.GetParent() + } +} + +// InterfaceConfig configures the interface with the given port. +func InterfaceConfig(t *testing.T, dut *ondatra.DUTDevice, dp *ondatra.Port) { + t.Helper() + d := &oc.Root{} + i := d.GetOrCreateInterface(dp.Name()) + i.Enabled = ygot.Bool(true) + i.Type = oc.IETFInterfaces_InterfaceType_ethernetCsmacd + gnmi.Replace(t, dut, gnmi.OC().Interface(dp.Name()).Config(), i) + ocComponent := opticalChannelComponentFromPort(t, dut, dp) + t.Logf("Got opticalChannelComponent from port: %s", ocComponent) + gnmi.Replace(t, dut, gnmi.OC().Component(ocComponent).OpticalChannel().Config(), &oc.Component_OpticalChannel{ + TargetOutputPower: ygot.Float64(targetOutputPowerdBm), + Frequency: ygot.Uint64(targetFrequencyMHz), + }) +} + +// ValidateInterfaceConfig validates the output power and frequency for the given port. +func ValidateInterfaceConfig(t *testing.T, dut *ondatra.DUTDevice, dp *ondatra.Port) { + t.Helper() + ocComponent := opticalChannelComponentFromPort(t, dut, dp) + t.Logf("Got opticalChannelComponent from port: %s", ocComponent) + + outputPower := gnmi.Get(t, dut, gnmi.OC().Component(ocComponent).OpticalChannel().TargetOutputPower().State()) + if math.Abs(float64(outputPower)-float64(targetOutputPowerdBm)) > targetOutputPowerTolerancedBm { + t.Fatalf("Output power is not within expected tolerance, got: %v want: %v tolerance: %v", outputPower, targetOutputPowerdBm, targetOutputPowerTolerancedBm) + } + + frequency := gnmi.Get(t, dut, gnmi.OC().Component(ocComponent).OpticalChannel().Frequency().State()) + if math.Abs(float64(frequency)-float64(targetFrequencyMHz)) > targetFrequencyToleranceMHz { + t.Fatalf("Frequency is not within expected tolerance, got: %v want: %v tolerance: %v", frequency, targetFrequencyMHz, targetFrequencyToleranceMHz) + } +} From 7002d516ad1a03b799a8e6ac12c728b6f869f93e Mon Sep 17 00:00:00 2001 From: ihebboubaker <126072465+ihebboubaker@users.noreply.github.com> Date: Thu, 30 May 2024 20:22:49 +0100 Subject: [PATCH 4/7] Create READMEs for RT-1.54: BGP Override AS-path split-horizon (#3011) README for RT-1.54: BGP Override AS-path split-horizon. (allow-own-as) --- .../README.md | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 feature/experimental/bgp/otg_tests/bgp_override_as_path_split_horizon_test/README.md diff --git a/feature/experimental/bgp/otg_tests/bgp_override_as_path_split_horizon_test/README.md b/feature/experimental/bgp/otg_tests/bgp_override_as_path_split_horizon_test/README.md new file mode 100644 index 00000000000..b74ba3fad48 --- /dev/null +++ b/feature/experimental/bgp/otg_tests/bgp_override_as_path_split_horizon_test/README.md @@ -0,0 +1,64 @@ +# RT-1.54: BGP Override AS-path split-horizon + +## Summary + +BGP Override AS-path split-horizon + +## Topology + + ATE Port1 (AS 65502) --- DUT Port1 (AS 65501) DUT Port2 ---eBGP --- ATE Port2 (AS 65503) + +## Procedure + +* Establish BGP Session: Configure and establish an eBGP session between the DUT (Port1) and the ATE (Port1). +* Baseline Test (No "allow-own-in"): + * Advertise a prefix from the ATE (e.g., 192.168.1.0/24) with an AS-path that includes AS 65501 (DUT's AS) in the middle (e.g., AS-path: 65502 65500 65501 65499). + * Verify that the ATE Port2 doesn't receive the route. due to the presence of its own AS in the path. + * Validate session state and capabilities received on DUT using telemetry. +* Test "allow-own-as 1": + * Enable "allow-own-as 1" on the DUT. + * Re-advertise the prefix from the ATE with the same AS-path. + * Verify that the DUT accepts the route. + * Verify that the ATE Port2 receives the route. + * Validate session state and capabilities received on DUT using telemetry. +* Test "allow-own-as 3": + * Change the DUT's configuration to "allow-own-as 3". + * Test with the following AS-path occurrences: + * 1 Occurrence: 65502 65500 65501 65499 + * 3 Occurrences: 65502 65501 65501 65501 65499 + * 4 Occurrences: 65502 65501 65501 65501 65501 65499 (Should be rejected) + * Verify that the ATE Port2 receives the route with 1 and 3 occurrences of AS 65501 but rejects it with 4 occurrences. + * Validate session state and capabilities received on DUT using telemetry. +* Test "allow-own-as 4: + * Change the DUT's configuration to "allow-own-as 4". + * Test with the following AS-path occurrences: + * 1 Occurrence: 65502 65500 65501 65499 + * 3 Occurrences: 65502 65501 65501 65501 65499 + * 4 Occurrences: 65502 65501 65501 65501 65501 65499 + * Verify that the ATE Port2 receives the route with 1, 3 and 4 occurrences of AS 65501. + * Validate session state and capabilities received on DUT using telemetry. + +## OpenConfig Path and RPC Coverage + +The below example yaml defines the OC paths intended to be covered by this test. + +```yaml +paths: + ## Config paths + /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/as-path-options/config/allow-own-as: + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/as-path-options/config/allow-own-as: + + ## State paths + /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/as-path-options/state/allow-own-as: + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/as-path-options/state/allow-own-as: + +rpcs: + gnmi: + gNMI.Set: + gNMI.Subscribe: +``` + +## Minimum DUT platform requirement + +* MFF - A modular form factor device containing LINECARDs, FABRIC and redundant CONTROLLER_CARD components +* FFF - fixed form factor From b01b42d0f2c2392c1e00039e44387302546b0bd7 Mon Sep 17 00:00:00 2001 From: ihebboubaker <126072465+ihebboubaker@users.noreply.github.com> Date: Thu, 30 May 2024 20:25:07 +0100 Subject: [PATCH 5/7] Create Readme for RT-1.55: BGP session mode (active/passive) (#3027) * Create Readme for RT-1.55: BGP session mode (active/passive) --- .../README.md | 46 +++++++++++++++++++ testregistry.textproto | 6 +++ 2 files changed, 52 insertions(+) create mode 100644 feature/bgp/bgp_session_mode_configuration_test/README.md diff --git a/feature/bgp/bgp_session_mode_configuration_test/README.md b/feature/bgp/bgp_session_mode_configuration_test/README.md new file mode 100644 index 00000000000..bba3cecb4d8 --- /dev/null +++ b/feature/bgp/bgp_session_mode_configuration_test/README.md @@ -0,0 +1,46 @@ +# RT-1.55: BGP session mode (active/passive) + +## Summary + +* Validate the correct behavior of BGP session establishment in both active and passive modes. +* Verify the accurate reflection of BGP transport mode in telemetry output. +* Confirm the functionality of passive mode configuration at both the neighbor and peer group levels. + +## Topology + +DUT Port1 (AS 65501) ---eBGP --- ATE Port1 (AS 65502) + +## Procedure + +* Configure both DUT and ATE to operate in BGP passive mode under the neighbor section. +* Verify that the BGP adjacency will not be established. +* Verify the telemetry path output to confirm that the neighbor's BGP transport mode is displayed as "passive for the DUT. +* Configure BGP session on ATE to operate in BGP active mode when interacting with DUT. +* Verify that a BGP adjacency is established between the ATE and DUT +* Verify the telemetry path output to confirm that the neighbor's BGP transport mode is displayed as "passive for the DUT. +* Redo the same above steps but configure the passive mode under the peer group instead of the bgp neighbor configuration. + +## OpenConfig Path and RPC Coverage + +This example yaml defines the OC paths intended to be covered by this test. OC paths used for test environment setup are not required to be listed here. + +```yaml +paths: + ## Config paths + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/transport/config/passive-mode: + /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/transport/config/passive-mode: + + ## State paths + /network-instances/network-instance/protocols/protocol/bgp/neighbors/neighbor/transport/state/passive-mode: + /network-instances/network-instance/protocols/protocol/bgp/peer-groups/peer-group/transport/state/passive-mode: + +rpcs: + gnmi: + gNMI.Set: + gNMI.Subscribe: +``` + +## Minimum DUT platform requirement + +* MFF - A modular form factor device containing LINECARDs, FABRIC and redundant CONTROLLER_CARD components +* FFF - fixed form factor diff --git a/testregistry.textproto b/testregistry.textproto index 2b6bac4785b..92451754997 100644 --- a/testregistry.textproto +++ b/testregistry.textproto @@ -561,6 +561,12 @@ test: { readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/bgp/multipath/otg_tests/bgp_multipath_wecmp_lbw_community_test/README.md" exec: " " } +test: { + id: "RT-1.55" + description: "BGP session mode (active/passive)" + readme: "https://github.com/openconfig/featureprofiles/blob/main/feature/bgp/bgp_session_mode_configuration_test/README.md" + exec: " " +} test: { id: "RT-1.7" description: "Local BGP Test" From 395e37d436357391cf2c83910011a912675e53ec Mon Sep 17 00:00:00 2001 From: yini101 <86263319+yini101@users.noreply.github.com> Date: Thu, 30 May 2024 12:59:44 -0700 Subject: [PATCH 6/7] MGT1: Remove deviation (#3031) Remove deviation Co-authored-by: anksaiki --- .../management/otg_tests/management_ha_test/metadata.textproto | 1 - 1 file changed, 1 deletion(-) 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 683c91c2817..e9db4bd8c9f 100644 --- a/feature/system/management/otg_tests/management_ha_test/metadata.textproto +++ b/feature/system/management/otg_tests/management_ha_test/metadata.textproto @@ -17,7 +17,6 @@ platform_exceptions: { default_network_instance: "default" skip_set_rp_match_set_options: true skip_setting_disable_metric_propagation: true - set_metric_as_preference: true set_no_peer_group: true explicit_enable_bgp_on_default_vrf: true } From 57039f271e6501c973b9ae1eae871754bbab11c2 Mon Sep 17 00:00:00 2001 From: Ram Date: Fri, 31 May 2024 11:09:06 +0530 Subject: [PATCH 7/7] chained-policy deviations (#3042) * chained-policy deviations * fix imports in script and readme * fixed go fmt --- .../otg_tests/chained_policies_test/README.md | 12 +- .../chained_policies_test.go | 311 +++++++++++++----- .../chained_policies_test/metadata.textproto | 15 + internal/deviations/deviations.go | 5 + proto/metadata.proto | 7 +- proto/metadata_go_proto/metadata.pb.go | 96 +++--- 6 files changed, 315 insertions(+), 131 deletions(-) diff --git a/feature/bgp/policybase/otg_tests/chained_policies_test/README.md b/feature/bgp/policybase/otg_tests/chained_policies_test/README.md index eab34543721..4134cc9d86c 100644 --- a/feature/bgp/policybase/otg_tests/chained_policies_test/README.md +++ b/feature/bgp/policybase/otg_tests/chained_policies_test/README.md @@ -256,11 +256,15 @@ For each section of configuration below, prepare a gnmi.SetBatch with all the c * /network-instances/network-instance/protocols/protocol/bgp/rib/afi-safis/afi-safi/ipv4-unicast/loc-rib/routes/route/prefix * /network-instances/network-instance/protocols/protocol/bgp/rib/attr-sets/attr-set/state/med -## Protocol/RPC Parameter Coverage -* gNMI - * Subscribe (ONCE) - * Set (REPLACE) +## OpenConfig Path and RPC Coverage +```yaml +rpcs: + gnmi: + gNMI.Get: + gNMI.Subscribe: + +``` ## Required DUT platform diff --git a/feature/bgp/policybase/otg_tests/chained_policies_test/chained_policies_test.go b/feature/bgp/policybase/otg_tests/chained_policies_test/chained_policies_test.go index a1d1d75183c..2f388556041 100644 --- a/feature/bgp/policybase/otg_tests/chained_policies_test/chained_policies_test.go +++ b/feature/bgp/policybase/otg_tests/chained_policies_test/chained_policies_test.go @@ -17,6 +17,7 @@ package chained_policies_test import ( "fmt" "net" + "strings" "testing" "time" @@ -33,8 +34,6 @@ import ( "github.com/openconfig/ygot/ygot" ) -// go through OKRs - const ( ipv4PrefixLen = 30 ipv6PrefixLen = 126 @@ -263,23 +262,32 @@ func configureImportRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice, operatio } stmt2.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE) stmt2.GetOrCreateActions().GetOrCreateBgpActions().SetSetLocalPref(localPref) - if operation == "set" { - gnmi.BatchReplace(batch, gnmi.OC().RoutingPolicy().Config(), rp) - } else if operation == "delete" { - gnmi.BatchDelete(batch, gnmi.OC().RoutingPolicy().Config()) + if deviations.SkipSettingStatementForPolicy(dut) { + gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) + } else { + if operation == "set" { + gnmi.BatchReplace(batch, gnmi.OC().RoutingPolicy().Config(), rp) + } else if operation == "delete" { + gnmi.BatchDelete(batch, gnmi.OC().RoutingPolicy().Config()) + } } - dni := deviations.DefaultNetworkInstance(dut) path := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort1.IPv4).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).ApplyPolicy() policy := root.GetOrCreateNetworkInstance(dni).GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).GetOrCreateBgp().GetOrCreateNeighbor(atePort1.IPv4).GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).GetOrCreateApplyPolicy() - policy.SetDefaultImportPolicy(oc.RoutingPolicy_DefaultPolicyType_REJECT_ROUTE) + if !deviations.DefaultImportExportPolicy(dut) { + policy.SetDefaultImportPolicy(oc.RoutingPolicy_DefaultPolicyType_REJECT_ROUTE) + } policy.SetImportPolicy([]string{v4PrefixPolicy, v4LPPolicy}) - if operation == "set" { - gnmi.BatchReplace(batch, path.Config(), policy) - } else if operation == "delete" { - gnmi.BatchDelete(batch, path.Config()) + if deviations.SkipSettingStatementForPolicy(dut) { + gnmi.Update(t, dut, path.Config(), policy) + } else { + if operation == "set" { + gnmi.BatchReplace(batch, path.Config(), policy) + } else if operation == "delete" { + gnmi.BatchDelete(batch, path.Config()) + } + batch.Set(t, dut) } - batch.Set(t, dut) } func validateImportRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice, ate *ondatra.ATEDevice) { @@ -287,23 +295,41 @@ func validateImportRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice, ate *onda path := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort1.IPv4).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).ApplyPolicy() policy := gnmi.Get[*oc.NetworkInstance_Protocol_Bgp_Neighbor_AfiSafi_ApplyPolicy](t, dut, path.State()) importPolicies := policy.GetImportPolicy() - if len(importPolicies) != 2 { - t.Errorf("ImportPolicy = %v, want %v", importPolicies, []string{v4PrefixPolicy, v4LPPolicy}) + if !deviations.FlattenPolicyWithMultipleStatements(dut) { + if len(importPolicies) != 2 { + t.Errorf("ImportPolicy = %v, want %v", importPolicies, []string{v4PrefixPolicy, v4LPPolicy}) + } } - if !deviations.BGPRibOcPathUnsupported(dut) { bgpRIBPath := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Rib() locRib := gnmi.Get[*oc.NetworkInstance_Protocol_Bgp_Rib_AfiSafi_Ipv4Unicast_LocRib](t, dut, bgpRIBPath.AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Ipv4Unicast().LocRib().State()) found := false for k, lr := range locRib.Route { - if lr.GetPrefix() == advertisedIPv41.address { + prefixAddr := strings.Split(lr.GetPrefix(), "/") + t.Logf("Route: %v, lr.GetPrefix() -> %v, advertisedIPv41.address: %s, prefixAddr[0]: %s", k, lr.GetPrefix(), advertisedIPv41.address, prefixAddr[0]) + if prefixAddr[0] == advertisedIPv41.address { found = true - t.Logf("Found Route(prefix %s, origin: %v, pathid: %d) => %s", k.Prefix, k.Origin, k.PathId, lr.GetPrefix()) - attrSet := gnmi.Get[*oc.NetworkInstance_Protocol_Bgp_Rib_AttrSet](t, dut, bgpRIBPath.AttrSet(lr.GetAttrIndex()).State()) - if attrSet == nil || attrSet.GetLocalPref() != localPref { - t.Errorf("No local pref found for prefix %s", advertisedIPv41.address) + if !deviations.SkipCheckingAttributeIndex(dut) { + t.Logf("Found Route(prefix %s, origin: %v, pathid: %d) => %s", k.Prefix, k.Origin, k.PathId, lr.GetPrefix()) + attrSet := gnmi.Get[*oc.NetworkInstance_Protocol_Bgp_Rib_AttrSet](t, dut, bgpRIBPath.AttrSet(lr.GetAttrIndex()).State()) + if attrSet == nil || attrSet.GetLocalPref() != localPref { + t.Errorf("No local pref found for prefix %s", advertisedIPv41.address) + } + break + } else { + attrSetList := gnmi.GetAll[*oc.NetworkInstance_Protocol_Bgp_Rib_AttrSet](t, dut, bgpRIBPath.AttrSetAny().State()) + foundLP := false + for _, attrSet := range attrSetList { + if attrSet.GetLocalPref() == localPref { + foundLP = true + t.Logf("Found local pref %d for prefix %s", attrSet.GetLocalPref(), advertisedIPv41.address) + break + } + } + if !foundLP { + t.Errorf("No local pref found for prefix %s", advertisedIPv41.address) + } } - break } } @@ -324,30 +350,55 @@ func configureExportRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice, operatio } stmt1.GetOrCreateActions().GetOrCreateBgpActions().GetOrCreateSetAsPathPrepend().SetAsn(dutAS) - pdef2 := rp.GetOrCreatePolicyDefinition(v4MedPolicy) - stmt2, err := pdef2.AppendNewStatement(v4MedStatement) - if err != nil { - t.Fatalf("AppendNewStatement(%s) failed: %v", v4MedStatement, err) + if deviations.FlattenPolicyWithMultipleStatements(dut) { + stmt2, err := pdef1.AppendNewStatement(v4MedStatement) + stmt2.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE) + stmt2.GetOrCreateActions().GetOrCreateBgpActions().SetSetMed(oc.UnionUint32(med)) + if err != nil { + t.Fatalf("AppendNewStatement(%s) failed: %v", v4MedStatement, err) + } + } else { + pdef2 := rp.GetOrCreatePolicyDefinition(v4MedPolicy) + stmt2, err := pdef2.AppendNewStatement(v4MedStatement) + stmt2.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE) + stmt2.GetOrCreateActions().GetOrCreateBgpActions().SetSetMed(oc.UnionUint32(med)) + if err != nil { + t.Fatalf("AppendNewStatement(%s) failed: %v", v4MedStatement, err) + } } - stmt2.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE) - stmt2.GetOrCreateActions().GetOrCreateBgpActions().SetSetMed(oc.UnionUint32(med)) - if operation == "set" { - gnmi.BatchReplace(batch, gnmi.OC().RoutingPolicy().Config(), rp) - } else if operation == "delete" { - gnmi.BatchDelete(batch, gnmi.OC().RoutingPolicy().Config()) + + if deviations.SkipSettingStatementForPolicy(dut) { + gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) + } else { + if operation == "set" { + gnmi.BatchReplace(batch, gnmi.OC().RoutingPolicy().Config(), rp) + } else if operation == "delete" { + gnmi.BatchDelete(batch, gnmi.OC().RoutingPolicy().Config()) + } } dni := deviations.DefaultNetworkInstance(dut) path := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort1.IPv4).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).ApplyPolicy() policy := root.GetOrCreateNetworkInstance(dni).GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).GetOrCreateBgp().GetOrCreateNeighbor(atePort1.IPv4).GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).GetOrCreateApplyPolicy() - policy.SetDefaultExportPolicy(oc.RoutingPolicy_DefaultPolicyType_REJECT_ROUTE) - policy.SetExportPolicy([]string{v4ASPPolicy, v4MedPolicy}) - if operation == "set" { - gnmi.BatchReplace(batch, path.Config(), policy) - } else if operation == "delete" { - gnmi.BatchDelete(batch, path.Config()) - } - batch.Set(t, dut) + if !deviations.DefaultImportExportPolicy(dut) { + policy.SetDefaultExportPolicy(oc.RoutingPolicy_DefaultPolicyType_REJECT_ROUTE) + } + if deviations.FlattenPolicyWithMultipleStatements(dut) { + policy.SetExportPolicy([]string{v4ASPPolicy}) + } else { + policy.SetExportPolicy([]string{v4ASPPolicy, v4MedPolicy}) + } + if deviations.SkipSettingStatementForPolicy(dut) { + gnmi.Update(t, dut, path.Config(), policy) + } else { + if operation == "set" { + gnmi.BatchReplace(batch, path.Config(), policy) + } else if operation == "delete" { + gnmi.BatchDelete(batch, path.Config()) + } + batch.Set(t, dut) + } + time.Sleep(time.Second * 60) } func validateExportRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice, ate *ondatra.ATEDevice) { @@ -355,20 +406,22 @@ func validateExportRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice, ate *onda path := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort1.IPv4).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).ApplyPolicy() policy := gnmi.Get[*oc.NetworkInstance_Protocol_Bgp_Neighbor_AfiSafi_ApplyPolicy](t, dut, path.State()) exportPolicies := policy.GetExportPolicy() - if len(exportPolicies) != 2 { - t.Errorf("ExportPolicy = %v, want %v", exportPolicies, []string{v4PrefixPolicy, v4LPPolicy}) + if !deviations.FlattenPolicyWithMultipleStatements(dut) { + if len(exportPolicies) != 2 { + t.Errorf("ExportPolicy = %v, want %v", exportPolicies, []string{v4ASPPolicy, v4MedPolicy}) + } } - bgpPrefixes := gnmi.GetAll[*otgtelemetry.BgpPeer_UnicastIpv4Prefix](t, ate.OTG(), gnmi.OTG().BgpPeer("atePort1.BGP4.peer").UnicastIpv4PrefixAny().State()) found := false for _, bgpPrefix := range bgpPrefixes { if bgpPrefix.Address != nil && bgpPrefix.GetAddress() == v42Route && bgpPrefix.PrefixLength != nil && bgpPrefix.GetPrefixLength() == v4RoutePrefix { found = true - t.Logf("Prefix recevied on OTG is correct, got prefix %v, want prefix %v", bgpPrefix, v42Route) + t.Logf("Prefix recevied on OTG is correct, got prefix %v, want prefix %v", bgpPrefix.GetAddress(), v42Route) if bgpPrefix.GetMultiExitDiscriminator() != med { t.Errorf("For Prefix %v, got MED %d want MED %d", bgpPrefix.GetAddress(), bgpPrefix.GetMultiExitDiscriminator(), med) } + t.Logf("For Prefix %v, got MED %d want MED %d", bgpPrefix.GetAddress(), bgpPrefix.GetMultiExitDiscriminator(), med) asPaths := bgpPrefix.AsPath for _, ap := range asPaths { count := 0 @@ -384,7 +437,6 @@ func validateExportRoutingPolicy(t *testing.T, dut *ondatra.DUTDevice, ate *onda break } } - if !found { t.Errorf("No Route found for prefix %s", v42Route) } @@ -417,23 +469,34 @@ func configureImportRoutingPolicyV6(t *testing.T, dut *ondatra.DUTDevice, operat } stmt2.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE) stmt2.GetOrCreateActions().GetOrCreateBgpActions().SetSetLocalPref(localPref) - if operation == "set" { - gnmi.BatchReplace(batch, gnmi.OC().RoutingPolicy().Config(), rp) - } else if operation == "delete" { - gnmi.BatchDelete(batch, gnmi.OC().RoutingPolicy().Config()) + if deviations.SkipSettingStatementForPolicy(dut) { + gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) + } else { + if operation == "set" { + gnmi.BatchReplace(batch, gnmi.OC().RoutingPolicy().Config(), rp) + } else if operation == "delete" { + gnmi.BatchDelete(batch, gnmi.OC().RoutingPolicy().Config()) + } } dni := deviations.DefaultNetworkInstance(dut) path := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort1.IPv6).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).ApplyPolicy() policy := root.GetOrCreateNetworkInstance(dni).GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).GetOrCreateBgp().GetOrCreateNeighbor(atePort1.IPv6).GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).GetOrCreateApplyPolicy() - policy.SetDefaultImportPolicy(oc.RoutingPolicy_DefaultPolicyType_REJECT_ROUTE) + if !deviations.DefaultImportExportPolicy(dut) { + policy.SetDefaultImportPolicy(oc.RoutingPolicy_DefaultPolicyType_REJECT_ROUTE) + } policy.SetImportPolicy([]string{v6PrefixPolicy, v6LPPolicy}) - if operation == "set" { - gnmi.BatchReplace(batch, path.Config(), policy) - } else if operation == "delete" { - gnmi.BatchDelete(batch, path.Config()) + if deviations.SkipSettingStatementForPolicy(dut) { + gnmi.Update(t, dut, path.Config(), policy) + } else { + if operation == "set" { + gnmi.BatchReplace(batch, path.Config(), policy) + } else if operation == "delete" { + gnmi.BatchDelete(batch, path.Config()) + } + batch.Set(t, dut) } - batch.Set(t, dut) + time.Sleep(time.Second * 60) } func validateImportRoutingPolicyV6(t *testing.T, dut *ondatra.DUTDevice, ate *ondatra.ATEDevice) { @@ -441,25 +504,42 @@ func validateImportRoutingPolicyV6(t *testing.T, dut *ondatra.DUTDevice, ate *on path := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort1.IPv6).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).ApplyPolicy() policy := gnmi.Get[*oc.NetworkInstance_Protocol_Bgp_Neighbor_AfiSafi_ApplyPolicy](t, dut, path.State()) importPolicies := policy.GetImportPolicy() - if len(importPolicies) != 2 { - t.Errorf("ImportPolicy = %v, want %v", importPolicies, []string{v6PrefixPolicy, v6LPPolicy}) + if !deviations.FlattenPolicyWithMultipleStatements(dut) { + if len(importPolicies) != 2 { + t.Errorf("ImportPolicy = %v, want %v", importPolicies, []string{v6PrefixPolicy, v6LPPolicy}) + } } if !deviations.BGPRibOcPathUnsupported(dut) { bgpRIBPath := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Rib() locRib := gnmi.Get[*oc.NetworkInstance_Protocol_Bgp_Rib_AfiSafi_Ipv6Unicast_LocRib](t, dut, bgpRIBPath.AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Ipv6Unicast().LocRib().State()) found := false for k, lr := range locRib.Route { - if lr.GetPrefix() == advertisedIPv61.address { + prefixAddr := strings.Split(lr.GetPrefix(), "/") + if prefixAddr[0] == advertisedIPv61.address { found = true t.Logf("Found Route(prefix %s, origin: %v, pathid: %d) => %s", k.Prefix, k.Origin, k.PathId, lr.GetPrefix()) - attrSet := gnmi.Get[*oc.NetworkInstance_Protocol_Bgp_Rib_AttrSet](t, dut, bgpRIBPath.AttrSet(lr.GetAttrIndex()).State()) - if attrSet == nil || attrSet.GetLocalPref() != localPref { - t.Errorf("No local pref found for prefix %s", advertisedIPv61.address) + if !deviations.SkipCheckingAttributeIndex(dut) { + attrSet := gnmi.Get[*oc.NetworkInstance_Protocol_Bgp_Rib_AttrSet](t, dut, bgpRIBPath.AttrSet(lr.GetAttrIndex()).State()) + if attrSet == nil || attrSet.GetLocalPref() != localPref { + t.Errorf("No local pref found for prefix %s", advertisedIPv61.address) + } + break + } else { + attrSetList := gnmi.GetAll[*oc.NetworkInstance_Protocol_Bgp_Rib_AttrSet](t, dut, bgpRIBPath.AttrSetAny().State()) + foundLP := false + for _, attrSet := range attrSetList { + if attrSet.GetLocalPref() == localPref { + foundLP = true + t.Logf("Found local pref %d for prefix %s", attrSet.GetLocalPref(), advertisedIPv61.address) + break + } + } + if !foundLP { + t.Errorf("No local pref found for prefix %s", advertisedIPv61.address) + } } - break } } - if !found { t.Errorf("No Route found for prefix %s", advertisedIPv61.address) } @@ -477,30 +557,54 @@ func configureExportRoutingPolicyV6(t *testing.T, dut *ondatra.DUTDevice, operat } stmt1.GetOrCreateActions().GetOrCreateBgpActions().GetOrCreateSetAsPathPrepend().SetAsn(dutAS) - pdef2 := rp.GetOrCreatePolicyDefinition(v6MedPolicy) - stmt2, err := pdef2.AppendNewStatement(v6MedStatement) - if err != nil { - t.Fatalf("AppendNewStatement(%s) failed: %v", v6MedStatement, err) - } - stmt2.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE) - stmt2.GetOrCreateActions().GetOrCreateBgpActions().SetSetMed(oc.UnionUint32(med)) - if operation == "set" { - gnmi.BatchReplace(batch, gnmi.OC().RoutingPolicy().Config(), rp) - } else if operation == "delete" { - gnmi.BatchDelete(batch, gnmi.OC().RoutingPolicy().Config()) + if deviations.FlattenPolicyWithMultipleStatements(dut) { + stmt2, err := pdef1.AppendNewStatement(v6MedStatement) + if err != nil { + t.Fatalf("AppendNewStatement(%s) failed: %v", v6MedStatement, err) + } + stmt2.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE) + stmt2.GetOrCreateActions().GetOrCreateBgpActions().SetSetMed(oc.UnionUint32(med)) + } else { + pdef2 := rp.GetOrCreatePolicyDefinition(v6MedPolicy) + stmt2, err := pdef2.AppendNewStatement(v6MedStatement) + if err != nil { + t.Fatalf("AppendNewStatement(%s) failed: %v", v6MedStatement, err) + } + stmt2.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE) + stmt2.GetOrCreateActions().GetOrCreateBgpActions().SetSetMed(oc.UnionUint32(med)) + } + if deviations.SkipSettingStatementForPolicy(dut) { + gnmi.Update(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) + } else { + if operation == "set" { + gnmi.BatchReplace(batch, gnmi.OC().RoutingPolicy().Config(), rp) + } else if operation == "delete" { + gnmi.BatchDelete(batch, gnmi.OC().RoutingPolicy().Config()) + } } dni := deviations.DefaultNetworkInstance(dut) path := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort1.IPv6).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).ApplyPolicy() policy := root.GetOrCreateNetworkInstance(dni).GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).GetOrCreateBgp().GetOrCreateNeighbor(atePort1.IPv6).GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).GetOrCreateApplyPolicy() - policy.SetDefaultExportPolicy(oc.RoutingPolicy_DefaultPolicyType_REJECT_ROUTE) - policy.SetExportPolicy([]string{v6ASPPolicy, v6MedPolicy}) - if operation == "set" { - gnmi.BatchReplace(batch, path.Config(), policy) - } else if operation == "delete" { - gnmi.BatchDelete(batch, path.Config()) - } - batch.Set(t, dut) + if !deviations.DefaultImportExportPolicy(dut) { + policy.SetDefaultExportPolicy(oc.RoutingPolicy_DefaultPolicyType_REJECT_ROUTE) + } + if deviations.FlattenPolicyWithMultipleStatements(dut) { + policy.SetExportPolicy([]string{v6ASPPolicy}) + } else { + policy.SetExportPolicy([]string{v6ASPPolicy, v6MedPolicy}) + } + if deviations.SkipSettingStatementForPolicy(dut) { + gnmi.Update(t, dut, path.Config(), policy) + } else { + if operation == "set" { + gnmi.BatchReplace(batch, path.Config(), policy) + } else if operation == "delete" { + gnmi.BatchDelete(batch, path.Config()) + } + batch.Set(t, dut) + } + time.Sleep(time.Second * 60) } func validateExportRoutingPolicyV6(t *testing.T, dut *ondatra.DUTDevice, ate *ondatra.ATEDevice) { @@ -508,8 +612,10 @@ func validateExportRoutingPolicyV6(t *testing.T, dut *ondatra.DUTDevice, ate *on path := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(atePort1.IPv6).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).ApplyPolicy() policy := gnmi.Get[*oc.NetworkInstance_Protocol_Bgp_Neighbor_AfiSafi_ApplyPolicy](t, dut, path.State()) exportPolicies := policy.GetExportPolicy() - if len(exportPolicies) != 2 { - t.Errorf("ExportPolicy = %v, want %v", exportPolicies, []string{v6PrefixPolicy, v6LPPolicy}) + if !deviations.FlattenPolicyWithMultipleStatements(dut) { + if len(exportPolicies) != 2 { + t.Errorf("ExportPolicy = %v, want %v", exportPolicies, []string{v6ASPPolicy, v6MedPolicy}) + } } bgpPrefixes := gnmi.GetAll[*otgtelemetry.BgpPeer_UnicastIpv6Prefix](t, ate.OTG(), gnmi.OTG().BgpPeer("atePort1.BGP6.peer").UnicastIpv6PrefixAny().State()) @@ -519,6 +625,7 @@ func validateExportRoutingPolicyV6(t *testing.T, dut *ondatra.DUTDevice, ate *on bgpPrefix.PrefixLength != nil && bgpPrefix.GetPrefixLength() == v6RoutePrefix { found = true t.Logf("Prefix recevied on OTG is correct, got prefix %v, want prefix %v", bgpPrefix, v62Route) + t.Logf("For Prefix %v, got MED %d want MED %d", bgpPrefix.GetAddress(), bgpPrefix.GetMultiExitDiscriminator(), med) if bgpPrefix.GetMultiExitDiscriminator() != med { t.Errorf("For Prefix %v, got MED %d want MED %d", bgpPrefix.GetAddress(), bgpPrefix.GetMultiExitDiscriminator(), med) } @@ -537,7 +644,6 @@ func validateExportRoutingPolicyV6(t *testing.T, dut *ondatra.DUTDevice, ate *on break } } - if !found { t.Errorf("No Route found for prefix %s", v62Route) } @@ -624,27 +730,60 @@ func (td *testData) advertiseRoutesWithEBGP(t *testing.T) { g.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) g.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) + if deviations.DefaultImportExportPolicy(td.dut) { + t.Logf("Configuring default route-policy for BGP on DUT") + rp := root.GetOrCreateRoutingPolicy() + pdef := rp.GetOrCreatePolicyDefinition("PERMIT-ALL") + stmt, err := pdef.AppendNewStatement("20") + if err != nil { + t.Fatalf("AppendNewStatement(%s) failed: %v", "20", err) + } + stmt.GetOrCreateActions().PolicyResult = oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE + gnmi.Update(t, td.dut, gnmi.OC().RoutingPolicy().Config(), rp) + } pgv4 := bgp.GetOrCreatePeerGroup(peerGrpNamev4) pgv4.PeerGroupName = ygot.String(peerGrpNamev4) pgv6 := bgp.GetOrCreatePeerGroup(peerGrpNamev6) pgv6.PeerGroupName = ygot.String(peerGrpNamev6) + pgv4.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) + pgv6.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) + nV41 := bgp.GetOrCreateNeighbor(atePort1.IPv4) nV41.SetPeerAs(ateAS1) nV41.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) nV41.PeerGroup = ygot.String(peerGrpNamev4) + if deviations.DefaultImportExportPolicy(td.dut) { + afisafiv41 := nV41.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST) + afisafiv41.GetOrCreateApplyPolicy().SetImportPolicy([]string{"PERMIT-ALL"}) + afisafiv41.GetOrCreateApplyPolicy().SetExportPolicy([]string{"PERMIT-ALL"}) + } nV42 := bgp.GetOrCreateNeighbor(atePort2.IPv4) nV42.SetPeerAs(ateAS2) nV42.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).Enabled = ygot.Bool(true) nV42.PeerGroup = ygot.String(peerGrpNamev4) - + if deviations.DefaultImportExportPolicy(td.dut) { + afisafiv42 := nV42.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST) + afisafiv42.GetOrCreateApplyPolicy().SetImportPolicy([]string{"PERMIT-ALL"}) + afisafiv42.GetOrCreateApplyPolicy().SetExportPolicy([]string{"PERMIT-ALL"}) + } nV61 := bgp.GetOrCreateNeighbor(atePort1.IPv6) nV61.SetPeerAs(ateAS1) nV61.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) nV61.PeerGroup = ygot.String(peerGrpNamev6) + if deviations.DefaultImportExportPolicy(td.dut) { + afisafiv61 := nV61.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST) + afisafiv61.GetOrCreateApplyPolicy().SetImportPolicy([]string{"PERMIT-ALL"}) + afisafiv61.GetOrCreateApplyPolicy().SetExportPolicy([]string{"PERMIT-ALL"}) + } nV62 := bgp.GetOrCreateNeighbor(atePort2.IPv6) nV62.SetPeerAs(ateAS2) nV62.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).Enabled = ygot.Bool(true) nV62.PeerGroup = ygot.String(peerGrpNamev6) + if deviations.DefaultImportExportPolicy(td.dut) { + afisafiv62 := nV62.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST) + afisafiv62.GetOrCreateApplyPolicy().SetImportPolicy([]string{"PERMIT-ALL"}) + afisafiv62.GetOrCreateApplyPolicy().SetExportPolicy([]string{"PERMIT-ALL"}) + } gnmi.Update(t, td.dut, gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(td.dut)).Config(), ni) // configure eBGP on OTG port1 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 11bbfd9320d..2b3e7bedf9a 100644 --- a/feature/bgp/policybase/otg_tests/chained_policies_test/metadata.textproto +++ b/feature/bgp/policybase/otg_tests/chained_policies_test/metadata.textproto @@ -15,6 +15,8 @@ platform_exceptions: { default_network_instance: "default" missing_value_for_defaults: true skip_set_rp_match_set_options: true + default_import_export_policy: false + skip_setting_statement_for_policy: true } } platform_exceptions: { @@ -25,3 +27,16 @@ platform_exceptions: { bgp_rib_oc_path_unsupported: true } } +platform_exceptions: { + platform: { + vendor: CISCO + } + deviations: { + bgp_rib_oc_path_unsupported: true + default_import_export_policy: true + skip_setting_statement_for_policy: true + skip_checking_attribute_index: true + flatten_policy_with_multiple_statements: true + } +} + diff --git a/internal/deviations/deviations.go b/internal/deviations/deviations.go index 2e50868558f..650331af322 100644 --- a/internal/deviations/deviations.go +++ b/internal/deviations/deviations.go @@ -1008,3 +1008,8 @@ func SkipSettingStatementForPolicy(dut *ondatra.DUTDevice) bool { func SkipCheckingAttributeIndex(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetSkipCheckingAttributeIndex() } + +// FlattenPolicyWithMultipleStatements return true if devices does not support policy-chaining +func FlattenPolicyWithMultipleStatements(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetFlattenPolicyWithMultipleStatements() +} diff --git a/proto/metadata.proto b/proto/metadata.proto index 8af8e0f03e6..3264364a028 100644 --- a/proto/metadata.proto +++ b/proto/metadata.proto @@ -18,6 +18,7 @@ package openconfig.testing; import "github.com/openconfig/ondatra/proto/testbed.proto"; + // Metadata about a Feature Profiles test. message Metadata { // UUID of the test. @@ -548,11 +549,15 @@ message Metadata { // wildcards has to be used. // CISCO: b/338523730 bool skip_checking_attribute_index = 188; + // Devices does not suppport policy-chaining, so needs to flatten policies + // with multiple statements. + // CISCO: b/338526243 + bool flatten_policy_with_multiple_statements = 189; // Reserved field numbers and identifiers. reserved 84, 9, 28, 20, 90, 97, 55, 89, 19; } - message PlatformExceptions { + message PlatformExceptions { Platform platform = 1; Deviations deviations = 2; } diff --git a/proto/metadata_go_proto/metadata.pb.go b/proto/metadata_go_proto/metadata.pb.go index 1b1341b09e8..43178dd5a0a 100644 --- a/proto/metadata_go_proto/metadata.pb.go +++ b/proto/metadata_go_proto/metadata.pb.go @@ -830,6 +830,10 @@ type Metadata_Deviations struct { // wildcards has to be used. // CISCO: b/338523730 SkipCheckingAttributeIndex bool `protobuf:"varint,188,opt,name=skip_checking_attribute_index,json=skipCheckingAttributeIndex,proto3" json:"skip_checking_attribute_index,omitempty"` + // Devices does not suppport policy-chaining, so needs to flatten policies + // with multiple statements. + // CISCO: b/338526243 + FlattenPolicyWithMultipleStatements bool `protobuf:"varint,189,opt,name=flatten_policy_with_multiple_statements,json=flattenPolicyWithMultipleStatements,proto3" json:"flatten_policy_with_multiple_statements,omitempty"` } func (x *Metadata_Deviations) Reset() { @@ -2068,6 +2072,13 @@ func (x *Metadata_Deviations) GetSkipCheckingAttributeIndex() bool { return false } +func (x *Metadata_Deviations) GetFlattenPolicyWithMultipleStatements() bool { + if x != nil { + return x.FlattenPolicyWithMultipleStatements + } + return false +} + type Metadata_PlatformExceptions struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2131,7 +2142,7 @@ var file_metadata_proto_rawDesc = []byte{ 0x74, 0x69, 0x6e, 0x67, 0x1a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x6f, 0x6e, 0x64, 0x61, 0x74, 0x72, 0x61, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x62, 0x65, - 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xbf, 0x6a, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x96, 0x6b, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x6c, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x61, 0x6e, 0x49, @@ -2165,7 +2176,7 @@ var file_metadata_proto_rawDesc = []byte{ 0x67, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x67, 0x65, 0x78, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x52, 0x0e, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x5f, - 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x1a, 0x92, 0x62, 0x0a, 0x0a, 0x44, 0x65, 0x76, 0x69, 0x61, 0x74, + 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x1a, 0xe9, 0x62, 0x0a, 0x0a, 0x44, 0x65, 0x76, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x69, 0x70, 0x76, 0x34, 0x5f, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x69, 0x70, 0x76, 0x34, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x45, @@ -2947,44 +2958,49 @@ var file_metadata_proto_rawDesc = []byte{ 0x67, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0xbc, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x73, 0x6b, 0x69, 0x70, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x49, - 0x6e, 0x64, 0x65, 0x78, 0x4a, 0x04, 0x08, 0x54, 0x10, 0x55, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, - 0x4a, 0x04, 0x08, 0x1c, 0x10, 0x1d, 0x4a, 0x04, 0x08, 0x14, 0x10, 0x15, 0x4a, 0x04, 0x08, 0x5a, - 0x10, 0x5b, 0x4a, 0x04, 0x08, 0x61, 0x10, 0x62, 0x4a, 0x04, 0x08, 0x37, 0x10, 0x38, 0x4a, 0x04, - 0x08, 0x59, 0x10, 0x5a, 0x4a, 0x04, 0x08, 0x13, 0x10, 0x14, 0x1a, 0xa0, 0x01, 0x0a, 0x12, 0x50, - 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x45, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x12, 0x41, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, - 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x47, 0x0a, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xfa, 0x01, - 0x0a, 0x07, 0x54, 0x65, 0x73, 0x74, 0x62, 0x65, 0x64, 0x12, 0x17, 0x0a, 0x13, 0x54, 0x45, 0x53, - 0x54, 0x42, 0x45, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, - 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x45, 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x44, 0x55, - 0x54, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x54, 0x45, 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x44, - 0x55, 0x54, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x34, 0x4c, 0x49, 0x4e, 0x4b, 0x53, 0x10, 0x02, 0x12, - 0x1a, 0x0a, 0x16, 0x54, 0x45, 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x41, - 0x54, 0x45, 0x5f, 0x32, 0x4c, 0x49, 0x4e, 0x4b, 0x53, 0x10, 0x03, 0x12, 0x1a, 0x0a, 0x16, 0x54, - 0x45, 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x41, 0x54, 0x45, 0x5f, 0x34, - 0x4c, 0x49, 0x4e, 0x4b, 0x53, 0x10, 0x04, 0x12, 0x1e, 0x0a, 0x1a, 0x54, 0x45, 0x53, 0x54, 0x42, - 0x45, 0x44, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x41, 0x54, 0x45, 0x5f, 0x39, 0x4c, 0x49, 0x4e, 0x4b, - 0x53, 0x5f, 0x4c, 0x41, 0x47, 0x10, 0x05, 0x12, 0x1e, 0x0a, 0x1a, 0x54, 0x45, 0x53, 0x54, 0x42, - 0x45, 0x44, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x41, 0x54, 0x45, 0x5f, 0x32, - 0x4c, 0x49, 0x4e, 0x4b, 0x53, 0x10, 0x06, 0x12, 0x1a, 0x0a, 0x16, 0x54, 0x45, 0x53, 0x54, 0x42, - 0x45, 0x44, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x41, 0x54, 0x45, 0x5f, 0x38, 0x4c, 0x49, 0x4e, 0x4b, - 0x53, 0x10, 0x07, 0x12, 0x15, 0x0a, 0x11, 0x54, 0x45, 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x44, - 0x55, 0x54, 0x5f, 0x34, 0x30, 0x30, 0x5a, 0x52, 0x10, 0x08, 0x22, 0x6d, 0x0a, 0x04, 0x54, 0x61, - 0x67, 0x73, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x41, 0x47, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, - 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x41, 0x47, 0x53, - 0x5f, 0x41, 0x47, 0x47, 0x52, 0x45, 0x47, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x18, - 0x0a, 0x14, 0x54, 0x41, 0x47, 0x53, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x43, 0x45, 0x4e, 0x54, 0x45, - 0x52, 0x5f, 0x45, 0x44, 0x47, 0x45, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x41, 0x47, 0x53, - 0x5f, 0x45, 0x44, 0x47, 0x45, 0x10, 0x03, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x41, 0x47, 0x53, 0x5f, - 0x54, 0x52, 0x41, 0x4e, 0x53, 0x49, 0x54, 0x10, 0x04, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x6e, 0x64, 0x65, 0x78, 0x12, 0x55, 0x0a, 0x27, 0x66, 0x6c, 0x61, 0x74, 0x74, 0x65, 0x6e, 0x5f, + 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x6d, 0x75, 0x6c, 0x74, + 0x69, 0x70, 0x6c, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, + 0xbd, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x23, 0x66, 0x6c, 0x61, 0x74, 0x74, 0x65, 0x6e, 0x50, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x57, 0x69, 0x74, 0x68, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, + 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0x04, 0x08, 0x54, 0x10, + 0x55, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x1c, 0x10, 0x1d, 0x4a, 0x04, 0x08, + 0x14, 0x10, 0x15, 0x4a, 0x04, 0x08, 0x5a, 0x10, 0x5b, 0x4a, 0x04, 0x08, 0x61, 0x10, 0x62, 0x4a, + 0x04, 0x08, 0x37, 0x10, 0x38, 0x4a, 0x04, 0x08, 0x59, 0x10, 0x5a, 0x4a, 0x04, 0x08, 0x13, 0x10, + 0x14, 0x1a, 0xa0, 0x01, 0x0a, 0x12, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x45, 0x78, + 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x41, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, + 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x70, 0x65, + 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, + 0x6d, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x47, 0x0a, 0x0a, 0x64, + 0x65, 0x76, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x27, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x74, 0x65, 0x73, + 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x44, 0x65, + 0x76, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xfa, 0x01, 0x0a, 0x07, 0x54, 0x65, 0x73, 0x74, 0x62, 0x65, 0x64, + 0x12, 0x17, 0x0a, 0x13, 0x54, 0x45, 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, + 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x45, 0x53, + 0x54, 0x42, 0x45, 0x44, 0x5f, 0x44, 0x55, 0x54, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x54, 0x45, + 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x34, 0x4c, + 0x49, 0x4e, 0x4b, 0x53, 0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x54, 0x45, 0x53, 0x54, 0x42, 0x45, + 0x44, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x41, 0x54, 0x45, 0x5f, 0x32, 0x4c, 0x49, 0x4e, 0x4b, 0x53, + 0x10, 0x03, 0x12, 0x1a, 0x0a, 0x16, 0x54, 0x45, 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x44, 0x55, + 0x54, 0x5f, 0x41, 0x54, 0x45, 0x5f, 0x34, 0x4c, 0x49, 0x4e, 0x4b, 0x53, 0x10, 0x04, 0x12, 0x1e, + 0x0a, 0x1a, 0x54, 0x45, 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x41, 0x54, + 0x45, 0x5f, 0x39, 0x4c, 0x49, 0x4e, 0x4b, 0x53, 0x5f, 0x4c, 0x41, 0x47, 0x10, 0x05, 0x12, 0x1e, + 0x0a, 0x1a, 0x54, 0x45, 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x44, 0x55, + 0x54, 0x5f, 0x41, 0x54, 0x45, 0x5f, 0x32, 0x4c, 0x49, 0x4e, 0x4b, 0x53, 0x10, 0x06, 0x12, 0x1a, + 0x0a, 0x16, 0x54, 0x45, 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x41, 0x54, + 0x45, 0x5f, 0x38, 0x4c, 0x49, 0x4e, 0x4b, 0x53, 0x10, 0x07, 0x12, 0x15, 0x0a, 0x11, 0x54, 0x45, + 0x53, 0x54, 0x42, 0x45, 0x44, 0x5f, 0x44, 0x55, 0x54, 0x5f, 0x34, 0x30, 0x30, 0x5a, 0x52, 0x10, + 0x08, 0x22, 0x6d, 0x0a, 0x04, 0x54, 0x61, 0x67, 0x73, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x41, 0x47, + 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, + 0x14, 0x0a, 0x10, 0x54, 0x41, 0x47, 0x53, 0x5f, 0x41, 0x47, 0x47, 0x52, 0x45, 0x47, 0x41, 0x54, + 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x54, 0x41, 0x47, 0x53, 0x5f, 0x44, 0x41, + 0x54, 0x41, 0x43, 0x45, 0x4e, 0x54, 0x45, 0x52, 0x5f, 0x45, 0x44, 0x47, 0x45, 0x10, 0x02, 0x12, + 0x0d, 0x0a, 0x09, 0x54, 0x41, 0x47, 0x53, 0x5f, 0x45, 0x44, 0x47, 0x45, 0x10, 0x03, 0x12, 0x10, + 0x0a, 0x0c, 0x54, 0x41, 0x47, 0x53, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x49, 0x54, 0x10, 0x04, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var (