diff --git a/feature/isis/otg_tests/weighted_ecmp_test/metadata.textproto b/feature/isis/otg_tests/weighted_ecmp_test/metadata.textproto index 4267c4fa359..8057787e787 100644 --- a/feature/isis/otg_tests/weighted_ecmp_test/metadata.textproto +++ b/feature/isis/otg_tests/weighted_ecmp_test/metadata.textproto @@ -20,6 +20,7 @@ platform_exceptions: { route_policy_under_afi_unsupported: true static_protocol_name: "STATIC" rib_wecmp: true + explicit_port_speed: true } } platform_exceptions: { @@ -30,5 +31,7 @@ platform_exceptions: { interface_ref_config_unsupported:true rib_wecmp: true wecmp_auto_unsupported: true + isis_loopback_required: true + weighted_ecmp_fixed_packet_verification: true } -} \ No newline at end of file +} diff --git a/feature/isis/otg_tests/weighted_ecmp_test/weighted_ecmp_test.go b/feature/isis/otg_tests/weighted_ecmp_test/weighted_ecmp_test.go index 5f1e3151ea1..32ef2866968 100644 --- a/feature/isis/otg_tests/weighted_ecmp_test/weighted_ecmp_test.go +++ b/feature/isis/otg_tests/weighted_ecmp_test/weighted_ecmp_test.go @@ -146,7 +146,7 @@ func TestWeightedECMPForISIS(t *testing.T) { ate := ondatra.ATE(t, "ate") aggIDs := configureDUT(t, dut) vendor = dut.Vendor() - //Enable weighted ECMP in ISIS and set LoadBalancing to Auto + // Enable weighted ECMP in ISIS and set LoadBalancing to Auto if !deviations.RibWecmp(dut) { b := &gnmi.SetBatch{} // isisPath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, isisInstance) @@ -188,6 +188,7 @@ func TestWeightedECMPForISIS(t *testing.T) { t.Errorf("Flow %s loss: got %f, want %f", flow.Name(), got, want) } } + time.Sleep(time.Minute) weights := trafficRXWeights(t, ate, []string{agg2.ateAggName, agg3.ateAggName, agg4.ateAggName}) for idx, weight := range equalDistributionWeights { if got, want := weights[idx], weight; got < want-ecmpTolerance || got > want+ecmpTolerance { @@ -228,14 +229,16 @@ func TestWeightedECMPForISIS(t *testing.T) { } top.Flows().Clear() - flows = configureFlows(t, top, ate1AdvV4, ate1AdvV6, ate2AdvV4, ate2AdvV6) - ate.OTG().PushConfig(t, top) - ate.OTG().StartProtocols(t) - VerifyISISTelemetry(t, dut, aggIDs, []*aggPortData{agg1, agg2}) - for _, agg := range []*aggPortData{agg1, agg2} { - bgpPath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP").Bgp() - gnmi.Await(t, dut, bgpPath.Neighbor(agg.ateLoopbackV4).SessionState().State(), 2*time.Minute, oc.Bgp_Neighbor_SessionState_ESTABLISHED) - gnmi.Await(t, dut, bgpPath.Neighbor(agg.ateLoopbackV6).SessionState().State(), 2*time.Minute, oc.Bgp_Neighbor_SessionState_ESTABLISHED) + if deviations.ISISLoopbackRequired(dut) { + flows = configureFlows(t, top, ate1AdvV4, ate1AdvV6, ate2AdvV4, ate2AdvV6) + ate.OTG().PushConfig(t, top) + ate.OTG().StartProtocols(t) + VerifyISISTelemetry(t, dut, aggIDs, []*aggPortData{agg1, agg2}) + for _, agg := range []*aggPortData{agg1, agg2} { + bgpPath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_BGP, "BGP").Bgp() + gnmi.Await(t, dut, bgpPath.Neighbor(agg.ateLoopbackV4).SessionState().State(), 3*time.Minute, oc.Bgp_Neighbor_SessionState_ESTABLISHED) + gnmi.Await(t, dut, bgpPath.Neighbor(agg.ateLoopbackV6).SessionState().State(), 3*time.Minute, oc.Bgp_Neighbor_SessionState_ESTABLISHED) + } } startTraffic(t, ate, top) @@ -247,6 +250,7 @@ func TestWeightedECMPForISIS(t *testing.T) { t.Errorf("Flow %s loss: got %f, want %f", flow.Name(), got, want) } } + time.Sleep(time.Minute) weights := trafficRXWeights(t, ate, []string{agg2.ateAggName, agg3.ateAggName, agg4.ateAggName}) for idx, weight := range unequalDistributionWeights { if got, want := weights[idx], weight; got < want-ecmpTolerance || got > want+ecmpTolerance { @@ -298,9 +302,12 @@ func randRange(t *testing.T, start, end uint32, count int) []uint32 { func configureFlows(t *testing.T, top gosnappi.Config, srcV4, srcV6, dstV4, dstV6 *ipAddr) []gosnappi.Flow { t.Helper() + dut := ondatra.DUT(t, "dut") top.Flows().Clear() fV4 := top.Flows().Add().SetName("flowV4") - fV4.Duration().FixedPackets().SetPackets(fixedPackets) + if deviations.WeightedEcmpFixedPacketVerification(dut) { + fV4.Duration().FixedPackets().SetPackets(fixedPackets) + } fV4.Metrics().SetEnable(true) fV4.TxRx().Device(). SetTxNames([]string{agg1.ateAggName + ".IPv4"}). @@ -317,7 +324,9 @@ func configureFlows(t *testing.T, top gosnappi.Config, srcV4, srcV6, dstV4, dstV udp.DstPort().SetValues(randRange(t, 49152, 65535, 5000)) fV6 := top.Flows().Add().SetName("flowV6") - fV6.Duration().FixedPackets().SetPackets(fixedPackets) + if deviations.WeightedEcmpFixedPacketVerification(dut) { + fV6.Duration().FixedPackets().SetPackets(fixedPackets) + } fV6.Metrics().SetEnable(true) fV6.TxRx().Device(). SetTxNames([]string{agg1.ateAggName + ".IPv6"}). @@ -416,6 +425,7 @@ func configureOTGBGP(t *testing.T, dev gosnappi.Device, agg *aggPortData, advV4, func configureOTGISIS(t *testing.T, dev gosnappi.Device, agg *aggPortData) { t.Helper() + dut := ondatra.DUT(t, "dut") isis := dev.Isis().SetSystemId(agg.ateISISSysID).SetName(agg.ateAggName + ".ISIS") isis.Basic().SetHostname(isis.Name()) isis.Advanced().SetAreaAddresses([]string{ateAreaAddress}) @@ -425,7 +435,7 @@ func configureOTGISIS(t *testing.T, dev gosnappi.Device, agg *aggPortData) { SetNetworkType(gosnappi.IsisInterfaceNetworkType.POINT_TO_POINT). SetLevelType(gosnappi.IsisInterfaceLevelType.LEVEL_2).SetMetric(10) isisInt.Advanced().SetAutoAdjustMtu(true).SetAutoAdjustArea(true).SetAutoAdjustSupportedProtocols(true) - if vendor == ondatra.CISCO { + if deviations.ISISLoopbackRequired(dut) { // configure ISIS loopback interface and advertise them via ISIS. isisPort2V4 := dev.Isis().V4Routes().Add().SetName(agg.ateAggName + ".ISISV4").SetLinkMetric(10) isisPort2V4.Addresses().Add().SetAddress(agg.ateLoopbackV4).SetPrefix(32) @@ -502,7 +512,7 @@ func configureDUT(t *testing.T, dut *ondatra.DUTDevice) []string { for _, aggID := range aggIDs { gnmi.Await(t, dut, gnmi.OC().Interface(aggID).AdminStatus().State(), 60*time.Second, oc.Interface_AdminStatus_UP) } - if dut.Vendor() != ondatra.CISCO { + if deviations.ISISLoopbackRequired(dut) { configureStaticRouteToATELoopbacks(t, dut) } configureRoutingPolicy(t, dut) @@ -600,6 +610,7 @@ func configureDUTISIS(t *testing.T, dut *ondatra.DUTDevice, aggIDs []string) { d := &oc.Root{} dutConfIsisPath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)).Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, isisInstance) + netInstance := d.GetOrCreateNetworkInstance(deviations.DefaultNetworkInstance(dut)) prot := netInstance.GetOrCreateProtocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, isisInstance) prot.Enabled = ygot.Bool(true) @@ -619,9 +630,11 @@ func configureDUTISIS(t *testing.T, dut *ondatra.DUTDevice, aggIDs []string) { isisLevel2 := isis.GetOrCreateLevel(2) isisLevel2.MetricStyle = oc.Isis_MetricStyle_WIDE_METRIC - gnmi.Update(t, dut, gnmi.OC().Config(), d) - // add loopback interface to ISIS - aggIDs = append(aggIDs, "Loopback0") + if deviations.ISISLoopbackRequired(dut) { + gnmi.Update(t, dut, gnmi.OC().Config(), d) + // add loopback interface to ISIS + aggIDs = append(aggIDs, "Loopback0") + } // Add other ISIS interfaces for _, aggID := range aggIDs { isisIntf := isis.GetOrCreateInterface(aggID) @@ -652,7 +665,11 @@ func configureDUTISIS(t *testing.T, dut *ondatra.DUTDevice, aggIDs []string) { isisIntfLevelAfiv6.Enabled = nil } } - gnmi.Update(t, dut, dutConfIsisPath.Config(), prot) + if deviations.ISISLoopbackRequired(dut) { + gnmi.Update(t, dut, dutConfIsisPath.Config(), prot) + } else { + gnmi.Update(t, dut, gnmi.OC().Config(), d) + } } func configureDUTBGP(t *testing.T, dut *ondatra.DUTDevice) { @@ -695,7 +712,7 @@ func configureDUTBGP(t *testing.T, dut *ondatra.DUTDevice) { bgpNbrV4.Enabled = ygot.Bool(true) bgpNbrV4T := bgpNbrV4.GetOrCreateTransport() localAddressLeafv4 := dutLoopback.IPv4 - if dut.Vendor() == ondatra.CISCO { + if deviations.ISISLoopbackRequired(dut) { localAddressLeafv4 = lb } bgpNbrV4T.LocalAddress = ygot.String(localAddressLeafv4) @@ -710,7 +727,7 @@ func configureDUTBGP(t *testing.T, dut *ondatra.DUTDevice) { bgpNbrV6.Enabled = ygot.Bool(true) bgpNbrV6T := bgpNbrV6.GetOrCreateTransport() localAddressLeafv6 := dutLoopback.IPv6 - if dut.Vendor() == ondatra.CISCO { + if deviations.ISISLoopbackRequired(dut) { localAddressLeafv6 = lb } bgpNbrV6T.LocalAddress = ygot.String(localAddressLeafv6) @@ -743,21 +760,23 @@ func VerifyISISTelemetry(t *testing.T, dut *ondatra.DUTDevice, dutIntfs []string t.Fatal("No IS-IS adjacencies reported.") } } - // verify loopback has been received via ISIS - t.Log("Starting route check") - for _, loopBack := range loopBacks { - batch := gnmi.OCBatch() - statePath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)) - id := formatID(loopBack.ateISISSysID) - iPv4Query := statePath.Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, isisInstance).Isis().Level(uint8(isisLevel)).Lsp(id).Tlv(oc.IsisLsdbTypes_ISIS_TLV_TYPE_EXTENDED_IPV4_REACHABILITY).ExtendedIpv4Reachability().Prefix(fmt.Sprintf(loopBack.ateLoopbackV4 + "/32")) - iPv6Query := statePath.Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, isisInstance).Isis().Level(uint8(isisLevel)).Lsp(id).Tlv(oc.IsisLsdbTypes_ISIS_TLV_TYPE_IPV6_REACHABILITY).ExtendedIpv4Reachability().Prefix(fmt.Sprintf(loopBack.ateLoopbackV6 + "/128")) - batch.AddPaths(iPv4Query, iPv6Query) - _, ok := gnmi.Watch(t, dut, batch.State(), 5*time.Minute, func(val *ygnmi.Value[*oc.Root]) bool { - _, present := val.Val() - return present - }).Await(t) - if !ok { - t.Fatalf("ISIS did not receive the route loopback %s", loopBack.ateLoopbackV4) + if deviations.ISISLoopbackRequired(dut) { + // verify loopback has been received via ISIS + t.Log("Starting route check") + for _, loopBack := range loopBacks { + batch := gnmi.OCBatch() + statePath := gnmi.OC().NetworkInstance(deviations.DefaultNetworkInstance(dut)) + id := formatID(loopBack.ateISISSysID) + iPv4Query := statePath.Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, isisInstance).Isis().Level(uint8(isisLevel)).Lsp(id).Tlv(oc.IsisLsdbTypes_ISIS_TLV_TYPE_EXTENDED_IPV4_REACHABILITY).ExtendedIpv4Reachability().Prefix(fmt.Sprintf(loopBack.ateLoopbackV4 + "/32")) + iPv6Query := statePath.Protocol(oc.PolicyTypes_INSTALL_PROTOCOL_TYPE_ISIS, isisInstance).Isis().Level(uint8(isisLevel)).Lsp(id).Tlv(oc.IsisLsdbTypes_ISIS_TLV_TYPE_IPV6_REACHABILITY).ExtendedIpv4Reachability().Prefix(fmt.Sprintf(loopBack.ateLoopbackV6 + "/128")) + batch.AddPaths(iPv4Query, iPv6Query) + _, ok := gnmi.Watch(t, dut, batch.State(), 5*time.Minute, func(val *ygnmi.Value[*oc.Root]) bool { + _, present := val.Val() + return present + }).Await(t) + if !ok { + t.Fatalf("ISIS did not receive the route loopback %s", loopBack.ateLoopbackV4) + } } } } diff --git a/internal/deviations/deviations.go b/internal/deviations/deviations.go index ccc70470ae0..61048759957 100644 --- a/internal/deviations/deviations.go +++ b/internal/deviations/deviations.go @@ -1067,3 +1067,13 @@ func WecmpAutoUnsupported(dut *ondatra.DUTDevice) bool { func RoutingPolicyChainingUnsupported(dut *ondatra.DUTDevice) bool { return lookupDUTDeviations(dut).GetRoutingPolicyChainingUnsupported() } + +// ISISLoopbackRequired returns true if isis loopback is required. +func ISISLoopbackRequired(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetIsisLoopbackRequired() +} + +// WeightedEcmpFixedPacketVerification returns true if fixed packet is used in traffic flow +func WeightedEcmpFixedPacketVerification(dut *ondatra.DUTDevice) bool { + return lookupDUTDeviations(dut).GetWeightedEcmpFixedPacketVerification() +} diff --git a/proto/metadata.proto b/proto/metadata.proto index 6c90d2ea153..0a1b0fa29f8 100644 --- a/proto/metadata.proto +++ b/proto/metadata.proto @@ -580,6 +580,10 @@ message Metadata { bool wecmp_auto_unsupported = 199; // policy chaining, ie. more than one policy at an attachement point is not supported bool routing_policy_chaining_unsupported = 200; + // isis loopback config required + bool isis_loopback_required = 201; + // weighted ecmp feature verification using fixed packet + bool weighted_ecmp_fixed_packet_verification = 202; // Reserved field numbers and identifiers. reserved 84, 9, 28, 20, 90, 97, 55, 89, 19, 36; diff --git a/proto/metadata_go_proto/metadata.pb.go b/proto/metadata_go_proto/metadata.pb.go index 1bfe93b3dd7..f9a00f4268a 100644 --- a/proto/metadata_go_proto/metadata.pb.go +++ b/proto/metadata_go_proto/metadata.pb.go @@ -14,8 +14,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.1 -// protoc v4.25.1 +// protoc-gen-go v1.28.1 +// protoc v3.21.12 // source: metadata.proto package metadata_go_proto @@ -862,6 +862,10 @@ type Metadata_Deviations struct { WecmpAutoUnsupported bool `protobuf:"varint,199,opt,name=wecmp_auto_unsupported,json=wecmpAutoUnsupported,proto3" json:"wecmp_auto_unsupported,omitempty"` // policy chaining, ie. more than one policy at an attachement point is not supported RoutingPolicyChainingUnsupported bool `protobuf:"varint,200,opt,name=routing_policy_chaining_unsupported,json=routingPolicyChainingUnsupported,proto3" json:"routing_policy_chaining_unsupported,omitempty"` + // isis loopback config required + IsisLoopbackRequired bool `protobuf:"varint,201,opt,name=isis_loopback_required,json=isisLoopbackRequired,proto3" json:"isis_loopback_required,omitempty"` + // weighted ecmp feature verification using fixed packet + WeightedEcmpFixedPacketVerification bool `protobuf:"varint,202,opt,name=weighted_ecmp_fixed_packet_verification,json=weightedEcmpFixedPacketVerification,proto3" json:"weighted_ecmp_fixed_packet_verification,omitempty"` } func (x *Metadata_Deviations) Reset() { @@ -2177,6 +2181,20 @@ func (x *Metadata_Deviations) GetRoutingPolicyChainingUnsupported() bool { return false } +func (x *Metadata_Deviations) GetIsisLoopbackRequired() bool { + if x != nil { + return x.IsisLoopbackRequired + } + return false +} + +func (x *Metadata_Deviations) GetWeightedEcmpFixedPacketVerification() bool { + if x != nil { + return x.WeightedEcmpFixedPacketVerification + } + return false +} + type Metadata_PlatformExceptions struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2240,7 +2258,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, 0x98, 0x71, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa6, 0x72, 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, @@ -2274,7 +2292,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, 0xeb, 0x68, 0x0a, 0x0a, 0x44, 0x65, 0x76, 0x69, 0x61, 0x74, + 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x1a, 0xf9, 0x69, 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, @@ -3109,44 +3127,53 @@ var file_metadata_proto_rawDesc = []byte{ 0x6e, 0x67, 0x5f, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0xc8, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x20, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x55, 0x6e, 0x73, 0x75, - 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 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, 0x4a, 0x04, 0x08, - 0x24, 0x10, 0x25, 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, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x35, 0x0a, 0x16, 0x69, 0x73, 0x69, 0x73, 0x5f, + 0x6c, 0x6f, 0x6f, 0x70, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, + 0x64, 0x18, 0xc9, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x69, 0x73, 0x69, 0x73, 0x4c, 0x6f, + 0x6f, 0x70, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x55, + 0x0a, 0x27, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x65, 0x64, 0x5f, 0x65, 0x63, 0x6d, 0x70, 0x5f, + 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x76, 0x65, 0x72, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xca, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x23, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x65, 0x64, 0x45, 0x63, 0x6d, 0x70, 0x46, 0x69, + 0x78, 0x65, 0x64, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x4a, 0x04, 0x08, 0x24, 0x10, + 0x25, 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 (