From aeaa2e548471f17cea4fb747d300db8c08d36e07 Mon Sep 17 00:00:00 2001 From: cprabha Date: Mon, 9 Oct 2023 15:10:12 -0700 Subject: [PATCH] TE-9.1 : FIB FAILURE DUE TO HARDWARE RESOURCE EXHAUST (#2048) * Initial Commit for TE-9.1 * removed commented code * Update fib_failed_due_to_hw_res_exhaust_test.go * Update fib_failed_due_to_hw_res_exhaust_test.go * Added deviation * fixing conflicts * Adding tag * Adding tag * fixing fmt issues * Updated with comments and resolved conflicts * updated i value * updated review comments * changed address block from v4 to v6 * Addressing review comments * Addressing review comments * updated with comments --------- Co-authored-by: Arul Kumar Sekar <128646204+arulkumarsekar@users.noreply.github.com> --- .../README.md | 33 ++ .../fib_failed_due_to_hw_res_exhaust_test.go | 503 ++++++++++++++++++ .../metadata.textproto | 46 ++ internal/deviations/deviations.go | 6 + proto/metadata.proto | 4 +- proto/metadata_go_proto/metadata.pb.go | 83 +-- 6 files changed, 640 insertions(+), 35 deletions(-) create mode 100644 feature/experimental/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/README.md create mode 100644 feature/experimental/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/fib_failed_due_to_hw_res_exhaust_test.go create mode 100644 feature/experimental/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/metadata.textproto diff --git a/feature/experimental/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/README.md b/feature/experimental/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/README.md new file mode 100644 index 00000000000..94fb48612b5 --- /dev/null +++ b/feature/experimental/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/README.md @@ -0,0 +1,33 @@ +# TE-9.1: FIB FAILURE DUE TO HARDWARE RESOURCE EXHAUST + +## Summary + +Validate gRIBI FIB_FAILED functionality. + +## Procedure + +* Connect ATE port-1 to DUT port-1, and ATE port-2 to DUT port-2. + +* Establish a gRIBI connection (SINGLE_PRIMARY and PRESERVE mode) to the DUT. + +* Establish BGP session between ATE Port1 --- DUT Port1. Inject unique BGP routes to exhaust FIB on DUT. + +* Continuously injecting the following gRIB structure until FIB FAILED is received. + Each DstIP and VIP should be unique and of /32. All the NHG and NH should be unique (of unique ID). + DstIP/32 -> NHG -> NH {next-hop:} -> VIP/32 -> NHG -> NH {next-hop: AtePort2Ip} + +* Expect FIB_PROGRAMMED message until the first FIB_FAILED message received. + +* Validate that traffic for the FIB_FAILED route will not get forwarded. + +* Pick any route that received FIB_PROGRAMMED. Validate that traffic hitting the route should be forwarded to port2 + + +## Protocol/RPC Parameter coverage + +* gRIBI + * Flush + +## Config parameter coverage + +## Telemery parameter coverage diff --git a/feature/experimental/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/fib_failed_due_to_hw_res_exhaust_test.go b/feature/experimental/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/fib_failed_due_to_hw_res_exhaust_test.go new file mode 100644 index 00000000000..ba900cbc571 --- /dev/null +++ b/feature/experimental/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/fib_failed_due_to_hw_res_exhaust_test.go @@ -0,0 +1,503 @@ +// 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 fib_failed_due_to_hw_res_exhaust_test + +import ( + "context" + "encoding/binary" + "fmt" + "net" + "testing" + "time" + + "github.com/open-traffic-generator/snappi/gosnappi" + "github.com/openconfig/featureprofiles/internal/attrs" + "github.com/openconfig/featureprofiles/internal/deviations" + "github.com/openconfig/featureprofiles/internal/fptest" + "github.com/openconfig/featureprofiles/internal/gribi" + "github.com/openconfig/gribigo/fluent" + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" + "github.com/openconfig/ondatra/gnmi/oc" + "github.com/openconfig/ondatra/otg" + "github.com/openconfig/ygnmi/ygnmi" + "github.com/openconfig/ygot/ygot" + + aftspb "github.com/openconfig/gribi/v1/proto/service" +) + +func TestMain(m *testing.M) { + fptest.RunTests(m) +} + +// Settings for configuring the baseline testbed with the test +// topology. +// +// The testbed consists of ate:port1 -> dut:port1, +// dut:port2 -> ate:port2. +// +// * ate:port1 -> dut:port1 subnet 192.0.2.1/30 +// * ate:port2 -> dut:port2 subnet 192.0.2.5/30 + +const ( + dstIPBlock = "203.0.113.0" + vipBlock = "198.51.100.0" + wantLoss = true + dutAS = 64500 + ateAS = 64501 + advertisedRoutesv6 = "2001:DB8:2::1" + advertisedRoutesv6MaskLen = 128 + tolerancePct = 2 + tolerance = 50 + plenIPv4 = 30 + plenIPv6 = 126 +) + +var ( + vendorSpecRoutecount = map[ondatra.Vendor]uint32{ + ondatra.JUNIPER: 2500000, + ondatra.NOKIA: 1600000, + } + dutPort1 = attrs.Attributes{ + Desc: "dutPort1", + IPv4: "192.0.2.1", + IPv6: "2001:db8::192:0:2:1", + IPv4Len: plenIPv4, + IPv6Len: plenIPv6, + } + atePort1 = attrs.Attributes{ + Name: "atePort1", + IPv4: "192.0.2.2", + MAC: "02:00:01:01:01:01", + IPv6: "2001:db8::192:0:2:2", + IPv4Len: plenIPv4, + IPv6Len: plenIPv6, + } + dutPort2 = attrs.Attributes{ + Desc: "dutPort2", + IPv4: "192.0.2.5", + IPv6: "2001:db8::192:0:2:5", + IPv4Len: plenIPv4, + IPv6Len: plenIPv6, + } + atePort2 = attrs.Attributes{ + Name: "atePort2", + IPv4: "192.0.2.6", + MAC: "02:00:02:01:01:01", + IPv6: "2001:db8::192:0:2:6", + IPv4Len: plenIPv4, + IPv6Len: plenIPv6, + } + fibPassedDstRoute string + fibFailedDstRoute string +) + +func configureBGP(dut *ondatra.DUTDevice) *oc.NetworkInstance_Protocol { + d := &oc.Root{} + ni1 := d.GetOrCreateNetworkInstance(deviations.DefaultNetworkInstance(dut)) + niProto := ni1.GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP") + bgp := niProto.GetOrCreateBgp() + + g := bgp.GetOrCreateGlobal() + g.As = ygot.Uint32(dutAS) + g.RouterId = ygot.String(dutPort1.IPv4) + 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) + + pg := bgp.GetOrCreatePeerGroup("BGP-PEER-GROUP-V6") + pg.PeerAs = ygot.Uint32(ateAS) + pg.PeerGroupName = ygot.String("BGP-PEER-GROUP-V6") + + if deviations.RoutePolicyUnderAFIUnsupported(dut) { + rpl := pg.GetOrCreateApplyPolicy() + rpl.SetExportPolicy([]string{"ALLOW"}) + rpl.SetImportPolicy([]string{"ALLOW"}) + } else { + pg1af4 := pg.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST) + pg1af4.Enabled = ygot.Bool(true) + pg1rpl4 := pg1af4.GetOrCreateApplyPolicy() + pg1rpl4.SetExportPolicy([]string{"ALLOW"}) + pg1rpl4.SetImportPolicy([]string{"ALLOW"}) + } + + bgpNbr := bgp.GetOrCreateNeighbor(atePort1.IPv6) + bgpNbr.PeerAs = ygot.Uint32(ateAS) + bgpNbr.Enabled = ygot.Bool(true) + bgpNbr.PeerGroup = ygot.String("BGP-PEER-GROUP-V6") + af6 := bgpNbr.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV6_UNICAST) + af6.Enabled = ygot.Bool(true) + af4 := bgpNbr.GetOrCreateAfiSafi(oc.BgpTypes_AFI_SAFI_TYPE_IPV4_UNICAST) + af4.Enabled = ygot.Bool(false) + return niProto +} + +func configureOTG(t *testing.T, otg *otg.OTG) (gosnappi.BgpV6Peer, gosnappi.DeviceIpv6, gosnappi.Config) { + t.Helper() + config := otg.NewConfig(t) + port1 := config.Ports().Add().SetName("port1") + port2 := config.Ports().Add().SetName("port2") + + iDut1Dev := config.Devices().Add().SetName(atePort1.Name) + iDut1Eth := iDut1Dev.Ethernets().Add().SetName(atePort1.Name + ".Eth").SetMac(atePort1.MAC) + iDut1Eth.Connection().SetChoice(gosnappi.EthernetConnectionChoice.PORT_NAME).SetPortName(port1.Name()) + iDut1Ipv4 := iDut1Eth.Ipv4Addresses().Add().SetName(atePort1.Name + ".IPv4") + iDut1Ipv4.SetAddress(atePort1.IPv4).SetGateway(dutPort1.IPv4).SetPrefix(uint32(atePort1.IPv4Len)) + iDut1Ipv6 := iDut1Eth.Ipv6Addresses().Add().SetName(atePort1.Name + ".IPv6") + iDut1Ipv6.SetAddress(atePort1.IPv6).SetGateway(dutPort1.IPv6).SetPrefix(uint32(atePort1.IPv6Len)) + + iDut2Dev := config.Devices().Add().SetName(atePort2.Name) + iDut2Eth := iDut2Dev.Ethernets().Add().SetName(atePort2.Name + ".Eth").SetMac(atePort2.MAC) + iDut2Eth.Connection().SetChoice(gosnappi.EthernetConnectionChoice.PORT_NAME).SetPortName(port2.Name()) + iDut2Ipv4 := iDut2Eth.Ipv4Addresses().Add().SetName(atePort2.Name + ".IPv4") + iDut2Ipv4.SetAddress(atePort2.IPv4).SetGateway(dutPort2.IPv4).SetPrefix(uint32(atePort2.IPv4Len)) + + iDut1Bgp := iDut1Dev.Bgp().SetRouterId(iDut1Ipv4.Address()) + iDut1Bgp6Peer := iDut1Bgp.Ipv6Interfaces().Add().SetIpv6Name(iDut1Ipv6.Name()).Peers().Add().SetName(atePort1.Name + ".BGP6.peer") + iDut1Bgp6Peer.SetPeerAddress(iDut1Ipv6.Gateway()).SetAsNumber(ateAS).SetAsType(gosnappi.BgpV6PeerAsType.EBGP) + iDut1Bgp6Peer.Capability().SetIpv4UnicastAddPath(true).SetIpv6UnicastAddPath(true) + iDut1Bgp6Peer.LearnedInformationFilter().SetUnicastIpv4Prefix(true).SetUnicastIpv6Prefix(true) + + t.Logf("Pushing config to ATE and starting protocols...") + otg.PushConfig(t, config) + time.Sleep(30 * time.Second) + otg.StartProtocols(t) + time.Sleep(30 * time.Second) + + return iDut1Bgp6Peer, iDut1Ipv6, config +} + +func configureRoutePolicy(t *testing.T, dut *ondatra.DUTDevice, name string, pr oc.E_RoutingPolicy_PolicyResultType) { + d := &oc.Root{} + rp := d.GetOrCreateRoutingPolicy() + pd := rp.GetOrCreatePolicyDefinition(name) + st, err := pd.AppendNewStatement("id-1") + if err != nil { + t.Fatal(err) + } + st.GetOrCreateActions().PolicyResult = pr + gnmi.Replace(t, dut, gnmi.OC().RoutingPolicy().Config(), rp) +} + +type testArgs struct { + ctx context.Context + dut *ondatra.DUTDevice + ate *ondatra.ATEDevice + otgBgpPeer gosnappi.BgpV6Peer + otgIPv6Device gosnappi.DeviceIpv6 + otgConfig gosnappi.Config + client *fluent.GRIBIClient + electionID gribi.Uint128 + otg *otg.OTG +} + +// TestFibFailDueToHwResExhaust is to test gRIBI FIB_FAILED functionality +// is supported due to hardware exhaust. +func TestFibFailDueToHwResExhaust(t *testing.T) { + ctx := context.Background() + dut := ondatra.DUT(t, "dut") + configureDUT(t, dut) + configureRoutePolicy(t, dut, "ALLOW", oc.RoutingPolicy_PolicyResultType_ACCEPT_ROUTE) + + t.Log("Configure/update Network Instance") + fptest.ConfigureDefaultNetworkInstance(t, dut) + + dutConfPath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP") + t.Run("configureBGP", func(t *testing.T) { + dutConf := configureBGP(dut) + gnmi.Replace(t, dut, dutConfPath.Config(), dutConf) + fptest.LogQuery(t, "DUT BGP Config", dutConfPath.Config(), gnmi.GetConfig(t, dut, dutConfPath.Config())) + }) + + ate := ondatra.ATE(t, "ate") + otg := ate.OTG() + var otgConfig gosnappi.Config + var otgBgpPeer gosnappi.BgpV6Peer + var otgIPv6Device gosnappi.DeviceIpv6 + otgBgpPeer, otgIPv6Device, otgConfig = configureOTG(t, otg) + + verifyBgpTelemetry(t, dut) + + gribic := dut.RawAPIs().GRIBI(t) + + // Connect gRIBI client to DUT referred to as gRIBI - using PRESERVE persistence and + // SINGLE_PRIMARY mode, with FIB ACK requested. Specify gRIBI as the leader. + client := fluent.NewClient() + client.Connection().WithStub(gribic).WithPersistence().WithInitialElectionID(1, 0). + WithFIBACK().WithRedundancyMode(fluent.ElectedPrimaryClient) + client.Start(ctx, t) + defer client.Stop(t) + + defer func() { + // Flush all entries after test. + if err := gribi.FlushAll(client); err != nil { + t.Error(err) + } + }() + + client.StartSending(ctx, t) + if err := awaitTimeout(ctx, t, client, time.Minute); err != nil { + t.Fatalf("Await got error during session negotiation for clientA: %v", err) + } + eID := gribi.BecomeLeader(t, client) + + t.Log("Flush existing gRIBI routes before test.") + if err := gribi.FlushAll(client); err != nil { + t.Fatal(err) + } + + args := &testArgs{ + ctx: ctx, + client: client, + dut: dut, + ate: ate, + otgBgpPeer: otgBgpPeer, + otgIPv6Device: otgIPv6Device, + otgConfig: otgConfig, + electionID: eID, + otg: otg, + } + start := time.Now() + injectEntry(ctx, t, args) + t.Logf("Main Function: Time elapsed %.2f seconds since start", time.Since(start).Seconds()) + + t.Log("Send traffic to any of the programmed entries and validate.") + sendTraffic(t, args) +} + +func sendTraffic(t *testing.T, args *testArgs) { + // Ensure that traffic can be forwarded between ATE port-1 and ATE port-2. + t.Helper() + t.Logf("TestBGP:start otg Traffic config") + flow1ipv4 := args.otgConfig.Flows().Add().SetName("Flow1") + flow1ipv4.Metrics().SetEnable(true) + flow1ipv4.TxRx().Device(). + SetTxNames([]string{atePort1.Name + ".IPv4"}). + SetRxNames([]string{atePort2.Name + ".IPv4"}) + flow1ipv4.Size().SetFixed(512) + flow1ipv4.Rate().SetPps(100) + flow1ipv4.Duration().SetChoice("continuous") + e1 := flow1ipv4.Packet().Add().Ethernet() + e1.Src().SetValue(atePort1.MAC) + v4 := flow1ipv4.Packet().Add().Ipv4() + v4.Src().SetValue(atePort1.IPv4) + v4.Dst().Increment().SetStart(fibPassedDstRoute) + + flow2ipv4 := args.otgConfig.Flows().Add().SetName("Flow2") + flow2ipv4.Metrics().SetEnable(true) + flow2ipv4.TxRx().Device(). + SetTxNames([]string{atePort1.Name + ".IPv4"}). + SetRxNames([]string{atePort2.Name + ".IPv4"}) + flow2ipv4.Size().SetFixed(512) + flow2ipv4.Rate().SetPps(100) + flow2ipv4.Duration().SetChoice("continuous") + e2 := flow2ipv4.Packet().Add().Ethernet() + e2.Src().SetValue(atePort1.MAC) + v4Flow2 := flow2ipv4.Packet().Add().Ipv4() + v4Flow2.Src().SetValue(atePort1.IPv4) + v4Flow2.Dst().Increment().SetStart(fibFailedDstRoute) + + args.otg.PushConfig(t, args.otgConfig) + args.otg.StartProtocols(t) + + t.Logf("Starting traffic") + args.otg.StartTraffic(t) + time.Sleep(15 * time.Second) + t.Logf("Stop traffic") + args.otg.StopTraffic(t) + + verifyTraffic(t, args, flow1ipv4.Name(), !wantLoss) + + if !deviations.GRIBISkipFIBFailedTrafficForwardingCheck(args.dut) { + verifyTraffic(t, args, flow2ipv4.Name(), wantLoss) + } +} + +func verifyTraffic(t *testing.T, args *testArgs, flowName string, wantLoss bool) { + t.Helper() + t.Logf("Verifying flow metrics for the flow %s\n", flowName) + recvMetric := gnmi.Get(t, args.otg, gnmi.OTG().Flow(flowName).State()) + txPackets := recvMetric.GetCounters().GetOutPkts() + rxPackets := recvMetric.GetCounters().GetInPkts() + lostPackets := txPackets - rxPackets + var lossPct uint64 + if txPackets != 0 { + lossPct = lostPackets * 100 / txPackets + } else { + t.Errorf("Traffic stats are not correct %v", recvMetric) + } + if wantLoss { + if lossPct < 100-tolerancePct { + t.Errorf("Traffic is expected to fail %s\n got %v, want 100%% failure", flowName, lossPct) + } else { + t.Logf("Traffic Loss Test Passed!") + } + } else { + if lossPct > tolerancePct { + t.Errorf("Traffic Loss Pct for Flow: %s\n got %v, want 0", flowName, lossPct) + } else { + t.Logf("Traffic Test Passed!") + } + } +} + +func verifyBgpTelemetry(t *testing.T, dut *ondatra.DUTDevice) { + t.Helper() + var nbrIP = []string{atePort1.IPv6} + t.Logf("Verifying BGP state.") + bgpPath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP").Bgp() + + for _, nbr := range nbrIP { + nbrPath := bgpPath.Neighbor(nbr) + // Get BGP adjacency state. + t.Logf("Waiting for BGP neighbor to establish...") + status, ok := gnmi.Watch(t, dut, nbrPath.SessionState().State(), time.Minute, func(val *ygnmi.Value[oc.E_Bgp_Neighbor_SessionState]) bool { + state, ok := val.Val() + return ok && state == oc.Bgp_Neighbor_SessionState_ESTABLISHED + }).Await(t) + if !ok { + t.Fatal("No BGP neighbor formed") + } + state, _ := status.Val() + t.Logf("BGP adjacency for %s: %v", nbr, state) + if want := oc.Bgp_Neighbor_SessionState_ESTABLISHED; state != want { + t.Errorf("BGP peer %s status got %d, want %d", nbr, state, want) + } + } +} + +// configureDUT configures port1-2 on the DUT. +func configureDUT(t *testing.T, dut *ondatra.DUTDevice) { + t.Helper() + d := gnmi.OC() + + p1 := dut.Port(t, "port1") + p2 := dut.Port(t, "port2") + + gnmi.Replace(t, dut, d.Interface(p1.Name()).Config(), dutPort1.NewOCInterface(p1.Name(), dut)) + gnmi.Replace(t, dut, d.Interface(p2.Name()).Config(), dutPort2.NewOCInterface(p2.Name(), dut)) + + if deviations.ExplicitPortSpeed(dut) { + fptest.SetPortSpeed(t, dut.Port(t, "port1")) + fptest.SetPortSpeed(t, dut.Port(t, "port2")) + } + if deviations.ExplicitInterfaceInDefaultVRF(dut) { + fptest.AssignToNetworkInstance(t, dut, p1.Name(), deviations.DefaultNetworkInstance(dut), 0) + fptest.AssignToNetworkInstance(t, dut, p2.Name(), deviations.DefaultNetworkInstance(dut), 0) + } +} + +func injectBGPRoutes(t *testing.T, args *testArgs) { + t.Helper() + + if _, ok := vendorSpecRoutecount[args.dut.Vendor()]; !ok { + t.Fatalf("Please provide BGP route count for vendor to maxout FIB %v in var vendorSpecRoutecount ", args.dut.Vendor()) + } + bgpNeti1Bgp6PeerRoutes := args.otgBgpPeer.V6Routes().Add().SetName(atePort1.Name + ".BGP6.Route") + bgpNeti1Bgp6PeerRoutes.SetNextHopIpv6Address(args.otgIPv6Device.Address()). + SetNextHopAddressType(gosnappi.BgpV6RouteRangeNextHopAddressType.IPV6). + SetNextHopMode(gosnappi.BgpV6RouteRangeNextHopMode.MANUAL) + bgpNeti1Bgp6PeerRoutes.Addresses().Add(). + SetAddress(advertisedRoutesv6). + SetPrefix(advertisedRoutesv6MaskLen). + SetCount(vendorSpecRoutecount[args.dut.Vendor()]).SetStep(2) + + args.otg.PushConfig(t, args.otgConfig) + time.Sleep(30 * time.Second) + args.otg.StartProtocols(t) + time.Sleep(30 * time.Second) +} + +// awaitTimeout calls a fluent client Await, adding a timeout to the context. +func awaitTimeout(ctx context.Context, t testing.TB, c *fluent.GRIBIClient, timeout time.Duration) error { + t.Helper() + subctx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + return c.Await(subctx, t) +} + +// createIPv4Entries creates IPv4 Entries given the totalCount and starting prefix. +func createIPv4Entries(t *testing.T, startIP string) []string { + t.Helper() + _, netCIDR, err := net.ParseCIDR(startIP) + if err != nil { + t.Fatalf("Failed to parse prefix: %v", err) + } + netMask := binary.BigEndian.Uint32(netCIDR.Mask) + firstIP := binary.BigEndian.Uint32(netCIDR.IP) + lastIP := (firstIP & netMask) | (netMask ^ 0xffffffff) + var entries []string + for i := firstIP; i <= lastIP; i++ { + ip := make(net.IP, 4) + binary.BigEndian.PutUint32(ip, i) + entries = append(entries, fmt.Sprint(ip)) + } + return entries +} + +// injectEntry programs gRIBI nh, nhg and ipv4 entry. +func injectEntry(ctx context.Context, t *testing.T, args *testArgs) { + t.Helper() + dstIPList := createIPv4Entries(t, fmt.Sprintf("%s/%d", dstIPBlock, 20)) + vipList := createIPv4Entries(t, fmt.Sprintf("%s/%d", vipBlock, 20)) + j := uint64(0) + +routeAddLoop: + for i := uint64(1); i <= uint64(1500); i += 2 { + vipNhIndex := i + dstNhIndex := vipNhIndex + 1 + + args.client.Modify().AddEntry(t, + fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(args.dut)). + WithIndex(vipNhIndex).WithIPAddress(atePort2.IPv4), + fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(args.dut)). + WithID(vipNhIndex).AddNextHop(vipNhIndex, 1), + fluent.IPv4Entry().WithNetworkInstance(deviations.DefaultNetworkInstance(args.dut)). + WithPrefix(vipList[j]+"/32").WithNextHopGroup(vipNhIndex), + ) + args.client.Modify().AddEntry(t, + fluent.NextHopEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(args.dut)). + WithIndex(dstNhIndex).WithIPAddress(vipList[j]), + fluent.NextHopGroupEntry().WithNetworkInstance(deviations.DefaultNetworkInstance(args.dut)). + WithID(dstNhIndex).AddNextHop(dstNhIndex, 1), + fluent.IPv4Entry().WithNetworkInstance(deviations.DefaultNetworkInstance(args.dut)). + WithPrefix(dstIPList[j]+"/32").WithNextHopGroup(dstNhIndex), + ) + + if err := awaitTimeout(args.ctx, t, args.client, time.Minute); err != nil { + t.Logf("Could not program entries via client, got err, check error codes: %v", err) + } + + for _, v := range args.client.Results(t) { + if v.ProgrammingResult == aftspb.AFTResult_FIB_FAILED { + t.Logf("FIB FAILED received %v", v.Details) + fibFailedDstRoute = dstIPList[j] + break routeAddLoop + } + } + j = j + 1 + // We are filling FIB with BGP routes. After FIB is full, trying to program + // routes through gRIBI client. Since FIB is already full , we should get + // FIB FAILED while programming gRIBI routes. Here we are trying to program + // 1500 VIP/Dst entries along with unique NH/NHG entries. + if i >= 1498 { + t.Fatalf("FIB FAILED is not received as expected") + } + if j == 1 { + fibPassedDstRoute = dstIPList[0] + injectBGPRoutes(t, args) + time.Sleep(5 * time.Minute) + } + } +} diff --git a/feature/experimental/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/metadata.textproto b/feature/experimental/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/metadata.textproto new file mode 100644 index 00000000000..6442cbf3b84 --- /dev/null +++ b/feature/experimental/gribi/otg_tests/fib_failed_due_to_hw_res_exhaust_test/metadata.textproto @@ -0,0 +1,46 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata + +uuid: "4f04fb5b-5bc0-4214-a74d-2a30c0433078" +plan_id: "TE-9.1" +description: "FIB FAILURE DUE TO HARDWARE RESOURCE EXHAUST" +testbed: TESTBED_DUT_ATE_2LINKS +platform_exceptions: { + platform: { + vendor: CISCO + } + deviations: { + ipv4_missing_enabled: true + } +} +platform_exceptions: { + platform: { + vendor: JUNIPER + } + deviations: { + skip_fib_failed_traffic_forwarding_check: true + } +} +platform_exceptions: { + platform: { + vendor: NOKIA + } + deviations: { + explicit_gribi_under_network_instance: true + explicit_port_speed: true + explicit_interface_in_default_vrf: true + interface_enabled: true + } +} +platform_exceptions: { + platform: { + vendor: ARISTA + } + deviations: { + omit_l2_mtu: true + interface_config_vrf_before_address: true + interface_enabled: true + default_network_instance: "default" + } +} +tags: TAGS_TRANSIT diff --git a/internal/deviations/deviations.go b/internal/deviations/deviations.go index d89cb18d95c..3f23bce0913 100644 --- a/internal/deviations/deviations.go +++ b/internal/deviations/deviations.go @@ -597,6 +597,12 @@ func ISISCounterPartChangesUnsupported(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetIsisCounterPartChangesUnsupported() } +// GRIBISkipFIBFailedTrafficForwardingCheck returns true for devices that do not +// support fib forwarding for fib failed routes. +func GRIBISkipFIBFailedTrafficForwardingCheck(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetSkipFibFailedTrafficForwardingCheck() +} + // SkipTCPNegotiatedMSSCheck returns true for devices that do not // support telemetry to check negotiated tcp mss value. func SkipTCPNegotiatedMSSCheck(dut *ondatra.DUTDevice) bool { diff --git a/proto/metadata.proto b/proto/metadata.proto index 593ee62ddb0..111dbb37170 100644 --- a/proto/metadata.proto +++ b/proto/metadata.proto @@ -339,7 +339,9 @@ message Metadata { bool isis_lsp_metadata_leafs_unsupported = 111; // QOS queue requires configuration with queue-id bool qos_queue_requires_id = 112; - + // Devices do not support forwarding for fib failed routes. + bool skip_fib_failed_traffic_forwarding_check = 113; + // Reserved field numbers and identifiers. reserved 84, 9, 28, 90; } diff --git a/proto/metadata_go_proto/metadata.pb.go b/proto/metadata_go_proto/metadata.pb.go index 365ce589048..6c5ffebe970 100644 --- a/proto/metadata_go_proto/metadata.pb.go +++ b/proto/metadata_go_proto/metadata.pb.go @@ -606,6 +606,8 @@ type Metadata_Deviations struct { IsisLspMetadataLeafsUnsupported bool `protobuf:"varint,111,opt,name=isis_lsp_metadata_leafs_unsupported,json=isisLspMetadataLeafsUnsupported,proto3" json:"isis_lsp_metadata_leafs_unsupported,omitempty"` // QOS queue requires configuration with queue-id QosQueueRequiresId bool `protobuf:"varint,112,opt,name=qos_queue_requires_id,json=qosQueueRequiresId,proto3" json:"qos_queue_requires_id,omitempty"` + // Devices do not support forwarding for fib failed routes. + SkipFibFailedTrafficForwardingCheck bool `protobuf:"varint,113,opt,name=skip_fib_failed_traffic_forwarding_check,json=skipFibFailedTrafficForwardingCheck,proto3" json:"skip_fib_failed_traffic_forwarding_check,omitempty"` } func (x *Metadata_Deviations) Reset() { @@ -1347,6 +1349,13 @@ func (x *Metadata_Deviations) GetQosQueueRequiresId() bool { return false } +func (x *Metadata_Deviations) GetSkipFibFailedTrafficForwardingCheck() bool { + if x != nil { + return x.SkipFibFailedTrafficForwardingCheck + } + return false +} + type Metadata_PlatformExceptions struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1410,7 +1419,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, 0xbb, 0x3f, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x92, 0x40, 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, @@ -1441,7 +1450,7 @@ var file_metadata_proto_rawDesc = []byte{ 0x72, 0x65, 0x67, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x67, 0x65, 0x78, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x52, 0x0e, 0x68, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, - 0x65, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x1a, 0xef, 0x37, 0x0a, 0x0a, 0x44, 0x65, 0x76, 0x69, + 0x65, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x1a, 0xc6, 0x38, 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, @@ -1887,38 +1896,44 @@ var file_metadata_proto_rawDesc = []byte{ 0x0a, 0x15, 0x71, 0x6f, 0x73, 0x5f, 0x71, 0x75, 0x65, 0x75, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x70, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x71, 0x6f, 0x73, 0x51, 0x75, 0x65, 0x75, 0x65, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x49, - 0x64, 0x4a, 0x04, 0x08, 0x54, 0x10, 0x55, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x4a, 0x04, 0x08, - 0x1c, 0x10, 0x1d, 0x4a, 0x04, 0x08, 0x5a, 0x10, 0x5b, 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, 0xc7, 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, 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, + 0x64, 0x12, 0x55, 0x0a, 0x28, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x66, 0x69, 0x62, 0x5f, 0x66, 0x61, + 0x69, 0x6c, 0x65, 0x64, 0x5f, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x66, 0x6f, 0x72, + 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x71, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x23, 0x73, 0x6b, 0x69, 0x70, 0x46, 0x69, 0x62, 0x46, 0x61, 0x69, 0x6c, + 0x65, 0x64, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, + 0x69, 0x6e, 0x67, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x04, 0x08, 0x54, 0x10, 0x55, 0x4a, 0x04, + 0x08, 0x09, 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x1c, 0x10, 0x1d, 0x4a, 0x04, 0x08, 0x5a, 0x10, 0x5b, + 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, 0xc7, 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, 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 (