diff --git a/feature/bgp/policybase/otg_tests/community_test/community_test.go b/feature/bgp/policybase/otg_tests/community_test/community_test.go new file mode 100644 index 00000000000..940e69e8ba6 --- /dev/null +++ b/feature/bgp/policybase/otg_tests/community_test/community_test.go @@ -0,0 +1,290 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// 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 community_test + +import ( + "sort" + "testing" + "time" + + "github.com/open-traffic-generator/snappi/gosnappi" + "github.com/openconfig/featureprofiles/internal/cfgplugins" + "github.com/openconfig/featureprofiles/internal/deviations" + "github.com/openconfig/featureprofiles/internal/fptest" + "github.com/openconfig/featureprofiles/internal/otgutils" + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" + "github.com/openconfig/ondatra/gnmi/oc" +) + +const ( + prefixV4Len = 30 + prefixV6Len = 126 + trafficPps = 100 + totalPackets = 1200 + bgpName = "BGP" +) + +var prefixesV4 = [][]string{ + {"198.51.100.0", "198.51.100.4"}, + {"198.51.100.8", "198.51.100.12"}, + {"198.51.100.16", "198.51.100.20"}, + {"198.51.100.24", "198.51.100.28"}, +} + +var prefixesV6 = [][]string{ + {"2048:db1:64:64::0", "2048:db1:64:64::4"}, + {"2048:db1:64:64::8", "2048:db1:64:64::12"}, + {"2048:db1:64:64::16", "2048:db1:64:64::20"}, + {"2048:db1:64:64::24", "2048:db1:64:64::28"}, +} + +func TestMain(m *testing.M) { + fptest.RunTests(m) +} + +func configureImportBGPPolicy(t *testing.T, dut *ondatra.DUTDevice, ipv4 string, ipv6 string, communitySetName string, communityMatch [3]string, matchSetOptions oc.E_BgpPolicy_MatchSetOptionsType) { + root := &oc.Root{} + rp := root.GetOrCreateRoutingPolicy() + pdef1 := rp.GetOrCreatePolicyDefinition("routePolicy") + stmt1, err := pdef1.AppendNewStatement("routePolicyStatement") + if err != nil { + t.Fatalf("AppendNewStatement(%s) failed: %v", "routePolicyStatement", err) + } + stmt1.GetOrCreateActions().SetPolicyResult(oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE) + + communitySet := rp.GetOrCreateDefinedSets().GetOrCreateBgpDefinedSets().GetOrCreateCommunitySet(communitySetName) + for _, commMatch := range communityMatch { + if commMatch != "" { + communitySet.SetCommunityMember([]oc.RoutingPolicy_DefinedSets_BgpDefinedSets_CommunitySet_CommunityMember_Union{oc.UnionString(commMatch)}) + } + } + communitySet.SetMatchSetOptions(matchSetOptions) + + if deviations.BGPConditionsMatchCommunitySetUnsupported(dut) { + stmt1.GetOrCreateConditions().GetOrCreateBgpConditions().SetCommunitySet(communitySetName) + } else { + stmt1.GetOrCreateConditions().GetOrCreateBgpConditions().GetOrCreateMatchCommunitySet().SetCommunitySet(communitySetName) + } + + gnmi.Replace(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) + + dni := deviations.DefaultNetworkInstance(dut) + pathV6 := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(ipv6).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).ApplyPolicy() + policyV6 := root.GetOrCreateNetworkInstance(dni).GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).GetOrCreateBgp().GetOrCreateNeighbor(ipv6).GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST).GetOrCreateApplyPolicy() + policyV6.SetDefaultImportPolicy(oc.RoutingPolicy_DefaultPolicyType_REJECT_ROUTE) + policyV6.SetImportPolicy([]string{"routePolicy"}) + gnmi.Replace(t, dut, pathV6.Config(), policyV6) + + pathV4 := gnmi.OC().NetworkInstance(dni).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).Bgp().Neighbor(ipv4).AfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).ApplyPolicy() + policyV4 := root.GetOrCreateNetworkInstance(dni).GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, bgpName).GetOrCreateBgp().GetOrCreateNeighbor(ipv4).GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST).GetOrCreateApplyPolicy() + policyV4.SetDefaultImportPolicy(oc.RoutingPolicy_DefaultPolicyType_REJECT_ROUTE) + policyV4.SetImportPolicy([]string{"routePolicy"}) + gnmi.Replace(t, dut, pathV4.Config(), policyV4) +} + +func configureOTG(t *testing.T, bs *cfgplugins.BGPSession, prefixesV4 [][]string, prefixesV6 [][]string, communityMembers [][][]int) { + devices := bs.ATETop.Devices().Items() + byName := func(i, j int) bool { return devices[i].Name() < devices[j].Name() } + sort.Slice(devices, byName) + + ipv4 := devices[1].Ethernets().Items()[0].Ipv4Addresses().Items()[0] + bgp4Peer := devices[1].Bgp().Ipv4Interfaces().Items()[0].Peers().Items()[0] + + bgp4PeerRoute := bgp4Peer.V4Routes().Add() + bgp4PeerRoute.SetName(bs.ATEPorts[1].Name + ".BGP4.peer.dut") + bgp4PeerRoute.SetNextHopIpv4Address(ipv4.Address()) + + ipv6 := devices[1].Ethernets().Items()[0].Ipv6Addresses().Items()[0] + bgp6Peer := devices[1].Bgp().Ipv6Interfaces().Items()[0].Peers().Items()[0] + + bgp6PeerRoute := bgp6Peer.V6Routes().Add() + bgp6PeerRoute.SetName(bs.ATEPorts[1].Name + ".BGP6.peer.dut") + bgp6PeerRoute.SetNextHopIpv6Address(ipv6.Address()) + + for index, prefixes := range prefixesV4 { + route4Address1 := bgp4PeerRoute.Addresses().Add().SetAddress(prefixes[0]) + route4Address1.SetPrefix(prefixV4Len) + route4Address2 := bgp4PeerRoute.Addresses().Add().SetAddress(prefixes[1]) + route4Address2.SetPrefix(prefixV4Len) + + route6Address1 := bgp6PeerRoute.Addresses().Add().SetAddress(prefixesV6[index][0]) + route6Address1.SetPrefix(prefixV6Len) + route6Address2 := bgp6PeerRoute.Addresses().Add().SetAddress(prefixesV6[index][1]) + route6Address2.SetPrefix(prefixV6Len) + + for _, commu := range communityMembers[index] { + if commu[0] != 0 { + commv4 := bgp4PeerRoute.Communities().Add() + commv4.SetType(gosnappi.BgpCommunityType.MANUAL_AS_NUMBER) + commv4.SetAsNumber(uint32(commu[0])) + commv4.SetAsCustom(uint32(commu[1])) + + commv6 := bgp6PeerRoute.Communities().Add() + commv6.SetType(gosnappi.BgpCommunityType.MANUAL_AS_NUMBER) + commv6.SetAsNumber(uint32(commu[0])) + commv6.SetAsCustom(uint32(commu[1])) + } + } + } +} + +func configureFlow(bs *cfgplugins.BGPSession, prefixPair []string, prefixType string) { + bs.ATETop.Flows().Clear() + + var rxNames []string + for i := 1; i < len(bs.ATEPorts); i++ { + rxNames = append(rxNames, bs.ATEPorts[i].Name+".BGP4.peer.dut") + } + flow := bs.ATETop.Flows().Add().SetName("flow") + flow.Metrics().SetEnable(true) + + if prefixType == "ipv4" { + flow.TxRx().Device(). + SetTxNames([]string{bs.ATEPorts[1].Name + ".IPv4"}). + SetRxNames(rxNames) + } else { + flow.TxRx().Device(). + SetTxNames([]string{bs.ATEPorts[1].Name + ".IPv6"}). + SetRxNames(rxNames) + } + + flow.Duration().FixedPackets().SetPackets(totalPackets) + flow.Size().SetFixed(1500) + flow.Rate().SetPps(trafficPps) + + e := flow.Packet().Add().Ethernet() + e.Src().SetValue(bs.ATEPorts[1].MAC) + + if prefixType == "ipv4" { + v4 := flow.Packet().Add().Ipv4() + v4.Src().SetValue(bs.ATEPorts[1].IPv4) + v4.Dst().SetValues(prefixPair) + } else { + v6 := flow.Packet().Add().Ipv6() + v6.Src().SetValue(bs.ATEPorts[1].IPv6) + v6.Dst().SetValues(prefixPair) + } +} + +func verifyTraffic(t *testing.T, ate *ondatra.ATEDevice, ports int, testResults bool) { + framesTx := gnmi.Get[uint64](t, ate.OTG(), gnmi.OTG().Port(ate.Port(t, "port1").ID()).Counters().OutFrames().State()) + framesRx := gnmi.Get[uint64](t, ate.OTG(), gnmi.OTG().Port(ate.Port(t, "port2").ID()).Counters().InFrames().State()) + + if framesTx == 0 { + t.Error("No traffic was generated and frames transmitted were 0") + } else if (testResults && framesRx == framesTx) || (!testResults && framesRx == 0) { + t.Logf("Traffic validation successful for criteria [%t] FramesTx: %d FramesRx: %d", testResults, framesTx, framesRx) + } else { + t.Errorf("Traffic validation failed for criteria [%t] FramesTx: %d FramesRx: %d", testResults, framesTx, framesRx) + } +} + +type testCase struct { + desc string + communitySetName string + communityMatch [3]string + matchSetOptions oc.E_BgpPolicy_MatchSetOptionsType + testResults [4]bool +} + +func TestCommunitySet(t *testing.T) { + bs := cfgplugins.NewBGPSession(t, cfgplugins.PortCount2) + bs.WithEBGP(t, oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST, true, true) + bs.WithEBGP(t, oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST, true, true) + + var communityMembers = [][][]int{ + { + {100, 1}, {200, 2}, {300, 3}, + }, + { + {100, 1}, {101, 1}, {200, 2}, + }, + { + {109, 1}, + }, + { + {400, 1}, + }, + } + + configureOTG(t, bs, prefixesV4, prefixesV6, communityMembers) + bs.PushAndStart(t) + + t.Log("Verify DUT BGP sessions up") + cfgplugins.VerifyDUTBGPEstablished(t, bs.DUT) + t.Log("Verify OTG BGP sessions up") + cfgplugins.VerifyOTGBGPEstablished(t, bs.ATE) + + ipv4 := bs.ATETop.Devices().Items()[1].Ethernets().Items()[0].Ipv4Addresses().Items()[0].Address() + ipv6 := bs.ATETop.Devices().Items()[1].Ethernets().Items()[0].Ipv6Addresses().Items()[0].Address() + + testCases := []testCase{ + { + desc: "Testing with any_my_3_comms", + communitySetName: "any_my_3_comms", + communityMatch: [3]string{"100:1", "200:2", "300:3"}, + matchSetOptions: oc.BgpPolicy_MatchSetOptionsType_ANY, + testResults: [4]bool{true, true, false, false}, + }, + { + desc: "Testing with all_3_comms", + communitySetName: "all_3_comms", + communityMatch: [3]string{"100:1", "200:2", "300:3"}, + matchSetOptions: oc.BgpPolicy_MatchSetOptionsType_ALL, + testResults: [4]bool{true, false, false, false}, + }, + { + desc: "Testing with no_3_comms", + communitySetName: "no_3_comms", + communityMatch: [3]string{"100:1", "200:2", "300:3"}, + matchSetOptions: oc.BgpPolicy_MatchSetOptionsType_INVERT, + testResults: [4]bool{false, false, true, true}, + }, + { + desc: "Testing with any_my_regex_comms", + communitySetName: "any_my_regex_comms", + communityMatch: [3]string{"10[0-9]:1"}, + matchSetOptions: oc.BgpPolicy_MatchSetOptionsType_ANY, + testResults: [4]bool{true, true, true, false}, + }, + } + for _, tc := range testCases { + t.Run(tc.desc, func(t *testing.T) { + + configureImportBGPPolicy(t, bs.DUT, ipv4, ipv6, tc.communitySetName, tc.communityMatch, tc.matchSetOptions) + sleepTime := time.Duration(totalPackets/trafficPps) + 5 + + for index, prefixPairV4 := range prefixesV4 { + + t.Logf("Running traffic test for IPv4 prefixes: [%s, %s]. Expected Result: [%t]", prefixPairV4[0], prefixPairV4[1], tc.testResults[index]) + configureFlow(bs, prefixPairV4, "ipv4") + bs.ATE.OTG().StartTraffic(t) + time.Sleep(sleepTime * time.Second) + bs.ATE.OTG().StopTraffic(t) + otgutils.LogFlowMetrics(t, bs.ATE.OTG(), bs.ATETop) + verifyTraffic(t, bs.ATE, int(cfgplugins.PortCount2), tc.testResults[index]) + + t.Logf("Running traffic test for IPv6 prefixes: [%s, %s]. Expected Result: [%t]", prefixesV6[index][0], prefixesV6[index][1], tc.testResults[index]) + configureFlow(bs, prefixesV6[index], "ipv6") + bs.ATE.OTG().StartTraffic(t) + time.Sleep(sleepTime * time.Second) + bs.ATE.OTG().StopTraffic(t) + otgutils.LogFlowMetrics(t, bs.ATE.OTG(), bs.ATETop) + verifyTraffic(t, bs.ATE, int(cfgplugins.PortCount2), tc.testResults[index]) + } + }) + } +} diff --git a/feature/bgp/policybase/otg_tests/community_test/metadata.textproto b/feature/bgp/policybase/otg_tests/community_test/metadata.textproto index e66b16e89df..b1a028971ba 100644 --- a/feature/bgp/policybase/otg_tests/community_test/metadata.textproto +++ b/feature/bgp/policybase/otg_tests/community_test/metadata.textproto @@ -1,7 +1,27 @@ # proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto # proto-message: Metadata +uuid: "4330effe-a20c-42fb-8372-80fb0901a325" plan_id: "RT-7.2" description: "BGP Policy Community Set" testbed: TESTBED_DUT_ATE_2LINKS tags: [TAGS_AGGREGATION, TAGS_TRANSIT, TAGS_DATACENTER_EDGE] +platform_exceptions: { + platform: { + vendor: ARISTA + } + deviations: { + isis_instance_enabled_required: true + route_policy_under_afi_unsupported: true + omit_l2_mtu: true + missing_value_for_defaults: true + interface_enabled: true + default_network_instance: "default" + isis_interface_afi_unsupported: true + skip_isis_set_level: true + skip_isis_set_metric_style_type: true + skip_set_rp_match_set_options: true + skip_setting_disable_metric_propagation: true + bgp_conditions_match_community_set_unsupported: true + } +}