From 77a11dc65a5c85ae91fa19a309f4589c4d8254fd Mon Sep 17 00:00:00 2001 From: Milan Lenco Date: Thu, 9 May 2019 09:47:05 +0200 Subject: [PATCH 01/13] Update NAT example for VPP 19.04. Signed-off-by: Milan Lenco --- examples/kvscheduler/nat/main.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/examples/kvscheduler/nat/main.go b/examples/kvscheduler/nat/main.go index 4e2595f62b..ab85d0a87a 100644 --- a/examples/kvscheduler/nat/main.go +++ b/examples/kvscheduler/nat/main.go @@ -38,6 +38,12 @@ import ( /* This example demonstrates natplugin v.2 + Add this config stanza to the VPP startup configuration: + + nat { + endpoint-dependent + } + Deploy microservices with servers: host-term1$ docker run -it --rm -e MICROSERVICE_LABEL=microservice-server1 lencomilan/ubuntu /bin/bash @@ -66,7 +72,7 @@ import ( # Accessing server 192.168.13.10:8080 running in the host should trigger # source-NAT in the post-routing, i.e. no need to route microservices from the host: - host-term3$ nc 192.168.13.10 8080 # host-term3 = microservice-client + host-term3$ nc 192.168.13.20 8080 # host-term3 = microservice-client */ func main() { @@ -160,6 +166,7 @@ func testLocalClientWithScheduler() { } // data change + /* UNCOMMENT TO TEST THE CONFIG CHANGE time.Sleep(time.Second * 10) fmt.Println("=== CHANGE ===") @@ -173,7 +180,7 @@ func testLocalClientWithScheduler() { fmt.Println(err) return } - + */ } const ( @@ -198,11 +205,11 @@ const ( vppTapServer1LogicalName = "vpp-tap-server1" vppTapServer1IPAddr = microserviceServer1NetPrefix + "1" - vppTapServer1Version = 1 + vppTapServer1Version = 2 vppTapServer2LogicalName = "vpp-tap-server2" vppTapServer2IPAddr = microserviceServer2NetPrefix + "1" - vppTapServer2Version = 1 + vppTapServer2Version = 2 linuxTapHostLogicalName = "linux-tap-host" linuxTapHostIPAddr = hostNetPrefix + "20" From 2ca31075cad16eaafcea6f4ff3e646aa3f9196a5 Mon Sep 17 00:00:00 2001 From: Milan Lenco Date: Fri, 10 May 2019 17:23:30 +0200 Subject: [PATCH 02/13] Rework RxPlacement and RxMode to allow per-queue configuration Signed-off-by: Milan Lenco --- api/models/vpp/interfaces/interface.pb.go | 465 ++++++++---------- api/models/vpp/interfaces/interface.proto | 20 +- plugins/vpp/ifplugin/descriptor/interface.go | 153 ++++-- .../vpp/ifplugin/descriptor/interface_crud.go | 98 ++-- plugins/vpp/ifplugin/vppcalls/if_vppcalls.go | 6 +- .../vpp1901/dump_interface_vppcalls.go | 30 +- .../vppcalls/vpp1901/rx_mode_vppcalls.go | 9 +- .../vppcalls/vpp1901/rx_placement_vppcalls.go | 8 +- .../vpp1904/dump_interface_vppcalls.go | 28 +- .../vppcalls/vpp1904/rx_mode_vppcalls.go | 9 +- .../vppcalls/vpp1904/rx_placement_vppcalls.go | 8 +- 11 files changed, 435 insertions(+), 399 deletions(-) diff --git a/api/models/vpp/interfaces/interface.pb.go b/api/models/vpp/interfaces/interface.pb.go index 13d6d536b1..ab16002802 100644 --- a/api/models/vpp/interfaces/interface.pb.go +++ b/api/models/vpp/interfaces/interface.pb.go @@ -67,28 +67,28 @@ func (x Interface_Type) String() string { return proto.EnumName(Interface_Type_name, int32(x)) } func (Interface_Type) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_interface_5716be75ac69639b, []int{0, 0} + return fileDescriptor_interface_e8af70d2126ce26f, []int{0, 0} } // from vpp/build-root/install-vpp-native/vpp/include/vnet/interface.h -type Interface_RxModeSettings_RxModeType int32 +type Interface_RxMode_Type int32 const ( - Interface_RxModeSettings_UNKNOWN Interface_RxModeSettings_RxModeType = 0 - Interface_RxModeSettings_POLLING Interface_RxModeSettings_RxModeType = 1 - Interface_RxModeSettings_INTERRUPT Interface_RxModeSettings_RxModeType = 2 - Interface_RxModeSettings_ADAPTIVE Interface_RxModeSettings_RxModeType = 3 - Interface_RxModeSettings_DEFAULT Interface_RxModeSettings_RxModeType = 4 + Interface_RxMode_UNKNOWN Interface_RxMode_Type = 0 + Interface_RxMode_POLLING Interface_RxMode_Type = 1 + Interface_RxMode_INTERRUPT Interface_RxMode_Type = 2 + Interface_RxMode_ADAPTIVE Interface_RxMode_Type = 3 + Interface_RxMode_DEFAULT Interface_RxMode_Type = 4 ) -var Interface_RxModeSettings_RxModeType_name = map[int32]string{ +var Interface_RxMode_Type_name = map[int32]string{ 0: "UNKNOWN", 1: "POLLING", 2: "INTERRUPT", 3: "ADAPTIVE", 4: "DEFAULT", } -var Interface_RxModeSettings_RxModeType_value = map[string]int32{ +var Interface_RxMode_Type_value = map[string]int32{ "UNKNOWN": 0, "POLLING": 1, "INTERRUPT": 2, @@ -96,11 +96,11 @@ var Interface_RxModeSettings_RxModeType_value = map[string]int32{ "DEFAULT": 4, } -func (x Interface_RxModeSettings_RxModeType) String() string { - return proto.EnumName(Interface_RxModeSettings_RxModeType_name, int32(x)) +func (x Interface_RxMode_Type) String() string { + return proto.EnumName(Interface_RxMode_Type_name, int32(x)) } -func (Interface_RxModeSettings_RxModeType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_interface_5716be75ac69639b, []int{0, 1, 0} +func (Interface_RxMode_Type) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_interface_e8af70d2126ce26f, []int{0, 1, 0} } type SubInterface_TagRewriteOptions int32 @@ -144,7 +144,7 @@ func (x SubInterface_TagRewriteOptions) String() string { return proto.EnumName(SubInterface_TagRewriteOptions_name, int32(x)) } func (SubInterface_TagRewriteOptions) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_interface_5716be75ac69639b, []int{1, 0} + return fileDescriptor_interface_e8af70d2126ce26f, []int{1, 0} } type MemifLink_MemifMode int32 @@ -170,7 +170,7 @@ func (x MemifLink_MemifMode) String() string { return proto.EnumName(MemifLink_MemifMode_name, int32(x)) } func (MemifLink_MemifMode) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_interface_5716be75ac69639b, []int{2, 0} + return fileDescriptor_interface_e8af70d2126ce26f, []int{2, 0} } type BondLink_Mode int32 @@ -205,7 +205,7 @@ func (x BondLink_Mode) String() string { return proto.EnumName(BondLink_Mode_name, int32(x)) } func (BondLink_Mode) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_interface_5716be75ac69639b, []int{8, 0} + return fileDescriptor_interface_e8af70d2126ce26f, []int{8, 0} } type BondLink_LoadBalance int32 @@ -231,21 +231,21 @@ func (x BondLink_LoadBalance) String() string { return proto.EnumName(BondLink_LoadBalance_name, int32(x)) } func (BondLink_LoadBalance) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_interface_5716be75ac69639b, []int{8, 1} + return fileDescriptor_interface_e8af70d2126ce26f, []int{8, 1} } type Interface struct { - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Type Interface_Type `protobuf:"varint,2,opt,name=type,proto3,enum=vpp.interfaces.Interface_Type" json:"type,omitempty"` - Enabled bool `protobuf:"varint,3,opt,name=enabled,proto3" json:"enabled,omitempty"` - PhysAddress string `protobuf:"bytes,4,opt,name=phys_address,json=physAddress,proto3" json:"phys_address,omitempty"` - IpAddresses []string `protobuf:"bytes,5,rep,name=ip_addresses,json=ipAddresses,proto3" json:"ip_addresses,omitempty"` - Vrf uint32 `protobuf:"varint,6,opt,name=vrf,proto3" json:"vrf,omitempty"` - SetDhcpClient bool `protobuf:"varint,7,opt,name=set_dhcp_client,json=setDhcpClient,proto3" json:"set_dhcp_client,omitempty"` - Mtu uint32 `protobuf:"varint,8,opt,name=mtu,proto3" json:"mtu,omitempty"` - Unnumbered *Interface_Unnumbered `protobuf:"bytes,9,opt,name=unnumbered,proto3" json:"unnumbered,omitempty"` - RxModeSettings *Interface_RxModeSettings `protobuf:"bytes,10,opt,name=rx_mode_settings,json=rxModeSettings,proto3" json:"rx_mode_settings,omitempty"` - RxPlacementSettings *Interface_RxPlacementSettings `protobuf:"bytes,11,opt,name=rx_placement_settings,json=rxPlacementSettings,proto3" json:"rx_placement_settings,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Type Interface_Type `protobuf:"varint,2,opt,name=type,proto3,enum=vpp.interfaces.Interface_Type" json:"type,omitempty"` + Enabled bool `protobuf:"varint,3,opt,name=enabled,proto3" json:"enabled,omitempty"` + PhysAddress string `protobuf:"bytes,4,opt,name=phys_address,json=physAddress,proto3" json:"phys_address,omitempty"` + IpAddresses []string `protobuf:"bytes,5,rep,name=ip_addresses,json=ipAddresses,proto3" json:"ip_addresses,omitempty"` + Vrf uint32 `protobuf:"varint,6,opt,name=vrf,proto3" json:"vrf,omitempty"` + SetDhcpClient bool `protobuf:"varint,7,opt,name=set_dhcp_client,json=setDhcpClient,proto3" json:"set_dhcp_client,omitempty"` + Mtu uint32 `protobuf:"varint,8,opt,name=mtu,proto3" json:"mtu,omitempty"` + Unnumbered *Interface_Unnumbered `protobuf:"bytes,9,opt,name=unnumbered,proto3" json:"unnumbered,omitempty"` + RxMode *Interface_RxMode `protobuf:"bytes,10,opt,name=rx_mode,json=rxMode,proto3" json:"rx_mode,omitempty"` + RxPlacement map[uint32]uint32 `protobuf:"bytes,11,rep,name=rx_placement,json=rxPlacement,proto3" json:"rx_placement,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` // Types that are valid to be assigned to Link: // *Interface_Sub // *Interface_Memif @@ -265,7 +265,7 @@ func (m *Interface) Reset() { *m = Interface{} } func (m *Interface) String() string { return proto.CompactTextString(m) } func (*Interface) ProtoMessage() {} func (*Interface) Descriptor() ([]byte, []int) { - return fileDescriptor_interface_5716be75ac69639b, []int{0} + return fileDescriptor_interface_e8af70d2126ce26f, []int{0} } func (m *Interface) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Interface.Unmarshal(m, b) @@ -393,16 +393,16 @@ func (m *Interface) GetUnnumbered() *Interface_Unnumbered { return nil } -func (m *Interface) GetRxModeSettings() *Interface_RxModeSettings { +func (m *Interface) GetRxMode() *Interface_RxMode { if m != nil { - return m.RxModeSettings + return m.RxMode } return nil } -func (m *Interface) GetRxPlacementSettings() *Interface_RxPlacementSettings { +func (m *Interface) GetRxPlacement() map[uint32]uint32 { if m != nil { - return m.RxPlacementSettings + return m.RxPlacement } return nil } @@ -666,7 +666,7 @@ func (m *Interface_Unnumbered) Reset() { *m = Interface_Unnumbered{} } func (m *Interface_Unnumbered) String() string { return proto.CompactTextString(m) } func (*Interface_Unnumbered) ProtoMessage() {} func (*Interface_Unnumbered) Descriptor() ([]byte, []int) { - return fileDescriptor_interface_5716be75ac69639b, []int{0, 0} + return fileDescriptor_interface_e8af70d2126ce26f, []int{0, 0} } func (m *Interface_Unnumbered) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Interface_Unnumbered.Unmarshal(m, b) @@ -697,120 +697,54 @@ func (*Interface_Unnumbered) XXX_MessageName() string { return "vpp.interfaces.Interface.Unnumbered" } -type Interface_RxModeSettings struct { - RxMode Interface_RxModeSettings_RxModeType `protobuf:"varint,1,opt,name=rx_mode,json=rxMode,proto3,enum=vpp.interfaces.Interface_RxModeSettings_RxModeType" json:"rx_mode,omitempty"` - QueueId uint32 `protobuf:"varint,2,opt,name=queue_id,json=queueId,proto3" json:"queue_id,omitempty"` - QueueIdValid uint32 `protobuf:"varint,3,opt,name=queue_id_valid,json=queueIdValid,proto3" json:"queue_id_valid,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` +type Interface_RxMode struct { + DefaultRxMode Interface_RxMode_Type `protobuf:"varint,1,opt,name=default_rx_mode,json=defaultRxMode,proto3,enum=vpp.interfaces.Interface_RxMode_Type" json:"default_rx_mode,omitempty"` + QueueRxMode map[uint32]Interface_RxMode_Type `protobuf:"bytes,2,rep,name=queue_rx_mode,json=queueRxMode,proto3" json:"queue_rx_mode,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3,enum=vpp.interfaces.Interface_RxMode_Type"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *Interface_RxModeSettings) Reset() { *m = Interface_RxModeSettings{} } -func (m *Interface_RxModeSettings) String() string { return proto.CompactTextString(m) } -func (*Interface_RxModeSettings) ProtoMessage() {} -func (*Interface_RxModeSettings) Descriptor() ([]byte, []int) { - return fileDescriptor_interface_5716be75ac69639b, []int{0, 1} +func (m *Interface_RxMode) Reset() { *m = Interface_RxMode{} } +func (m *Interface_RxMode) String() string { return proto.CompactTextString(m) } +func (*Interface_RxMode) ProtoMessage() {} +func (*Interface_RxMode) Descriptor() ([]byte, []int) { + return fileDescriptor_interface_e8af70d2126ce26f, []int{0, 1} } -func (m *Interface_RxModeSettings) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Interface_RxModeSettings.Unmarshal(m, b) +func (m *Interface_RxMode) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Interface_RxMode.Unmarshal(m, b) } -func (m *Interface_RxModeSettings) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Interface_RxModeSettings.Marshal(b, m, deterministic) +func (m *Interface_RxMode) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Interface_RxMode.Marshal(b, m, deterministic) } -func (dst *Interface_RxModeSettings) XXX_Merge(src proto.Message) { - xxx_messageInfo_Interface_RxModeSettings.Merge(dst, src) +func (dst *Interface_RxMode) XXX_Merge(src proto.Message) { + xxx_messageInfo_Interface_RxMode.Merge(dst, src) } -func (m *Interface_RxModeSettings) XXX_Size() int { - return xxx_messageInfo_Interface_RxModeSettings.Size(m) +func (m *Interface_RxMode) XXX_Size() int { + return xxx_messageInfo_Interface_RxMode.Size(m) } -func (m *Interface_RxModeSettings) XXX_DiscardUnknown() { - xxx_messageInfo_Interface_RxModeSettings.DiscardUnknown(m) +func (m *Interface_RxMode) XXX_DiscardUnknown() { + xxx_messageInfo_Interface_RxMode.DiscardUnknown(m) } -var xxx_messageInfo_Interface_RxModeSettings proto.InternalMessageInfo - -func (m *Interface_RxModeSettings) GetRxMode() Interface_RxModeSettings_RxModeType { - if m != nil { - return m.RxMode - } - return Interface_RxModeSettings_UNKNOWN -} +var xxx_messageInfo_Interface_RxMode proto.InternalMessageInfo -func (m *Interface_RxModeSettings) GetQueueId() uint32 { +func (m *Interface_RxMode) GetDefaultRxMode() Interface_RxMode_Type { if m != nil { - return m.QueueId + return m.DefaultRxMode } - return 0 + return Interface_RxMode_UNKNOWN } -func (m *Interface_RxModeSettings) GetQueueIdValid() uint32 { +func (m *Interface_RxMode) GetQueueRxMode() map[uint32]Interface_RxMode_Type { if m != nil { - return m.QueueIdValid + return m.QueueRxMode } - return 0 -} - -func (*Interface_RxModeSettings) XXX_MessageName() string { - return "vpp.interfaces.Interface.RxModeSettings" -} - -type Interface_RxPlacementSettings struct { - Queue uint32 `protobuf:"varint,1,opt,name=queue,proto3" json:"queue,omitempty"` - Worker uint32 `protobuf:"varint,2,opt,name=worker,proto3" json:"worker,omitempty"` - IsMain bool `protobuf:"varint,3,opt,name=is_main,json=isMain,proto3" json:"is_main,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Interface_RxPlacementSettings) Reset() { *m = Interface_RxPlacementSettings{} } -func (m *Interface_RxPlacementSettings) String() string { return proto.CompactTextString(m) } -func (*Interface_RxPlacementSettings) ProtoMessage() {} -func (*Interface_RxPlacementSettings) Descriptor() ([]byte, []int) { - return fileDescriptor_interface_5716be75ac69639b, []int{0, 2} -} -func (m *Interface_RxPlacementSettings) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Interface_RxPlacementSettings.Unmarshal(m, b) -} -func (m *Interface_RxPlacementSettings) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Interface_RxPlacementSettings.Marshal(b, m, deterministic) -} -func (dst *Interface_RxPlacementSettings) XXX_Merge(src proto.Message) { - xxx_messageInfo_Interface_RxPlacementSettings.Merge(dst, src) -} -func (m *Interface_RxPlacementSettings) XXX_Size() int { - return xxx_messageInfo_Interface_RxPlacementSettings.Size(m) -} -func (m *Interface_RxPlacementSettings) XXX_DiscardUnknown() { - xxx_messageInfo_Interface_RxPlacementSettings.DiscardUnknown(m) -} - -var xxx_messageInfo_Interface_RxPlacementSettings proto.InternalMessageInfo - -func (m *Interface_RxPlacementSettings) GetQueue() uint32 { - if m != nil { - return m.Queue - } - return 0 -} - -func (m *Interface_RxPlacementSettings) GetWorker() uint32 { - if m != nil { - return m.Worker - } - return 0 -} - -func (m *Interface_RxPlacementSettings) GetIsMain() bool { - if m != nil { - return m.IsMain - } - return false + return nil } -func (*Interface_RxPlacementSettings) XXX_MessageName() string { - return "vpp.interfaces.Interface.RxPlacementSettings" +func (*Interface_RxMode) XXX_MessageName() string { + return "vpp.interfaces.Interface.RxMode" } type SubInterface struct { @@ -829,7 +763,7 @@ func (m *SubInterface) Reset() { *m = SubInterface{} } func (m *SubInterface) String() string { return proto.CompactTextString(m) } func (*SubInterface) ProtoMessage() {} func (*SubInterface) Descriptor() ([]byte, []int) { - return fileDescriptor_interface_5716be75ac69639b, []int{1} + return fileDescriptor_interface_e8af70d2126ce26f, []int{1} } func (m *SubInterface) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SubInterface.Unmarshal(m, b) @@ -914,7 +848,7 @@ func (m *MemifLink) Reset() { *m = MemifLink{} } func (m *MemifLink) String() string { return proto.CompactTextString(m) } func (*MemifLink) ProtoMessage() {} func (*MemifLink) Descriptor() ([]byte, []int) { - return fileDescriptor_interface_5716be75ac69639b, []int{2} + return fileDescriptor_interface_e8af70d2126ce26f, []int{2} } func (m *MemifLink) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_MemifLink.Unmarshal(m, b) @@ -1015,7 +949,7 @@ func (m *VxlanLink) Reset() { *m = VxlanLink{} } func (m *VxlanLink) String() string { return proto.CompactTextString(m) } func (*VxlanLink) ProtoMessage() {} func (*VxlanLink) Descriptor() ([]byte, []int) { - return fileDescriptor_interface_5716be75ac69639b, []int{3} + return fileDescriptor_interface_e8af70d2126ce26f, []int{3} } func (m *VxlanLink) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_VxlanLink.Unmarshal(m, b) @@ -1078,7 +1012,7 @@ func (m *AfpacketLink) Reset() { *m = AfpacketLink{} } func (m *AfpacketLink) String() string { return proto.CompactTextString(m) } func (*AfpacketLink) ProtoMessage() {} func (*AfpacketLink) Descriptor() ([]byte, []int) { - return fileDescriptor_interface_5716be75ac69639b, []int{4} + return fileDescriptor_interface_e8af70d2126ce26f, []int{4} } func (m *AfpacketLink) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_AfpacketLink.Unmarshal(m, b) @@ -1124,7 +1058,7 @@ func (m *TapLink) Reset() { *m = TapLink{} } func (m *TapLink) String() string { return proto.CompactTextString(m) } func (*TapLink) ProtoMessage() {} func (*TapLink) Descriptor() ([]byte, []int) { - return fileDescriptor_interface_5716be75ac69639b, []int{5} + return fileDescriptor_interface_e8af70d2126ce26f, []int{5} } func (m *TapLink) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TapLink.Unmarshal(m, b) @@ -1206,7 +1140,7 @@ func (m *IPSecLink) Reset() { *m = IPSecLink{} } func (m *IPSecLink) String() string { return proto.CompactTextString(m) } func (*IPSecLink) ProtoMessage() {} func (*IPSecLink) Descriptor() ([]byte, []int) { - return fileDescriptor_interface_5716be75ac69639b, []int{6} + return fileDescriptor_interface_e8af70d2126ce26f, []int{6} } func (m *IPSecLink) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_IPSecLink.Unmarshal(m, b) @@ -1337,7 +1271,7 @@ func (m *VmxNet3Link) Reset() { *m = VmxNet3Link{} } func (m *VmxNet3Link) String() string { return proto.CompactTextString(m) } func (*VmxNet3Link) ProtoMessage() {} func (*VmxNet3Link) Descriptor() ([]byte, []int) { - return fileDescriptor_interface_5716be75ac69639b, []int{7} + return fileDescriptor_interface_e8af70d2126ce26f, []int{7} } func (m *VmxNet3Link) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_VmxNet3Link.Unmarshal(m, b) @@ -1396,7 +1330,7 @@ func (m *BondLink) Reset() { *m = BondLink{} } func (m *BondLink) String() string { return proto.CompactTextString(m) } func (*BondLink) ProtoMessage() {} func (*BondLink) Descriptor() ([]byte, []int) { - return fileDescriptor_interface_5716be75ac69639b, []int{8} + return fileDescriptor_interface_e8af70d2126ce26f, []int{8} } func (m *BondLink) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BondLink.Unmarshal(m, b) @@ -1461,7 +1395,7 @@ func (m *BondLink_BondedInterface) Reset() { *m = BondLink_BondedInterfa func (m *BondLink_BondedInterface) String() string { return proto.CompactTextString(m) } func (*BondLink_BondedInterface) ProtoMessage() {} func (*BondLink_BondedInterface) Descriptor() ([]byte, []int) { - return fileDescriptor_interface_5716be75ac69639b, []int{8, 0} + return fileDescriptor_interface_e8af70d2126ce26f, []int{8, 0} } func (m *BondLink_BondedInterface) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BondLink_BondedInterface.Unmarshal(m, b) @@ -1507,9 +1441,10 @@ func (*BondLink_BondedInterface) XXX_MessageName() string { } func init() { proto.RegisterType((*Interface)(nil), "vpp.interfaces.Interface") + proto.RegisterMapType((map[uint32]uint32)(nil), "vpp.interfaces.Interface.RxPlacementEntry") proto.RegisterType((*Interface_Unnumbered)(nil), "vpp.interfaces.Interface.Unnumbered") - proto.RegisterType((*Interface_RxModeSettings)(nil), "vpp.interfaces.Interface.RxModeSettings") - proto.RegisterType((*Interface_RxPlacementSettings)(nil), "vpp.interfaces.Interface.RxPlacementSettings") + proto.RegisterType((*Interface_RxMode)(nil), "vpp.interfaces.Interface.RxMode") + proto.RegisterMapType((map[uint32]Interface_RxMode_Type)(nil), "vpp.interfaces.Interface.RxMode.QueueRxModeEntry") proto.RegisterType((*SubInterface)(nil), "vpp.interfaces.SubInterface") proto.RegisterType((*MemifLink)(nil), "vpp.interfaces.MemifLink") proto.RegisterType((*VxlanLink)(nil), "vpp.interfaces.VxlanLink") @@ -1520,7 +1455,7 @@ func init() { proto.RegisterType((*BondLink)(nil), "vpp.interfaces.BondLink") proto.RegisterType((*BondLink_BondedInterface)(nil), "vpp.interfaces.BondLink.BondedInterface") proto.RegisterEnum("vpp.interfaces.Interface_Type", Interface_Type_name, Interface_Type_value) - proto.RegisterEnum("vpp.interfaces.Interface_RxModeSettings_RxModeType", Interface_RxModeSettings_RxModeType_name, Interface_RxModeSettings_RxModeType_value) + proto.RegisterEnum("vpp.interfaces.Interface_RxMode_Type", Interface_RxMode_Type_name, Interface_RxMode_Type_value) proto.RegisterEnum("vpp.interfaces.SubInterface_TagRewriteOptions", SubInterface_TagRewriteOptions_name, SubInterface_TagRewriteOptions_value) proto.RegisterEnum("vpp.interfaces.MemifLink_MemifMode", MemifLink_MemifMode_name, MemifLink_MemifMode_value) proto.RegisterEnum("vpp.interfaces.BondLink_Mode", BondLink_Mode_name, BondLink_Mode_value) @@ -1528,127 +1463,127 @@ func init() { } func init() { - proto.RegisterFile("models/vpp/interfaces/interface.proto", fileDescriptor_interface_5716be75ac69639b) -} - -var fileDescriptor_interface_5716be75ac69639b = []byte{ - // 1883 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x57, 0xdd, 0x72, 0xdb, 0xc6, - 0x15, 0x16, 0x7f, 0x24, 0x92, 0x87, 0x3f, 0x82, 0xd7, 0x71, 0x03, 0x2b, 0x76, 0xa2, 0xb2, 0x69, - 0xa3, 0x69, 0xc7, 0x92, 0x45, 0x65, 0xa6, 0x99, 0xf6, 0x0a, 0x14, 0xa1, 0x9a, 0x31, 0x45, 0xa2, - 0x20, 0x68, 0x3b, 0x9d, 0xce, 0x60, 0x40, 0x60, 0x09, 0x6d, 0x05, 0x02, 0x30, 0x76, 0x49, 0x53, - 0x99, 0xe9, 0x33, 0xf4, 0x5d, 0xfa, 0x04, 0xbd, 0xec, 0x45, 0x5f, 0xa0, 0xd7, 0xbd, 0xec, 0x55, - 0xa6, 0x2f, 0xd0, 0xd9, 0x1f, 0x82, 0xd4, 0x8f, 0x33, 0xb9, 0xe1, 0xec, 0x7e, 0xe7, 0x7c, 0x67, - 0x97, 0x67, 0xcf, 0x1f, 0xe0, 0x97, 0xf3, 0x24, 0xc0, 0x11, 0x3d, 0x59, 0xa6, 0xe9, 0x09, 0x89, - 0x19, 0xce, 0x66, 0x9e, 0x8f, 0xe9, 0x66, 0x79, 0x9c, 0x66, 0x09, 0x4b, 0x50, 0x6b, 0x99, 0xa6, - 0xc7, 0x1b, 0xf9, 0xc1, 0x8b, 0x90, 0xb0, 0xab, 0xc5, 0xf4, 0xd8, 0x4f, 0xe6, 0x27, 0x61, 0x12, - 0x26, 0x27, 0x42, 0x6d, 0xba, 0x98, 0x89, 0x9d, 0xd8, 0x88, 0x95, 0xa4, 0x1f, 0x3c, 0xdb, 0x3e, - 0x25, 0xa5, 0xd8, 0x97, 0xbf, 0x52, 0xda, 0xfe, 0xa1, 0x0e, 0xb5, 0xfe, 0xda, 0x36, 0x42, 0x50, - 0x8e, 0xbd, 0x39, 0xd6, 0x0b, 0x87, 0x85, 0xa3, 0x9a, 0x2d, 0xd6, 0xa8, 0x03, 0x65, 0x76, 0x93, - 0x62, 0xbd, 0x78, 0x58, 0x38, 0x6a, 0x75, 0x3e, 0x3f, 0xbe, 0x7d, 0x9b, 0xe3, 0x9c, 0x7c, 0xec, - 0xdc, 0xa4, 0xd8, 0x16, 0xba, 0x48, 0x87, 0x0a, 0x8e, 0xbd, 0x69, 0x84, 0x03, 0xbd, 0x74, 0x58, - 0x38, 0xaa, 0xda, 0xeb, 0x2d, 0xfa, 0x39, 0x34, 0xd2, 0xab, 0x1b, 0xea, 0x7a, 0x41, 0x90, 0x61, - 0x4a, 0xf5, 0xb2, 0x38, 0xa9, 0xce, 0x31, 0x43, 0x42, 0x5c, 0x85, 0xa4, 0x6b, 0x05, 0x4c, 0xf5, - 0xdd, 0xc3, 0x12, 0x57, 0x21, 0xa9, 0xb1, 0x86, 0x90, 0x06, 0xa5, 0x65, 0x36, 0xd3, 0xf7, 0x0e, - 0x0b, 0x47, 0x4d, 0x9b, 0x2f, 0xd1, 0xaf, 0x60, 0x9f, 0x62, 0xe6, 0x06, 0x57, 0x7e, 0xea, 0xfa, - 0x11, 0xc1, 0x31, 0xd3, 0x2b, 0xe2, 0xe4, 0x26, 0xc5, 0xac, 0x77, 0xe5, 0xa7, 0xe7, 0x02, 0xe4, - 0xcc, 0x39, 0x5b, 0xe8, 0x55, 0xc9, 0x9c, 0xb3, 0x05, 0xea, 0x01, 0x2c, 0xe2, 0x78, 0x31, 0x9f, - 0xe2, 0x0c, 0x07, 0x7a, 0xed, 0xb0, 0x70, 0x54, 0xef, 0x7c, 0xf9, 0xf1, 0x7f, 0x39, 0xc9, 0x75, - 0xed, 0x2d, 0x1e, 0xb2, 0x41, 0xcb, 0x56, 0x2e, 0x77, 0xb5, 0x4b, 0x31, 0x63, 0x24, 0x0e, 0xa9, - 0x0e, 0xc2, 0xd6, 0xd1, 0xc7, 0x6d, 0xd9, 0xab, 0xcb, 0x24, 0xc0, 0x63, 0xa5, 0x6f, 0xb7, 0xb2, - 0x5b, 0x7b, 0xe4, 0xc1, 0x93, 0x6c, 0xe5, 0xa6, 0x91, 0xe7, 0xe3, 0x39, 0x8e, 0xd9, 0xc6, 0x70, - 0x5d, 0x18, 0x7e, 0xf1, 0x63, 0x86, 0xad, 0x35, 0x2b, 0xb7, 0xfe, 0x38, 0xbb, 0x0f, 0xa2, 0x97, - 0x50, 0xa2, 0x8b, 0xa9, 0x1e, 0x08, 0x83, 0xcf, 0xee, 0x1a, 0x1c, 0x2f, 0xa6, 0xb9, 0xcd, 0x57, - 0x3b, 0x36, 0x57, 0x45, 0xa7, 0xb0, 0x3b, 0xc7, 0x73, 0x32, 0xd3, 0xb1, 0xe0, 0x3c, 0xbd, 0xcb, - 0xb9, 0xe4, 0xc2, 0x01, 0x89, 0xaf, 0x5f, 0xed, 0xd8, 0x52, 0x13, 0xfd, 0x0e, 0xaa, 0xde, 0x2c, - 0xf5, 0xfc, 0x6b, 0xcc, 0xf4, 0xd9, 0xc3, 0x27, 0x19, 0x4a, 0xae, 0x88, 0xb9, 0x3e, 0xfa, 0x0d, - 0x94, 0x98, 0x97, 0xea, 0xa1, 0xa0, 0x7d, 0x7a, 0x97, 0xe6, 0x78, 0xa9, 0x62, 0x70, 0x2d, 0x7e, - 0xb7, 0xe5, 0x2a, 0xf2, 0x62, 0xfd, 0xea, 0xe1, 0xbb, 0xbd, 0xe1, 0xc2, 0xf5, 0xdd, 0x84, 0x26, - 0xa7, 0x88, 0x74, 0xd0, 0xc9, 0xc3, 0x94, 0xbe, 0x35, 0xc6, 0xfe, 0x9a, 0x22, 0x34, 0xd1, 0x37, - 0x50, 0x5d, 0xce, 0x57, 0x6e, 0x8c, 0xd9, 0x99, 0xfe, 0x17, 0xc1, 0xfa, 0xec, 0xde, 0x41, 0xf3, - 0xd5, 0x10, 0xb3, 0x33, 0xc5, 0xab, 0x2c, 0xe5, 0x16, 0x1d, 0x43, 0x79, 0x9a, 0xc4, 0x81, 0x7e, - 0x2d, 0x58, 0xfa, 0x5d, 0x56, 0x37, 0x89, 0x03, 0x45, 0x11, 0x7a, 0x07, 0xdf, 0x00, 0x6c, 0xc2, - 0x0d, 0xfd, 0x1a, 0x1e, 0xe5, 0xca, 0xee, 0x07, 0xc2, 0xae, 0x5c, 0x92, 0xaa, 0x4c, 0xdd, 0xcf, - 0x05, 0x6f, 0x09, 0xbb, 0xea, 0xa7, 0x07, 0x3f, 0x14, 0xa0, 0x75, 0x3b, 0xba, 0xd0, 0x00, 0x2a, - 0x2a, 0x42, 0x05, 0xa9, 0xd5, 0x39, 0xfb, 0xa9, 0x81, 0xa9, 0xb6, 0x22, 0xbf, 0xf7, 0x64, 0x8c, - 0xa2, 0xa7, 0x50, 0x7d, 0xbf, 0xc0, 0x0b, 0xec, 0x92, 0x40, 0x54, 0x86, 0xa6, 0x5d, 0x11, 0xfb, - 0x7e, 0x80, 0xbe, 0x84, 0xd6, 0x5a, 0xe4, 0x2e, 0xbd, 0x88, 0xc8, 0x1a, 0xd0, 0xb4, 0x1b, 0x4a, - 0xe1, 0x0d, 0xc7, 0xda, 0x16, 0xc0, 0xc6, 0x2c, 0xaa, 0x43, 0x65, 0x32, 0x7c, 0x3d, 0x1c, 0xbd, - 0x1d, 0x6a, 0x3b, 0x7c, 0x63, 0x8d, 0x06, 0x83, 0xfe, 0xf0, 0x0f, 0x5a, 0x01, 0x35, 0xa1, 0xd6, - 0x1f, 0x3a, 0xa6, 0x6d, 0x4f, 0x2c, 0x47, 0x2b, 0xa2, 0x06, 0x54, 0x8d, 0x9e, 0x61, 0x39, 0xfd, - 0x37, 0xa6, 0x56, 0xe2, 0x9a, 0x3d, 0xf3, 0xc2, 0x98, 0x0c, 0x1c, 0xad, 0x7c, 0xf0, 0x67, 0x78, - 0xfc, 0x40, 0xdc, 0xa3, 0x4f, 0x60, 0x57, 0x1c, 0x2c, 0xfe, 0x75, 0xd3, 0x96, 0x1b, 0xf4, 0x33, - 0xd8, 0xfb, 0x90, 0x64, 0xd7, 0x38, 0x53, 0xb7, 0x57, 0x3b, 0xf4, 0x29, 0x54, 0x08, 0x75, 0xe7, - 0x1e, 0x89, 0x55, 0xe5, 0xda, 0x23, 0xf4, 0xd2, 0x23, 0x71, 0xfb, 0x1f, 0x05, 0x28, 0x8b, 0xab, - 0x22, 0x68, 0x4d, 0x86, 0x3d, 0xf3, 0xa2, 0x3f, 0x34, 0x7b, 0xae, 0xf3, 0x9d, 0x65, 0x6a, 0x3b, - 0xe8, 0x11, 0x34, 0xc7, 0x93, 0xae, 0x2b, 0x2e, 0x7a, 0x61, 0x9c, 0x9b, 0x5a, 0x01, 0x3d, 0x81, - 0x47, 0xe3, 0xd1, 0x85, 0xf3, 0xd6, 0xb0, 0x4d, 0x77, 0x30, 0x1a, 0x59, 0x5d, 0xe3, 0xfc, 0xb5, - 0x56, 0x44, 0x55, 0x28, 0xf7, 0xac, 0xde, 0x6b, 0xad, 0x84, 0x6a, 0xb0, 0x7b, 0x69, 0x5e, 0xf6, - 0x2f, 0xb4, 0x32, 0xaa, 0x40, 0xc9, 0x31, 0x2c, 0x6d, 0x97, 0xff, 0x59, 0xe3, 0xc2, 0xb5, 0x8c, - 0xf3, 0xd7, 0xa6, 0xa3, 0xed, 0x21, 0x0d, 0x1a, 0x6f, 0xde, 0x0d, 0x8c, 0xa1, 0xeb, 0x4c, 0x86, - 0x43, 0x73, 0xa0, 0x55, 0x38, 0xd2, 0xb7, 0xc6, 0xe6, 0xf9, 0x1a, 0xa9, 0xf2, 0x73, 0xde, 0x5c, - 0xbe, 0x1b, 0x9a, 0xce, 0xd9, 0xd6, 0xf1, 0x35, 0x7e, 0xcb, 0xee, 0x68, 0xd8, 0xdb, 0xc2, 0xa0, - 0xbb, 0x07, 0xe5, 0x88, 0xc4, 0xd7, 0xed, 0xff, 0x15, 0xa1, 0xb1, 0x9d, 0xda, 0xe8, 0x0b, 0xa8, - 0xa7, 0x5e, 0xc6, 0x4b, 0xcc, 0x56, 0xf5, 0x07, 0x09, 0x0d, 0x79, 0x0f, 0x78, 0x02, 0x7b, 0x74, - 0x31, 0xdd, 0xbc, 0xf5, 0x2e, 0x5d, 0x4c, 0xfb, 0xbc, 0xe8, 0x35, 0x99, 0x17, 0xba, 0xd9, 0x07, - 0x37, 0x49, 0x19, 0x49, 0xa4, 0xcb, 0x5a, 0x9d, 0xe3, 0x1f, 0xab, 0x23, 0xc7, 0x8e, 0x17, 0xda, - 0xf8, 0x43, 0x46, 0x18, 0x1e, 0x09, 0x12, 0xb5, 0xeb, 0xcc, 0x0b, 0xed, 0x0f, 0x72, 0x87, 0x9e, - 0x03, 0xa4, 0x0b, 0x7a, 0xe5, 0x06, 0x09, 0x3b, 0x7d, 0x2f, 0xda, 0x43, 0xd5, 0xae, 0x71, 0xa4, - 0xc7, 0x01, 0xde, 0xa1, 0x98, 0x17, 0x9e, 0xea, 0xbb, 0xe2, 0x1e, 0x62, 0xad, 0xb0, 0x8e, 0x6a, - 0x07, 0x62, 0xdd, 0xfe, 0x5b, 0x01, 0x1e, 0xdd, 0x3b, 0x89, 0x47, 0x4f, 0xaf, 0x3f, 0x36, 0xba, - 0x03, 0xb3, 0xa7, 0xed, 0xf0, 0x17, 0xb0, 0x26, 0xe3, 0x57, 0xa7, 0x5a, 0x61, 0xbd, 0xec, 0xc8, - 0x17, 0xb2, 0x46, 0xd6, 0xa9, 0x56, 0x52, 0xab, 0x8e, 0x56, 0x46, 0xfb, 0x50, 0x77, 0x6c, 0x63, - 0x38, 0x1e, 0x18, 0x8e, 0x79, 0x7a, 0xaa, 0xed, 0xde, 0x06, 0x3a, 0xda, 0xde, 0x2d, 0xa0, 0x73, - 0xaa, 0x55, 0x6e, 0x03, 0x1d, 0xad, 0xda, 0xfe, 0x77, 0x11, 0x6a, 0x79, 0x71, 0x44, 0xbf, 0x85, - 0xf2, 0x56, 0x2a, 0xfe, 0xe2, 0xa3, 0x55, 0x54, 0xae, 0x78, 0x9e, 0xd8, 0x82, 0xc0, 0x03, 0x77, - 0xee, 0x51, 0xa6, 0x02, 0xb7, 0x6a, 0xab, 0x1d, 0x6a, 0x41, 0x31, 0xcf, 0xb4, 0x22, 0x09, 0xd0, - 0x57, 0xb0, 0x4f, 0x13, 0x5e, 0x42, 0xdd, 0x19, 0x89, 0xb0, 0x78, 0x57, 0xd9, 0x6b, 0x5b, 0x12, - 0xbe, 0x50, 0x28, 0x37, 0x48, 0xb1, 0x9f, 0x61, 0x26, 0x7c, 0x5a, 0xb3, 0xd5, 0x0e, 0x7d, 0x06, - 0xb5, 0x8c, 0xc4, 0xa1, 0x4b, 0xc9, 0xf7, 0x58, 0xb9, 0xb6, 0xca, 0x81, 0x31, 0xf9, 0x5e, 0x44, - 0xcc, 0x74, 0x31, 0x9b, 0xe1, 0x4c, 0x8a, 0x2b, 0x42, 0x0c, 0x12, 0x12, 0x0a, 0x9c, 0xbd, 0x72, - 0x45, 0xae, 0x51, 0xd5, 0x6d, 0xab, 0xd9, 0xea, 0x8f, 0x62, 0xcf, 0x85, 0x2c, 0x17, 0xd6, 0xa4, - 0x90, 0x29, 0x61, 0xbb, 0xa3, 0xdc, 0x24, 0xca, 0x4c, 0x03, 0xaa, 0xa6, 0xf3, 0xca, 0xb4, 0x87, - 0xa6, 0xa3, 0xed, 0xa0, 0x3d, 0x28, 0xf6, 0x2d, 0xad, 0xc0, 0x7d, 0x6b, 0x4d, 0x86, 0x8e, 0xdb, - 0x1f, 0x7e, 0x6b, 0x9e, 0x3b, 0x5a, 0xb1, 0xfd, 0x57, 0xa8, 0xe5, 0xb5, 0x9d, 0xdf, 0x8d, 0x66, - 0x7e, 0x3e, 0x61, 0xa8, 0x68, 0xa6, 0x99, 0xbf, 0x1e, 0x30, 0xbe, 0x80, 0x7a, 0x40, 0x59, 0xae, - 0x50, 0x94, 0x0a, 0x01, 0x65, 0x6b, 0x05, 0x3e, 0x5e, 0xc4, 0x44, 0x39, 0x93, 0x2f, 0xd1, 0x33, - 0xa8, 0xcd, 0x17, 0x11, 0x23, 0xbe, 0x47, 0x99, 0xf2, 0xe3, 0x06, 0x68, 0xbf, 0x84, 0xc6, 0x76, - 0x03, 0x43, 0x87, 0xd0, 0xb8, 0x4a, 0x28, 0x73, 0xc9, 0xec, 0x56, 0x42, 0x71, 0xac, 0x3f, 0xe3, - 0x09, 0xd5, 0xfe, 0x7b, 0x01, 0x2a, 0xaa, 0x79, 0xf1, 0x61, 0x69, 0x89, 0x33, 0xca, 0xf3, 0x47, - 0x96, 0xa8, 0xf5, 0xf6, 0x9e, 0x9d, 0xe2, 0x5d, 0x3b, 0xfc, 0x95, 0x59, 0xe2, 0xce, 0x89, 0x9f, - 0x25, 0x14, 0x67, 0x4b, 0xe2, 0x63, 0x71, 0xeb, 0x9a, 0xdd, 0x62, 0xc9, 0xe5, 0x16, 0xca, 0x4d, - 0x65, 0x2b, 0x77, 0xf3, 0xa0, 0x65, 0xf9, 0x62, 0xd9, 0xca, 0x5e, 0x3f, 0xe9, 0x21, 0x34, 0xd8, - 0xb6, 0x86, 0xcc, 0x30, 0x60, 0xb9, 0x46, 0xfb, 0xbf, 0x25, 0xa8, 0xe5, 0xfd, 0x90, 0x3b, 0x09, - 0xd3, 0x58, 0x45, 0x21, 0x5f, 0x72, 0xbf, 0x7a, 0x31, 0x23, 0x6e, 0x86, 0xd3, 0xc8, 0xbb, 0x51, - 0xf5, 0x13, 0x38, 0x64, 0x0b, 0x84, 0x37, 0x8d, 0x28, 0xf1, 0xbd, 0x88, 0x37, 0x2e, 0xe9, 0xc4, - 0x8a, 0xd8, 0xf7, 0x53, 0x11, 0x2f, 0x78, 0x9e, 0x30, 0xcc, 0x65, 0x32, 0x10, 0xab, 0x12, 0x90, - 0x42, 0xc9, 0xa3, 0x29, 0x59, 0x87, 0xa2, 0x00, 0xc6, 0x29, 0xe1, 0x05, 0x43, 0x31, 0xb9, 0x54, - 0x46, 0xa2, 0xb2, 0xc5, 0xc5, 0x67, 0x00, 0x7e, 0x76, 0x93, 0xb2, 0xc4, 0xf5, 0xa2, 0x50, 0x44, - 0x62, 0xab, 0xf3, 0x89, 0x4c, 0x37, 0x31, 0x06, 0x9f, 0x0b, 0xa1, 0x11, 0x85, 0x76, 0xcd, 0x5f, - 0x2f, 0xd1, 0x11, 0x68, 0xf2, 0x40, 0x45, 0xbd, 0xc6, 0x37, 0x22, 0x4e, 0x6b, 0x76, 0x4b, 0xe0, - 0x92, 0xf4, 0x1a, 0xdf, 0xf0, 0xa6, 0xac, 0x4e, 0xdf, 0x52, 0x05, 0xd9, 0x94, 0xa5, 0x60, 0xa3, - 0xfb, 0x12, 0x6a, 0x3c, 0xc5, 0x43, 0x71, 0x93, 0xba, 0xb8, 0xc9, 0xe3, 0xad, 0x9b, 0xf0, 0x12, - 0x19, 0xf2, 0x8b, 0x54, 0x89, 0x5a, 0xf1, 0xa9, 0x56, 0x39, 0x4c, 0xf0, 0xb8, 0xed, 0x86, 0xb0, - 0xdd, 0x94, 0x7e, 0xe3, 0x28, 0xb7, 0x7c, 0x04, 0xda, 0xda, 0x7b, 0xb9, 0x62, 0x53, 0xde, 0x57, - 0x39, 0x71, 0x4b, 0x53, 0x8e, 0xe2, 0xee, 0x22, 0x48, 0x5d, 0x1c, 0xfb, 0x5e, 0xaa, 0xb7, 0xc4, - 0x43, 0xb5, 0x24, 0x3e, 0x09, 0x52, 0x93, 0xa3, 0xed, 0x00, 0xea, 0x5b, 0x63, 0x0c, 0x7f, 0x5c, - 0x45, 0xc4, 0x51, 0x12, 0xaa, 0x67, 0x07, 0x09, 0x99, 0x51, 0x12, 0xf2, 0xc7, 0xcd, 0x56, 0xef, - 0x65, 0xec, 0xc8, 0xcc, 0xa9, 0x64, 0xab, 0xf7, 0x22, 0xb4, 0x9e, 0x42, 0x95, 0xad, 0x45, 0x32, - 0xf0, 0x2a, 0x4c, 0x8a, 0xda, 0xff, 0x2a, 0x41, 0x75, 0x3d, 0xf7, 0xa8, 0x1a, 0x56, 0xc8, 0x6b, - 0xd8, 0xa9, 0x2a, 0x92, 0xb2, 0xad, 0x3c, 0xff, 0xd8, 0xbc, 0x74, 0xbc, 0x55, 0x1e, 0xbf, 0x86, - 0x62, 0x34, 0x15, 0x87, 0xb4, 0xee, 0x4f, 0xf1, 0x39, 0x61, 0x90, 0x78, 0x41, 0xd7, 0x8b, 0xbc, - 0xd8, 0xc7, 0x76, 0x31, 0x9a, 0xa2, 0x09, 0x3c, 0xe2, 0x03, 0x17, 0x0e, 0xdc, 0x8d, 0xb6, 0xde, - 0x38, 0x2c, 0x3d, 0x34, 0xbe, 0xe7, 0x46, 0xba, 0x82, 0x91, 0x37, 0x36, 0x5b, 0x9b, 0xde, 0x06, - 0xe8, 0x41, 0x04, 0xfb, 0x77, 0x94, 0x1e, 0xfc, 0xc2, 0x7a, 0x0e, 0x40, 0xa8, 0x9b, 0x7a, 0x94, - 0x92, 0x25, 0x56, 0x9e, 0xad, 0x11, 0x6a, 0x49, 0x80, 0x07, 0x01, 0xa1, 0x6e, 0x94, 0xc4, 0xa1, - 0xcb, 0xc8, 0x1c, 0x27, 0x0b, 0xa6, 0x52, 0xab, 0x49, 0xe8, 0x20, 0x89, 0x43, 0x47, 0x82, 0xed, - 0xef, 0xa0, 0x2c, 0x6a, 0xe6, 0xad, 0x59, 0x6a, 0x1f, 0xea, 0xf6, 0x68, 0x32, 0xec, 0xb9, 0xf6, - 0xa8, 0xdb, 0x1f, 0x6a, 0x05, 0x3e, 0xaa, 0x18, 0xe7, 0x7c, 0x7c, 0x72, 0xf9, 0x44, 0x32, 0xb1, - 0xb4, 0x22, 0x1f, 0x3f, 0xde, 0x8d, 0x6c, 0xad, 0xc4, 0xc7, 0x8f, 0xae, 0x3d, 0x32, 0x7a, 0xe7, - 0xc6, 0xd8, 0xd1, 0xca, 0xbc, 0xff, 0x0d, 0x8c, 0x73, 0x4b, 0xdb, 0x6d, 0x7f, 0x05, 0xf5, 0x2d, - 0x97, 0xf1, 0x3a, 0x3c, 0xe8, 0x68, 0x3b, 0x9c, 0x38, 0x38, 0xfb, 0x5a, 0x2b, 0x88, 0x45, 0xe7, - 0x4c, 0x2b, 0x76, 0xbf, 0xfd, 0xe7, 0x7f, 0x3e, 0x2f, 0xfc, 0xa9, 0xb7, 0xf5, 0x85, 0x1a, 0x91, - 0xd0, 0x63, 0x09, 0xff, 0xfa, 0x7c, 0xe1, 0x85, 0x38, 0x66, 0x27, 0x5e, 0x4a, 0x4e, 0x1e, 0xfc, - 0xf0, 0xfd, 0xfd, 0x32, 0x4d, 0xb7, 0xfc, 0x3f, 0xdd, 0x13, 0x5f, 0xa8, 0x67, 0xff, 0x0f, 0x00, - 0x00, 0xff, 0xff, 0x50, 0xfe, 0x0f, 0x64, 0x27, 0x0f, 0x00, 0x00, + proto.RegisterFile("models/vpp/interfaces/interface.proto", fileDescriptor_interface_e8af70d2126ce26f) +} + +var fileDescriptor_interface_e8af70d2126ce26f = []byte{ + // 1881 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x57, 0xcd, 0x72, 0xe3, 0xc6, + 0xf1, 0x17, 0x3f, 0xc4, 0x8f, 0xe6, 0x87, 0x66, 0xe7, 0x6f, 0xff, 0x83, 0x95, 0x77, 0x6d, 0x86, + 0x89, 0x63, 0x95, 0x53, 0xa6, 0x96, 0x94, 0xab, 0xb2, 0xb1, 0xab, 0x52, 0x05, 0x92, 0x50, 0x96, + 0xbb, 0x14, 0xc8, 0x80, 0xe0, 0xee, 0x3a, 0x17, 0x14, 0x08, 0x0c, 0x29, 0x64, 0x41, 0x00, 0x02, + 0x86, 0x5c, 0xca, 0x55, 0x79, 0x86, 0xdc, 0xf2, 0x20, 0x79, 0x82, 0x1c, 0x73, 0xc8, 0x0b, 0xe4, + 0x98, 0xca, 0x31, 0xc7, 0xbc, 0x40, 0x6a, 0x3e, 0x40, 0x41, 0x5a, 0xc9, 0xce, 0x45, 0x9a, 0xf9, + 0x75, 0xff, 0x7a, 0x9a, 0x3d, 0x3d, 0xdd, 0x0d, 0xf8, 0x7c, 0x1d, 0xba, 0xc4, 0x4f, 0x4e, 0xb7, + 0x51, 0x74, 0xea, 0x05, 0x94, 0xc4, 0x4b, 0xdb, 0x21, 0xc9, 0xcd, 0xb2, 0x13, 0xc5, 0x21, 0x0d, + 0x71, 0x73, 0x1b, 0x45, 0x9d, 0x1b, 0xf9, 0xf1, 0x57, 0x2b, 0x8f, 0x5e, 0x6e, 0x16, 0x1d, 0x27, + 0x5c, 0x9f, 0xae, 0xc2, 0x55, 0x78, 0xca, 0xd5, 0x16, 0x9b, 0x25, 0xdf, 0xf1, 0x0d, 0x5f, 0x09, + 0xfa, 0xf1, 0x93, 0xec, 0x29, 0x51, 0x42, 0x1c, 0xf1, 0x57, 0x48, 0xdb, 0x7f, 0xae, 0x43, 0x75, + 0x94, 0xda, 0xc6, 0x18, 0x8a, 0x81, 0xbd, 0x26, 0x4a, 0xae, 0x95, 0x3b, 0xa9, 0x1a, 0x7c, 0x8d, + 0x7b, 0x50, 0xa4, 0xd7, 0x11, 0x51, 0xf2, 0xad, 0xdc, 0x49, 0xb3, 0xf7, 0x69, 0xe7, 0xb6, 0x37, + 0x9d, 0x3d, 0xb9, 0x63, 0x5e, 0x47, 0xc4, 0xe0, 0xba, 0x58, 0x81, 0x32, 0x09, 0xec, 0x85, 0x4f, + 0x5c, 0xa5, 0xd0, 0xca, 0x9d, 0x54, 0x8c, 0x74, 0x8b, 0x7f, 0x0a, 0xf5, 0xe8, 0xf2, 0x3a, 0xb1, + 0x6c, 0xd7, 0x8d, 0x49, 0x92, 0x28, 0x45, 0x7e, 0x52, 0x8d, 0x61, 0xaa, 0x80, 0x98, 0x8a, 0x17, + 0xa5, 0x0a, 0x24, 0x51, 0x0e, 0x5b, 0x05, 0xa6, 0xe2, 0x45, 0x6a, 0x0a, 0x61, 0x04, 0x85, 0x6d, + 0xbc, 0x54, 0x4a, 0xad, 0xdc, 0x49, 0xc3, 0x60, 0x4b, 0xfc, 0x0b, 0x38, 0x4a, 0x08, 0xb5, 0xdc, + 0x4b, 0x27, 0xb2, 0x1c, 0xdf, 0x23, 0x01, 0x55, 0xca, 0xfc, 0xe4, 0x46, 0x42, 0xe8, 0xf0, 0xd2, + 0x89, 0x06, 0x1c, 0x64, 0xcc, 0x35, 0xdd, 0x28, 0x15, 0xc1, 0x5c, 0xd3, 0x0d, 0x1e, 0x02, 0x6c, + 0x82, 0x60, 0xb3, 0x5e, 0x90, 0x98, 0xb8, 0x4a, 0xb5, 0x95, 0x3b, 0xa9, 0xf5, 0x7e, 0xfe, 0xf0, + 0xaf, 0x9c, 0xef, 0x75, 0x8d, 0x0c, 0x0f, 0xff, 0x1a, 0xca, 0xf1, 0xce, 0x62, 0xa1, 0x56, 0x80, + 0x9b, 0x68, 0x3d, 0x6c, 0xc2, 0xd8, 0x5d, 0x84, 0x2e, 0x31, 0x4a, 0x31, 0xff, 0x8f, 0x2f, 0xa0, + 0x1e, 0xef, 0xac, 0xc8, 0xb7, 0x1d, 0xb2, 0x66, 0x7e, 0xd7, 0x5a, 0x85, 0x93, 0x5a, 0xef, 0xcb, + 0x1f, 0xe2, 0x4f, 0x53, 0x65, 0x2d, 0xa0, 0xf1, 0xb5, 0x51, 0x8b, 0x6f, 0x10, 0xfc, 0x0c, 0x0a, + 0xc9, 0x66, 0xa1, 0xb8, 0xdc, 0x8b, 0x27, 0x77, 0xad, 0xcc, 0x36, 0x8b, 0xbd, 0xa1, 0x17, 0x07, + 0x06, 0x53, 0xc5, 0x5d, 0x38, 0x5c, 0x93, 0xb5, 0xb7, 0x54, 0x08, 0xe7, 0x3c, 0xbe, 0xcb, 0xb9, + 0x60, 0xc2, 0xb1, 0x17, 0xbc, 0x7b, 0x71, 0x60, 0x08, 0x4d, 0xfc, 0x0d, 0x54, 0xec, 0x65, 0x64, + 0x3b, 0xef, 0x08, 0x55, 0x96, 0xf7, 0x9f, 0xa4, 0x4a, 0xb9, 0x24, 0xee, 0xf5, 0xf1, 0x2f, 0xa1, + 0x40, 0xed, 0x48, 0x59, 0x71, 0xda, 0x4f, 0xee, 0xd2, 0x4c, 0x3b, 0x92, 0x0c, 0xa6, 0xc5, 0x7c, + 0xdb, 0xee, 0x7c, 0x3b, 0x50, 0x2e, 0xef, 0xf7, 0xed, 0x35, 0x13, 0xa6, 0xbe, 0x71, 0x4d, 0x46, + 0xe1, 0x19, 0xae, 0x78, 0xf7, 0x53, 0x46, 0xd3, 0x19, 0x71, 0x52, 0x0a, 0xd7, 0xc4, 0xcf, 0xa1, + 0xb2, 0x5d, 0xef, 0xac, 0x80, 0xd0, 0x33, 0xe5, 0x0f, 0x9c, 0xf5, 0xc9, 0x07, 0x07, 0xad, 0x77, + 0x3a, 0xa1, 0x67, 0x92, 0x57, 0xde, 0x8a, 0x2d, 0xee, 0x40, 0x71, 0x11, 0x06, 0xae, 0xf2, 0x8e, + 0xb3, 0x94, 0xbb, 0xac, 0x7e, 0x18, 0xb8, 0x92, 0xc2, 0xf5, 0x8e, 0x9f, 0x03, 0xdc, 0x64, 0x10, + 0xfe, 0x12, 0x1e, 0xed, 0x95, 0xad, 0xf7, 0x1e, 0xbd, 0xb4, 0xbc, 0x48, 0x3e, 0xbe, 0xa3, 0xbd, + 0xe0, 0x8d, 0x47, 0x2f, 0x47, 0xd1, 0xf1, 0x3f, 0xf3, 0x50, 0x32, 0xd2, 0x8c, 0x39, 0x72, 0xc9, + 0xd2, 0xde, 0xf8, 0xd4, 0x4a, 0x93, 0x2e, 0xc7, 0x5f, 0xe7, 0xe7, 0x3f, 0x96, 0x74, 0xe2, 0x91, + 0x36, 0x24, 0x5b, 0x9a, 0x9b, 0x43, 0xe3, 0x6a, 0x43, 0x36, 0x64, 0x6f, 0x2c, 0xcf, 0x33, 0xb0, + 0xfb, 0xa3, 0xc6, 0x7e, 0xc7, 0x58, 0x62, 0x2d, 0x13, 0xf1, 0xea, 0x06, 0x39, 0x26, 0x80, 0xee, + 0x2a, 0xb0, 0xe7, 0xf7, 0x8e, 0x5c, 0x73, 0x6f, 0x1b, 0x06, 0x5b, 0xe2, 0x6f, 0xe1, 0x70, 0x6b, + 0xfb, 0x9b, 0xb4, 0xbe, 0xfc, 0x8f, 0xbf, 0x40, 0x70, 0xbe, 0xc9, 0x3f, 0xcf, 0xb5, 0x5f, 0x42, + 0x91, 0x41, 0xb8, 0x06, 0xe5, 0xb9, 0xfe, 0x4a, 0x9f, 0xbc, 0xd1, 0xd1, 0x01, 0xdb, 0x4c, 0x27, + 0xe3, 0xf1, 0x48, 0xff, 0x2d, 0xca, 0xe1, 0x06, 0x54, 0x47, 0xba, 0xa9, 0x19, 0xc6, 0x7c, 0x6a, + 0xa2, 0x3c, 0xae, 0x43, 0x45, 0x1d, 0xaa, 0x53, 0x73, 0xf4, 0x5a, 0x43, 0x05, 0xa6, 0x39, 0xd4, + 0xce, 0xd5, 0xf9, 0xd8, 0x44, 0xc5, 0xe3, 0xdf, 0x00, 0xba, 0xfb, 0xb8, 0xee, 0x71, 0xf9, 0xa3, + 0xac, 0xcb, 0x8d, 0xac, 0x2f, 0x7f, 0xcd, 0x49, 0x67, 0x30, 0x34, 0xe7, 0xfa, 0x50, 0x3b, 0x1f, + 0xe9, 0xda, 0xd0, 0x32, 0xbf, 0x9b, 0x6a, 0xe8, 0x00, 0x3f, 0x82, 0xc6, 0x6c, 0xde, 0xb7, 0xb8, + 0x2b, 0xe7, 0xea, 0x40, 0x43, 0x39, 0xfc, 0x31, 0x3c, 0x9a, 0x4d, 0xce, 0xcd, 0x37, 0xaa, 0xa1, + 0x59, 0xe3, 0xc9, 0x64, 0xda, 0x57, 0x07, 0xaf, 0x50, 0x1e, 0x57, 0xa0, 0x38, 0x9c, 0x0e, 0x5f, + 0xa1, 0x02, 0xae, 0xc2, 0xe1, 0x85, 0x76, 0x31, 0x3a, 0x47, 0x45, 0x5c, 0x86, 0x82, 0xa9, 0x4e, + 0xd1, 0x21, 0xfb, 0x39, 0xea, 0xb9, 0x35, 0x55, 0x07, 0xaf, 0x34, 0x13, 0x95, 0x30, 0x82, 0xfa, + 0xeb, 0xb7, 0x63, 0x55, 0xb7, 0xcc, 0xb9, 0xae, 0x6b, 0x63, 0x54, 0x66, 0xc8, 0x68, 0x3a, 0xd3, + 0x06, 0x29, 0x52, 0x61, 0xe7, 0xbc, 0xbe, 0x78, 0xab, 0x6b, 0xe6, 0x59, 0xe6, 0xf8, 0x2a, 0xf3, + 0xb2, 0x3f, 0xd1, 0x87, 0x19, 0x0c, 0xfa, 0x25, 0x28, 0xfa, 0x5e, 0xf0, 0xae, 0xfd, 0x9f, 0x3c, + 0xd4, 0xb3, 0xc5, 0x02, 0x7f, 0x06, 0xb5, 0xc8, 0x8e, 0x49, 0x40, 0xad, 0x4c, 0x8b, 0x00, 0x01, + 0xe9, 0xac, 0x51, 0x7c, 0x0c, 0xa5, 0x64, 0xb3, 0xb0, 0x3c, 0x37, 0x8d, 0x4b, 0xb2, 0x59, 0x8c, + 0x5c, 0x6c, 0x40, 0x83, 0xda, 0x2b, 0x2b, 0x7e, 0x6f, 0x85, 0x11, 0xf5, 0xc2, 0x80, 0x77, 0x84, + 0x66, 0xaf, 0xf3, 0x43, 0x95, 0xa9, 0x63, 0xda, 0x2b, 0x83, 0xbc, 0x8f, 0x3d, 0x4a, 0x26, 0x9c, + 0x94, 0x18, 0x35, 0x6a, 0xaf, 0x8c, 0xf7, 0x62, 0x87, 0x9f, 0x02, 0x44, 0x9b, 0xe4, 0xd2, 0x72, + 0x43, 0xda, 0xbd, 0xe2, 0x3d, 0xa4, 0x62, 0x54, 0x19, 0x32, 0x64, 0x00, 0x6b, 0x63, 0xd4, 0x5e, + 0x75, 0x95, 0x43, 0xee, 0x07, 0x5f, 0x4b, 0xac, 0x27, 0x7b, 0x06, 0x5f, 0xb7, 0xff, 0x94, 0x83, + 0x47, 0x1f, 0x9c, 0xc4, 0xf2, 0x63, 0x38, 0x9a, 0xa9, 0xfd, 0xb1, 0x36, 0x44, 0x07, 0xec, 0x06, + 0xa6, 0xf3, 0xd9, 0x8b, 0x2e, 0xca, 0xa5, 0xcb, 0x9e, 0xb8, 0xa1, 0xe9, 0x64, 0xda, 0x45, 0x05, + 0xb9, 0xea, 0xa1, 0x22, 0x3e, 0x82, 0x9a, 0x69, 0xa8, 0xfa, 0x6c, 0xac, 0x9a, 0x5a, 0xb7, 0x8b, + 0x0e, 0x6f, 0x03, 0x3d, 0x54, 0xba, 0x05, 0xf4, 0xba, 0xa8, 0x7c, 0x1b, 0xe8, 0xa1, 0x4a, 0xfb, + 0x1f, 0x79, 0xa8, 0xee, 0xcb, 0x2d, 0xfe, 0x15, 0x14, 0x33, 0x8f, 0xfb, 0x67, 0x0f, 0xd6, 0x65, + 0xb1, 0xe2, 0x4d, 0x85, 0x13, 0xf0, 0xff, 0x43, 0x69, 0x6d, 0x27, 0x94, 0xc4, 0xfc, 0x2a, 0x2a, + 0x86, 0xdc, 0xe1, 0x26, 0xe4, 0x3d, 0xd1, 0x92, 0x1b, 0x46, 0xde, 0x73, 0xf1, 0x17, 0x70, 0x94, + 0x84, 0xac, 0x28, 0x5b, 0x4b, 0xcf, 0x27, 0xfc, 0x5e, 0x45, 0x43, 0x6e, 0x0a, 0xf8, 0x5c, 0xa2, + 0xcc, 0x60, 0x42, 0x9c, 0x98, 0x50, 0x1e, 0xd3, 0xaa, 0x21, 0x77, 0xf8, 0x13, 0xa8, 0xc6, 0x5e, + 0xb0, 0xb2, 0x12, 0xef, 0x7b, 0x22, 0x43, 0x5b, 0x61, 0xc0, 0xcc, 0xfb, 0x9e, 0x67, 0xcc, 0x62, + 0xb3, 0x5c, 0x92, 0x58, 0x88, 0xcb, 0x5c, 0x0c, 0x02, 0xe2, 0x0a, 0x8c, 0xbd, 0xb3, 0x78, 0xcd, + 0x48, 0x64, 0x4b, 0xae, 0xc4, 0x3b, 0x5e, 0x34, 0x12, 0x26, 0xa4, 0x7b, 0x61, 0x55, 0x08, 0xa9, + 0x14, 0xb6, 0x7b, 0x32, 0x4c, 0xbc, 0x7e, 0xd5, 0xa1, 0xa2, 0x99, 0x2f, 0x34, 0x43, 0xd7, 0x4c, + 0x74, 0x80, 0x4b, 0x90, 0x1f, 0x4d, 0x51, 0x8e, 0xc5, 0x76, 0x3a, 0xd7, 0x4d, 0x6b, 0xa4, 0xbf, + 0xd4, 0x06, 0x26, 0xca, 0xb7, 0xff, 0x08, 0xd5, 0x7d, 0xb7, 0x60, 0xbe, 0x25, 0xb1, 0xb3, 0x1f, + 0x43, 0x64, 0x36, 0x27, 0xb1, 0x93, 0x4e, 0x21, 0x9f, 0x41, 0xcd, 0x4d, 0xe8, 0x5e, 0x21, 0x2f, + 0x14, 0xdc, 0x84, 0xa6, 0x0a, 0x6c, 0x06, 0x09, 0x3c, 0x19, 0x4c, 0xb6, 0xc4, 0x4f, 0xa0, 0xba, + 0xde, 0xf8, 0xd4, 0x73, 0xec, 0x84, 0xca, 0x38, 0xde, 0x00, 0xed, 0x67, 0x50, 0xcf, 0xb6, 0x44, + 0xdc, 0x82, 0xfa, 0x65, 0x98, 0x50, 0xcb, 0x5b, 0xde, 0x7a, 0x50, 0x0c, 0x1b, 0x2d, 0xd9, 0x83, + 0x6a, 0xff, 0x25, 0x07, 0x65, 0xd9, 0x0e, 0xd9, 0x44, 0xb5, 0x25, 0x71, 0xc2, 0xde, 0x8f, 0xa8, + 0x44, 0xe9, 0xf6, 0x03, 0x3b, 0xf9, 0xbb, 0x76, 0xd8, 0x2d, 0xd3, 0xd0, 0x5a, 0x7b, 0x4e, 0x1c, + 0x26, 0x24, 0xde, 0x7a, 0x0e, 0xe1, 0x5e, 0x57, 0x8d, 0x26, 0x0d, 0x2f, 0x32, 0x28, 0x33, 0x15, + 0xef, 0xac, 0x9b, 0x0b, 0x2d, 0x8a, 0x1b, 0x8b, 0x77, 0x46, 0x7a, 0xa5, 0x2d, 0xa8, 0xd3, 0xac, + 0x86, 0x78, 0x61, 0x40, 0xf7, 0x1a, 0xed, 0x7f, 0x17, 0xa0, 0xba, 0xef, 0xb0, 0x2c, 0x48, 0x24, + 0x09, 0x64, 0x16, 0xb2, 0x25, 0x8b, 0xab, 0x1d, 0x50, 0xcf, 0x8a, 0x49, 0xe4, 0xdb, 0xd7, 0x72, + 0x3c, 0x04, 0x06, 0x19, 0x1c, 0xc1, 0x8f, 0xa1, 0xe2, 0x87, 0x8e, 0xed, 0xb3, 0x56, 0x28, 0x82, + 0x58, 0xe6, 0xfb, 0x51, 0xc4, 0xf3, 0x85, 0xac, 0x43, 0x4a, 0x98, 0x4c, 0x24, 0x62, 0x45, 0x00, + 0x42, 0x28, 0x78, 0x49, 0xe4, 0xa5, 0xa9, 0xc8, 0x81, 0x59, 0xe4, 0xb1, 0x82, 0x21, 0x99, 0x4c, + 0x2a, 0x32, 0x51, 0xda, 0x62, 0xe2, 0x33, 0x00, 0x27, 0xbe, 0x8e, 0x68, 0x68, 0xd9, 0xfe, 0x8a, + 0x67, 0x62, 0xb3, 0xf7, 0x91, 0x78, 0x6e, 0x7c, 0x56, 0x1e, 0x70, 0xa1, 0xea, 0xaf, 0x8c, 0xaa, + 0x93, 0x2e, 0xf1, 0x09, 0x20, 0x71, 0xa0, 0xa4, 0xb2, 0x2e, 0x51, 0x15, 0x71, 0xe5, 0xb8, 0x20, + 0xbd, 0x22, 0xd7, 0xac, 0xcd, 0xcb, 0xd3, 0x33, 0xaa, 0x20, 0xda, 0xbc, 0x10, 0xdc, 0xe8, 0x3e, + 0x83, 0x2a, 0x7b, 0xe2, 0x2b, 0xee, 0x49, 0x8d, 0x7b, 0xf2, 0x7f, 0x19, 0x4f, 0x58, 0x89, 0x5c, + 0x31, 0x47, 0x2a, 0x9e, 0x5c, 0xb1, 0xd1, 0x57, 0x06, 0x8c, 0xf3, 0x98, 0xed, 0x3a, 0xb7, 0xdd, + 0x10, 0x71, 0x63, 0x28, 0xb3, 0x7c, 0x02, 0x28, 0x8d, 0xde, 0x5e, 0xb1, 0x21, 0xfc, 0x95, 0x41, + 0xcc, 0x68, 0x8a, 0x79, 0xdd, 0xda, 0xb8, 0x91, 0x45, 0x02, 0xc7, 0x8e, 0x94, 0x26, 0xbf, 0xa8, + 0xa6, 0xc0, 0xe7, 0x6e, 0xa4, 0x31, 0xb4, 0xed, 0x42, 0x2d, 0x33, 0x18, 0xb1, 0xcb, 0x95, 0x44, + 0xe2, 0x87, 0x2b, 0x79, 0xed, 0x20, 0x20, 0xcd, 0x0f, 0x57, 0xec, 0x72, 0xe3, 0xdd, 0x95, 0xc8, + 0x1d, 0xf1, 0x72, 0xca, 0xf1, 0xee, 0x8a, 0xa7, 0xd6, 0x63, 0xa8, 0xd0, 0x54, 0x24, 0x12, 0xaf, + 0x4c, 0x85, 0xa8, 0xfd, 0xf7, 0x02, 0x54, 0xd2, 0x49, 0x4a, 0xd6, 0xb0, 0xdc, 0xbe, 0x86, 0x75, + 0x65, 0x91, 0x14, 0x6d, 0xe5, 0xe9, 0x43, 0x13, 0x58, 0x27, 0x53, 0x1e, 0xbf, 0x86, 0xbc, 0xbf, + 0xe0, 0x87, 0x34, 0x3f, 0x1c, 0xf5, 0xf7, 0x84, 0x71, 0x68, 0xbb, 0x7d, 0xdb, 0xb7, 0x03, 0x87, + 0x18, 0x79, 0x7f, 0x81, 0xe7, 0xf0, 0x88, 0x8d, 0x70, 0xc4, 0xb5, 0x6e, 0xb4, 0x95, 0x3a, 0x1f, + 0x95, 0x4e, 0x1e, 0x34, 0xd2, 0xe7, 0x8c, 0x7d, 0x63, 0x33, 0xd0, 0xe2, 0x36, 0x90, 0x1c, 0xfb, + 0x70, 0x74, 0x47, 0xe9, 0xde, 0xcf, 0xb0, 0xa7, 0x00, 0x5e, 0x62, 0x45, 0x76, 0x92, 0x78, 0x5b, + 0x22, 0x23, 0x5b, 0xf5, 0x92, 0xa9, 0x00, 0x58, 0x12, 0x78, 0x89, 0xe5, 0x87, 0xc1, 0xca, 0xa2, + 0xde, 0x9a, 0x84, 0x1b, 0x2a, 0x9f, 0x56, 0xc3, 0x4b, 0xc6, 0x61, 0xb0, 0x32, 0x05, 0xd8, 0xfe, + 0x0e, 0x8a, 0xbc, 0x66, 0xde, 0x9a, 0x96, 0x8e, 0xa0, 0x66, 0x4c, 0xe6, 0xfa, 0xd0, 0x32, 0x26, + 0xfd, 0x91, 0x8e, 0x72, 0x6c, 0x54, 0x51, 0x07, 0x6c, 0x40, 0xb2, 0xd8, 0x44, 0x32, 0x9f, 0xa2, + 0x3c, 0x1b, 0x3f, 0xde, 0x4e, 0x0c, 0x54, 0x60, 0xe3, 0x47, 0xdf, 0x98, 0xa8, 0xc3, 0x81, 0x3a, + 0x33, 0x51, 0x91, 0xf5, 0xbf, 0xb1, 0x3a, 0x98, 0xa2, 0xc3, 0xf6, 0x17, 0x50, 0xcb, 0x84, 0x8c, + 0xd5, 0xe1, 0x71, 0x0f, 0x1d, 0x30, 0xe2, 0xf8, 0xec, 0x6b, 0x94, 0xe3, 0x8b, 0xde, 0x19, 0xca, + 0xf7, 0x5f, 0xfe, 0xed, 0x5f, 0x9f, 0xe6, 0x7e, 0x3f, 0xcc, 0x7c, 0xc6, 0xfa, 0xde, 0xca, 0xa6, + 0x21, 0xfb, 0x44, 0xfd, 0xca, 0x5e, 0x91, 0x80, 0x9e, 0xda, 0x91, 0x77, 0x7a, 0xef, 0xd7, 0xf1, + 0xb7, 0xdb, 0x28, 0xca, 0xc4, 0x7f, 0x51, 0xe2, 0x9f, 0xb1, 0x67, 0xff, 0x0d, 0x00, 0x00, 0xff, + 0xff, 0x93, 0xc9, 0x70, 0x14, 0x4c, 0x0f, 0x00, 0x00, } diff --git a/api/models/vpp/interfaces/interface.proto b/api/models/vpp/interfaces/interface.proto index aee0eb5fa4..04691fe0ec 100644 --- a/api/models/vpp/interfaces/interface.proto +++ b/api/models/vpp/interfaces/interface.proto @@ -40,27 +40,21 @@ message Interface { } Unnumbered unnumbered = 9; - message RxModeSettings { + message RxMode { // from vpp/build-root/install-vpp-native/vpp/include/vnet/interface.h - enum RxModeType { + enum Type { UNKNOWN = 0; POLLING = 1; INTERRUPT = 2; ADAPTIVE = 3; DEFAULT = 4; }; - RxModeType rx_mode = 1; - uint32 queue_id = 2; - uint32 queue_id_valid = 3; + Type default_rx_mode = 1; // used for queues not listed in queue_rx_mode + map queue_rx_mode = 2; // queue ID -> Rx mode } - RxModeSettings rx_mode_settings = 10; + RxMode rx_mode = 10; - message RxPlacementSettings { - uint32 queue = 1; - uint32 worker = 2; - bool is_main = 3; - } - RxPlacementSettings rx_placement_settings = 11; + map rx_placement = 11; // queue ID -> worker ID (main thread has always ID=0) oneof link { SubInterface sub = 100; /* sub-interface configuration */ @@ -70,7 +64,7 @@ message Interface { VxlanLink vxlan = 104; /* VXLAN-specific configuration */ IPSecLink ipsec = 105; /* IPSec tunnel-specific configuration */ VmxNet3Link vmx_net3 = 106; /* VmxNet3-specific configuration */ - BondLink bond = 107; /* Bond interface-specific configuration */ + BondLink bond = 107; /* Bond interface-specific configuration */ }; }; diff --git a/plugins/vpp/ifplugin/descriptor/interface.go b/plugins/vpp/ifplugin/descriptor/interface.go index 9bfcbef549..51a72b2b7d 100644 --- a/plugins/vpp/ifplugin/descriptor/interface.go +++ b/plugins/vpp/ifplugin/descriptor/interface.go @@ -207,8 +207,7 @@ func (d *InterfaceDescriptor) EquivalentInterfaces(key string, oldIntf, newIntf oldIntf.SetDhcpClient != newIntf.SetDhcpClient { return false } - if !proto.Equal(oldIntf.Unnumbered, newIntf.Unnumbered) || - !proto.Equal(getRxPlacement(oldIntf), getRxPlacement(newIntf)) { + if !proto.Equal(oldIntf.Unnumbered, newIntf.Unnumbered) { return false } @@ -226,11 +225,16 @@ func (d *InterfaceDescriptor) EquivalentInterfaces(key string, oldIntf, newIntf // TODO: for TAPv2 the RxMode dump is unstable // (it goes between POLLING and INTERRUPT, maybe it should actually return ADAPTIVE?) if oldIntf.Type != interfaces.Interface_TAP || oldIntf.GetTap().GetVersion() != 2 { - if !proto.Equal(getRxMode(oldIntf), getRxMode(newIntf)) { + if !d.equivalentRxMode(oldIntf, newIntf) { return false } } + // handle unspecified Rx placement + if d.equivalentRxPlacement(oldIntf.GetRxPlacement(), newIntf.GetRxPlacement()) { + return false + } + // handle default/unspecified MTU (except VxLAN and IPSec tunnel) if newIntf.Type != interfaces.Interface_VXLAN_TUNNEL && newIntf.Type != interfaces.Interface_IPSEC_TUNNEL { if d.getInterfaceMTU(newIntf) != 0 && d.getInterfaceMTU(oldIntf) != d.getInterfaceMTU(newIntf) { @@ -252,6 +256,63 @@ func (d *InterfaceDescriptor) EquivalentInterfaces(key string, oldIntf, newIntf return true } +// equivalentRxMode compares Rx modes for equivalency. +func (d *InterfaceDescriptor) equivalentRxMode(oldIntf, newIntf *interfaces.Interface) bool { + oldMode := oldIntf.GetRxMode() + newMode := newIntf.GetRxMode() + if newMode == nil { + // undefined + return true + } + /* Note: default Rx mode cannot be dumped - compare only if these are two NB + configurations (not a refreshed value). + */ + if oldMode.GetDefaultRxMode() != interfaces.Interface_RxMode_UNKNOWN && + newMode.GetDefaultRxMode() != interfaces.Interface_RxMode_UNKNOWN { + defOldMode := normalizeRxMode(oldMode.GetDefaultRxMode(), oldIntf) + defNewMode := normalizeRxMode(newMode.GetDefaultRxMode(), newIntf) + if defOldMode != defNewMode { + return false + } + } + for queue, oldMode := range oldMode.QueueRxMode { + oldMode = normalizeRxMode(oldMode, oldIntf) + newMode := normalizeRxMode(getQueueRxMode(queue, newMode), newIntf) + if oldMode != newMode { + return false + } + } + for queue, newMode := range newMode.QueueRxMode { + newMode = normalizeRxMode(newMode, newIntf) + oldMode := normalizeRxMode(getQueueRxMode(queue, oldMode), oldIntf) + if oldMode != newMode { + return false + } + } + return true +} + +// equivalentRxMode compares Rx placements for equivalency. +func (d *InterfaceDescriptor) equivalentRxPlacement(oldPlacement, newPlacement map[uint32]uint32) bool { + + if newPlacement == nil { + // undefined + return true + } + + if len(oldPlacement) != len(newPlacement) { + return false + } + + for q, oldW := range oldPlacement { + if newW, ok := newPlacement[q]; !ok || oldW != newW { + return false + } + } + + return true +} + // equivalentTypeSpecificConfig compares type-specific sections of two interface configurations. func (d *InterfaceDescriptor) equivalentTypeSpecificConfig(oldIntf, newIntf *interfaces.Interface) bool { switch oldIntf.Type { @@ -404,8 +465,19 @@ func (d *InterfaceDescriptor) Validate(key string, intf *interfaces.Interface) e if _, ok := d.ethernetIfs[intf.Name]; !ok { return kvs.NewInvalidValueError(ErrDPDKInterfaceMissing, "name") } - if getRxMode(intf).GetRxMode() != interfaces.Interface_RxModeSettings_POLLING { - return kvs.NewInvalidValueError(ErrUnsupportedRxMode, "rx_mode_settings.rx_mode") + if intf.GetRxMode() != nil { + defRxMode := normalizeRxMode(intf.GetRxMode().GetDefaultRxMode(), intf) + if defRxMode != interfaces.Interface_RxMode_POLLING { + return kvs.NewInvalidValueError(ErrUnsupportedRxMode, + "rx_mode_settings.rx_mode.default_rx_mode") + } + for queue, rxMode := range intf.GetRxMode().GetQueueRxMode() { + rxMode = normalizeRxMode(rxMode, intf) + if rxMode != interfaces.Interface_RxMode_POLLING { + return kvs.NewInvalidValueError(ErrUnsupportedRxMode, + fmt.Sprintf("rx_mode_settings.rx_mode.queue_rx_mode[%d]", queue)) + } + } } case interfaces.Interface_AF_PACKET: if intf.GetAfpacket().GetHostIfName() == "" { @@ -426,6 +498,16 @@ func (d *InterfaceDescriptor) Validate(key string, intf *interfaces.Interface) e } } + // validate Rx Mode + if intf.GetRxMode() != nil { + for queue, rxMode := range intf.GetRxMode().GetQueueRxMode() { + if rxMode == interfaces.Interface_RxMode_UNKNOWN { + return kvs.NewInvalidValueError(ErrUnsupportedRxMode, + fmt.Sprintf("rx_mode_settings.rx_mode.queue_rx_mode[%d]", queue)) + } + } + } + return nil } @@ -613,40 +695,6 @@ func (d *InterfaceDescriptor) resolveMemifSocketFilename(memifIf *interfaces.Mem return registeredID, nil } -// getRxMode returns the RX mode of the given interface. -// If the mode is not defined, it returns the default settings for the given -// interface type. -func getRxMode(intf *interfaces.Interface) *interfaces.Interface_RxModeSettings { - if rxModeSettings := intf.RxModeSettings; rxModeSettings != nil { - return rxModeSettings - } - - rxModeSettings := &interfaces.Interface_RxModeSettings{ - RxMode: interfaces.Interface_RxModeSettings_DEFAULT, - } - // return default mode for the given interface type - switch intf.GetType() { - case interfaces.Interface_DPDK: - rxModeSettings.RxMode = interfaces.Interface_RxModeSettings_POLLING - case interfaces.Interface_AF_PACKET: - rxModeSettings.RxMode = interfaces.Interface_RxModeSettings_INTERRUPT - case interfaces.Interface_TAP: - if intf.GetTap().GetVersion() == 2 { - // TAP v2 - rxModeSettings.RxMode = interfaces.Interface_RxModeSettings_INTERRUPT - } - } - return rxModeSettings -} - -// getRxPlacement returns the RX placement of the given interface. -func getRxPlacement(intf *interfaces.Interface) *interfaces.Interface_RxPlacementSettings { - if rxPlacementSettings := intf.GetRxPlacementSettings(); rxPlacementSettings != nil { - return rxPlacementSettings - } - return &interfaces.Interface_RxPlacementSettings{} -} - // getMemifSocketFilename returns the memif socket filename. func (d *InterfaceDescriptor) getMemifSocketFilename(memif *interfaces.MemifLink) string { if socketFilename := memif.GetSocketFilename(); socketFilename != "" { @@ -687,6 +735,33 @@ func (d *InterfaceDescriptor) getMemifRingSize(memif *interfaces.MemifLink) uint return memif.GetRingSize() } +// getQueueRxMode reads queue RX mode from the configuration. +func getQueueRxMode(queue uint32, mode *interfaces.Interface_RxMode) interfaces.Interface_RxMode_Type { + if mode, hasQueueSpecific := mode.QueueRxMode[queue]; hasQueueSpecific { + return mode + } + return mode.GetDefaultRxMode() +} + +// normalizeRxMode resolves default Rx mode for specific interfaces. +func normalizeRxMode(mode interfaces.Interface_RxMode_Type, iface *interfaces.Interface) interfaces.Interface_RxMode_Type { + if mode != interfaces.Interface_RxMode_DEFAULT && mode != interfaces.Interface_RxMode_UNKNOWN { + return mode + } + switch iface.GetType() { + case interfaces.Interface_DPDK: + return interfaces.Interface_RxMode_POLLING + case interfaces.Interface_AF_PACKET: + return interfaces.Interface_RxMode_INTERRUPT + case interfaces.Interface_TAP: + if iface.GetTap().GetVersion() == 2 { + // TAP v2 + return interfaces.Interface_RxMode_INTERRUPT + } + } + return interfaces.Interface_RxMode_DEFAULT +} + // getTapConfig returns the TAP-specific configuration section (handling undefined attributes). func getTapConfig(intf *interfaces.Interface) *interfaces.TapLink { tapCfg := &interfaces.TapLink{ diff --git a/plugins/vpp/ifplugin/descriptor/interface_crud.go b/plugins/vpp/ifplugin/descriptor/interface_crud.go index 8bbd81b35b..96a5b705cb 100644 --- a/plugins/vpp/ifplugin/descriptor/interface_crud.go +++ b/plugins/vpp/ifplugin/descriptor/interface_crud.go @@ -1,7 +1,6 @@ package descriptor import ( - "github.com/gogo/protobuf/proto" "github.com/pkg/errors" interfaces "github.com/ligato/vpp-agent/api/models/vpp/interfaces" @@ -143,36 +142,16 @@ func (d *InterfaceDescriptor) Create(key string, intf *interfaces.Interface) (me d.bondIDs[intf.GetBond().GetId()] = intf.GetName() } - /* - Rx-mode - - Legend: - P - polling - I - interrupt - A - adaptive - - Interfaces - supported modes: - * tap interface - PIA - * memory interface - PIA - * vxlan tunnel - PIA - * software loopback - PIA - * ethernet csmad - P - * af packet - PIA - */ - if intf.RxModeSettings != nil { - rxMode := getRxMode(intf) - err = d.ifHandler.SetRxMode(ifIdx, rxMode) - if err != nil { - err = errors.Errorf("failed to set Rx-mode for interface %s: %v", intf.Name, err) - d.log.Error(err) - return nil, err - } + err = d.configureRxMode(intf, ifIdx, nil) + if err != nil { + return nil, err } // rx-placement - if intf.GetRxPlacementSettings() != nil { - if err = d.ifHandler.SetRxPlacement(ifIdx, intf.GetRxPlacementSettings()); err != nil { - err = errors.Errorf("failed to set rx-placement for interface %s: %v", intf.Name, err) + for queue, worker := range intf.GetRxPlacement() { + if err = d.ifHandler.SetRxPlacement(ifIdx, queue, worker); err != nil { + err = errors.Errorf("failed to set rx-placement for queue %d of the interface %s: %v", + queue, intf.Name, err) d.log.Error(err) return nil, err } @@ -235,6 +214,48 @@ func (d *InterfaceDescriptor) Create(key string, intf *interfaces.Interface) (me return metadata, nil } +// configureRxMode (re-)configures Rx mode for the interface. +func (d *InterfaceDescriptor) configureRxMode(iface *interfaces.Interface, ifIdx uint32, + oldMode *interfaces.Interface_RxMode) (err error) { + + newMode := iface.GetRxMode() + if newMode == nil { + if oldMode != nil { + // revert back to default for all queues + err = d.ifHandler.SetRxMode(ifIdx, 0, interfaces.Interface_RxMode_DEFAULT, true) + if err != nil { + err = errors.Errorf("failed to set default Rx-mode for interface %s: %v", iface, err) + d.log.Error(err) + return err + } + } + return + } + + if oldMode != nil || newMode.GetDefaultRxMode() != interfaces.Interface_RxMode_UNKNOWN { + // overwrite previous default Rx mode + defRxMode := normalizeRxMode(newMode.GetDefaultRxMode(), iface) + err = d.ifHandler.SetRxMode(ifIdx, 0, defRxMode, true) + if err != nil { + err = errors.Errorf("failed to set default Rx-mode for interface %s: %v", iface.Name, err) + d.log.Error(err) + return err + } + } + + for queue, rxMode := range newMode.GetQueueRxMode() { + err = d.ifHandler.SetRxMode(ifIdx, queue, rxMode, false) + if err != nil { + err = errors.Errorf("failed to set Rx-mode for queue %d of the interface %s: %v", + queue, iface.Name, err) + d.log.Error(err) + return err + } + } + + return nil +} + // Delete removes VPP interface. func (d *InterfaceDescriptor) Delete(key string, intf *interfaces.Interface, metadata *ifaceidx.IfaceMetadata) error { var err error @@ -288,23 +309,22 @@ func (d *InterfaceDescriptor) Update(key string, oldIntf, newIntf *interfaces.In ifIdx := oldMetadata.SwIfIndex // rx-mode - oldRx := getRxMode(oldIntf) - newRx := getRxMode(newIntf) - if !proto.Equal(oldRx, newRx) { - err = d.ifHandler.SetRxMode(ifIdx, newRx) + if !d.equivalentRxMode(oldIntf, newIntf) { + err = d.configureRxMode(newIntf, ifIdx, oldIntf.GetRxMode()) if err != nil { - err = errors.Errorf("failed to modify rx-mode for interface %s: %v", newIntf.Name, err) - d.log.Error(err) return oldMetadata, err } } // rx-placement - if newIntf.GetRxPlacementSettings() != nil && !proto.Equal(getRxPlacement(oldIntf), getRxPlacement(newIntf)) { - if err = d.ifHandler.SetRxPlacement(ifIdx, newIntf.GetRxPlacementSettings()); err != nil { - err = errors.Errorf("failed to modify rx-placement for interface %s: %v", newIntf.Name, err) - d.log.Error(err) - return oldMetadata, err + if !d.equivalentRxPlacement(oldIntf.GetRxPlacement(), newIntf.GetRxPlacement()) { + for queue, worker := range newIntf.GetRxPlacement() { + if err = d.ifHandler.SetRxPlacement(ifIdx, queue, worker); err != nil { + err = errors.Errorf("failed to set rx-placement for queue %d of the interface %s: %v", + queue, newIntf.Name, err) + d.log.Error(err) + return nil, err + } } } diff --git a/plugins/vpp/ifplugin/vppcalls/if_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/if_vppcalls.go index 35b2a65441..d33c96799b 100644 --- a/plugins/vpp/ifplugin/vppcalls/if_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/if_vppcalls.go @@ -153,10 +153,10 @@ type InterfaceVppAPI interface { RegisterMemifSocketFilename(filename []byte, id uint32) error // SetInterfaceMtu calls HwInterfaceSetMtu bin API with desired MTU value. SetInterfaceMtu(ifIdx uint32, mtu uint32) error - // SetRxMode calls SwInterfaceSetRxMode bin - SetRxMode(ifIdx uint32, rxModeSettings *interfaces.Interface_RxModeSettings) error + // SetRxMode calls SwInterfaceSetRxMode bin API + SetRxMode(ifIdx uint32, queueID uint32, rxMode interfaces.Interface_RxMode_Type, isDefaultMode bool) error // SetRxPlacement configures rx-placement for interface - SetRxPlacement(ifIdx uint32, rxPlacement *interfaces.Interface_RxPlacementSettings) error + SetRxPlacement(ifIdx uint32, queueID, workerID uint32) error // SetInterfaceVrf sets VRF table for the interface SetInterfaceVrf(ifaceIndex, vrfID uint32) error // SetInterfaceVrfIPv6 sets IPV6 VRF table for the interface diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go index 83dd09ac6e..a7fe084b38 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go @@ -749,19 +749,25 @@ func (h *InterfaceVppHandler) dumpRxPlacement(ifs map[uint32]*vppcalls.Interface if stop { break } + + fmt.Printf("Received RX details: %+v", rxDetails) + ifData, ok := ifs[rxDetails.SwIfIndex] if !ok { h.log.Warnf("Received rx-placement data for unknown interface with index %d", rxDetails.SwIfIndex) continue } - ifData.Interface.RxModeSettings = &interfaces.Interface_RxModeSettings{ - RxMode: getRxModeType(rxDetails.Mode), - QueueId: rxDetails.QueueID, + if ifData.Interface.RxMode == nil { + ifData.Interface.RxMode = &interfaces.Interface_RxMode{} + } + if ifData.Interface.RxMode.QueueRxMode == nil { + ifData.Interface.RxMode.QueueRxMode = make(map[uint32]interfaces.Interface_RxMode_Type) } - ifData.Interface.RxPlacementSettings = &interfaces.Interface_RxPlacementSettings{ - Queue: rxDetails.QueueID, - Worker: rxDetails.WorkerID, + ifData.Interface.RxMode.QueueRxMode[rxDetails.QueueID] = getRxModeType(rxDetails.Mode) + if ifData.Interface.RxPlacement == nil { + ifData.Interface.RxPlacement = make(map[uint32]uint32) } + ifData.Interface.RxPlacement[rxDetails.QueueID] = rxDetails.WorkerID } return nil } @@ -816,18 +822,18 @@ func memifModetoNB(mode uint8) interfaces.MemifLink_MemifMode { } // Convert binary API rx-mode to northbound representation -func getRxModeType(mode uint8) interfaces.Interface_RxModeSettings_RxModeType { +func getRxModeType(mode uint8) interfaces.Interface_RxMode_Type { switch mode { case 1: - return interfaces.Interface_RxModeSettings_POLLING + return interfaces.Interface_RxMode_POLLING case 2: - return interfaces.Interface_RxModeSettings_INTERRUPT + return interfaces.Interface_RxMode_INTERRUPT case 3: - return interfaces.Interface_RxModeSettings_ADAPTIVE + return interfaces.Interface_RxMode_ADAPTIVE case 4: - return interfaces.Interface_RxModeSettings_DEFAULT + return interfaces.Interface_RxMode_DEFAULT default: - return interfaces.Interface_RxModeSettings_UNKNOWN + return interfaces.Interface_RxMode_UNKNOWN } } diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_mode_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_mode_vppcalls.go index b28a34be1c..c81d4adfd3 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_mode_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_mode_vppcalls.go @@ -20,12 +20,13 @@ import ( ) // SetRxMode implements interface handler. -func (h *InterfaceVppHandler) SetRxMode(ifIdx uint32, rxModeSettings *interfaces.Interface_RxModeSettings) error { +func (h *InterfaceVppHandler) SetRxMode(ifIdx uint32, queueID uint32, rxMode interfaces.Interface_RxMode_Type, isDefaultMode bool) error { + req := &binapi_interface.SwInterfaceSetRxMode{ SwIfIndex: ifIdx, - Mode: uint8(rxModeSettings.RxMode), - QueueID: rxModeSettings.QueueId, - QueueIDValid: uint8(rxModeSettings.QueueIdValid), + Mode: uint8(rxMode), + QueueID: queueID, + QueueIDValid: boolToUint(!isDefaultMode), } reply := &binapi_interface.SwInterfaceSetRxModeReply{} diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_placement_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_placement_vppcalls.go index 479e75b253..290198e4f4 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_placement_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_placement_vppcalls.go @@ -20,12 +20,12 @@ import ( ) // SetRxPlacement implements interface handler. -func (h *InterfaceVppHandler) SetRxPlacement(ifIdx uint32, rxPlacement *interfaces.Interface_RxPlacementSettings) error { +func (h *InterfaceVppHandler) SetRxPlacement(ifIdx uint32, queueID, workerID uint32) error { req := &binapi_interface.SwInterfaceSetRxPlacement{ SwIfIndex: ifIdx, - QueueID: rxPlacement.Queue, - WorkerID: rxPlacement.Worker, - IsMain: boolToUint(rxPlacement.IsMain), + QueueID: queueID, + WorkerID: workerID, + IsMain: boolToUint(workerID == 0), } reply := &binapi_interface.SwInterfaceSetRxPlacementReply{} diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls.go index 77e06e4607..bbb7aa0328 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls.go @@ -763,19 +763,23 @@ func (h *InterfaceVppHandler) dumpRxPlacement(ifs map[uint32]*vppcalls.Interface if stop { break } + ifData, ok := ifs[rxDetails.SwIfIndex] if !ok { h.log.Warnf("Received rx-placement data for unknown interface with index %d", rxDetails.SwIfIndex) continue } - ifData.Interface.RxModeSettings = &interfaces.Interface_RxModeSettings{ - RxMode: getRxModeType(rxDetails.Mode), - QueueId: rxDetails.QueueID, + if ifData.Interface.RxMode == nil { + ifData.Interface.RxMode = &interfaces.Interface_RxMode{} + } + if ifData.Interface.RxMode.QueueRxMode == nil { + ifData.Interface.RxMode.QueueRxMode = make(map[uint32]interfaces.Interface_RxMode_Type) } - ifData.Interface.RxPlacementSettings = &interfaces.Interface_RxPlacementSettings{ - Queue: rxDetails.QueueID, - Worker: rxDetails.WorkerID, + ifData.Interface.RxMode.QueueRxMode[rxDetails.QueueID] = getRxModeType(rxDetails.Mode) + if ifData.Interface.RxPlacement == nil { + ifData.Interface.RxPlacement = make(map[uint32]uint32) } + ifData.Interface.RxPlacement[rxDetails.QueueID] = rxDetails.WorkerID } return nil } @@ -830,18 +834,18 @@ func memifModetoNB(mode uint8) interfaces.MemifLink_MemifMode { } // Convert binary API rx-mode to northbound representation -func getRxModeType(mode uint8) interfaces.Interface_RxModeSettings_RxModeType { +func getRxModeType(mode uint8) interfaces.Interface_RxMode_Type { switch mode { case 1: - return interfaces.Interface_RxModeSettings_POLLING + return interfaces.Interface_RxMode_POLLING case 2: - return interfaces.Interface_RxModeSettings_INTERRUPT + return interfaces.Interface_RxMode_INTERRUPT case 3: - return interfaces.Interface_RxModeSettings_ADAPTIVE + return interfaces.Interface_RxMode_ADAPTIVE case 4: - return interfaces.Interface_RxModeSettings_DEFAULT + return interfaces.Interface_RxMode_DEFAULT default: - return interfaces.Interface_RxModeSettings_UNKNOWN + return interfaces.Interface_RxMode_UNKNOWN } } diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_mode_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_mode_vppcalls.go index 64fab34580..e2df8c1bde 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_mode_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_mode_vppcalls.go @@ -20,12 +20,13 @@ import ( ) // SetRxMode implements interface handler. -func (h *InterfaceVppHandler) SetRxMode(ifIdx uint32, rxModeSettings *interfaces.Interface_RxModeSettings) error { +func (h *InterfaceVppHandler) SetRxMode(ifIdx uint32, queueID uint32, rxMode interfaces.Interface_RxMode_Type, isDefaultMode bool) error { + req := &binapi_interface.SwInterfaceSetRxMode{ SwIfIndex: ifIdx, - Mode: uint8(rxModeSettings.RxMode), - QueueID: rxModeSettings.QueueId, - QueueIDValid: uint8(rxModeSettings.QueueIdValid), + Mode: uint8(rxMode), + QueueID: queueID, + QueueIDValid: boolToUint(!isDefaultMode), } reply := &binapi_interface.SwInterfaceSetRxModeReply{} diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_placement_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_placement_vppcalls.go index 0ce1468285..49adf9e9be 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_placement_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_placement_vppcalls.go @@ -20,12 +20,12 @@ import ( ) // SetRxPlacement implements interface handler. -func (h *InterfaceVppHandler) SetRxPlacement(ifIdx uint32, rxPlacement *interfaces.Interface_RxPlacementSettings) error { +func (h *InterfaceVppHandler) SetRxPlacement(ifIdx uint32, queueID, workerID uint32) error { req := &binapi_interface.SwInterfaceSetRxPlacement{ SwIfIndex: ifIdx, - QueueID: rxPlacement.Queue, - WorkerID: rxPlacement.Worker, - IsMain: boolToUint(rxPlacement.IsMain), + QueueID: queueID, + WorkerID: workerID, + IsMain: boolToUint(workerID == 0), } reply := &binapi_interface.SwInterfaceSetRxPlacementReply{} From 52b1eefedaef4cf1664fc077da69059aa2e76deb Mon Sep 17 00:00:00 2001 From: Milan Lenco Date: Fri, 10 May 2019 17:36:39 +0200 Subject: [PATCH 03/13] Fix build. Signed-off-by: Milan Lenco --- plugins/vpp/ifplugin/vppcalls/vpp1901/rx_placement_vppcalls.go | 1 - plugins/vpp/ifplugin/vppcalls/vpp1904/rx_placement_vppcalls.go | 1 - 2 files changed, 2 deletions(-) diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_placement_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_placement_vppcalls.go index 290198e4f4..f33f60a175 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_placement_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_placement_vppcalls.go @@ -15,7 +15,6 @@ package vpp1901 import ( - interfaces "github.com/ligato/vpp-agent/api/models/vpp/interfaces" binapi_interface "github.com/ligato/vpp-agent/plugins/vpp/binapi/vpp1901/interfaces" ) diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_placement_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_placement_vppcalls.go index 49adf9e9be..22eb91d587 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_placement_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_placement_vppcalls.go @@ -15,7 +15,6 @@ package vpp1904 import ( - interfaces "github.com/ligato/vpp-agent/api/models/vpp/interfaces" binapi_interface "github.com/ligato/vpp-agent/plugins/vpp/binapi/vpp1904/interfaces" ) From 90849287f734b7103212e22ff6b96820ee49147e Mon Sep 17 00:00:00 2001 From: Milan Lenco Date: Mon, 13 May 2019 14:42:23 +0200 Subject: [PATCH 04/13] Use arrays instead of maps for RxMode and placement. Signed-off-by: Milan Lenco --- api/models/vpp/interfaces/interface.pb.go | 354 +++++++++++------- api/models/vpp/interfaces/interface.proto | 17 +- plugins/vpp/ifplugin/descriptor/interface.go | 149 +++++--- .../vpp/ifplugin/descriptor/interface_crud.go | 62 +-- plugins/vpp/ifplugin/vppcalls/if_vppcalls.go | 4 +- .../vpp1901/dump_interface_vppcalls.go | 28 +- .../vppcalls/vpp1901/rx_mode_vppcalls.go | 8 +- .../vppcalls/vpp1901/rx_placement_vppcalls.go | 9 +- .../vpp1904/dump_interface_vppcalls.go | 26 +- .../vppcalls/vpp1904/rx_mode_vppcalls.go | 8 +- .../vppcalls/vpp1904/rx_placement_vppcalls.go | 9 +- 11 files changed, 417 insertions(+), 257 deletions(-) diff --git a/api/models/vpp/interfaces/interface.pb.go b/api/models/vpp/interfaces/interface.pb.go index 5854ac7d2c..d242cacf4b 100644 --- a/api/models/vpp/interfaces/interface.pb.go +++ b/api/models/vpp/interfaces/interface.pb.go @@ -249,17 +249,17 @@ func (BondLink_LoadBalance) EnumDescriptor() ([]byte, []int) { } type Interface struct { - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Type Interface_Type `protobuf:"varint,2,opt,name=type,proto3,enum=vpp.interfaces.Interface_Type" json:"type,omitempty"` - Enabled bool `protobuf:"varint,3,opt,name=enabled,proto3" json:"enabled,omitempty"` - PhysAddress string `protobuf:"bytes,4,opt,name=phys_address,json=physAddress,proto3" json:"phys_address,omitempty"` - IpAddresses []string `protobuf:"bytes,5,rep,name=ip_addresses,json=ipAddresses,proto3" json:"ip_addresses,omitempty"` - Vrf uint32 `protobuf:"varint,6,opt,name=vrf,proto3" json:"vrf,omitempty"` - SetDhcpClient bool `protobuf:"varint,7,opt,name=set_dhcp_client,json=setDhcpClient,proto3" json:"set_dhcp_client,omitempty"` - Mtu uint32 `protobuf:"varint,8,opt,name=mtu,proto3" json:"mtu,omitempty"` - Unnumbered *Interface_Unnumbered `protobuf:"bytes,9,opt,name=unnumbered,proto3" json:"unnumbered,omitempty"` - RxMode *Interface_RxMode `protobuf:"bytes,10,opt,name=rx_mode,json=rxMode,proto3" json:"rx_mode,omitempty"` - RxPlacement map[uint32]uint32 `protobuf:"bytes,11,rep,name=rx_placement,json=rxPlacement,proto3" json:"rx_placement,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Type Interface_Type `protobuf:"varint,2,opt,name=type,proto3,enum=vpp.interfaces.Interface_Type" json:"type,omitempty"` + Enabled bool `protobuf:"varint,3,opt,name=enabled,proto3" json:"enabled,omitempty"` + PhysAddress string `protobuf:"bytes,4,opt,name=phys_address,json=physAddress,proto3" json:"phys_address,omitempty"` + IpAddresses []string `protobuf:"bytes,5,rep,name=ip_addresses,json=ipAddresses,proto3" json:"ip_addresses,omitempty"` + Vrf uint32 `protobuf:"varint,6,opt,name=vrf,proto3" json:"vrf,omitempty"` + SetDhcpClient bool `protobuf:"varint,7,opt,name=set_dhcp_client,json=setDhcpClient,proto3" json:"set_dhcp_client,omitempty"` + Mtu uint32 `protobuf:"varint,8,opt,name=mtu,proto3" json:"mtu,omitempty"` + Unnumbered *Interface_Unnumbered `protobuf:"bytes,9,opt,name=unnumbered,proto3" json:"unnumbered,omitempty"` + RxMode []*Interface_RxMode `protobuf:"bytes,10,rep,name=rx_mode,json=rxMode,proto3" json:"rx_mode,omitempty"` + RxPlacement []*Interface_RxPlacement `protobuf:"bytes,11,rep,name=rx_placement,json=rxPlacement,proto3" json:"rx_placement,omitempty"` // Types that are valid to be assigned to Link: // *Interface_Sub // *Interface_Memif @@ -407,14 +407,14 @@ func (m *Interface) GetUnnumbered() *Interface_Unnumbered { return nil } -func (m *Interface) GetRxMode() *Interface_RxMode { +func (m *Interface) GetRxMode() []*Interface_RxMode { if m != nil { return m.RxMode } return nil } -func (m *Interface) GetRxPlacement() map[uint32]uint32 { +func (m *Interface) GetRxPlacement() []*Interface_RxPlacement { if m != nil { return m.RxPlacement } @@ -712,11 +712,12 @@ func (*Interface_Unnumbered) XXX_MessageName() string { } type Interface_RxMode struct { - DefaultRxMode Interface_RxMode_Type `protobuf:"varint,1,opt,name=default_rx_mode,json=defaultRxMode,proto3,enum=vpp.interfaces.Interface_RxMode_Type" json:"default_rx_mode,omitempty"` - QueueRxMode map[uint32]Interface_RxMode_Type `protobuf:"bytes,2,rep,name=queue_rx_mode,json=queueRxMode,proto3" json:"queue_rx_mode,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3,enum=vpp.interfaces.Interface_RxMode_Type"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Queue uint32 `protobuf:"varint,1,opt,name=queue,proto3" json:"queue,omitempty"` + Mode Interface_RxMode_Type `protobuf:"varint,2,opt,name=mode,proto3,enum=vpp.interfaces.Interface_RxMode_Type" json:"mode,omitempty"` + DefaultMode bool `protobuf:"varint,3,opt,name=default_mode,json=defaultMode,proto3" json:"default_mode,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Interface_RxMode) Reset() { *m = Interface_RxMode{} } @@ -743,24 +744,89 @@ func (m *Interface_RxMode) XXX_DiscardUnknown() { var xxx_messageInfo_Interface_RxMode proto.InternalMessageInfo -func (m *Interface_RxMode) GetDefaultRxMode() Interface_RxMode_Type { +func (m *Interface_RxMode) GetQueue() uint32 { if m != nil { - return m.DefaultRxMode + return m.Queue + } + return 0 +} + +func (m *Interface_RxMode) GetMode() Interface_RxMode_Type { + if m != nil { + return m.Mode } return Interface_RxMode_UNKNOWN } -func (m *Interface_RxMode) GetQueueRxMode() map[uint32]Interface_RxMode_Type { +func (m *Interface_RxMode) GetDefaultMode() bool { if m != nil { - return m.QueueRxMode + return m.DefaultMode } - return nil + return false } func (*Interface_RxMode) XXX_MessageName() string { return "vpp.interfaces.Interface.RxMode" } +type Interface_RxPlacement struct { + Queue uint32 `protobuf:"varint,1,opt,name=queue,proto3" json:"queue,omitempty"` + Worker uint32 `protobuf:"varint,2,opt,name=worker,proto3" json:"worker,omitempty"` + MainThread bool `protobuf:"varint,3,opt,name=main_thread,json=mainThread,proto3" json:"main_thread,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Interface_RxPlacement) Reset() { *m = Interface_RxPlacement{} } +func (m *Interface_RxPlacement) String() string { return proto.CompactTextString(m) } +func (*Interface_RxPlacement) ProtoMessage() {} +func (*Interface_RxPlacement) Descriptor() ([]byte, []int) { + return fileDescriptor_1ac7cab935c1dc4d, []int{0, 2} +} +func (m *Interface_RxPlacement) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Interface_RxPlacement.Unmarshal(m, b) +} +func (m *Interface_RxPlacement) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Interface_RxPlacement.Marshal(b, m, deterministic) +} +func (m *Interface_RxPlacement) XXX_Merge(src proto.Message) { + xxx_messageInfo_Interface_RxPlacement.Merge(m, src) +} +func (m *Interface_RxPlacement) XXX_Size() int { + return xxx_messageInfo_Interface_RxPlacement.Size(m) +} +func (m *Interface_RxPlacement) XXX_DiscardUnknown() { + xxx_messageInfo_Interface_RxPlacement.DiscardUnknown(m) +} + +var xxx_messageInfo_Interface_RxPlacement proto.InternalMessageInfo + +func (m *Interface_RxPlacement) GetQueue() uint32 { + if m != nil { + return m.Queue + } + return 0 +} + +func (m *Interface_RxPlacement) GetWorker() uint32 { + if m != nil { + return m.Worker + } + return 0 +} + +func (m *Interface_RxPlacement) GetMainThread() bool { + if m != nil { + return m.MainThread + } + return false +} + +func (*Interface_RxPlacement) XXX_MessageName() string { + return "vpp.interfaces.Interface.RxPlacement" +} + type SubInterface struct { ParentName string `protobuf:"bytes,1,opt,name=parent_name,json=parentName,proto3" json:"parent_name,omitempty"` SubId uint32 `protobuf:"varint,2,opt,name=sub_id,json=subId,proto3" json:"sub_id,omitempty"` @@ -1469,10 +1535,9 @@ func init() { proto.RegisterEnum("vpp.interfaces.BondLink_Mode", BondLink_Mode_name, BondLink_Mode_value) proto.RegisterEnum("vpp.interfaces.BondLink_LoadBalance", BondLink_LoadBalance_name, BondLink_LoadBalance_value) proto.RegisterType((*Interface)(nil), "vpp.interfaces.Interface") - proto.RegisterMapType((map[uint32]uint32)(nil), "vpp.interfaces.Interface.RxPlacementEntry") proto.RegisterType((*Interface_Unnumbered)(nil), "vpp.interfaces.Interface.Unnumbered") proto.RegisterType((*Interface_RxMode)(nil), "vpp.interfaces.Interface.RxMode") - proto.RegisterMapType((map[uint32]Interface_RxMode_Type)(nil), "vpp.interfaces.Interface.RxMode.QueueRxModeEntry") + proto.RegisterType((*Interface_RxPlacement)(nil), "vpp.interfaces.Interface.RxPlacement") proto.RegisterType((*SubInterface)(nil), "vpp.interfaces.SubInterface") proto.RegisterType((*MemifLink)(nil), "vpp.interfaces.MemifLink") proto.RegisterType((*VxlanLink)(nil), "vpp.interfaces.VxlanLink") @@ -1489,124 +1554,123 @@ func init() { } var fileDescriptor_1ac7cab935c1dc4d = []byte{ - // 1895 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x57, 0xcd, 0x92, 0xdb, 0xc6, - 0x11, 0x5e, 0xfe, 0x2c, 0x49, 0x34, 0x7f, 0x16, 0x9a, 0xd8, 0x09, 0xbc, 0x96, 0x6c, 0x86, 0x89, - 0xe3, 0x2d, 0xa7, 0xcc, 0x15, 0xb9, 0xae, 0x8a, 0x62, 0x57, 0xa5, 0x0a, 0x24, 0xb1, 0x16, 0x25, - 0x2e, 0xc8, 0x80, 0xa0, 0x24, 0xe7, 0x82, 0x02, 0x81, 0x21, 0x16, 0x11, 0x08, 0x40, 0xc0, 0x90, - 0xe2, 0xba, 0x2a, 0xcf, 0x90, 0x5b, 0x9e, 0x27, 0xc7, 0x1c, 0x72, 0xc9, 0x31, 0xc7, 0x54, 0x8e, - 0x39, 0xe6, 0x05, 0x52, 0xf3, 0x03, 0x12, 0xbb, 0x5a, 0xd9, 0xb9, 0xec, 0xce, 0x7c, 0xdd, 0x5f, - 0x4f, 0xb3, 0xa7, 0xa7, 0xbb, 0x01, 0x9f, 0xad, 0x23, 0x17, 0x07, 0xe9, 0xf9, 0x36, 0x8e, 0xcf, - 0xfd, 0x90, 0xe0, 0x64, 0x65, 0x3b, 0x38, 0x3d, 0x2c, 0xbb, 0x71, 0x12, 0x91, 0x08, 0xb5, 0xb6, - 0x71, 0xdc, 0x3d, 0xc8, 0x4f, 0xbf, 0xf4, 0x7c, 0x72, 0xbd, 0x59, 0x76, 0x9d, 0x68, 0x7d, 0xee, - 0x45, 0x5e, 0x74, 0xce, 0xd4, 0x96, 0x9b, 0x15, 0xdb, 0xb1, 0x0d, 0x5b, 0x71, 0xfa, 0xe9, 0xc3, - 0xfc, 0x29, 0x71, 0x8a, 0x1d, 0xfe, 0x97, 0x4b, 0x3b, 0x7f, 0x69, 0x80, 0x34, 0xce, 0x6c, 0x23, - 0x04, 0xe5, 0xd0, 0x5e, 0x63, 0xa5, 0xd0, 0x2e, 0x9c, 0x49, 0x06, 0x5b, 0xa3, 0x3e, 0x94, 0xc9, - 0x4d, 0x8c, 0x95, 0x62, 0xbb, 0x70, 0xd6, 0xea, 0x7f, 0xd2, 0xbd, 0xed, 0x4d, 0x77, 0x4f, 0xee, - 0x9a, 0x37, 0x31, 0x36, 0x98, 0x2e, 0x52, 0xa0, 0x8a, 0x43, 0x7b, 0x19, 0x60, 0x57, 0x29, 0xb5, - 0x0b, 0x67, 0x35, 0x23, 0xdb, 0xa2, 0x9f, 0x43, 0x23, 0xbe, 0xbe, 0x49, 0x2d, 0xdb, 0x75, 0x13, - 0x9c, 0xa6, 0x4a, 0x99, 0x9d, 0x54, 0xa7, 0x98, 0xca, 0x21, 0xaa, 0xe2, 0xc7, 0x99, 0x02, 0x4e, - 0x95, 0xe3, 0x76, 0x89, 0xaa, 0xf8, 0xb1, 0x9a, 0x41, 0x48, 0x86, 0xd2, 0x36, 0x59, 0x29, 0x95, - 0x76, 0xe1, 0xac, 0x69, 0xd0, 0x25, 0xfa, 0x15, 0x9c, 0xa4, 0x98, 0x58, 0xee, 0xb5, 0x13, 0x5b, - 0x4e, 0xe0, 0xe3, 0x90, 0x28, 0x55, 0x76, 0x72, 0x33, 0xc5, 0x64, 0x74, 0xed, 0xc4, 0x43, 0x06, - 0x52, 0xe6, 0x9a, 0x6c, 0x94, 0x1a, 0x67, 0xae, 0xc9, 0x06, 0x8d, 0x00, 0x36, 0x61, 0xb8, 0x59, - 0x2f, 0x71, 0x82, 0x5d, 0x45, 0x6a, 0x17, 0xce, 0xea, 0xfd, 0x5f, 0xbe, 0xff, 0x57, 0x2e, 0xf6, - 0xba, 0x46, 0x8e, 0x87, 0x7e, 0x0b, 0xd5, 0x64, 0x67, 0xd1, 0x50, 0x2b, 0xc0, 0x4c, 0xb4, 0xdf, - 0x6f, 0xc2, 0xd8, 0x5d, 0x45, 0x2e, 0x36, 0x2a, 0x09, 0xfb, 0x8f, 0xae, 0xa0, 0x91, 0xec, 0xac, - 0x38, 0xb0, 0x1d, 0xbc, 0xa6, 0x7e, 0xd7, 0xdb, 0xa5, 0xb3, 0x7a, 0xff, 0x8b, 0x1f, 0xe2, 0xcf, - 0x32, 0x65, 0x2d, 0x24, 0xc9, 0x8d, 0x51, 0x4f, 0x0e, 0x08, 0x7a, 0x0c, 0xa5, 0x74, 0xb3, 0x54, - 0x5c, 0xe6, 0xc5, 0xc3, 0xbb, 0x56, 0xe6, 0x9b, 0xe5, 0xde, 0xd0, 0xd3, 0x23, 0x83, 0xaa, 0xa2, - 0x1e, 0x1c, 0xaf, 0xf1, 0xda, 0x5f, 0x29, 0x98, 0x71, 0x3e, 0xba, 0xcb, 0xb9, 0xa2, 0xc2, 0x89, - 0x1f, 0xbe, 0x7e, 0x7a, 0x64, 0x70, 0x4d, 0xf4, 0x35, 0xd4, 0xec, 0x55, 0x6c, 0x3b, 0xaf, 0x31, - 0x51, 0x56, 0xf7, 0x9f, 0xa4, 0x0a, 0xb9, 0x20, 0xee, 0xf5, 0xd1, 0xaf, 0xa1, 0x44, 0xec, 0x58, - 0xf1, 0x18, 0xed, 0x67, 0x77, 0x69, 0xa6, 0x1d, 0x0b, 0x06, 0xd5, 0xa2, 0xbe, 0x6d, 0x77, 0x81, - 0x1d, 0x2a, 0xd7, 0xf7, 0xfb, 0xf6, 0x82, 0x0a, 0x33, 0xdf, 0x98, 0x26, 0xa5, 0xb0, 0x0c, 0x57, - 0xfc, 0xfb, 0x29, 0xe3, 0xd9, 0x1c, 0x3b, 0x19, 0x85, 0x69, 0xa2, 0x27, 0x50, 0xdb, 0xae, 0x77, - 0x56, 0x88, 0xc9, 0x85, 0xf2, 0x47, 0xc6, 0xfa, 0xf8, 0x9d, 0x83, 0xd6, 0x3b, 0x1d, 0x93, 0x0b, - 0xc1, 0xab, 0x6e, 0xf9, 0x16, 0x75, 0xa1, 0xbc, 0x8c, 0x42, 0x57, 0x79, 0xcd, 0x58, 0xca, 0x5d, - 0xd6, 0x20, 0x0a, 0x5d, 0x41, 0x61, 0x7a, 0xa7, 0x4f, 0x00, 0x0e, 0x19, 0x84, 0xbe, 0x80, 0x07, - 0x7b, 0x65, 0xeb, 0xad, 0x4f, 0xae, 0x2d, 0x3f, 0x16, 0x8f, 0xef, 0x64, 0x2f, 0x78, 0xe9, 0x93, - 0xeb, 0x71, 0x7c, 0xfa, 0xaf, 0x22, 0x54, 0x8c, 0x2c, 0x63, 0x4e, 0x5c, 0xbc, 0xb2, 0x37, 0x01, - 0xb1, 0xb2, 0xa4, 0x2b, 0xb0, 0xd7, 0xf9, 0xd9, 0x8f, 0x25, 0x1d, 0x7f, 0xa4, 0x4d, 0xc1, 0x16, - 0xe6, 0x16, 0xd0, 0x7c, 0xb3, 0xc1, 0x1b, 0xbc, 0x37, 0x56, 0x64, 0x19, 0xd8, 0xfb, 0x51, 0x63, - 0xbf, 0xa7, 0x2c, 0xbe, 0x16, 0x89, 0xf8, 0xe6, 0x80, 0x9c, 0x62, 0x90, 0xef, 0x2a, 0xd0, 0xe7, - 0xf7, 0x1a, 0xdf, 0x30, 0x6f, 0x9b, 0x06, 0x5d, 0xa2, 0x6f, 0xe0, 0x78, 0x6b, 0x07, 0x9b, 0xac, - 0xbe, 0xfc, 0x9f, 0xbf, 0x80, 0x73, 0xbe, 0x2e, 0x3e, 0x29, 0x74, 0x9e, 0x41, 0x99, 0x42, 0xa8, - 0x0e, 0xd5, 0x85, 0xfe, 0x5c, 0x9f, 0xbe, 0xd4, 0xe5, 0x23, 0xba, 0x99, 0x4d, 0x27, 0x93, 0xb1, - 0xfe, 0xad, 0x5c, 0x40, 0x4d, 0x90, 0xc6, 0xba, 0xa9, 0x19, 0xc6, 0x62, 0x66, 0xca, 0x45, 0xd4, - 0x80, 0x9a, 0x3a, 0x52, 0x67, 0xe6, 0xf8, 0x85, 0x26, 0x97, 0xa8, 0xe6, 0x48, 0xbb, 0x54, 0x17, - 0x13, 0x53, 0x2e, 0x9f, 0xfe, 0x0e, 0xe4, 0xbb, 0x8f, 0xeb, 0x1e, 0x97, 0x3f, 0xc8, 0xbb, 0xdc, - 0xcc, 0xfb, 0xf2, 0xd7, 0x82, 0x70, 0x06, 0x41, 0x6b, 0xa1, 0x8f, 0xb4, 0xcb, 0xb1, 0xae, 0x8d, - 0x2c, 0xf3, 0xbb, 0x99, 0x26, 0x1f, 0xa1, 0x07, 0xd0, 0x9c, 0x2f, 0x06, 0x16, 0x73, 0xe5, 0x52, - 0x1d, 0x6a, 0x72, 0x01, 0x7d, 0x08, 0x0f, 0xe6, 0xd3, 0x4b, 0xf3, 0xa5, 0x6a, 0x68, 0xd6, 0x64, - 0x3a, 0x9d, 0x0d, 0xd4, 0xe1, 0x73, 0xb9, 0x88, 0x6a, 0x50, 0x1e, 0xcd, 0x46, 0xcf, 0xe5, 0x12, - 0x92, 0xe0, 0xf8, 0x4a, 0xbb, 0x1a, 0x5f, 0xca, 0x65, 0x54, 0x85, 0x92, 0xa9, 0xce, 0xe4, 0x63, - 0xfa, 0x73, 0xd4, 0x4b, 0x6b, 0xa6, 0x0e, 0x9f, 0x6b, 0xa6, 0x5c, 0x41, 0x32, 0x34, 0x5e, 0xbc, - 0x9a, 0xa8, 0xba, 0x65, 0x2e, 0x74, 0x5d, 0x9b, 0xc8, 0x55, 0x8a, 0x8c, 0x67, 0x73, 0x6d, 0x98, - 0x21, 0x35, 0x7a, 0xce, 0x8b, 0xab, 0x57, 0xba, 0x66, 0x5e, 0xe4, 0x8e, 0x97, 0xa8, 0x97, 0x83, - 0xa9, 0x3e, 0xca, 0x61, 0x30, 0xa8, 0x40, 0x39, 0xf0, 0xc3, 0xd7, 0x9d, 0xff, 0x16, 0xa1, 0x91, - 0x2f, 0x16, 0xe8, 0x53, 0xa8, 0xc7, 0x76, 0x82, 0x43, 0x62, 0xe5, 0x5a, 0x04, 0x70, 0x48, 0xa7, - 0x8d, 0xe2, 0x43, 0xa8, 0xa4, 0x9b, 0xa5, 0xe5, 0xbb, 0x59, 0x5c, 0xd2, 0xcd, 0x72, 0xec, 0x22, - 0x03, 0x9a, 0xc4, 0xf6, 0xac, 0xe4, 0xad, 0x15, 0xc5, 0xc4, 0x8f, 0x42, 0xd6, 0x11, 0x5a, 0xfd, - 0xee, 0x0f, 0x55, 0xa6, 0xae, 0x69, 0x7b, 0x06, 0x7e, 0x9b, 0xf8, 0x04, 0x4f, 0x19, 0x29, 0x35, - 0xea, 0xc4, 0xf6, 0x8c, 0xb7, 0x7c, 0x87, 0x1e, 0x01, 0xc4, 0x9b, 0xf4, 0xda, 0x72, 0x23, 0xd2, - 0x7b, 0xc3, 0x7a, 0x48, 0xcd, 0x90, 0x28, 0x32, 0xa2, 0x00, 0x6d, 0x63, 0xc4, 0xf6, 0x7a, 0xca, - 0x31, 0xf3, 0x83, 0xad, 0x05, 0xd6, 0x17, 0x3d, 0x83, 0xad, 0x3b, 0x7f, 0x2e, 0xc0, 0x83, 0x77, - 0x4e, 0xa2, 0xf9, 0x31, 0x1a, 0xcf, 0xd5, 0xc1, 0x44, 0x1b, 0xc9, 0x47, 0xf4, 0x06, 0x66, 0x8b, - 0xf9, 0xd3, 0x9e, 0x5c, 0xc8, 0x96, 0x7d, 0x7e, 0x43, 0xb3, 0xe9, 0xac, 0x27, 0x97, 0xc4, 0xaa, - 0x2f, 0x97, 0xd1, 0x09, 0xd4, 0x4d, 0x43, 0xd5, 0xe7, 0x13, 0xd5, 0xd4, 0x7a, 0x3d, 0xf9, 0xf8, - 0x36, 0xd0, 0x97, 0x2b, 0xb7, 0x80, 0x7e, 0x4f, 0xae, 0xde, 0x06, 0xfa, 0x72, 0xad, 0xf3, 0xcf, - 0x22, 0x48, 0xfb, 0x72, 0x8b, 0x7e, 0x03, 0xe5, 0xdc, 0xe3, 0xfe, 0xc5, 0x7b, 0xeb, 0x32, 0x5f, - 0xb1, 0xa6, 0xc2, 0x08, 0xe8, 0xa7, 0x50, 0x59, 0xdb, 0x29, 0xc1, 0x09, 0xbb, 0x8a, 0x9a, 0x21, - 0x76, 0xa8, 0x05, 0x45, 0x9f, 0xb7, 0xe4, 0xa6, 0x51, 0xf4, 0x5d, 0xf4, 0x39, 0x9c, 0xa4, 0x11, - 0x2d, 0xca, 0xd6, 0xca, 0x0f, 0x30, 0xbb, 0x57, 0xde, 0x90, 0x5b, 0x1c, 0xbe, 0x14, 0x28, 0x35, - 0x98, 0x62, 0x27, 0xc1, 0x84, 0xc5, 0x54, 0x32, 0xc4, 0x0e, 0x7d, 0x0c, 0x52, 0xe2, 0x87, 0x9e, - 0x95, 0xfa, 0xdf, 0x63, 0x11, 0xda, 0x1a, 0x05, 0xe6, 0xfe, 0xf7, 0x2c, 0x63, 0x96, 0x9b, 0xd5, - 0x0a, 0x27, 0x5c, 0x5c, 0x65, 0x62, 0xe0, 0x10, 0x53, 0xa0, 0xec, 0x9d, 0xc5, 0x6a, 0x46, 0x2a, - 0x5a, 0x72, 0x2d, 0xd9, 0xb1, 0xa2, 0x91, 0x52, 0x21, 0xd9, 0x0b, 0x25, 0x2e, 0x24, 0x42, 0xd8, - 0xe9, 0x8b, 0x30, 0xb1, 0xfa, 0xd5, 0x80, 0x9a, 0x66, 0x3e, 0xd5, 0x0c, 0x5d, 0x33, 0xe5, 0x23, - 0x54, 0x81, 0xe2, 0x78, 0x26, 0x17, 0x68, 0x6c, 0x67, 0x0b, 0xdd, 0xb4, 0xc6, 0xfa, 0x33, 0x6d, - 0x68, 0xca, 0xc5, 0xce, 0x9f, 0x40, 0xda, 0x77, 0x0b, 0xea, 0x5b, 0x9a, 0x38, 0xfb, 0x31, 0x44, - 0x64, 0x73, 0x9a, 0x38, 0xd9, 0x14, 0xf2, 0x29, 0xd4, 0xdd, 0x94, 0xec, 0x15, 0x8a, 0x5c, 0xc1, - 0x4d, 0x49, 0xa6, 0x40, 0x67, 0x90, 0xd0, 0x17, 0xc1, 0xa4, 0x4b, 0xf4, 0x10, 0xa4, 0xf5, 0x26, - 0x20, 0xbe, 0x63, 0xa7, 0x44, 0xc4, 0xf1, 0x00, 0x74, 0x1e, 0x43, 0x23, 0xdf, 0x12, 0x51, 0x1b, - 0x1a, 0xd7, 0x51, 0x4a, 0x2c, 0x7f, 0x75, 0xeb, 0x41, 0x51, 0x6c, 0xbc, 0xa2, 0x0f, 0xaa, 0xf3, - 0x8f, 0x02, 0x54, 0x45, 0x3b, 0xa4, 0x13, 0xd5, 0x16, 0x27, 0x29, 0x7d, 0x3f, 0xbc, 0x12, 0x65, - 0xdb, 0x77, 0xec, 0x14, 0xef, 0xda, 0xa1, 0xb7, 0x4c, 0x22, 0x6b, 0xed, 0x3b, 0x49, 0x94, 0xe2, - 0x64, 0xeb, 0x3b, 0x98, 0x79, 0x2d, 0x19, 0x2d, 0x12, 0x5d, 0xe5, 0x50, 0x6a, 0x2a, 0xd9, 0x59, - 0x87, 0x0b, 0x2d, 0xf3, 0x1b, 0x4b, 0x76, 0x46, 0x76, 0xa5, 0x6d, 0x68, 0x90, 0xbc, 0x06, 0x7f, - 0x61, 0x40, 0x0e, 0x1a, 0x8f, 0x00, 0xf8, 0xac, 0x67, 0x79, 0x69, 0xc4, 0x52, 0xa2, 0x66, 0x48, - 0x1c, 0xf9, 0x36, 0x8d, 0x3a, 0xff, 0x29, 0x81, 0xb4, 0x6f, 0xc0, 0x34, 0x86, 0x38, 0x0d, 0x45, - 0x92, 0xd2, 0x25, 0x0d, 0xbb, 0x1d, 0x12, 0xdf, 0x4a, 0x70, 0x1c, 0xd8, 0x37, 0x62, 0x7a, 0x04, - 0x0a, 0x19, 0x0c, 0x41, 0x1f, 0x41, 0x2d, 0x88, 0x1c, 0x3b, 0xa0, 0x9d, 0x92, 0xc7, 0xb8, 0xca, - 0xf6, 0xe3, 0x98, 0xa5, 0x13, 0x5e, 0x47, 0x04, 0x53, 0x19, 0xcf, 0xd3, 0x1a, 0x07, 0xb8, 0x90, - 0xf3, 0xd2, 0xd8, 0xcf, 0x32, 0x95, 0x01, 0xf3, 0xd8, 0xa7, 0x4e, 0x0b, 0x26, 0x95, 0xf2, 0x44, - 0x15, 0xb6, 0xa8, 0xf8, 0x02, 0xc0, 0x49, 0x6e, 0x62, 0x12, 0x59, 0x76, 0xe0, 0xb1, 0x44, 0x6d, - 0xf5, 0x3f, 0xe0, 0xaf, 0x91, 0x8d, 0xd2, 0x43, 0x26, 0x54, 0x03, 0xcf, 0x90, 0x9c, 0x6c, 0x89, - 0xce, 0x40, 0xe6, 0x07, 0x0a, 0x2a, 0x6d, 0x22, 0x12, 0x0f, 0x3b, 0xc3, 0x39, 0xe9, 0x39, 0xbe, - 0xa1, 0x53, 0x80, 0x38, 0x3d, 0xa7, 0x0a, 0x7c, 0x0a, 0xe0, 0x82, 0x83, 0xee, 0x63, 0x90, 0x68, - 0x05, 0xf0, 0x98, 0x27, 0x75, 0xe6, 0xc9, 0x4f, 0x72, 0x9e, 0xd0, 0x0a, 0xea, 0x51, 0x47, 0x6a, - 0xbe, 0x58, 0xd1, 0xc9, 0x58, 0x04, 0x8c, 0xf1, 0xa8, 0xed, 0x06, 0xb3, 0xdd, 0xe4, 0x71, 0xa3, - 0x28, 0xb5, 0x7c, 0x06, 0x72, 0x16, 0xbd, 0xbd, 0x62, 0x93, 0xfb, 0x2b, 0x82, 0x98, 0xd3, 0x14, - 0x57, 0xbc, 0x71, 0x63, 0x0b, 0x87, 0x8e, 0x1d, 0x2b, 0x2d, 0x76, 0x51, 0x2d, 0x8e, 0x2f, 0xdc, - 0x58, 0xa3, 0x68, 0xc7, 0x85, 0x7a, 0x6e, 0x6e, 0xa2, 0x97, 0x2b, 0x88, 0x38, 0x88, 0x3c, 0x71, - 0xed, 0x22, 0x5d, 0xb4, 0x20, 0xf2, 0xe8, 0xe5, 0x26, 0xbb, 0x37, 0x3c, 0xb5, 0xf8, 0xc3, 0xaa, - 0x26, 0xbb, 0x37, 0x2c, 0xaf, 0x3e, 0x82, 0x1a, 0xc9, 0x44, 0x3c, 0x2f, 0xab, 0x84, 0x8b, 0x3a, - 0x7f, 0x2f, 0x41, 0x2d, 0x1b, 0xb4, 0x44, 0x89, 0x2b, 0xec, 0x4b, 0x5c, 0x4f, 0xd4, 0x50, 0xde, - 0x75, 0x1e, 0xbd, 0x6f, 0x40, 0xeb, 0xe6, 0xaa, 0xe7, 0x57, 0x50, 0x0c, 0x96, 0xec, 0x90, 0xd6, - 0xbb, 0x5f, 0x02, 0x7b, 0xc2, 0x24, 0xb2, 0xdd, 0x81, 0x1d, 0xd8, 0xa1, 0x83, 0x8d, 0x62, 0xb0, - 0x44, 0x0b, 0x78, 0x40, 0x27, 0x3c, 0xec, 0x5a, 0x07, 0x6d, 0xa5, 0xc1, 0x26, 0xa9, 0xb3, 0xf7, - 0x1a, 0x19, 0x30, 0xc6, 0xbe, 0xef, 0x19, 0xf2, 0xf2, 0x36, 0x90, 0x9e, 0x06, 0x70, 0x72, 0x47, - 0xe9, 0xde, 0xaf, 0xb4, 0x47, 0x00, 0x7e, 0x6a, 0xc5, 0x76, 0x9a, 0xfa, 0x5b, 0x2c, 0x22, 0x2b, - 0xf9, 0xe9, 0x8c, 0x03, 0x34, 0x09, 0xfc, 0xd4, 0x0a, 0xa2, 0xd0, 0xb3, 0x88, 0xbf, 0xc6, 0xd1, - 0x86, 0x88, 0xa7, 0xd5, 0xf4, 0xd3, 0x49, 0x14, 0x7a, 0x26, 0x07, 0x3b, 0xdf, 0x41, 0x99, 0x95, - 0xd4, 0x5b, 0xc3, 0xd4, 0x09, 0xd4, 0x8d, 0xe9, 0x42, 0x1f, 0x59, 0xc6, 0x74, 0x30, 0xd6, 0xe5, - 0x02, 0x9d, 0x64, 0xd4, 0x21, 0x9d, 0x9f, 0x2c, 0x3a, 0xb0, 0x2c, 0x66, 0x72, 0x91, 0x4e, 0x27, - 0xaf, 0xa6, 0x86, 0x5c, 0xa2, 0xd3, 0xc9, 0xc0, 0x98, 0xaa, 0xa3, 0xa1, 0x3a, 0x37, 0xe5, 0x32, - 0x6d, 0x8f, 0x13, 0x75, 0x38, 0x93, 0x8f, 0x3b, 0x9f, 0x43, 0x3d, 0x17, 0x32, 0x5a, 0xa6, 0x27, - 0x7d, 0xf9, 0x88, 0x12, 0x27, 0x17, 0x5f, 0xc9, 0x05, 0xb6, 0xe8, 0x5f, 0xc8, 0xc5, 0xc1, 0xb3, - 0xbf, 0xfd, 0xfb, 0x93, 0xc2, 0x1f, 0x46, 0xb9, 0xaf, 0xdc, 0xc0, 0xf7, 0x6c, 0x12, 0xd1, 0x2f, - 0xd8, 0x2f, 0x6d, 0x0f, 0x87, 0xe4, 0xdc, 0x8e, 0xfd, 0xf3, 0x7b, 0x3f, 0x9e, 0xbf, 0xd9, 0xc6, - 0x71, 0x2e, 0xfe, 0xcb, 0x0a, 0xfb, 0xca, 0xbd, 0xf8, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xfe, - 0x3c, 0xb0, 0x4a, 0x6b, 0x0f, 0x00, 0x00, + // 1875 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x57, 0xcd, 0x72, 0xe3, 0xc6, + 0x11, 0x16, 0x7f, 0x44, 0x12, 0xcd, 0x1f, 0x41, 0x13, 0xdb, 0xc1, 0xca, 0xbb, 0x36, 0xc3, 0x64, + 0x63, 0x55, 0x52, 0xa6, 0x56, 0x94, 0xab, 0x62, 0x27, 0x27, 0x90, 0x84, 0x2c, 0xae, 0x28, 0x90, + 0x01, 0xc1, 0xdd, 0x75, 0x2a, 0x55, 0x28, 0x10, 0x18, 0x82, 0x88, 0x40, 0x00, 0x0b, 0x0c, 0x29, + 0xca, 0x55, 0x79, 0x86, 0xdc, 0xf2, 0x3c, 0x39, 0xfa, 0x90, 0x4b, 0x8e, 0x39, 0xe7, 0x98, 0x63, + 0x5e, 0x20, 0x35, 0x3f, 0xa0, 0x28, 0xad, 0x64, 0x5f, 0xa4, 0xe9, 0xaf, 0xfb, 0x9b, 0x69, 0xf4, + 0x74, 0xf7, 0x34, 0xe1, 0xe5, 0x32, 0x72, 0x71, 0x90, 0x9e, 0xac, 0xe3, 0xf8, 0xc4, 0x0f, 0x09, + 0x4e, 0xe6, 0xb6, 0x83, 0xd3, 0xbb, 0x65, 0x3b, 0x4e, 0x22, 0x12, 0xa1, 0xc6, 0x3a, 0x8e, 0xdb, + 0x77, 0xfa, 0xa3, 0x2f, 0x3d, 0x9f, 0x2c, 0x56, 0xb3, 0xb6, 0x13, 0x2d, 0x4f, 0xbc, 0xc8, 0x8b, + 0x4e, 0x98, 0xd9, 0x6c, 0x35, 0x67, 0x12, 0x13, 0xd8, 0x8a, 0xd3, 0x8f, 0x9e, 0xef, 0x9e, 0x12, + 0xa7, 0xd8, 0xe1, 0x7f, 0xb9, 0xb6, 0xf5, 0xf7, 0x2a, 0x48, 0x83, 0x6c, 0x6f, 0x84, 0xa0, 0x18, + 0xda, 0x4b, 0xac, 0xe4, 0x9a, 0xb9, 0x63, 0xc9, 0x60, 0x6b, 0xd4, 0x81, 0x22, 0xb9, 0x8d, 0xb1, + 0x92, 0x6f, 0xe6, 0x8e, 0x1b, 0x9d, 0xcf, 0xda, 0xf7, 0xbd, 0x69, 0x6f, 0xc9, 0x6d, 0xf3, 0x36, + 0xc6, 0x06, 0xb3, 0x45, 0x0a, 0x94, 0x71, 0x68, 0xcf, 0x02, 0xec, 0x2a, 0x85, 0x66, 0xee, 0xb8, + 0x62, 0x64, 0x22, 0xfa, 0x05, 0xd4, 0xe2, 0xc5, 0x6d, 0x6a, 0xd9, 0xae, 0x9b, 0xe0, 0x34, 0x55, + 0x8a, 0xec, 0xa4, 0x2a, 0xc5, 0x54, 0x0e, 0x51, 0x13, 0x3f, 0xce, 0x0c, 0x70, 0xaa, 0xec, 0x37, + 0x0b, 0xd4, 0xc4, 0x8f, 0xd5, 0x0c, 0x42, 0x32, 0x14, 0xd6, 0xc9, 0x5c, 0x29, 0x35, 0x73, 0xc7, + 0x75, 0x83, 0x2e, 0xd1, 0xaf, 0xe1, 0x20, 0xc5, 0xc4, 0x72, 0x17, 0x4e, 0x6c, 0x39, 0x81, 0x8f, + 0x43, 0xa2, 0x94, 0xd9, 0xc9, 0xf5, 0x14, 0x93, 0xfe, 0xc2, 0x89, 0x7b, 0x0c, 0xa4, 0xcc, 0x25, + 0x59, 0x29, 0x15, 0xce, 0x5c, 0x92, 0x15, 0xea, 0x03, 0xac, 0xc2, 0x70, 0xb5, 0x9c, 0xe1, 0x04, + 0xbb, 0x8a, 0xd4, 0xcc, 0x1d, 0x57, 0x3b, 0xbf, 0x7a, 0xfa, 0x2b, 0xa7, 0x5b, 0x5b, 0x63, 0x87, + 0x87, 0xbe, 0x81, 0x72, 0xb2, 0xb1, 0x68, 0xa8, 0x15, 0x68, 0x16, 0x8e, 0xab, 0x9d, 0xe6, 0xd3, + 0x5b, 0x18, 0x9b, 0xab, 0xc8, 0xc5, 0x46, 0x29, 0x61, 0xff, 0xd1, 0x05, 0xd4, 0x92, 0x8d, 0x15, + 0x07, 0xb6, 0x83, 0x97, 0xd4, 0xef, 0x2a, 0xe3, 0xbf, 0xfc, 0x31, 0xfe, 0x38, 0x33, 0x36, 0xaa, + 0xc9, 0x9d, 0x80, 0x5e, 0x41, 0x21, 0x5d, 0xcd, 0x14, 0x97, 0x7d, 0xc3, 0xf3, 0x87, 0x1b, 0x4c, + 0x56, 0xb3, 0xed, 0x1e, 0x17, 0x7b, 0x06, 0x35, 0x45, 0xa7, 0xb0, 0xbf, 0xc4, 0x4b, 0x7f, 0xae, + 0x60, 0xc6, 0x79, 0xf6, 0x90, 0x73, 0x45, 0x95, 0x43, 0x3f, 0xbc, 0xbe, 0xd8, 0x33, 0xb8, 0x25, + 0xfa, 0x3d, 0x54, 0xec, 0x79, 0x6c, 0x3b, 0xd7, 0x98, 0x28, 0xf3, 0xc7, 0x4f, 0x52, 0x85, 0x5e, + 0x10, 0xb7, 0xf6, 0xe8, 0xb7, 0x50, 0x20, 0x76, 0xac, 0x78, 0x8c, 0xf6, 0xf3, 0x87, 0x34, 0xd3, + 0x8e, 0x05, 0x83, 0x5a, 0x51, 0xdf, 0xd6, 0x9b, 0xc0, 0x0e, 0x95, 0xc5, 0xe3, 0xbe, 0xbd, 0xa1, + 0xca, 0xcc, 0x37, 0x66, 0x49, 0x29, 0x2c, 0xb9, 0x15, 0xff, 0x71, 0xca, 0x60, 0x3c, 0xc1, 0x4e, + 0x46, 0x61, 0x96, 0xe8, 0x6b, 0xa8, 0xac, 0x97, 0x1b, 0x2b, 0xc4, 0xe4, 0x4c, 0xf9, 0x0b, 0x63, + 0x7d, 0xfa, 0xc1, 0x41, 0xcb, 0x8d, 0x8e, 0xc9, 0x99, 0xe0, 0x95, 0xd7, 0x5c, 0x44, 0x6d, 0x28, + 0xce, 0xa2, 0xd0, 0x55, 0xae, 0x19, 0x4b, 0x79, 0xc8, 0xea, 0x46, 0xa1, 0x2b, 0x28, 0xcc, 0xee, + 0xe8, 0x6b, 0x80, 0xbb, 0xe4, 0x41, 0xbf, 0x81, 0xc3, 0xad, 0xb1, 0x75, 0xe3, 0x93, 0x85, 0xe5, + 0xc7, 0xa2, 0xee, 0x0e, 0xb6, 0x8a, 0xb7, 0x3e, 0x59, 0x0c, 0xe2, 0xa3, 0x1f, 0x72, 0x50, 0xe2, + 0x49, 0x83, 0x3e, 0x82, 0xfd, 0xf7, 0x2b, 0xbc, 0xe2, 0x25, 0x5a, 0x37, 0xb8, 0x80, 0xbe, 0x81, + 0x22, 0x4b, 0x3d, 0x5e, 0xa3, 0x2f, 0x7f, 0x2a, 0xf5, 0x44, 0xa9, 0x52, 0x0a, 0xad, 0x36, 0x17, + 0xcf, 0xed, 0x55, 0x40, 0x78, 0xf6, 0xf2, 0x7a, 0xad, 0x0a, 0x8c, 0x5a, 0xb7, 0x5e, 0x43, 0x91, + 0x12, 0x50, 0x15, 0xca, 0x53, 0xfd, 0x52, 0x1f, 0xbd, 0xd5, 0xe5, 0x3d, 0x2a, 0x8c, 0x47, 0xc3, + 0xe1, 0x40, 0xff, 0x56, 0xce, 0xa1, 0x3a, 0x48, 0x03, 0xdd, 0xd4, 0x0c, 0x63, 0x3a, 0x36, 0xe5, + 0x3c, 0xaa, 0x41, 0x45, 0xed, 0xab, 0x63, 0x73, 0xf0, 0x46, 0x93, 0x0b, 0xd4, 0xb2, 0xaf, 0x9d, + 0xab, 0xd3, 0xa1, 0x29, 0x17, 0x8f, 0xfe, 0x0c, 0xd5, 0x9d, 0xf4, 0x7d, 0xe2, 0x73, 0x3e, 0x81, + 0xd2, 0x4d, 0x94, 0x5c, 0xe3, 0x84, 0x7d, 0x50, 0xdd, 0x10, 0x12, 0xfa, 0x1c, 0xaa, 0x4b, 0xdb, + 0x0f, 0x2d, 0xb2, 0x48, 0xb0, 0x9d, 0xb5, 0x16, 0xa0, 0x90, 0xc9, 0x90, 0xd6, 0x3f, 0x72, 0xc2, + 0x55, 0x04, 0x8d, 0xa9, 0xde, 0xd7, 0xce, 0x07, 0xba, 0xd6, 0xb7, 0xcc, 0xef, 0xc6, 0x9a, 0xbc, + 0x87, 0x0e, 0xa1, 0x3e, 0x99, 0x76, 0x2d, 0xe6, 0xe8, 0xb9, 0xda, 0xd3, 0xe4, 0x1c, 0xfa, 0x18, + 0x0e, 0x27, 0xa3, 0x73, 0xf3, 0xad, 0x6a, 0x68, 0xd6, 0x70, 0x34, 0x1a, 0x77, 0xd5, 0xde, 0xa5, + 0x9c, 0x47, 0x15, 0x28, 0xf6, 0xc7, 0xfd, 0x4b, 0xb9, 0x80, 0x24, 0xd8, 0xbf, 0xd2, 0xae, 0x06, + 0xe7, 0x72, 0x11, 0x95, 0xa1, 0x60, 0xaa, 0x63, 0x79, 0x9f, 0x7e, 0xac, 0x7a, 0x6e, 0x8d, 0xd5, + 0xde, 0xa5, 0x66, 0xca, 0x25, 0x24, 0x43, 0xed, 0xcd, 0xbb, 0xa1, 0xaa, 0x5b, 0xe6, 0x54, 0xd7, + 0xb5, 0xa1, 0x5c, 0xa6, 0xc8, 0x60, 0x3c, 0xd1, 0x7a, 0x19, 0x52, 0xa1, 0xe7, 0xbc, 0xb9, 0x7a, + 0xa7, 0x6b, 0xe6, 0xd9, 0xce, 0xf1, 0x12, 0xf5, 0xb2, 0x3b, 0xd2, 0xfb, 0x3b, 0x18, 0x74, 0x4b, + 0x50, 0x0c, 0xfc, 0xf0, 0xba, 0xf5, 0xbf, 0x3c, 0xd4, 0x76, 0x2b, 0x96, 0x7e, 0x7c, 0x6c, 0x27, + 0x38, 0x24, 0xd6, 0x4e, 0x8b, 0x06, 0x0e, 0xe9, 0xb4, 0x51, 0x7f, 0x0c, 0xa5, 0x74, 0x35, 0xb3, + 0x7c, 0x57, 0x44, 0x6d, 0x3f, 0x5d, 0xcd, 0x06, 0x2e, 0x32, 0xa0, 0x4e, 0x6c, 0xcf, 0x4a, 0x6e, + 0xac, 0x28, 0x26, 0x7e, 0x14, 0xb2, 0xb0, 0x35, 0x3a, 0xed, 0x1f, 0x6b, 0x0f, 0x6d, 0xd3, 0xf6, + 0x0c, 0x7c, 0x93, 0xf8, 0x04, 0x8f, 0x18, 0x29, 0x35, 0xaa, 0xc4, 0xf6, 0x8c, 0x1b, 0x2e, 0xa1, + 0x17, 0x00, 0xf1, 0x2a, 0x5d, 0x58, 0x6e, 0x44, 0x4e, 0xdf, 0xb3, 0x1e, 0x5e, 0x31, 0x24, 0x8a, + 0xf4, 0x29, 0x40, 0x9f, 0x11, 0x62, 0x7b, 0xa7, 0xca, 0x3e, 0xf3, 0x83, 0xad, 0x05, 0xd6, 0x11, + 0x3d, 0x9b, 0xad, 0x5b, 0x7f, 0xcb, 0xc1, 0xe1, 0x07, 0x27, 0xd1, 0xec, 0xe9, 0x0f, 0x26, 0x6a, + 0x77, 0xa8, 0xf5, 0xe5, 0x3d, 0x7a, 0x03, 0xe3, 0xe9, 0xe4, 0xe2, 0x54, 0xce, 0x65, 0xcb, 0x0e, + 0xbf, 0xa1, 0xf1, 0x68, 0x7c, 0x2a, 0x17, 0xc4, 0xaa, 0x23, 0x17, 0xd1, 0x01, 0x54, 0x4d, 0x43, + 0xd5, 0x27, 0x43, 0xd5, 0xd4, 0x4e, 0x4f, 0xe5, 0xfd, 0xfb, 0x40, 0x47, 0x2e, 0xdd, 0x03, 0x3a, + 0xa7, 0x72, 0xf9, 0x3e, 0xd0, 0x91, 0x2b, 0xad, 0x7f, 0xe7, 0x41, 0xda, 0xf6, 0x3c, 0xf4, 0x3b, + 0x51, 0x56, 0x39, 0x16, 0xb1, 0x5f, 0x3e, 0xd9, 0x1c, 0xf9, 0x8a, 0x35, 0x75, 0x5e, 0x54, 0x9f, + 0x40, 0x69, 0x69, 0xa7, 0x44, 0x24, 0x70, 0xc5, 0x10, 0x12, 0x6a, 0x40, 0xde, 0xe7, 0x79, 0x5b, + 0x37, 0xf2, 0xbe, 0x8b, 0xbe, 0x80, 0x83, 0x34, 0xa2, 0x9d, 0xd1, 0x9a, 0xfb, 0x01, 0x66, 0xf7, + 0xca, 0x1f, 0xc4, 0x06, 0x87, 0xcf, 0x05, 0x4a, 0x37, 0x4c, 0xb1, 0x93, 0x60, 0xc2, 0x62, 0x2a, + 0x19, 0x42, 0x42, 0x9f, 0x82, 0x94, 0xf8, 0xa1, 0x67, 0xa5, 0xfe, 0xf7, 0x58, 0x84, 0xb6, 0x42, + 0x81, 0x89, 0xff, 0x3d, 0xcb, 0x98, 0xd9, 0x6a, 0x3e, 0xc7, 0x09, 0x57, 0x97, 0x99, 0x1a, 0x38, + 0xc4, 0x0c, 0x28, 0x7b, 0x63, 0xb1, 0x9a, 0x4b, 0xc5, 0x93, 0x58, 0x49, 0x36, 0x7f, 0x64, 0x32, + 0x55, 0x92, 0xad, 0x52, 0xe2, 0x4a, 0x22, 0x94, 0xad, 0x8e, 0x08, 0x13, 0xeb, 0x49, 0x35, 0xa8, + 0x68, 0xe6, 0x85, 0x66, 0xe8, 0x9a, 0x29, 0xef, 0xa1, 0x12, 0xe4, 0x07, 0x63, 0x39, 0x47, 0x63, + 0x3b, 0x9e, 0xea, 0xa6, 0x35, 0xd0, 0x5f, 0x6b, 0x3d, 0x53, 0xce, 0xb7, 0xfe, 0x0a, 0xd2, 0xb6, + 0x65, 0x53, 0xdf, 0xd2, 0xc4, 0xd9, 0x8e, 0x01, 0x22, 0x9b, 0xd3, 0xc4, 0xc9, 0xa6, 0x80, 0xcf, + 0xa1, 0xea, 0xa6, 0x64, 0x6b, 0x90, 0xe7, 0x06, 0x6e, 0x4a, 0x32, 0x03, 0x3a, 0x03, 0x84, 0xbe, + 0x08, 0x26, 0x5d, 0xa2, 0xe7, 0x20, 0x2d, 0x57, 0x01, 0xf1, 0x1d, 0x3b, 0x25, 0x22, 0x8e, 0x77, + 0x40, 0xeb, 0x15, 0xd4, 0x76, 0xdf, 0x25, 0xd4, 0x84, 0xda, 0x22, 0x4a, 0x89, 0xe5, 0xcf, 0xef, + 0x15, 0x14, 0xc5, 0x06, 0x73, 0x5a, 0x50, 0xad, 0x7f, 0xe5, 0xa0, 0x2c, 0xde, 0x24, 0x3a, 0xd1, + 0xac, 0x71, 0x92, 0xd2, 0xfa, 0xe1, 0xad, 0x2a, 0x13, 0x3f, 0xd8, 0x27, 0xff, 0x70, 0x1f, 0x7a, + 0xcb, 0x24, 0xb2, 0x96, 0xbe, 0x93, 0x44, 0x29, 0x4e, 0xd6, 0xbe, 0xc3, 0xbb, 0xac, 0x64, 0x34, + 0x48, 0x74, 0xb5, 0x83, 0xd2, 0xad, 0x92, 0x8d, 0x75, 0x77, 0xa1, 0x45, 0x7e, 0x63, 0xc9, 0xc6, + 0xc8, 0xae, 0xb4, 0x09, 0x35, 0xb2, 0x6b, 0xc1, 0x2b, 0x0c, 0xc8, 0x9d, 0xc5, 0x0b, 0x00, 0x3e, + 0x6b, 0x59, 0x5e, 0x1a, 0xb1, 0x94, 0xa8, 0x18, 0x12, 0x47, 0xbe, 0x4d, 0xa3, 0xd6, 0x7f, 0x0b, + 0x20, 0x6d, 0x5f, 0x41, 0x1a, 0x43, 0x9c, 0x86, 0x22, 0x49, 0xe9, 0x92, 0x86, 0xdd, 0x0e, 0x89, + 0x6f, 0x25, 0x38, 0x0e, 0xec, 0xdb, 0xac, 0xc5, 0x52, 0xc8, 0x60, 0x08, 0x7a, 0x06, 0x95, 0x20, + 0x72, 0xec, 0x80, 0x3e, 0x57, 0x3c, 0xc6, 0x65, 0x26, 0x0f, 0x62, 0x96, 0x4e, 0x78, 0x19, 0x11, + 0x4c, 0x75, 0x3c, 0x4f, 0x2b, 0x1c, 0xe0, 0x4a, 0xce, 0x4b, 0x63, 0x3f, 0xcb, 0x54, 0x06, 0x4c, + 0x62, 0x9f, 0x3a, 0x2d, 0x98, 0x54, 0xcb, 0x13, 0x55, 0xec, 0x45, 0xd5, 0x67, 0x00, 0x4e, 0x72, + 0x1b, 0x93, 0xc8, 0xb2, 0x03, 0x8f, 0x25, 0x6a, 0xa3, 0xf3, 0x11, 0xaf, 0x46, 0x36, 0xca, 0xf6, + 0x98, 0x52, 0x0d, 0x3c, 0x43, 0x72, 0xb2, 0x25, 0x3a, 0x06, 0x99, 0x1f, 0x28, 0xa8, 0xd7, 0xf8, + 0x96, 0xa5, 0xb1, 0x64, 0x34, 0x18, 0xce, 0x49, 0x97, 0xf8, 0x96, 0x3e, 0xc5, 0xe2, 0xf4, 0x1d, + 0x53, 0xe0, 0x4f, 0x31, 0x57, 0xdc, 0xd9, 0xbe, 0x02, 0x89, 0x76, 0x00, 0x8f, 0x79, 0x52, 0x65, + 0x9e, 0xfc, 0x6c, 0xc7, 0x13, 0xda, 0x41, 0x3d, 0xea, 0x48, 0xc5, 0x17, 0x2b, 0x3a, 0x99, 0x8a, + 0x80, 0x31, 0x1e, 0xdd, 0xbb, 0xc6, 0xf6, 0xae, 0xf3, 0xb8, 0x51, 0x94, 0xee, 0x7c, 0x0c, 0x72, + 0x16, 0xbd, 0xad, 0x61, 0x9d, 0xfb, 0x2b, 0x82, 0xb8, 0x63, 0x29, 0xae, 0x78, 0xe5, 0xc6, 0x16, + 0x0e, 0x1d, 0x3b, 0x56, 0x1a, 0xec, 0xa2, 0x1a, 0x1c, 0x9f, 0xba, 0xb1, 0x46, 0xd1, 0x96, 0x0b, + 0xd5, 0x9d, 0xe1, 0x85, 0x5e, 0xae, 0x20, 0xe2, 0x20, 0xf2, 0xc4, 0xb5, 0x8b, 0x74, 0xd1, 0x82, + 0xc8, 0xa3, 0x97, 0x9b, 0x6c, 0xde, 0xf3, 0xd4, 0xe2, 0x85, 0x55, 0x4e, 0x36, 0xef, 0x59, 0x5e, + 0x3d, 0x83, 0x0a, 0xc9, 0x54, 0x3c, 0x2f, 0xcb, 0x84, 0xab, 0x5a, 0xff, 0x2c, 0x40, 0x25, 0x9b, + 0x76, 0x44, 0x8b, 0xcb, 0x6d, 0x5b, 0xdc, 0xa9, 0xe8, 0xa1, 0xfc, 0xd5, 0x79, 0xf1, 0xd4, 0x94, + 0xd4, 0xde, 0xe9, 0x9e, 0x5f, 0x41, 0x3e, 0x98, 0xb1, 0x43, 0x1a, 0x1f, 0x4e, 0xe2, 0x5b, 0xc2, + 0x30, 0xb2, 0xdd, 0xae, 0x1d, 0xd8, 0xa1, 0x83, 0x8d, 0x7c, 0x30, 0x43, 0x53, 0x38, 0xa4, 0x63, + 0x16, 0x76, 0xad, 0x3b, 0x6b, 0xa5, 0xc6, 0x66, 0xe9, 0xe3, 0x27, 0x37, 0xe9, 0x32, 0xc6, 0xf6, + 0xdd, 0x33, 0xe4, 0xd9, 0x7d, 0x20, 0x3d, 0x0a, 0xe0, 0xe0, 0x81, 0xd1, 0xa3, 0xbf, 0x92, 0x5e, + 0x00, 0xf8, 0xa9, 0x15, 0xdb, 0x69, 0xea, 0xaf, 0xb1, 0x88, 0xac, 0xe4, 0xa7, 0x63, 0x0e, 0xd0, + 0x24, 0xf0, 0x53, 0x2b, 0x88, 0x42, 0xcf, 0x22, 0xfe, 0x12, 0x47, 0x2b, 0x22, 0x4a, 0xab, 0xee, + 0xa7, 0xc3, 0x28, 0xf4, 0x4c, 0x0e, 0xb6, 0xbe, 0x83, 0x22, 0x6b, 0xa9, 0xf7, 0x46, 0xad, 0x03, + 0xa8, 0x1a, 0xa3, 0xa9, 0xde, 0xb7, 0x8c, 0x51, 0x77, 0xa0, 0xcb, 0x39, 0x3a, 0xc9, 0xa8, 0x3d, + 0x3a, 0x5d, 0x59, 0x74, 0x60, 0x99, 0x8e, 0xe5, 0x3c, 0x9d, 0x4e, 0xde, 0x8d, 0x0c, 0xb9, 0x40, + 0xa7, 0x93, 0xae, 0x31, 0x52, 0xfb, 0x3d, 0x75, 0x62, 0xca, 0x45, 0xfa, 0x3c, 0x0e, 0xd5, 0xde, + 0x58, 0xde, 0x6f, 0x7d, 0x01, 0xd5, 0x9d, 0x90, 0xd1, 0x36, 0x3d, 0xec, 0xc8, 0x7b, 0x94, 0x38, + 0x3c, 0xfb, 0x4a, 0xce, 0xb1, 0x45, 0xe7, 0x4c, 0xce, 0x77, 0x5f, 0xff, 0xf0, 0x9f, 0xcf, 0x72, + 0x7f, 0xea, 0xef, 0xfc, 0xca, 0x0c, 0x7c, 0xcf, 0x26, 0x11, 0xfd, 0x05, 0xf9, 0xa5, 0xed, 0xe1, + 0x90, 0x9c, 0xd8, 0xb1, 0x7f, 0xf2, 0xe8, 0x8f, 0xd7, 0x3f, 0xac, 0xe3, 0x78, 0x27, 0xfe, 0xb3, + 0x12, 0xfb, 0x95, 0x79, 0xf6, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7e, 0xc9, 0xc7, 0xfb, 0xeb, + 0x0e, 0x00, 0x00, } diff --git a/api/models/vpp/interfaces/interface.proto b/api/models/vpp/interfaces/interface.proto index 3f3d239a0a..7fe566525b 100644 --- a/api/models/vpp/interfaces/interface.proto +++ b/api/models/vpp/interfaces/interface.proto @@ -49,12 +49,21 @@ message Interface { ADAPTIVE = 3; DEFAULT = 4; }; - Type default_rx_mode = 1; // used for queues not listed in queue_rx_mode - map queue_rx_mode = 2; // queue ID -> Rx mode + uint32 queue = 1; + Type mode = 2; + bool default_mode = 3; // if enabled, will be ignored and the given + // will be used for all queues without explicitly + // selected Rx mode } - RxMode rx_mode = 10; + repeated RxMode rx_mode = 10; - map rx_placement = 11; // queue ID -> worker ID (main thread has always ID=0) + message RxPlacement { + uint32 queue = 1; // select from interval <0, number-of-queues) + uint32 worker = 2; // select from interval <0, number-of-workers) + bool main_thread = 3; // let the main thread to process the given queue + // - if enabled, value of is ignored + } + repeated RxPlacement rx_placement = 11; oneof link { SubInterface sub = 100; /* sub-interface configuration */ diff --git a/plugins/vpp/ifplugin/descriptor/interface.go b/plugins/vpp/ifplugin/descriptor/interface.go index 744eb983e0..ca5c9e0edd 100644 --- a/plugins/vpp/ifplugin/descriptor/interface.go +++ b/plugins/vpp/ifplugin/descriptor/interface.go @@ -102,6 +102,15 @@ var ( // RX mode. ErrUnsupportedRxMode = errors.New("unsupported RX Mode") + // ErrUndefinedRxMode is returned when the Rx mode is not defined. + ErrUndefinedRxMode = errors.New("undefined RX Mode") + + // ErrUnsupportedRxMode is returned when Rx mode has multiple definitions for the same queue. + ErrRedefinedRxMode = errors.New("redefined RX Mode") + + // ErrRedefinedRxPlacement is returned when Rx placement has multiple definitions for the same queue. + ErrRedefinedRxPlacement = errors.New("redefined RX Placement") + // ErrSubInterfaceWithoutParent is returned when interface of type sub-interface is defined without parent. ErrSubInterfaceWithoutParent = errors.Errorf("subinterface with no parent interface defined") @@ -258,33 +267,38 @@ func (d *InterfaceDescriptor) EquivalentInterfaces(key string, oldIntf, newIntf // equivalentRxMode compares Rx modes for equivalency. func (d *InterfaceDescriptor) equivalentRxMode(oldIntf, newIntf *interfaces.Interface) bool { - oldMode := oldIntf.GetRxMode() - newMode := newIntf.GetRxMode() - if newMode == nil { + if len(newIntf.GetRxMode()) == 0 { // undefined return true } /* Note: default Rx mode cannot be dumped - compare only if these are two NB - configurations (not a refreshed value). + configurations (not a refreshed, i.e. dumped, value). */ - if oldMode.GetDefaultRxMode() != interfaces.Interface_RxMode_UNKNOWN && - newMode.GetDefaultRxMode() != interfaces.Interface_RxMode_UNKNOWN { - defOldMode := normalizeRxMode(oldMode.GetDefaultRxMode(), oldIntf) - defNewMode := normalizeRxMode(newMode.GetDefaultRxMode(), newIntf) - if defOldMode != defNewMode { + oldDefMode := getDefaultRxMode(oldIntf) + newDefMode := getDefaultRxMode(newIntf) + if oldDefMode != interfaces.Interface_RxMode_UNKNOWN && + newDefMode != interfaces.Interface_RxMode_UNKNOWN { + if oldDefMode != newDefMode { return false } } - for queue, oldMode := range oldMode.QueueRxMode { - oldMode = normalizeRxMode(oldMode, oldIntf) - newMode := normalizeRxMode(getQueueRxMode(queue, newMode), newIntf) + // compare queue-specific RX modes + for _, rxMode := range oldIntf.GetRxMode() { + if rxMode.DefaultMode { + continue + } + oldMode := normalizeRxMode(rxMode.Mode, oldIntf) + newMode := getQueueRxMode(rxMode.Queue, newIntf) if oldMode != newMode { return false } } - for queue, newMode := range newMode.QueueRxMode { - newMode = normalizeRxMode(newMode, newIntf) - oldMode := normalizeRxMode(getQueueRxMode(queue, oldMode), oldIntf) + for _, rxMode := range newIntf.GetRxMode() { + if rxMode.DefaultMode { + continue + } + newMode := normalizeRxMode(rxMode.Mode, newIntf) + oldMode := getQueueRxMode(rxMode.Queue, oldIntf) if oldMode != newMode { return false } @@ -293,9 +307,8 @@ func (d *InterfaceDescriptor) equivalentRxMode(oldIntf, newIntf *interfaces.Inte } // equivalentRxMode compares Rx placements for equivalency. -func (d *InterfaceDescriptor) equivalentRxPlacement(oldPlacement, newPlacement map[uint32]uint32) bool { - - if newPlacement == nil { +func (d *InterfaceDescriptor) equivalentRxPlacement(oldPlacement, newPlacement []*interfaces.Interface_RxPlacement) bool { + if len(newPlacement) == 0{ // undefined return true } @@ -304,8 +317,19 @@ func (d *InterfaceDescriptor) equivalentRxPlacement(oldPlacement, newPlacement m return false } - for q, oldW := range oldPlacement { - if newW, ok := newPlacement[q]; !ok || oldW != newW { + for _, old := range oldPlacement { + found := false + for _, new := range newPlacement { + if old.Queue == new.Queue { + found = true + if (old.MainThread != new.MainThread) || + (!old.MainThread && old.Worker != new.Worker) { + return false + } + break + } + } + if !found { return false } } @@ -487,18 +511,15 @@ func (d *InterfaceDescriptor) Validate(key string, intf *interfaces.Interface) e if _, ok := d.ethernetIfs[intf.Name]; !ok { return kvs.NewInvalidValueError(ErrDPDKInterfaceMissing, "name") } - if intf.GetRxMode() != nil { - defRxMode := normalizeRxMode(intf.GetRxMode().GetDefaultRxMode(), intf) - if defRxMode != interfaces.Interface_RxMode_POLLING { - return kvs.NewInvalidValueError(ErrUnsupportedRxMode, - "rx_mode_settings.rx_mode.default_rx_mode") - } - for queue, rxMode := range intf.GetRxMode().GetQueueRxMode() { - rxMode = normalizeRxMode(rxMode, intf) - if rxMode != interfaces.Interface_RxMode_POLLING { + for _, rxMode := range intf.GetRxMode() { + mode := normalizeRxMode(rxMode.Mode, intf) + if mode != interfaces.Interface_RxMode_POLLING { + if rxMode.DefaultMode { return kvs.NewInvalidValueError(ErrUnsupportedRxMode, - fmt.Sprintf("rx_mode_settings.rx_mode.queue_rx_mode[%d]", queue)) + "rx_mode[default]") } + return kvs.NewInvalidValueError(ErrUnsupportedRxMode, + fmt.Sprintf("rx_mode[.queue=%d]", rxMode.Queue)) } } case interfaces.Interface_AF_PACKET: @@ -519,11 +540,36 @@ func (d *InterfaceDescriptor) Validate(key string, intf *interfaces.Interface) e } // validate Rx Mode - if intf.GetRxMode() != nil { - for queue, rxMode := range intf.GetRxMode().GetQueueRxMode() { - if rxMode == interfaces.Interface_RxMode_UNKNOWN { - return kvs.NewInvalidValueError(ErrUnsupportedRxMode, - fmt.Sprintf("rx_mode_settings.rx_mode.queue_rx_mode[%d]", queue)) + for i, rxMode1 := range intf.GetRxMode() { + if rxMode1.Mode == interfaces.Interface_RxMode_UNKNOWN { + if rxMode1.DefaultMode { + return kvs.NewInvalidValueError(ErrUndefinedRxMode,"rx_mode[default]") + } + return kvs.NewInvalidValueError(ErrUndefinedRxMode, + fmt.Sprintf("rx_mode[.queue=%d]", rxMode1.Queue)) + } + for j := i + 1; j < len(intf.GetRxMode()); j++ { + rxMode2 := intf.GetRxMode()[j] + if rxMode1.DefaultMode != rxMode2.DefaultMode { + continue + } + if rxMode1.DefaultMode { + return kvs.NewInvalidValueError(ErrRedefinedRxMode,"rx_mode[default]") + } + if rxMode1.Queue == rxMode2.Queue { + return kvs.NewInvalidValueError(ErrRedefinedRxMode, + fmt.Sprintf("rx_mode[.queue=%d]", rxMode1.Queue)) + } + } + } + + // validate Rx Placement + for i, rxPlacement1 := range intf.GetRxPlacement() { + for j := i + 1; j < len(intf.GetRxPlacement()); j++ { + rxPlacement2 := intf.GetRxPlacement()[j] + if rxPlacement1.Queue == rxPlacement2.Queue { + return kvs.NewInvalidValueError(ErrRedefinedRxPlacement, + fmt.Sprintf("rx_placement[.queue=%d]", rxPlacement1.Queue)) } } } @@ -755,17 +801,34 @@ func (d *InterfaceDescriptor) getMemifRingSize(memif *interfaces.MemifLink) uint return memif.GetRingSize() } -// getQueueRxMode reads queue RX mode from the configuration. -func getQueueRxMode(queue uint32, mode *interfaces.Interface_RxMode) interfaces.Interface_RxMode_Type { - if mode, hasQueueSpecific := mode.QueueRxMode[queue]; hasQueueSpecific { - return mode +// getQueueRxMode reads RX mode for the given queue from the interface configuration. +func getQueueRxMode(queue uint32, iface *interfaces.Interface) (mode interfaces.Interface_RxMode_Type) { + for _, rxMode := range iface.GetRxMode() { + if rxMode.DefaultMode { + mode = rxMode.Mode + continue // keep looking for a queue-specific RX mode + } + if rxMode.Queue == queue { + mode = rxMode.Mode + break + } + } + return normalizeRxMode(mode, iface) +} + +// getDefaultRxMode reads default RX mode from the interface configuration. +func getDefaultRxMode(iface *interfaces.Interface) (rxMode interfaces.Interface_RxMode_Type) { + for _, rxMode := range iface.GetRxMode() { + if rxMode.DefaultMode { + return normalizeRxMode(rxMode.Mode, iface) + } } - return mode.GetDefaultRxMode() + return interfaces.Interface_RxMode_UNKNOWN } -// normalizeRxMode resolves default Rx mode for specific interfaces. +// normalizeRxMode resolves default/undefined Rx mode for specific interfaces. func normalizeRxMode(mode interfaces.Interface_RxMode_Type, iface *interfaces.Interface) interfaces.Interface_RxMode_Type { - if mode != interfaces.Interface_RxMode_DEFAULT && mode != interfaces.Interface_RxMode_UNKNOWN { + if mode != interfaces.Interface_RxMode_DEFAULT { return mode } switch iface.GetType() { @@ -779,7 +842,7 @@ func normalizeRxMode(mode interfaces.Interface_RxMode_Type, iface *interfaces.In return interfaces.Interface_RxMode_INTERRUPT } } - return interfaces.Interface_RxMode_DEFAULT + return mode } // getTapConfig returns the TAP-specific configuration section (handling undefined attributes). diff --git a/plugins/vpp/ifplugin/descriptor/interface_crud.go b/plugins/vpp/ifplugin/descriptor/interface_crud.go index 96a5b705cb..007a6aa296 100644 --- a/plugins/vpp/ifplugin/descriptor/interface_crud.go +++ b/plugins/vpp/ifplugin/descriptor/interface_crud.go @@ -142,16 +142,16 @@ func (d *InterfaceDescriptor) Create(key string, intf *interfaces.Interface) (me d.bondIDs[intf.GetBond().GetId()] = intf.GetName() } - err = d.configureRxMode(intf, ifIdx, nil) + err = d.configureRxMode(intf, ifIdx, false) if err != nil { return nil, err } // rx-placement - for queue, worker := range intf.GetRxPlacement() { - if err = d.ifHandler.SetRxPlacement(ifIdx, queue, worker); err != nil { + for _, rxPlacement := range intf.GetRxPlacement() { + if err = d.ifHandler.SetRxPlacement(ifIdx, rxPlacement); err != nil { err = errors.Errorf("failed to set rx-placement for queue %d of the interface %s: %v", - queue, intf.Name, err) + rxPlacement.Queue, intf.Name, err) d.log.Error(err) return nil, err } @@ -216,26 +216,32 @@ func (d *InterfaceDescriptor) Create(key string, intf *interfaces.Interface) (me // configureRxMode (re-)configures Rx mode for the interface. func (d *InterfaceDescriptor) configureRxMode(iface *interfaces.Interface, ifIdx uint32, - oldMode *interfaces.Interface_RxMode) (err error) { + reconfigure bool) (err error) { - newMode := iface.GetRxMode() - if newMode == nil { - if oldMode != nil { - // revert back to default for all queues - err = d.ifHandler.SetRxMode(ifIdx, 0, interfaces.Interface_RxMode_DEFAULT, true) - if err != nil { - err = errors.Errorf("failed to set default Rx-mode for interface %s: %v", iface, err) - d.log.Error(err) - return err - } + // first, revert back to default for all queues + if reconfigure { + err = d.ifHandler.SetRxMode(ifIdx, &interfaces.Interface_RxMode{ + DefaultMode: true, + Mode: normalizeRxMode(interfaces.Interface_RxMode_DEFAULT, iface), + }) + if err != nil { + err = errors.Errorf("failed to set default Rx-mode for interface %s: %v", iface, err) + d.log.Error(err) + return err } + } + + if len(iface.GetRxMode()) == 0 { return } - if oldMode != nil || newMode.GetDefaultRxMode() != interfaces.Interface_RxMode_UNKNOWN { - // overwrite previous default Rx mode - defRxMode := normalizeRxMode(newMode.GetDefaultRxMode(), iface) - err = d.ifHandler.SetRxMode(ifIdx, 0, defRxMode, true) + // configure the default Rx mode + defRxMode := getDefaultRxMode(iface) + if defRxMode != interfaces.Interface_RxMode_UNKNOWN { + err = d.ifHandler.SetRxMode(ifIdx, &interfaces.Interface_RxMode{ + DefaultMode: true, + Mode: defRxMode, + }) if err != nil { err = errors.Errorf("failed to set default Rx-mode for interface %s: %v", iface.Name, err) d.log.Error(err) @@ -243,11 +249,15 @@ func (d *InterfaceDescriptor) configureRxMode(iface *interfaces.Interface, ifIdx } } - for queue, rxMode := range newMode.GetQueueRxMode() { - err = d.ifHandler.SetRxMode(ifIdx, queue, rxMode, false) + // configure per-queue RX mode + for _, rxMode := range iface.GetRxMode() { + if rxMode.DefaultMode { + continue + } + err = d.ifHandler.SetRxMode(ifIdx, rxMode) if err != nil { err = errors.Errorf("failed to set Rx-mode for queue %d of the interface %s: %v", - queue, iface.Name, err) + rxMode.Queue, iface.Name, err) d.log.Error(err) return err } @@ -310,7 +320,7 @@ func (d *InterfaceDescriptor) Update(key string, oldIntf, newIntf *interfaces.In // rx-mode if !d.equivalentRxMode(oldIntf, newIntf) { - err = d.configureRxMode(newIntf, ifIdx, oldIntf.GetRxMode()) + err = d.configureRxMode(newIntf, ifIdx, len(oldIntf.GetRxMode()) != 0) if err != nil { return oldMetadata, err } @@ -318,10 +328,10 @@ func (d *InterfaceDescriptor) Update(key string, oldIntf, newIntf *interfaces.In // rx-placement if !d.equivalentRxPlacement(oldIntf.GetRxPlacement(), newIntf.GetRxPlacement()) { - for queue, worker := range newIntf.GetRxPlacement() { - if err = d.ifHandler.SetRxPlacement(ifIdx, queue, worker); err != nil { + for _, rxPlacement := range newIntf.GetRxPlacement() { + if err = d.ifHandler.SetRxPlacement(ifIdx, rxPlacement); err != nil { err = errors.Errorf("failed to set rx-placement for queue %d of the interface %s: %v", - queue, newIntf.Name, err) + rxPlacement.Queue, newIntf.Name, err) d.log.Error(err) return nil, err } diff --git a/plugins/vpp/ifplugin/vppcalls/if_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/if_vppcalls.go index d33c96799b..08ff520df8 100644 --- a/plugins/vpp/ifplugin/vppcalls/if_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/if_vppcalls.go @@ -154,9 +154,9 @@ type InterfaceVppAPI interface { // SetInterfaceMtu calls HwInterfaceSetMtu bin API with desired MTU value. SetInterfaceMtu(ifIdx uint32, mtu uint32) error // SetRxMode calls SwInterfaceSetRxMode bin API - SetRxMode(ifIdx uint32, queueID uint32, rxMode interfaces.Interface_RxMode_Type, isDefaultMode bool) error + SetRxMode(ifIdx uint32, rxMode *interfaces.Interface_RxMode) error // SetRxPlacement configures rx-placement for interface - SetRxPlacement(ifIdx uint32, queueID, workerID uint32) error + SetRxPlacement(ifIdx uint32, rxPlacement *interfaces.Interface_RxPlacement) error // SetInterfaceVrf sets VRF table for the interface SetInterfaceVrf(ifaceIndex, vrfID uint32) error // SetInterfaceVrfIPv6 sets IPV6 VRF table for the interface diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go index a7fe084b38..4d348cb6c7 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go @@ -750,24 +750,30 @@ func (h *InterfaceVppHandler) dumpRxPlacement(ifs map[uint32]*vppcalls.Interface break } - fmt.Printf("Received RX details: %+v", rxDetails) + fmt.Printf("Received RX details: %+v\n", rxDetails) ifData, ok := ifs[rxDetails.SwIfIndex] if !ok { h.log.Warnf("Received rx-placement data for unknown interface with index %d", rxDetails.SwIfIndex) continue } - if ifData.Interface.RxMode == nil { - ifData.Interface.RxMode = &interfaces.Interface_RxMode{} - } - if ifData.Interface.RxMode.QueueRxMode == nil { - ifData.Interface.RxMode.QueueRxMode = make(map[uint32]interfaces.Interface_RxMode_Type) - } - ifData.Interface.RxMode.QueueRxMode[rxDetails.QueueID] = getRxModeType(rxDetails.Mode) - if ifData.Interface.RxPlacement == nil { - ifData.Interface.RxPlacement = make(map[uint32]uint32) + + ifData.Interface.RxMode = append(ifData.Interface.RxMode, + &interfaces.Interface_RxMode{ + Queue: rxDetails.QueueID, + Mode: getRxModeType(rxDetails.Mode), + }) + + var worker uint32 + if rxDetails.WorkerID > 0 { + worker = rxDetails.WorkerID - 1 } - ifData.Interface.RxPlacement[rxDetails.QueueID] = rxDetails.WorkerID + ifData.Interface.RxPlacement = append(ifData.Interface.RxPlacement, + &interfaces.Interface_RxPlacement{ + Queue: rxDetails.QueueID, + Worker: worker, + MainThread: rxDetails.WorkerID == 0, + }) } return nil } diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_mode_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_mode_vppcalls.go index c81d4adfd3..4d1fe84cca 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_mode_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_mode_vppcalls.go @@ -20,13 +20,13 @@ import ( ) // SetRxMode implements interface handler. -func (h *InterfaceVppHandler) SetRxMode(ifIdx uint32, queueID uint32, rxMode interfaces.Interface_RxMode_Type, isDefaultMode bool) error { +func (h *InterfaceVppHandler) SetRxMode(ifIdx uint32,rxMode *interfaces.Interface_RxMode) error { req := &binapi_interface.SwInterfaceSetRxMode{ SwIfIndex: ifIdx, - Mode: uint8(rxMode), - QueueID: queueID, - QueueIDValid: boolToUint(!isDefaultMode), + Mode: uint8(rxMode.Mode), + QueueID: rxMode.Queue, + QueueIDValid: boolToUint(!rxMode.DefaultMode), } reply := &binapi_interface.SwInterfaceSetRxModeReply{} diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_placement_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_placement_vppcalls.go index f33f60a175..ef8ce09420 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_placement_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_placement_vppcalls.go @@ -16,15 +16,16 @@ package vpp1901 import ( binapi_interface "github.com/ligato/vpp-agent/plugins/vpp/binapi/vpp1901/interfaces" + interfaces "github.com/ligato/vpp-agent/api/models/vpp/interfaces" ) // SetRxPlacement implements interface handler. -func (h *InterfaceVppHandler) SetRxPlacement(ifIdx uint32, queueID, workerID uint32) error { +func (h *InterfaceVppHandler) SetRxPlacement(ifIdx uint32, rxPlacement *interfaces.Interface_RxPlacement) error { req := &binapi_interface.SwInterfaceSetRxPlacement{ SwIfIndex: ifIdx, - QueueID: queueID, - WorkerID: workerID, - IsMain: boolToUint(workerID == 0), + QueueID: rxPlacement.Queue, + WorkerID: rxPlacement.Worker, + IsMain: boolToUint(rxPlacement.MainThread), } reply := &binapi_interface.SwInterfaceSetRxPlacementReply{} diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls.go index 3de8337079..53eb4e7bad 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls.go @@ -771,17 +771,23 @@ func (h *InterfaceVppHandler) dumpRxPlacement(ifs map[uint32]*vppcalls.Interface h.log.Warnf("Received rx-placement data for unknown interface with index %d", rxDetails.SwIfIndex) continue } - if ifData.Interface.RxMode == nil { - ifData.Interface.RxMode = &interfaces.Interface_RxMode{} - } - if ifData.Interface.RxMode.QueueRxMode == nil { - ifData.Interface.RxMode.QueueRxMode = make(map[uint32]interfaces.Interface_RxMode_Type) - } - ifData.Interface.RxMode.QueueRxMode[rxDetails.QueueID] = getRxModeType(rxDetails.Mode) - if ifData.Interface.RxPlacement == nil { - ifData.Interface.RxPlacement = make(map[uint32]uint32) + + ifData.Interface.RxMode = append(ifData.Interface.RxMode, + &interfaces.Interface_RxMode{ + Queue: rxDetails.QueueID, + Mode: getRxModeType(rxDetails.Mode), + }) + + var worker uint32 + if rxDetails.WorkerID > 0 { + worker = rxDetails.WorkerID - 1 } - ifData.Interface.RxPlacement[rxDetails.QueueID] = rxDetails.WorkerID + ifData.Interface.RxPlacement = append(ifData.Interface.RxPlacement, + &interfaces.Interface_RxPlacement{ + Queue: rxDetails.QueueID, + Worker: worker, + MainThread: rxDetails.WorkerID == 0, + }) } return nil } diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_mode_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_mode_vppcalls.go index e2df8c1bde..24a89df425 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_mode_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_mode_vppcalls.go @@ -20,13 +20,13 @@ import ( ) // SetRxMode implements interface handler. -func (h *InterfaceVppHandler) SetRxMode(ifIdx uint32, queueID uint32, rxMode interfaces.Interface_RxMode_Type, isDefaultMode bool) error { +func (h *InterfaceVppHandler) SetRxMode(ifIdx uint32,rxMode *interfaces.Interface_RxMode) error { req := &binapi_interface.SwInterfaceSetRxMode{ SwIfIndex: ifIdx, - Mode: uint8(rxMode), - QueueID: queueID, - QueueIDValid: boolToUint(!isDefaultMode), + Mode: uint8(rxMode.Mode), + QueueID: rxMode.Queue, + QueueIDValid: boolToUint(!rxMode.DefaultMode), } reply := &binapi_interface.SwInterfaceSetRxModeReply{} diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_placement_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_placement_vppcalls.go index 22eb91d587..cc5779b70f 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_placement_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_placement_vppcalls.go @@ -16,15 +16,16 @@ package vpp1904 import ( binapi_interface "github.com/ligato/vpp-agent/plugins/vpp/binapi/vpp1904/interfaces" + interfaces "github.com/ligato/vpp-agent/api/models/vpp/interfaces" ) // SetRxPlacement implements interface handler. -func (h *InterfaceVppHandler) SetRxPlacement(ifIdx uint32, queueID, workerID uint32) error { +func (h *InterfaceVppHandler) SetRxPlacement(ifIdx uint32, rxPlacement *interfaces.Interface_RxPlacement) error { req := &binapi_interface.SwInterfaceSetRxPlacement{ SwIfIndex: ifIdx, - QueueID: queueID, - WorkerID: workerID, - IsMain: boolToUint(workerID == 0), + QueueID: rxPlacement.Queue, + WorkerID: rxPlacement.Worker, + IsMain: boolToUint(rxPlacement.MainThread), } reply := &binapi_interface.SwInterfaceSetRxPlacementReply{} From 319e6c16d97e8cf011e99bd3269ec806899e70ce Mon Sep 17 00:00:00 2001 From: Milan Lenco Date: Wed, 15 May 2019 14:36:20 +0200 Subject: [PATCH 05/13] Add dependency on link-state for rx placement and rx mode. Signed-off-by: Milan Lenco --- api/models/vpp/interfaces/keys.go | 159 +++++++++ api/models/vpp/interfaces/keys_test.go | 312 ++++++++++++++++++ .../ifplugin/descriptor/adapter/interface.go | 2 +- .../descriptor/adapter/rxplacement.go | 233 +++++++++++++ plugins/vpp/ifplugin/descriptor/interface.go | 200 ++--------- .../vpp/ifplugin/descriptor/interface_crud.go | 88 +---- plugins/vpp/ifplugin/descriptor/link_state.go | 102 ++++++ plugins/vpp/ifplugin/descriptor/rx_mode.go | 306 +++++++++++++++++ .../vpp/ifplugin/descriptor/rx_placement.go | 119 +++++++ plugins/vpp/ifplugin/ifaceidx/ifaceidx.go | 1 + plugins/vpp/ifplugin/ifplugin.go | 87 ++--- plugins/vpp/ifplugin/interface_state.go | 8 +- plugins/vpp/ifplugin/publish_state.go | 15 +- .../vpp1901/dump_interface_vppcalls.go | 2 - 14 files changed, 1322 insertions(+), 312 deletions(-) create mode 100644 plugins/vpp/ifplugin/descriptor/adapter/rxplacement.go create mode 100644 plugins/vpp/ifplugin/descriptor/link_state.go create mode 100644 plugins/vpp/ifplugin/descriptor/rx_mode.go create mode 100644 plugins/vpp/ifplugin/descriptor/rx_placement.go diff --git a/api/models/vpp/interfaces/keys.go b/api/models/vpp/interfaces/keys.go index 87fa0755e4..a659fbc197 100644 --- a/api/models/vpp/interfaces/keys.go +++ b/api/models/vpp/interfaces/keys.go @@ -109,6 +109,32 @@ const ( DHCPLeaseKeyPrefix = "vpp/interface/dhcp-lease/" ) +/* Interface Link State */ + +const ( + // interface link states as described in the keys + linkUpState = "UP" + linkDownState = "DOWN" + + // linkStateKeyTemplate is a template for keys representing + // the link state of VPP interfaces (up/down). + linkStateKeyTemplate = "vpp/interface/{ifName}/link-state/{linkState}" +) + +/* Interface Rx-placement (derived) */ +const ( + // rxPlacementKeyTemplate is a template for (derived) key representing + // rx-placement configured for a given interface queue. + rxPlacementKeyTemplate = "vpp/interface/{iface}/rx-placement/queue/{queue}" +) + +/* Interface Rx-mode (derived) */ +const ( + // rxModeKeyTemplate is a template for (derived) key representing + // rx-mode configuration for all queues of a given interface. + rxModeKeyTemplate = "vpp/interface/{iface}/rx-mode" +) + const ( // InvalidKeyPart is used in key for parts which are invalid InvalidKeyPart = "" @@ -401,6 +427,139 @@ func ParseNameFromDHCPLeaseKey(key string) (iface string, isDHCPLeaseKey bool) { return } +/* Link State (notification) */ + +// LinkStateKey returns key representing link state of a VPP interface. +func LinkStateKey(ifaceName string, linkIsUp bool) string { + if ifaceName == "" { + ifaceName = InvalidKeyPart + } + linkState := linkDownState + if linkIsUp { + linkState = linkUpState + } + key := strings.Replace(linkStateKeyTemplate, "{ifName}", ifaceName, 1) + key = strings.Replace(key, "{linkState}", linkState, 1) + return key +} + +// ParseLinkStateKey parses key representing link state of a VPP interface. +func ParseLinkStateKey(key string) (ifaceName string, isLinkUp bool, isLinkStateKey bool) { + if suffix := strings.TrimPrefix(key, "vpp/interface/"); suffix != key { + parts := strings.Split(suffix, "/") + linkState := -1 + for i, part := range parts { + if part == "link-state" { + linkState = i + } + } + if linkState != len(parts)-2 { + return + } + + switch parts[len(parts)-1] { + case linkDownState: + case linkUpState: + isLinkUp = true + default: + return + } + + // beware: interface name may contain forward slashes + ifaceName = strings.Join(parts[:linkState], "/") + if ifaceName == InvalidKeyPart { + isLinkUp = false + ifaceName = "" + return + } + isLinkStateKey = true + } + return +} + +/* Rx placement (derived) */ + +// RxPlacementKey returns a key representing rx-placement configured for a given +// interface queue. +func RxPlacementKey(ifaceName string, queue uint32) string { + if ifaceName == "" { + ifaceName = InvalidKeyPart + } + key := strings.Replace(rxPlacementKeyTemplate, "{iface}", ifaceName, 1) + key = strings.Replace(key, "{queue}", strconv.Itoa(int(queue)), 1) + return key +} + +// ParseRxPlacementKey parses key representing rx-placement configured for a given +// interface queue. +func ParseRxPlacementKey(key string) (ifaceName string, queue uint32, isRxPlacementKey bool) { + if suffix := strings.TrimPrefix(key, "vpp/interface/"); suffix != key { + parts := strings.Split(suffix, "/") + rxPlacement := -1 + for i, part := range parts { + if part == "rx-placement" { + rxPlacement = i + } + } + if rxPlacement != len(parts)-3 { + return + } + + if parts[len(parts)-2] != "queue" { + return + } + + queueID, err := strconv.Atoi(parts[len(parts)-1]) + if err != nil || queueID < 0 { + return + } + + // beware: interface name may contain forward slashes + ifaceName = strings.Join(parts[:rxPlacement], "/") + if ifaceName == InvalidKeyPart { + ifaceName = "" + return + } + + queue = uint32(queueID) + isRxPlacementKey = true + } + return +} + +/* Rx mode (derived) */ + +// RxModeKey returns a key representing rx-mode configuration for all queues +// of a given interface. +func RxModeKey(ifaceName string) string { + if ifaceName == "" { + ifaceName = InvalidKeyPart + } + return strings.Replace(rxModeKeyTemplate, "{iface}", ifaceName, 1) +} + +// ParseRxModeKey parses key representing rx-mode configuration for all queues +// of a given interface. +func ParseRxModeKey(key string) (ifaceName string, isRxModeKey bool) { + if suffix := strings.TrimPrefix(key, "vpp/interface/"); suffix != key { + parts := strings.Split(suffix, "/") + if len(parts) == 0 || parts[len(parts)-1] != "rx-mode" { + isRxModeKey = false + return + } + + // beware: interface name may contain forward slashes + ifaceName = strings.Join(parts[:len(parts)-1], "/") + if ifaceName == InvalidKeyPart { + ifaceName = "" + return + } + + isRxModeKey = true + } + return +} + // MarshalJSON ensures that field of type 'oneOf' is correctly marshaled // by using gogo lib marshaller func (m *Interface) MarshalJSON() ([]byte, error) { diff --git a/api/models/vpp/interfaces/keys_test.go b/api/models/vpp/interfaces/keys_test.go index 6020a2f5f9..92239d1e42 100644 --- a/api/models/vpp/interfaces/keys_test.go +++ b/api/models/vpp/interfaces/keys_test.go @@ -842,3 +842,315 @@ func TestDHCPLeaseKey(t *testing.T) { }) } } + +func TestLinkStateKey(t *testing.T) { + tests := []struct { + name string + iface string + linkIsUp bool + expectedKey string + }{ + { + name: "link is UP", + iface: "memif0", + linkIsUp: true, + expectedKey: "vpp/interface/memif0/link-state/UP", + }, + { + name: "link is DOWN", + iface: "memif0", + linkIsUp: false, + expectedKey: "vpp/interface/memif0/link-state/DOWN", + }, + { + name: "invalid interface name", + iface: "", + linkIsUp: true, + expectedKey: "vpp/interface//link-state/UP", + }, + { + name: "Gbe interface", + iface: "GigabitEthernet0/8/0", + linkIsUp: false, + expectedKey: "vpp/interface/GigabitEthernet0/8/0/link-state/DOWN", + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + key := LinkStateKey(test.iface, test.linkIsUp) + if key != test.expectedKey { + t.Errorf("failed for: iface=%s linkIsUp=%v\n"+ + "expected key:\n\t%q\ngot key:\n\t%q", + test.iface, test.linkIsUp, test.expectedKey, key) + } + }) + } +} + +func TestParseLinkStateKey(t *testing.T) { + tests := []struct { + name string + key string + expectedIface string + expectedIsLinkUp bool + expectedIsLinkStateKey bool + }{ + { + name: "link is UP", + key: "vpp/interface/memif0/link-state/UP", + expectedIface: "memif0", + expectedIsLinkUp: true, + expectedIsLinkStateKey: true, + }, + { + name: "link is DOWN", + key: "vpp/interface/memif0/link-state/DOWN", + expectedIface: "memif0", + expectedIsLinkUp: false, + expectedIsLinkStateKey: true, + }, + { + name: "invalid interface name", + key: "vpp/interface//link-state/DOWN", + expectedIsLinkStateKey: false, + }, + { + name: "Gbe interface", + key: "vpp/interface/GigabitEthernet0/8/0/link-state/UP", + expectedIface: "GigabitEthernet0/8/0", + expectedIsLinkUp: true, + expectedIsLinkStateKey: true, + }, + { + name: "invalid link state", + key: "vpp/interface/GigabitEthernet0/8/0/link-state/", + expectedIsLinkStateKey: false, + }, + { + name: "missing link state", + key: "vpp/interface/GigabitEthernet0/8/0/link-state", + expectedIsLinkStateKey: false, + }, + { + name: "not link state key", + key: "vpp/interface/unnumbered/GigabitEthernet0/8/0", + expectedIsLinkStateKey: false, + }, + + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + iface, isLinkUp, isLinkStateKey := ParseLinkStateKey(test.key) + if isLinkStateKey != test.expectedIsLinkStateKey { + t.Errorf("expected isLinkStateKey: %v\tgot: %v", + test.expectedIsLinkStateKey, isLinkStateKey) + } + if iface != test.expectedIface { + t.Errorf("expected iface: %s\tgot: %s", test.expectedIface, iface) + } + if isLinkUp != test.expectedIsLinkUp { + t.Errorf("expected isLinkUp: %t\tgot: %t", test.expectedIsLinkUp, isLinkUp) + } + }) + } +} + +func TestRxPlacementKey(t *testing.T) { + tests := []struct { + name string + iface string + queue uint32 + expectedKey string + }{ + { + name: "queue 0", + iface: "memif0", + queue: 0, + expectedKey: "vpp/interface/memif0/rx-placement/queue/0", + }, + { + name: "queue 1", + iface: "memif0", + queue: 1, + expectedKey: "vpp/interface/memif0/rx-placement/queue/1", + }, + { + name: "invalid interface name", + iface: "", + queue: 1, + expectedKey: "vpp/interface//rx-placement/queue/1", + }, + { + name: "Gbe interface", + iface: "GigabitEthernet0/8/0", + queue: 2, + expectedKey: "vpp/interface/GigabitEthernet0/8/0/rx-placement/queue/2", + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + key := RxPlacementKey(test.iface, test.queue) + if key != test.expectedKey { + t.Errorf("failed for: iface=%s queue=%d\n"+ + "expected key:\n\t%q\ngot key:\n\t%q", + test.iface, test.queue, test.expectedKey, key) + } + }) + } +} + +func TestParseRxPlacementKey(t *testing.T) { + tests := []struct { + name string + key string + expectedIface string + expectedQueue uint32 + expectedIsRxPlacementKey bool + }{ + { + name: "queue 0", + key: "vpp/interface/memif0/rx-placement/queue/0", + expectedIface: "memif0", + expectedQueue: 0, + expectedIsRxPlacementKey: true, + }, + { + name: "queue 1", + key: "vpp/interface/memif0/rx-placement/queue/1", + expectedIface: "memif0", + expectedQueue: 1, + expectedIsRxPlacementKey: true, + }, + { + name: "invalid interface name", + key: "vpp/interface//rx-placement/queue/1", + expectedIsRxPlacementKey: false, + }, + { + name: "invalid queue", + key: "vpp/interface/memif0/rx-placement/queue/", + expectedIsRxPlacementKey: false, + }, + { + name: "missing queue", + key: "vpp/interface/memif0/rx-placement/", + expectedIsRxPlacementKey: false, + }, + { + name: "missing queue ID", + key: "vpp/interface/memif0/rx-placement/queue", + expectedIsRxPlacementKey: false, + }, + { + name: "Gbe interface", + key: "vpp/interface/GigabitEthernet0/8/0/rx-placement/queue/3", + expectedIface: "GigabitEthernet0/8/0", + expectedQueue: 3, + expectedIsRxPlacementKey: true, + }, + { + name: "not rx placement key", + key: "vpp/interface/memif0/link-state/DOWN", + expectedIsRxPlacementKey: false, + }, + + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + iface, queue, isRxPlacementKey := ParseRxPlacementKey(test.key) + if isRxPlacementKey != test.expectedIsRxPlacementKey { + t.Errorf("expected isRxPlacementKey: %v\tgot: %v", + test.expectedIsRxPlacementKey, isRxPlacementKey) + } + if queue != test.expectedQueue { + t.Errorf("expected queue: %d\tgot: %d", test.expectedQueue, queue) + } + if iface != test.expectedIface { + t.Errorf("expected iface: %s\tgot: %s", test.expectedIface, iface) + } + }) + } +} + +func TestRxModeKey(t *testing.T) { + tests := []struct { + name string + iface string + expectedKey string + }{ + { + name: "memif", + iface: "memif0", + expectedKey: "vpp/interface/memif0/rx-mode", + }, + { + name: "Gbe", + iface: "GigabitEthernet0/8/0", + expectedKey: "vpp/interface/GigabitEthernet0/8/0/rx-mode", + }, + { + name: "invalid interface name", + iface: "", + expectedKey: "vpp/interface//rx-mode", + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + key := RxModeKey(test.iface) + if key != test.expectedKey { + t.Errorf("failed for: iface=%s\n"+ + "expected key:\n\t%q\ngot key:\n\t%q", + test.iface, test.expectedKey, key) + } + }) + } +} + +func TestParseRxModeKey(t *testing.T) { + tests := []struct { + name string + key string + expectedIface string + expectedIsRxModeKey bool + }{ + { + name: "memif", + key: "vpp/interface/memif0/rx-mode", + expectedIface: "memif0", + expectedIsRxModeKey: true, + }, + { + name: "Gbe", + key: "vpp/interface/GigabitEthernet0/8/0/rx-mode", + expectedIface: "GigabitEthernet0/8/0", + expectedIsRxModeKey: true, + }, + { + name: "invalid interface name", + key: "vpp/interface//rx-mode", + expectedIsRxModeKey: false, + }, + { + name: "missing rx-mode suffix", + key: "vpp/interface/", + expectedIsRxModeKey: false, + }, + { + name: "not rx-mode key", + key: "vpp/interface/memif0/address/192.168.1.12/24", + expectedIsRxModeKey: false, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + iface, isRxModeKey := ParseRxModeKey(test.key) + if isRxModeKey != test.expectedIsRxModeKey { + t.Errorf("expected isRxModeKey: %v\tgot: %v", + test.expectedIsRxModeKey, isRxModeKey) + } + if iface != test.expectedIface { + t.Errorf("expected iface: %s\tgot: %s", test.expectedIface, iface) + } + }) + } +} diff --git a/plugins/vpp/ifplugin/descriptor/adapter/interface.go b/plugins/vpp/ifplugin/descriptor/adapter/interface.go index edcdd85618..d7c7bb4173 100644 --- a/plugins/vpp/ifplugin/descriptor/adapter/interface.go +++ b/plugins/vpp/ifplugin/descriptor/adapter/interface.go @@ -4,9 +4,9 @@ package adapter import ( "github.com/gogo/protobuf/proto" - "github.com/ligato/vpp-agent/api/models/vpp/interfaces" . "github.com/ligato/vpp-agent/plugins/kvscheduler/api" "github.com/ligato/vpp-agent/plugins/vpp/ifplugin/ifaceidx" + "github.com/ligato/vpp-agent/api/models/vpp/interfaces" ) ////////// type-safe key-value pair with metadata ////////// diff --git a/plugins/vpp/ifplugin/descriptor/adapter/rxplacement.go b/plugins/vpp/ifplugin/descriptor/adapter/rxplacement.go new file mode 100644 index 0000000000..6eaca98a22 --- /dev/null +++ b/plugins/vpp/ifplugin/descriptor/adapter/rxplacement.go @@ -0,0 +1,233 @@ +// Code generated by adapter-generator. DO NOT EDIT. + +package adapter + +import ( + "github.com/gogo/protobuf/proto" + . "github.com/ligato/vpp-agent/plugins/kvscheduler/api" + "github.com/ligato/vpp-agent/api/models/vpp/interfaces" +) + +////////// type-safe key-value pair with metadata ////////// + +type RxPlacementKVWithMetadata struct { + Key string + Value *vpp_interfaces.Interface_RxPlacement + Metadata interface{} + Origin ValueOrigin +} + +////////// type-safe Descriptor structure ////////// + +type RxPlacementDescriptor struct { + Name string + KeySelector KeySelector + ValueTypeName string + KeyLabel func(key string) string + ValueComparator func(key string, oldValue, newValue *vpp_interfaces.Interface_RxPlacement) bool + NBKeyPrefix string + WithMetadata bool + MetadataMapFactory MetadataMapFactory + Validate func(key string, value *vpp_interfaces.Interface_RxPlacement) error + Create func(key string, value *vpp_interfaces.Interface_RxPlacement) (metadata interface{}, err error) + Delete func(key string, value *vpp_interfaces.Interface_RxPlacement, metadata interface{}) error + Update func(key string, oldValue, newValue *vpp_interfaces.Interface_RxPlacement, oldMetadata interface{}) (newMetadata interface{}, err error) + UpdateWithRecreate func(key string, oldValue, newValue *vpp_interfaces.Interface_RxPlacement, metadata interface{}) bool + Retrieve func(correlate []RxPlacementKVWithMetadata) ([]RxPlacementKVWithMetadata, error) + IsRetriableFailure func(err error) bool + DerivedValues func(key string, value *vpp_interfaces.Interface_RxPlacement) []KeyValuePair + Dependencies func(key string, value *vpp_interfaces.Interface_RxPlacement) []Dependency + RetrieveDependencies []string /* descriptor name */ +} + +////////// Descriptor adapter ////////// + +type RxPlacementDescriptorAdapter struct { + descriptor *RxPlacementDescriptor +} + +func NewRxPlacementDescriptor(typedDescriptor *RxPlacementDescriptor) *KVDescriptor { + adapter := &RxPlacementDescriptorAdapter{descriptor: typedDescriptor} + descriptor := &KVDescriptor{ + Name: typedDescriptor.Name, + KeySelector: typedDescriptor.KeySelector, + ValueTypeName: typedDescriptor.ValueTypeName, + KeyLabel: typedDescriptor.KeyLabel, + NBKeyPrefix: typedDescriptor.NBKeyPrefix, + WithMetadata: typedDescriptor.WithMetadata, + MetadataMapFactory: typedDescriptor.MetadataMapFactory, + IsRetriableFailure: typedDescriptor.IsRetriableFailure, + RetrieveDependencies: typedDescriptor.RetrieveDependencies, + } + if typedDescriptor.ValueComparator != nil { + descriptor.ValueComparator = adapter.ValueComparator + } + if typedDescriptor.Validate != nil { + descriptor.Validate = adapter.Validate + } + if typedDescriptor.Create != nil { + descriptor.Create = adapter.Create + } + if typedDescriptor.Delete != nil { + descriptor.Delete = adapter.Delete + } + if typedDescriptor.Update != nil { + descriptor.Update = adapter.Update + } + if typedDescriptor.UpdateWithRecreate != nil { + descriptor.UpdateWithRecreate = adapter.UpdateWithRecreate + } + if typedDescriptor.Retrieve != nil { + descriptor.Retrieve = adapter.Retrieve + } + if typedDescriptor.Dependencies != nil { + descriptor.Dependencies = adapter.Dependencies + } + if typedDescriptor.DerivedValues != nil { + descriptor.DerivedValues = adapter.DerivedValues + } + return descriptor +} + +func (da *RxPlacementDescriptorAdapter) ValueComparator(key string, oldValue, newValue proto.Message) bool { + typedOldValue, err1 := castRxPlacementValue(key, oldValue) + typedNewValue, err2 := castRxPlacementValue(key, newValue) + if err1 != nil || err2 != nil { + return false + } + return da.descriptor.ValueComparator(key, typedOldValue, typedNewValue) +} + +func (da *RxPlacementDescriptorAdapter) Validate(key string, value proto.Message) (err error) { + typedValue, err := castRxPlacementValue(key, value) + if err != nil { + return err + } + return da.descriptor.Validate(key, typedValue) +} + +func (da *RxPlacementDescriptorAdapter) Create(key string, value proto.Message) (metadata Metadata, err error) { + typedValue, err := castRxPlacementValue(key, value) + if err != nil { + return nil, err + } + return da.descriptor.Create(key, typedValue) +} + +func (da *RxPlacementDescriptorAdapter) Update(key string, oldValue, newValue proto.Message, oldMetadata Metadata) (newMetadata Metadata, err error) { + oldTypedValue, err := castRxPlacementValue(key, oldValue) + if err != nil { + return nil, err + } + newTypedValue, err := castRxPlacementValue(key, newValue) + if err != nil { + return nil, err + } + typedOldMetadata, err := castRxPlacementMetadata(key, oldMetadata) + if err != nil { + return nil, err + } + return da.descriptor.Update(key, oldTypedValue, newTypedValue, typedOldMetadata) +} + +func (da *RxPlacementDescriptorAdapter) Delete(key string, value proto.Message, metadata Metadata) error { + typedValue, err := castRxPlacementValue(key, value) + if err != nil { + return err + } + typedMetadata, err := castRxPlacementMetadata(key, metadata) + if err != nil { + return err + } + return da.descriptor.Delete(key, typedValue, typedMetadata) +} + +func (da *RxPlacementDescriptorAdapter) UpdateWithRecreate(key string, oldValue, newValue proto.Message, metadata Metadata) bool { + oldTypedValue, err := castRxPlacementValue(key, oldValue) + if err != nil { + return true + } + newTypedValue, err := castRxPlacementValue(key, newValue) + if err != nil { + return true + } + typedMetadata, err := castRxPlacementMetadata(key, metadata) + if err != nil { + return true + } + return da.descriptor.UpdateWithRecreate(key, oldTypedValue, newTypedValue, typedMetadata) +} + +func (da *RxPlacementDescriptorAdapter) Retrieve(correlate []KVWithMetadata) ([]KVWithMetadata, error) { + var correlateWithType []RxPlacementKVWithMetadata + for _, kvpair := range correlate { + typedValue, err := castRxPlacementValue(kvpair.Key, kvpair.Value) + if err != nil { + continue + } + typedMetadata, err := castRxPlacementMetadata(kvpair.Key, kvpair.Metadata) + if err != nil { + continue + } + correlateWithType = append(correlateWithType, + RxPlacementKVWithMetadata{ + Key: kvpair.Key, + Value: typedValue, + Metadata: typedMetadata, + Origin: kvpair.Origin, + }) + } + + typedValues, err := da.descriptor.Retrieve(correlateWithType) + if err != nil { + return nil, err + } + var values []KVWithMetadata + for _, typedKVWithMetadata := range typedValues { + kvWithMetadata := KVWithMetadata{ + Key: typedKVWithMetadata.Key, + Metadata: typedKVWithMetadata.Metadata, + Origin: typedKVWithMetadata.Origin, + } + kvWithMetadata.Value = typedKVWithMetadata.Value + values = append(values, kvWithMetadata) + } + return values, err +} + +func (da *RxPlacementDescriptorAdapter) DerivedValues(key string, value proto.Message) []KeyValuePair { + typedValue, err := castRxPlacementValue(key, value) + if err != nil { + return nil + } + return da.descriptor.DerivedValues(key, typedValue) +} + +func (da *RxPlacementDescriptorAdapter) Dependencies(key string, value proto.Message) []Dependency { + typedValue, err := castRxPlacementValue(key, value) + if err != nil { + return nil + } + return da.descriptor.Dependencies(key, typedValue) +} + +////////// Helper methods ////////// + +func castRxPlacementValue(key string, value proto.Message) (*vpp_interfaces.Interface_RxPlacement, error) { + typedValue, ok := value.(*vpp_interfaces.Interface_RxPlacement) + if !ok { + return nil, ErrInvalidValueType(key, value) + } + return typedValue, nil +} + +func castRxPlacementMetadata(key string, metadata Metadata) (interface{}, error) { + if metadata == nil { + return nil, nil + } + typedMetadata, ok := metadata.(interface{}) + if !ok { + return nil, ErrInvalidMetadataType(key) + } + return typedMetadata, nil +} diff --git a/plugins/vpp/ifplugin/descriptor/interface.go b/plugins/vpp/ifplugin/descriptor/interface.go index ca5c9e0edd..c8d6f2d3ff 100644 --- a/plugins/vpp/ifplugin/descriptor/interface.go +++ b/plugins/vpp/ifplugin/descriptor/interface.go @@ -98,16 +98,6 @@ var ( // ErrInterfaceLinkMismatch is returned when interface type does not match the link configuration. ErrInterfaceLinkMismatch = errors.New("VPP interface type and link configuration do not match") - // ErrUnsupportedRxMode is returned when the given interface type does not support the chosen - // RX mode. - ErrUnsupportedRxMode = errors.New("unsupported RX Mode") - - // ErrUndefinedRxMode is returned when the Rx mode is not defined. - ErrUndefinedRxMode = errors.New("undefined RX Mode") - - // ErrUnsupportedRxMode is returned when Rx mode has multiple definitions for the same queue. - ErrRedefinedRxMode = errors.New("redefined RX Mode") - // ErrRedefinedRxPlacement is returned when Rx placement has multiple definitions for the same queue. ErrRedefinedRxPlacement = errors.New("redefined RX Placement") @@ -231,19 +221,6 @@ func (d *InterfaceDescriptor) EquivalentInterfaces(key string, oldIntf, newIntf } } - // TODO: for TAPv2 the RxMode dump is unstable - // (it goes between POLLING and INTERRUPT, maybe it should actually return ADAPTIVE?) - if oldIntf.Type != interfaces.Interface_TAP || oldIntf.GetTap().GetVersion() != 2 { - if !d.equivalentRxMode(oldIntf, newIntf) { - return false - } - } - - // handle unspecified Rx placement - if d.equivalentRxPlacement(oldIntf.GetRxPlacement(), newIntf.GetRxPlacement()) { - return false - } - // handle default/unspecified MTU (except VxLAN and IPSec tunnel) if newIntf.Type != interfaces.Interface_VXLAN_TUNNEL && newIntf.Type != interfaces.Interface_IPSEC_TUNNEL { if d.getInterfaceMTU(newIntf) != 0 && d.getInterfaceMTU(oldIntf) != d.getInterfaceMTU(newIntf) { @@ -265,78 +242,6 @@ func (d *InterfaceDescriptor) EquivalentInterfaces(key string, oldIntf, newIntf return true } -// equivalentRxMode compares Rx modes for equivalency. -func (d *InterfaceDescriptor) equivalentRxMode(oldIntf, newIntf *interfaces.Interface) bool { - if len(newIntf.GetRxMode()) == 0 { - // undefined - return true - } - /* Note: default Rx mode cannot be dumped - compare only if these are two NB - configurations (not a refreshed, i.e. dumped, value). - */ - oldDefMode := getDefaultRxMode(oldIntf) - newDefMode := getDefaultRxMode(newIntf) - if oldDefMode != interfaces.Interface_RxMode_UNKNOWN && - newDefMode != interfaces.Interface_RxMode_UNKNOWN { - if oldDefMode != newDefMode { - return false - } - } - // compare queue-specific RX modes - for _, rxMode := range oldIntf.GetRxMode() { - if rxMode.DefaultMode { - continue - } - oldMode := normalizeRxMode(rxMode.Mode, oldIntf) - newMode := getQueueRxMode(rxMode.Queue, newIntf) - if oldMode != newMode { - return false - } - } - for _, rxMode := range newIntf.GetRxMode() { - if rxMode.DefaultMode { - continue - } - newMode := normalizeRxMode(rxMode.Mode, newIntf) - oldMode := getQueueRxMode(rxMode.Queue, oldIntf) - if oldMode != newMode { - return false - } - } - return true -} - -// equivalentRxMode compares Rx placements for equivalency. -func (d *InterfaceDescriptor) equivalentRxPlacement(oldPlacement, newPlacement []*interfaces.Interface_RxPlacement) bool { - if len(newPlacement) == 0{ - // undefined - return true - } - - if len(oldPlacement) != len(newPlacement) { - return false - } - - for _, old := range oldPlacement { - found := false - for _, new := range newPlacement { - if old.Queue == new.Queue { - found = true - if (old.MainThread != new.MainThread) || - (!old.MainThread && old.Worker != new.Worker) { - return false - } - break - } - } - if !found { - return false - } - } - - return true -} - // equivalentTypeSpecificConfig compares type-specific sections of two interface configurations. func (d *InterfaceDescriptor) equivalentTypeSpecificConfig(oldIntf, newIntf *interfaces.Interface) bool { switch oldIntf.Type { @@ -511,17 +416,6 @@ func (d *InterfaceDescriptor) Validate(key string, intf *interfaces.Interface) e if _, ok := d.ethernetIfs[intf.Name]; !ok { return kvs.NewInvalidValueError(ErrDPDKInterfaceMissing, "name") } - for _, rxMode := range intf.GetRxMode() { - mode := normalizeRxMode(rxMode.Mode, intf) - if mode != interfaces.Interface_RxMode_POLLING { - if rxMode.DefaultMode { - return kvs.NewInvalidValueError(ErrUnsupportedRxMode, - "rx_mode[default]") - } - return kvs.NewInvalidValueError(ErrUnsupportedRxMode, - fmt.Sprintf("rx_mode[.queue=%d]", rxMode.Queue)) - } - } case interfaces.Interface_AF_PACKET: if intf.GetAfpacket().GetHostIfName() == "" { return kvs.NewInvalidValueError(ErrAfPacketWithoutHostName, "link.afpacket.host_if_name") @@ -539,31 +433,7 @@ func (d *InterfaceDescriptor) Validate(key string, intf *interfaces.Interface) e } } - // validate Rx Mode - for i, rxMode1 := range intf.GetRxMode() { - if rxMode1.Mode == interfaces.Interface_RxMode_UNKNOWN { - if rxMode1.DefaultMode { - return kvs.NewInvalidValueError(ErrUndefinedRxMode,"rx_mode[default]") - } - return kvs.NewInvalidValueError(ErrUndefinedRxMode, - fmt.Sprintf("rx_mode[.queue=%d]", rxMode1.Queue)) - } - for j := i + 1; j < len(intf.GetRxMode()); j++ { - rxMode2 := intf.GetRxMode()[j] - if rxMode1.DefaultMode != rxMode2.DefaultMode { - continue - } - if rxMode1.DefaultMode { - return kvs.NewInvalidValueError(ErrRedefinedRxMode,"rx_mode[default]") - } - if rxMode1.Queue == rxMode2.Queue { - return kvs.NewInvalidValueError(ErrRedefinedRxMode, - fmt.Sprintf("rx_mode[.queue=%d]", rxMode1.Queue)) - } - } - } - - // validate Rx Placement + // validate Rx Placement before it gets derived out for i, rxPlacement1 := range intf.GetRxPlacement() { for j := i + 1; j < len(intf.GetRxPlacement()); j++ { rxPlacement2 := intf.GetRxPlacement()[j] @@ -664,7 +534,9 @@ func (d *InterfaceDescriptor) Dependencies(key string, intf *interfaces.Interfac // - empty value for enabled DHCP client // - configuration for every slave of a bonded interface // - one empty value for every IP address to be assigned to the interface -// - one empty value for VRF table to put the interface into. +// - one empty value for VRF table to put the interface into +// - one value with interface configuration reduced to RxMode if set +// - one Interface_RxPlacement for every queue with configured Rx placement. func (d *InterfaceDescriptor) DerivedValues(key string, intf *interfaces.Interface) (derValues []kvs.KeyValuePair) { // unnumbered interface if intf.GetUnnumbered() != nil { @@ -730,6 +602,26 @@ func (d *InterfaceDescriptor) DerivedValues(key string, intf *interfaces.Interfa } } + // Rx mode + if len(intf.GetRxMode()) > 0 { + derValues = append(derValues, kvs.KeyValuePair{ + Key: interfaces.RxModeKey(intf.GetName()), + Value: &interfaces.Interface{ + Name: intf.GetName(), + Type: intf.GetType(), + RxMode: intf.GetRxMode(), + }, + }) + } + + // Rx placement + for _, rxPlacement := range intf.GetRxPlacement() { + derValues = append(derValues, kvs.KeyValuePair{ + Key: interfaces.RxPlacementKey(intf.GetName(), rxPlacement.GetQueue()), + Value: rxPlacement, + }) + } + // TODO: define derived value for UP/DOWN state (needed for subinterfaces) return derValues @@ -801,50 +693,6 @@ func (d *InterfaceDescriptor) getMemifRingSize(memif *interfaces.MemifLink) uint return memif.GetRingSize() } -// getQueueRxMode reads RX mode for the given queue from the interface configuration. -func getQueueRxMode(queue uint32, iface *interfaces.Interface) (mode interfaces.Interface_RxMode_Type) { - for _, rxMode := range iface.GetRxMode() { - if rxMode.DefaultMode { - mode = rxMode.Mode - continue // keep looking for a queue-specific RX mode - } - if rxMode.Queue == queue { - mode = rxMode.Mode - break - } - } - return normalizeRxMode(mode, iface) -} - -// getDefaultRxMode reads default RX mode from the interface configuration. -func getDefaultRxMode(iface *interfaces.Interface) (rxMode interfaces.Interface_RxMode_Type) { - for _, rxMode := range iface.GetRxMode() { - if rxMode.DefaultMode { - return normalizeRxMode(rxMode.Mode, iface) - } - } - return interfaces.Interface_RxMode_UNKNOWN -} - -// normalizeRxMode resolves default/undefined Rx mode for specific interfaces. -func normalizeRxMode(mode interfaces.Interface_RxMode_Type, iface *interfaces.Interface) interfaces.Interface_RxMode_Type { - if mode != interfaces.Interface_RxMode_DEFAULT { - return mode - } - switch iface.GetType() { - case interfaces.Interface_DPDK: - return interfaces.Interface_RxMode_POLLING - case interfaces.Interface_AF_PACKET: - return interfaces.Interface_RxMode_INTERRUPT - case interfaces.Interface_TAP: - if iface.GetTap().GetVersion() == 2 { - // TAP v2 - return interfaces.Interface_RxMode_INTERRUPT - } - } - return mode -} - // getTapConfig returns the TAP-specific configuration section (handling undefined attributes). func getTapConfig(intf *interfaces.Interface) (tapLink *interfaces.TapLink) { tapLink = new(interfaces.TapLink) diff --git a/plugins/vpp/ifplugin/descriptor/interface_crud.go b/plugins/vpp/ifplugin/descriptor/interface_crud.go index 007a6aa296..e8a6071056 100644 --- a/plugins/vpp/ifplugin/descriptor/interface_crud.go +++ b/plugins/vpp/ifplugin/descriptor/interface_crud.go @@ -142,21 +142,6 @@ func (d *InterfaceDescriptor) Create(key string, intf *interfaces.Interface) (me d.bondIDs[intf.GetBond().GetId()] = intf.GetName() } - err = d.configureRxMode(intf, ifIdx, false) - if err != nil { - return nil, err - } - - // rx-placement - for _, rxPlacement := range intf.GetRxPlacement() { - if err = d.ifHandler.SetRxPlacement(ifIdx, rxPlacement); err != nil { - err = errors.Errorf("failed to set rx-placement for queue %d of the interface %s: %v", - rxPlacement.Queue, intf.Name, err) - d.log.Error(err) - return nil, err - } - } - // MAC address. Note: physical interfaces cannot have the MAC address changed. The bond interface uses its own // binary API call to set MAC address. if intf.GetPhysAddress() != "" && @@ -214,58 +199,6 @@ func (d *InterfaceDescriptor) Create(key string, intf *interfaces.Interface) (me return metadata, nil } -// configureRxMode (re-)configures Rx mode for the interface. -func (d *InterfaceDescriptor) configureRxMode(iface *interfaces.Interface, ifIdx uint32, - reconfigure bool) (err error) { - - // first, revert back to default for all queues - if reconfigure { - err = d.ifHandler.SetRxMode(ifIdx, &interfaces.Interface_RxMode{ - DefaultMode: true, - Mode: normalizeRxMode(interfaces.Interface_RxMode_DEFAULT, iface), - }) - if err != nil { - err = errors.Errorf("failed to set default Rx-mode for interface %s: %v", iface, err) - d.log.Error(err) - return err - } - } - - if len(iface.GetRxMode()) == 0 { - return - } - - // configure the default Rx mode - defRxMode := getDefaultRxMode(iface) - if defRxMode != interfaces.Interface_RxMode_UNKNOWN { - err = d.ifHandler.SetRxMode(ifIdx, &interfaces.Interface_RxMode{ - DefaultMode: true, - Mode: defRxMode, - }) - if err != nil { - err = errors.Errorf("failed to set default Rx-mode for interface %s: %v", iface.Name, err) - d.log.Error(err) - return err - } - } - - // configure per-queue RX mode - for _, rxMode := range iface.GetRxMode() { - if rxMode.DefaultMode { - continue - } - err = d.ifHandler.SetRxMode(ifIdx, rxMode) - if err != nil { - err = errors.Errorf("failed to set Rx-mode for queue %d of the interface %s: %v", - rxMode.Queue, iface.Name, err) - d.log.Error(err) - return err - } - } - - return nil -} - // Delete removes VPP interface. func (d *InterfaceDescriptor) Delete(key string, intf *interfaces.Interface, metadata *ifaceidx.IfaceMetadata) error { var err error @@ -318,26 +251,6 @@ func (d *InterfaceDescriptor) Delete(key string, intf *interfaces.Interface, met func (d *InterfaceDescriptor) Update(key string, oldIntf, newIntf *interfaces.Interface, oldMetadata *ifaceidx.IfaceMetadata) (newMetadata *ifaceidx.IfaceMetadata, err error) { ifIdx := oldMetadata.SwIfIndex - // rx-mode - if !d.equivalentRxMode(oldIntf, newIntf) { - err = d.configureRxMode(newIntf, ifIdx, len(oldIntf.GetRxMode()) != 0) - if err != nil { - return oldMetadata, err - } - } - - // rx-placement - if !d.equivalentRxPlacement(oldIntf.GetRxPlacement(), newIntf.GetRxPlacement()) { - for _, rxPlacement := range newIntf.GetRxPlacement() { - if err = d.ifHandler.SetRxPlacement(ifIdx, rxPlacement); err != nil { - err = errors.Errorf("failed to set rx-placement for queue %d of the interface %s: %v", - rxPlacement.Queue, newIntf.Name, err) - d.log.Error(err) - return nil, err - } - } - } - // admin status if newIntf.Enabled != oldIntf.Enabled { if newIntf.Enabled { @@ -540,6 +453,7 @@ func (d *InterfaceDescriptor) Retrieve(correlate []adapter.InterfaceKVWithMetada Vrf: intf.Interface.Vrf, IPAddresses: intf.Interface.IpAddresses, TAPHostIfName: tapHostIfName, + LinkIsUp: intf.Meta.LinkState == 1, } retrieved = append(retrieved, adapter.InterfaceKVWithMetadata{ Key: models.Key(intf.Interface), diff --git a/plugins/vpp/ifplugin/descriptor/link_state.go b/plugins/vpp/ifplugin/descriptor/link_state.go new file mode 100644 index 0000000000..0120a2c1f9 --- /dev/null +++ b/plugins/vpp/ifplugin/descriptor/link_state.go @@ -0,0 +1,102 @@ +// Copyright (c) 2018 Cisco and/or its affiliates. +// +// 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 descriptor + +import ( + prototypes "github.com/gogo/protobuf/types" + "github.com/ligato/cn-infra/logging" + + interfaces "github.com/ligato/vpp-agent/api/models/vpp/interfaces" + kvs "github.com/ligato/vpp-agent/plugins/kvscheduler/api" + "github.com/ligato/vpp-agent/plugins/vpp/ifplugin/ifaceidx" +) + +const ( + // LinkStateDescriptorName is the name of the descriptor notifying about the + // link state changes of VPP interfaces. + LinkStateDescriptorName = "vpp-interface-link-state" +) + +// LinkStateDescriptor notifies kvscheduler about the link state changes of VPP +// interfaces. +type LinkStateDescriptor struct { + // input arguments + log logging.Logger + kvscheduler kvs.KVScheduler + ifaceIdx ifaceidx.IfaceMetadataIndex +} + +// NewLinkStateDescriptor creates a new instance of the Link-State descriptor. +func NewLinkStateDescriptor(kvscheduler kvs.KVScheduler, ifaceIdx ifaceidx.IfaceMetadataIndex, + log logging.PluginLogger) (descr *kvs.KVDescriptor, ctx *LinkStateDescriptor) { + + descrCtx := &LinkStateDescriptor{ + log: log.NewLogger("interface-link-state"), + kvscheduler: kvscheduler, + ifaceIdx: ifaceIdx, + } + return &kvs.KVDescriptor{ + Name: LinkStateDescriptorName, + KeySelector: descrCtx.IsInterfaceLinkStateKey, + Retrieve: descrCtx.Retrieve, + RetrieveDependencies: []string{InterfaceDescriptorName}, // link state read from interface metadata + }, descrCtx +} + +// IsInterfaceLinkStateKey returns for keys representing +// link-state of VPP interfaces. +func (w *LinkStateDescriptor) IsInterfaceLinkStateKey(key string) bool { + _, _, isLinkStateKey := interfaces.ParseLinkStateKey(key) + return isLinkStateKey +} + +// Retrieve returns key for every VPP interface describing the state of the link +// (value is empty). +func (w *LinkStateDescriptor) Retrieve(correlate []kvs.KVWithMetadata) (values []kvs.KVWithMetadata, err error) { + for _, ifaceName := range w.ifaceIdx.ListAllInterfaces() { + ifaceMeta, _ := w.ifaceIdx.LookupByName(ifaceName) + values = append(values, kvs.KVWithMetadata{ + Key: interfaces.LinkStateKey(ifaceName, ifaceMeta.LinkIsUp), + Value: &prototypes.Empty{}, + Origin: kvs.FromSB, + }) + } + + return values, nil +} + +// UpdateLinkState notifies scheduler about a change in the link state of an interface. +func (w *LinkStateDescriptor) UpdateLinkState(ifaceState *interfaces.InterfaceNotification) { + + operStatus := ifaceState.State.OperStatus + if operStatus == interfaces.InterfaceState_DELETED || + operStatus == interfaces.InterfaceState_UNKNOWN_STATUS { + // interface link is neither up nor down + w.kvscheduler.PushSBNotification( + interfaces.LinkStateKey(ifaceState.State.Name, true), + nil, + nil) + w.kvscheduler.PushSBNotification( + interfaces.LinkStateKey(ifaceState.State.Name, false), + nil, + nil) + return + } + + w.kvscheduler.PushSBNotification( + interfaces.LinkStateKey(ifaceState.State.Name, operStatus == interfaces.InterfaceState_UP), + &prototypes.Empty{}, + nil) +} \ No newline at end of file diff --git a/plugins/vpp/ifplugin/descriptor/rx_mode.go b/plugins/vpp/ifplugin/descriptor/rx_mode.go new file mode 100644 index 0000000000..3360b37d66 --- /dev/null +++ b/plugins/vpp/ifplugin/descriptor/rx_mode.go @@ -0,0 +1,306 @@ +// Copyright (c) 2018 Cisco and/or its affiliates. +// +// 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 descriptor + +import ( + "fmt" + + "github.com/gogo/protobuf/proto" + "github.com/ligato/cn-infra/logging" + "github.com/pkg/errors" + + interfaces "github.com/ligato/vpp-agent/api/models/vpp/interfaces" + kvs "github.com/ligato/vpp-agent/plugins/kvscheduler/api" + "github.com/ligato/vpp-agent/plugins/vpp/ifplugin/descriptor/adapter" + "github.com/ligato/vpp-agent/plugins/vpp/ifplugin/ifaceidx" + "github.com/ligato/vpp-agent/plugins/vpp/ifplugin/vppcalls" +) + +const ( + // RxModeDescriptorName is the name of the descriptor for the unnumbered + // config-subsection of VPP interfaces. + RxModeDescriptorName = "vpp-interface-rx-mode" + + // dependency labels + linkIsUpDep = "interface-link-is-UP" +) + +// A list of non-retriable errors: +var ( + // ErrUnsupportedRxMode is returned when the given interface type does not support the chosen + // RX mode. + ErrUnsupportedRxMode = errors.New("unsupported RX Mode") + + // ErrUndefinedRxMode is returned when the Rx mode is not defined. + ErrUndefinedRxMode = errors.New("undefined RX Mode") + + // ErrUnsupportedRxMode is returned when Rx mode has multiple definitions for the same queue. + ErrRedefinedRxMode = errors.New("redefined RX Mode") +) + +// RxModeDescriptor configures Rx mode for VPP interface queues. +type RxModeDescriptor struct { + log logging.Logger + ifHandler vppcalls.InterfaceVppAPI + ifIndex ifaceidx.IfaceMetadataIndex +} + +// NewRxModeDescriptor creates a new instance of RxModeDescriptor. +func NewRxModeDescriptor(ifHandler vppcalls.InterfaceVppAPI, ifIndex ifaceidx.IfaceMetadataIndex, + log logging.PluginLogger) *kvs.KVDescriptor { + + ctx := &RxModeDescriptor{ + ifHandler: ifHandler, + ifIndex: ifIndex, + log: log.NewLogger("rx-mode-descriptor"), + } + + typedDescr := &adapter.RxModeDescriptor{ + Name: RxModeDescriptorName, + KeySelector: ctx.IsInterfaceRxModeKey, + // proto message Interface is only used as container for RxMode + ValueTypeName: proto.MessageName(&interfaces.Interface{}), + ValueComparator: ctx.EquivalentRxMode, + Validate: ctx.Validate, + Create: ctx.Create, + Update: ctx.Update, + Delete: ctx.Delete, + Dependencies: ctx.Dependencies, + } + + return adapter.NewRxModeDescriptor(typedDescr) +} + +// IsInterfaceRxModeKey returns true if the key is identifying RxMode configuration. +func (d *RxModeDescriptor) IsInterfaceRxModeKey(key string) bool { + _, isValid := interfaces.ParseRxModeKey(key) + return isValid +} + +// EquivalentRxMode compares Rx modes for equivalency. +func (d *RxModeDescriptor) EquivalentRxMode(key string, oldIntf, newIntf *interfaces.Interface) bool { + /* Note: default Rx mode cannot be dumped - compare only if these are two NB + configurations (not a refreshed, i.e. dumped, value). + */ + oldDefMode := getDefaultRxMode(oldIntf) + newDefMode := getDefaultRxMode(newIntf) + if oldDefMode != interfaces.Interface_RxMode_UNKNOWN && + newDefMode != interfaces.Interface_RxMode_UNKNOWN { + if oldDefMode != newDefMode { + return false + } + } + // compare queue-specific RX modes + for _, rxMode := range oldIntf.GetRxMode() { + if rxMode.DefaultMode { + continue + } + oldMode := normalizeRxMode(rxMode.Mode, oldIntf) + newMode := getQueueRxMode(rxMode.Queue, newIntf) + if oldMode != newMode { + return false + } + } + for _, rxMode := range newIntf.GetRxMode() { + if rxMode.DefaultMode { + continue + } + newMode := normalizeRxMode(rxMode.Mode, newIntf) + oldMode := getQueueRxMode(rxMode.Queue, oldIntf) + if oldMode != newMode { + return false + } + } + return true +} + +// Validate validates Rx mode configuration. +func (d *RxModeDescriptor) Validate(key string, ifaceWithRxMode *interfaces.Interface) error { + for i, rxMode1 := range ifaceWithRxMode.GetRxMode() { + if rxMode1.Mode == interfaces.Interface_RxMode_UNKNOWN { + if rxMode1.DefaultMode { + return kvs.NewInvalidValueError(ErrUndefinedRxMode,"rx_mode[default]") + } + return kvs.NewInvalidValueError(ErrUndefinedRxMode, + fmt.Sprintf("rx_mode[.queue=%d]", rxMode1.Queue)) + } + for j := i + 1; j < len(ifaceWithRxMode.GetRxMode()); j++ { + rxMode2 := ifaceWithRxMode.GetRxMode()[j] + if rxMode1.DefaultMode != rxMode2.DefaultMode { + continue + } + if rxMode1.DefaultMode { + return kvs.NewInvalidValueError(ErrRedefinedRxMode,"rx_mode[default]") + } + if rxMode1.Queue == rxMode2.Queue { + return kvs.NewInvalidValueError(ErrRedefinedRxMode, + fmt.Sprintf("rx_mode[.queue=%d]", rxMode1.Queue)) + } + } + } + + if ifaceWithRxMode.GetType() == interfaces.Interface_DPDK { + for _, rxMode := range ifaceWithRxMode.GetRxMode() { + mode := normalizeRxMode(rxMode.Mode, ifaceWithRxMode) + if mode != interfaces.Interface_RxMode_POLLING { + if rxMode.DefaultMode { + return kvs.NewInvalidValueError(ErrUnsupportedRxMode, + "rx_mode[default]") + } + return kvs.NewInvalidValueError(ErrUnsupportedRxMode, + fmt.Sprintf("rx_mode[.queue=%d]", rxMode.Queue)) + } + } + } + return nil +} + +// Create configures RxMode for a given interface. +// Please note the proto message Interface is only used as container for RxMode. +// Only interface name, type and Rx mode are set. +func (d *RxModeDescriptor) Create(key string, ifaceWithRxMode *interfaces.Interface) (metadata interface{}, err error) { + err = d.configureRxMode(ifaceWithRxMode, kvs.TxnOperation_CREATE) + return nil, err +} + +// Update modifies Rx mode configuration. +func (d *RxModeDescriptor) Update(key string, _, ifaceWithRxMode *interfaces.Interface, + oldMetadata interface{}) (newMetadata interface{}, err error) { + + err = d.configureRxMode(ifaceWithRxMode, kvs.TxnOperation_UPDATE) + return nil, err +} + +// Delete reverts back to the default rx mode configuration. +func (d *RxModeDescriptor) Delete(key string, ifaceWithRxMode *interfaces.Interface, metadata interface{}) error { + return d.configureRxMode(ifaceWithRxMode, kvs.TxnOperation_DELETE) +} + +// configureRxMode (re-)configures Rx mode for the interface. +func (d *RxModeDescriptor) configureRxMode(iface *interfaces.Interface, op kvs.TxnOperation) (err error) { + + ifMeta, found := d.ifIndex.LookupByName(iface.Name) + if !found { + err = errors.Errorf("failed to find interface %s", iface.Name) + d.log.Error(err) + return err + } + ifIdx := ifMeta.SwIfIndex + + defRxMode := getDefaultRxMode(iface) + + // first, revert back to default for all queues + revertToDefault := op == kvs.TxnOperation_DELETE || + (op == kvs.TxnOperation_UPDATE && defRxMode == interfaces.Interface_RxMode_UNKNOWN) + if revertToDefault { + err = d.ifHandler.SetRxMode(ifIdx, &interfaces.Interface_RxMode{ + DefaultMode: true, + Mode: normalizeRxMode(interfaces.Interface_RxMode_DEFAULT, iface), + }) + if err != nil { + // treat error as warning here + d.log.Warn(err) + err = nil + } + } + + if op == kvs.TxnOperation_DELETE { + return + } + + // configure the requested default Rx mode + if defRxMode != interfaces.Interface_RxMode_UNKNOWN { + err = d.ifHandler.SetRxMode(ifIdx, &interfaces.Interface_RxMode{ + DefaultMode: true, + Mode: defRxMode, + }) + if err != nil { + err = errors.Errorf("failed to set default Rx-mode for interface %s: %v", iface.Name, err) + d.log.Error(err) + return err + } + } + + // configure per-queue RX mode + for _, rxMode := range iface.GetRxMode() { + if rxMode.DefaultMode || rxMode.Mode == defRxMode { + continue + } + err = d.ifHandler.SetRxMode(ifIdx, rxMode) + if err != nil { + err = errors.Errorf("failed to set Rx-mode for queue %d of the interface %s: %v", + rxMode.Queue, iface.Name, err) + d.log.Error(err) + return err + } + } + + return nil +} + +// Dependencies informs scheduler that Rx mode configuration cannot be applied +// until the interface link is UP. +func (d *RxModeDescriptor) Dependencies(key string, ifaceWithRxMode *interfaces.Interface) (deps []kvs.Dependency) { + return []kvs.Dependency{ + { + Label: linkIsUpDep, + Key: interfaces.LinkStateKey(ifaceWithRxMode.Name, true), + }, + } +} + +// getDefaultRxMode reads default RX mode from the interface configuration. +func getDefaultRxMode(iface *interfaces.Interface) (rxMode interfaces.Interface_RxMode_Type) { + for _, rxMode := range iface.GetRxMode() { + if rxMode.DefaultMode { + return normalizeRxMode(rxMode.Mode, iface) + } + } + return interfaces.Interface_RxMode_UNKNOWN +} + +// getQueueRxMode reads RX mode for the given queue from the interface configuration. +func getQueueRxMode(queue uint32, iface *interfaces.Interface) (mode interfaces.Interface_RxMode_Type) { + for _, rxMode := range iface.GetRxMode() { + if rxMode.DefaultMode { + mode = rxMode.Mode + continue // keep looking for a queue-specific RX mode + } + if rxMode.Queue == queue { + mode = rxMode.Mode + break + } + } + return normalizeRxMode(mode, iface) +} + +// normalizeRxMode resolves default/undefined Rx mode for specific interfaces. +func normalizeRxMode(mode interfaces.Interface_RxMode_Type, iface *interfaces.Interface) interfaces.Interface_RxMode_Type { + if mode != interfaces.Interface_RxMode_DEFAULT { + return mode + } + switch iface.GetType() { + case interfaces.Interface_DPDK: + return interfaces.Interface_RxMode_POLLING + case interfaces.Interface_AF_PACKET: + return interfaces.Interface_RxMode_INTERRUPT + case interfaces.Interface_TAP: + if iface.GetTap().GetVersion() == 2 { + // TAP v2 + return interfaces.Interface_RxMode_INTERRUPT + } + } + return mode +} diff --git a/plugins/vpp/ifplugin/descriptor/rx_placement.go b/plugins/vpp/ifplugin/descriptor/rx_placement.go new file mode 100644 index 0000000000..393e3b51ac --- /dev/null +++ b/plugins/vpp/ifplugin/descriptor/rx_placement.go @@ -0,0 +1,119 @@ +// Copyright (c) 2018 Cisco and/or its affiliates. +// +// 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 descriptor + +import ( + "github.com/pkg/errors" + "github.com/gogo/protobuf/proto" + "github.com/ligato/cn-infra/logging" + + interfaces "github.com/ligato/vpp-agent/api/models/vpp/interfaces" + kvs "github.com/ligato/vpp-agent/plugins/kvscheduler/api" + "github.com/ligato/vpp-agent/plugins/vpp/ifplugin/descriptor/adapter" + "github.com/ligato/vpp-agent/plugins/vpp/ifplugin/ifaceidx" + "github.com/ligato/vpp-agent/plugins/vpp/ifplugin/vppcalls" +) + +const ( + // RxPlacementDescriptorName is the name of the descriptor for the rx-placement + // config-subsection of VPP interfaces. + RxPlacementDescriptorName = "vpp-interface-rx-placement" +) + +// RxPlacementDescriptor configures Rx placement for VPP interface queues. +type RxPlacementDescriptor struct { + log logging.Logger + ifHandler vppcalls.InterfaceVppAPI + ifIndex ifaceidx.IfaceMetadataIndex +} + +// NewRxPlacementDescriptor creates a new instance of RxPlacementDescriptor. +func NewRxPlacementDescriptor(ifHandler vppcalls.InterfaceVppAPI, ifIndex ifaceidx.IfaceMetadataIndex, + log logging.PluginLogger) *kvs.KVDescriptor { + + ctx := &RxPlacementDescriptor{ + ifHandler: ifHandler, + ifIndex: ifIndex, + log: log.NewLogger("rx-placement-descriptor"), + } + + typedDescr := &adapter.RxPlacementDescriptor{ + Name: RxPlacementDescriptorName, + KeySelector: ctx.IsInterfaceRxPlacementKey, + ValueComparator: ctx.EquivalentRxPlacement, + ValueTypeName: proto.MessageName(&interfaces.Interface{}), + Create: ctx.Create, + Delete: ctx.Delete, + Dependencies: ctx.Dependencies, + } + + return adapter.NewRxPlacementDescriptor(typedDescr) +} + +// IsInterfaceRxPlacementKey returns true if the key is identifying RxPlacement +// configuration. +func (d *RxPlacementDescriptor) IsInterfaceRxPlacementKey(key string) bool { + _, _, isValid := interfaces.ParseRxPlacementKey(key) + return isValid +} + +// EquivalentRxMode compares Rx placements for equivalency. +func (d *RxPlacementDescriptor) EquivalentRxPlacement(key string, + oldRxPl, newRxPl *interfaces.Interface_RxPlacement) bool { + + if (oldRxPl.MainThread != newRxPl.MainThread) || + (!oldRxPl.MainThread && oldRxPl.Worker != newRxPl.Worker) { + return false + } + return true +} + +// Create configures RxPlacement for a given interface queue. +// Please note the proto message Interface is only used as container for RxMode. +// Only interface name, type and Rx mode are set. +func (d *RxPlacementDescriptor) Create(key string, rxPlacement *interfaces.Interface_RxPlacement) (metadata interface{}, err error) { + ifaceName, _, _ := interfaces.ParseRxPlacementKey(key) + ifMeta, found := d.ifIndex.LookupByName(ifaceName) + if !found { + err = errors.Errorf("failed to find interface %s", ifaceName) + d.log.Error(err) + return nil, err + } + + if err = d.ifHandler.SetRxPlacement(ifMeta.SwIfIndex, rxPlacement); err != nil { + err = errors.Errorf("failed to set rx-placement for queue %d of the interface %s: %v", + rxPlacement.Queue, ifaceName, err) + d.log.Error(err) + return nil, err + } + return nil, err +} + +// Delete is NOOP (Rx placement cannot be returned back to default). +func (d *RxPlacementDescriptor) Delete(key string, rxPlacement *interfaces.Interface_RxPlacement, metadata interface{}) error { + return nil +} + +// Dependencies informs scheduler that Rx placement configuration cannot be applied +// until the interface link is UP. +func (d *RxPlacementDescriptor) Dependencies(key string, rxPlacement *interfaces.Interface_RxPlacement) (deps []kvs.Dependency) { + ifaceName, _, _ := interfaces.ParseRxPlacementKey(key) + return []kvs.Dependency{ + { + Label: linkIsUpDep, + Key: interfaces.LinkStateKey(ifaceName, true), + }, + } +} \ No newline at end of file diff --git a/plugins/vpp/ifplugin/ifaceidx/ifaceidx.go b/plugins/vpp/ifplugin/ifaceidx/ifaceidx.go index 58c2d1da3a..5c19ceafcc 100644 --- a/plugins/vpp/ifplugin/ifaceidx/ifaceidx.go +++ b/plugins/vpp/ifplugin/ifaceidx/ifaceidx.go @@ -63,6 +63,7 @@ type IfaceMetadata struct { Vrf uint32 IPAddresses []string TAPHostIfName string /* host interface name set for the Linux-side of the TAP interface; empty for non-TAPs */ + LinkIsUp bool // Note: this is updated only on refresh! (i.e. suitable to use for Retrieve) } // GetIndex returns sw_if_index assigned to the interface. diff --git a/plugins/vpp/ifplugin/ifplugin.go b/plugins/vpp/ifplugin/ifplugin.go index 1e0193a3b4..782beca639 100644 --- a/plugins/vpp/ifplugin/ifplugin.go +++ b/plugins/vpp/ifplugin/ifplugin.go @@ -14,6 +14,8 @@ //go:generate descriptor-adapter --descriptor-name Interface --value-type *vpp_interfaces.Interface --meta-type *ifaceidx.IfaceMetadata --import "ifaceidx" --import "github.com/ligato/vpp-agent/api/models/vpp/interfaces" --output-dir "descriptor" //go:generate descriptor-adapter --descriptor-name Unnumbered --value-type *vpp_interfaces.Interface_Unnumbered --import "github.com/ligato/vpp-agent/api/models/vpp/interfaces" --output-dir "descriptor" +//go:generate descriptor-adapter --descriptor-name RxMode --value-type *vpp_interfaces.Interface --import "github.com/ligato/vpp-agent/api/models/vpp/interfaces" --output-dir "descriptor" +//go:generate descriptor-adapter --descriptor-name RxPlacement --value-type *vpp_interfaces.Interface_RxPlacement --import "github.com/ligato/vpp-agent/api/models/vpp/interfaces" --output-dir "descriptor" //go:generate descriptor-adapter --descriptor-name BondedInterface --value-type *vpp_interfaces.BondLink_BondedInterface --import "github.com/ligato/vpp-agent/api/models/vpp/interfaces" --output-dir "descriptor" package ifplugin @@ -78,7 +80,8 @@ type IfPlugin struct { dhcpIndex idxmap.NamedMapping // descriptors - dhcpDescriptor *descriptor.DHCPDescriptor + linkStateDescriptor *descriptor.LinkStateDescriptor + dhcpDescriptor *descriptor.DHCPDescriptor // from config file defaultMtu uint32 @@ -167,10 +170,17 @@ func (p *IfPlugin) Init() error { } ifaceDescrCtx.SetInterfaceIndex(p.intfIndex) - // -> descriptors for derived values - var dhcpDescriptor *kvs.KVDescriptor + // -> descriptors for derived values / notifications + var ( + linkStateDescriptor *kvs.KVDescriptor + dhcpDescriptor *kvs.KVDescriptor + ) dhcpDescriptor, p.dhcpDescriptor = descriptor.NewDHCPDescriptor(p.KVScheduler, p.ifHandler, p.intfIndex, p.Log) + linkStateDescriptor, p.linkStateDescriptor = descriptor.NewLinkStateDescriptor( + p.KVScheduler, p.intfIndex, p.Log) + rxModeDescriptor := descriptor.NewRxModeDescriptor(p.ifHandler, p.intfIndex, p.Log) + rxPlacementDescriptor := descriptor.NewRxPlacementDescriptor(p.ifHandler, p.intfIndex, p.Log) addrDescriptor := descriptor.NewInterfaceAddressDescriptor(p.ifHandler, p.intfIndex, p.Log) unIfDescriptor := descriptor.NewUnnumberedIfDescriptor(p.ifHandler, p.intfIndex, p.Log) bondIfDescriptor, _ := descriptor.NewBondedInterfaceDescriptor(p.ifHandler, p.intfIndex, p.Log) @@ -178,6 +188,9 @@ func (p *IfPlugin) Init() error { err = p.KVScheduler.RegisterKVDescriptor( dhcpDescriptor, + linkStateDescriptor, + rxModeDescriptor, + rxPlacementDescriptor, addrDescriptor, unIfDescriptor, bondIfDescriptor, @@ -201,43 +214,45 @@ func (p *IfPlugin) Init() error { p.wg.Add(1) go p.watchStatusEvents() + } - // start interface state publishing - p.wg.Add(1) - go p.publishIfStateEvents() - - // start interface state updater - p.ifStateChan = make(chan *interfaces.InterfaceNotification, 1000) - // Interface state updater - p.ifStateUpdater = &InterfaceStateUpdater{} - - var n int - var t time.Time - ifNotifHandler := func(state *interfaces.InterfaceNotification) { - select { - case p.ifStateChan <- state: - // OK - default: - // full - if time.Since(t) > time.Second { - p.Log.Debugf("ifStateChan channel is full (%d)", n) - n = 0 - } else { - n++ - } - t = time.Now() + // start interface state publishing + p.wg.Add(1) + go p.publishIfStateEvents() + + // start interface state updater + p.ifStateChan = make(chan *interfaces.InterfaceNotification, 1000) + // Interface state updater + p.ifStateUpdater = &InterfaceStateUpdater{} + + var n int + var t time.Time + ifNotifHandler := func(state *interfaces.InterfaceNotification) { + select { + case p.ifStateChan <- state: + // OK + default: + // full + if time.Since(t) > time.Second { + p.Log.Debugf("ifStateChan channel is full (%d)", n) + n = 0 + } else { + n++ } + t = time.Now() } + } - if err := p.ifStateUpdater.Init(p.ctx, p.Log, p.KVScheduler, p.GoVppmux, p.intfIndex, ifNotifHandler); err != nil { - return err - } + err = p.ifStateUpdater.Init(p.ctx, p.Log, p.KVScheduler, p.GoVppmux, p.intfIndex, + ifNotifHandler, p.publishStats) + if err != nil { + return err + } + if p.publishStats { if err = p.subscribeWatcher(); err != nil { return err } - - p.Log.Debug("ifStateUpdater Initialized") } return nil @@ -259,11 +274,9 @@ func (p *IfPlugin) subscribeWatcher() (err error) { // AfterInit delegates the call to ifStateUpdater. func (p *IfPlugin) AfterInit() error { - if p.publishStats { - err := p.ifStateUpdater.AfterInit() - if err != nil { - return err - } + err := p.ifStateUpdater.AfterInit() + if err != nil { + return err } if p.StatusCheck != nil { diff --git a/plugins/vpp/ifplugin/interface_state.go b/plugins/vpp/ifplugin/interface_state.go index 14031f56ec..b76fbbec6b 100644 --- a/plugins/vpp/ifplugin/interface_state.go +++ b/plugins/vpp/ifplugin/interface_state.go @@ -71,7 +71,7 @@ type InterfaceStateUpdater struct { // Init members (channels, maps...) and start go routines func (c *InterfaceStateUpdater) Init(ctx context.Context, logger logging.PluginLogger, kvScheduler kvs.KVScheduler, goVppMux govppmux.StatsAPI, swIfIndexes ifaceidx.IfaceMetadataIndex, - publishIfState func(notification *intf.InterfaceNotification)) (err error) { + publishIfState func(notification *intf.InterfaceNotification), readCounters bool) (err error) { // Logger c.log = logger.NewLogger("if-state") @@ -109,8 +109,10 @@ func (c *InterfaceStateUpdater) Init(ctx context.Context, logger logging.PluginL go c.watchVPPNotifications(childCtx) // Periodically read VPP counters and combined counters for VPP statistics - c.wg.Add(1) - go c.startReadingCounters(childCtx) + if readCounters { + c.wg.Add(1) + go c.startReadingCounters(childCtx) + } c.wg.Add(1) go c.startUpdatingIfStateDetails(childCtx) diff --git a/plugins/vpp/ifplugin/publish_state.go b/plugins/vpp/ifplugin/publish_state.go index bfca6c1de2..ebf729ee09 100644 --- a/plugins/vpp/ifplugin/publish_state.go +++ b/plugins/vpp/ifplugin/publish_state.go @@ -130,12 +130,15 @@ func (p *IfPlugin) publishIfStateEvents() { }) } - if p.PushNotification != nil && - (ifState.Type == interfaces.InterfaceNotification_UPDOWN || - ifState.State.OperStatus == interfaces.InterfaceState_DELETED) { - p.PushNotification(&vpp.Notification{ - Interface: ifState, - }) + if ifState.Type == interfaces.InterfaceNotification_UPDOWN || + ifState.State.OperStatus == interfaces.InterfaceState_DELETED { + + p.linkStateDescriptor.UpdateLinkState(ifState) + if p.PushNotification != nil { + p.PushNotification(&vpp.Notification{ + Interface: ifState, + }) + } } p.publishLock.Unlock() diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go index 4d348cb6c7..ec97d5b39d 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go @@ -750,8 +750,6 @@ func (h *InterfaceVppHandler) dumpRxPlacement(ifs map[uint32]*vppcalls.Interface break } - fmt.Printf("Received RX details: %+v\n", rxDetails) - ifData, ok := ifs[rxDetails.SwIfIndex] if !ok { h.log.Warnf("Received rx-placement data for unknown interface with index %d", rxDetails.SwIfIndex) From 6a7cecf8c8d85f08bd2e2d3f53ad18f34cb541b8 Mon Sep 17 00:00:00 2001 From: Milan Lenco Date: Thu, 16 May 2019 07:59:30 +0200 Subject: [PATCH 06/13] Update and add UTs for rx placement and rx mode Signed-off-by: Milan Lenco --- .../vpp1901/dump_interface_vppcalls_test.go | 116 ++++++++++++++++++ .../vppcalls/vpp1901/rx_mode_vppcalls_test.go | 48 ++++++-- .../vpp1901/rx_placement_vppcalls_test.go | 46 +++++-- .../vppcalls/vpp1904/rx_mode_vppcalls_test.go | 48 ++++++-- .../vpp1904/rx_placement_vppcalls_test.go | 46 +++++-- plugins/vpp/vppcallmock/vpp_ctx_mock.go | 4 +- 6 files changed, 257 insertions(+), 51 deletions(-) diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls_test.go b/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls_test.go index c460b9015d..a962e1a3e7 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls_test.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls_test.go @@ -18,6 +18,8 @@ import ( "net" "testing" + govppapi "git.fd.io/govpp.git/api" + interfaces2 "github.com/ligato/vpp-agent/api/models/vpp/interfaces" "github.com/ligato/vpp-agent/plugins/vpp/binapi/vpp1901/dhcp" "github.com/ligato/vpp-agent/plugins/vpp/binapi/vpp1901/interfaces" @@ -399,3 +401,117 @@ func TestDumpMemifSocketDetails(t *testing.T) { Expect(ok).To(BeTrue()) Expect(socketID).To(Equal(uint32(1))) } + +func TestDumpInterfacesRxPlacement(t *testing.T) { + ctx, ifHandler := ifTestSetup(t) + defer ctx.TeardownTestCtx() + + ctx.MockReplies([]*vppcallmock.HandleReplies{ + { + Name: (&interfaces.SwInterfaceDump{}).GetMessageName(), + Ping: true, + Message: &interfaces.SwInterfaceDetails{ + InterfaceName: []byte("memif1"), + }, + }, + { + Name: (&interfaces.SwInterfaceGetTable{}).GetMessageName(), + Ping: false, + Message: &interfaces.SwInterfaceGetTableReply{}, + }, + { + Name: (&ip.IPAddressDump{}).GetMessageName(), + Ping: true, + Message: &ip.IPAddressDetails{}, + }, + { + Name: (&memif.MemifSocketFilenameDump{}).GetMessageName(), + Ping: true, + Message: &memif.MemifSocketFilenameDetails{ + SocketID: 1, + SocketFilename: []byte("test"), + }, + }, + { + Name: (&memif.MemifDump{}).GetMessageName(), + Ping: true, + Message: &memif.MemifDetails{ + ID: 2, + SwIfIndex: 0, + Role: 1, // Slave + Mode: 1, // IP + SocketID: 1, + RingSize: 0, + BufferSize: 0, + }, + }, + { + Name: (&tap.SwInterfaceTapDump{}).GetMessageName(), + Ping: true, + }, + { + Name: (&tapv2.SwInterfaceTapV2Dump{}).GetMessageName(), + Ping: true, + }, + { + Name: (&vxlan.VxlanTunnelDump{}).GetMessageName(), + Ping: true, + }, + { + Name: (&interfaces.SwInterfaceRxPlacementDump{}).GetMessageName(), + Ping: true, + Messages: []govppapi.Message{ + &interfaces.SwInterfaceRxPlacementDetails{ + SwIfIndex: 0, + QueueID: 0, + WorkerID: 0, // main thread + Mode: 3, // adaptive + }, + &interfaces.SwInterfaceRxPlacementDetails{ + SwIfIndex: 0, + QueueID: 1, + WorkerID: 1, // worker 0 + Mode: 2, // interrupt + }, + &interfaces.SwInterfaceRxPlacementDetails{ + SwIfIndex: 0, + QueueID: 2, + WorkerID: 2, // worker 1 + Mode: 1, // polling + }, + }, + }, + }) + + intfs, err := ifHandler.DumpInterfaces() + Expect(err).To(BeNil()) + Expect(intfs).To(HaveLen(1)) + intface := intfs[0].Interface + + // Check memif + Expect(intface.GetMemif().SocketFilename).To(Equal("test")) + Expect(intface.GetMemif().Id).To(Equal(uint32(2))) + Expect(intface.GetMemif().Mode).To(Equal(interfaces2.MemifLink_IP)) + Expect(intface.GetMemif().Master).To(BeFalse()) + + rxMode := intface.GetRxMode() + Expect(rxMode).To(HaveLen(3)) + Expect(rxMode[0].Queue).To(BeEquivalentTo(0)) + Expect(rxMode[0].Mode).To(BeEquivalentTo(interfaces2.Interface_RxMode_ADAPTIVE)) + Expect(rxMode[1].Queue).To(BeEquivalentTo(1)) + Expect(rxMode[1].Mode).To(BeEquivalentTo(interfaces2.Interface_RxMode_INTERRUPT)) + Expect(rxMode[2].Queue).To(BeEquivalentTo(2)) + Expect(rxMode[2].Mode).To(BeEquivalentTo(interfaces2.Interface_RxMode_POLLING)) + + rxPlacement := intface.GetRxPlacement() + Expect(rxPlacement).To(HaveLen(3)) + Expect(rxPlacement[0].Queue).To(BeEquivalentTo(0)) + Expect(rxPlacement[0].MainThread).To(BeTrue()) + Expect(rxPlacement[0].Worker).To(BeEquivalentTo(0)) + Expect(rxPlacement[1].Queue).To(BeEquivalentTo(1)) + Expect(rxPlacement[1].MainThread).To(BeFalse()) + Expect(rxPlacement[1].Worker).To(BeEquivalentTo(0)) + Expect(rxPlacement[2].Queue).To(BeEquivalentTo(2)) + Expect(rxPlacement[2].MainThread).To(BeFalse()) + Expect(rxPlacement[2].Worker).To(BeEquivalentTo(1)) +} diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_mode_vppcalls_test.go b/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_mode_vppcalls_test.go index 09ad96048f..5b6eae7fbd 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_mode_vppcalls_test.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_mode_vppcalls_test.go @@ -28,10 +28,10 @@ func TestSetRxMode(t *testing.T) { ctx.MockVpp.MockReply(&interfaces.SwInterfaceSetRxModeReply{}) - err := ifHandler.SetRxMode(1, &ifModel.Interface_RxModeSettings{ - RxMode: ifModel.Interface_RxModeSettings_DEFAULT, - QueueId: 1, - QueueIdValid: 2, + err := ifHandler.SetRxMode(1, &ifModel.Interface_RxMode{ + Mode: ifModel.Interface_RxMode_DEFAULT, + Queue: 1, + DefaultMode: false, }) Expect(err).To(BeNil()) @@ -40,7 +40,7 @@ func TestSetRxMode(t *testing.T) { Expect(vppMsg.SwIfIndex).To(BeEquivalentTo(1)) Expect(vppMsg.Mode).To(BeEquivalentTo(4)) Expect(vppMsg.QueueID).To(BeEquivalentTo(1)) - Expect(vppMsg.QueueIDValid).To(BeEquivalentTo(2)) + Expect(vppMsg.QueueIDValid).To(BeEquivalentTo(1)) } func TestSetRxModeError(t *testing.T) { @@ -49,10 +49,10 @@ func TestSetRxModeError(t *testing.T) { ctx.MockVpp.MockReply(&interfaces.SwInterfaceSetRxMode{}) - err := ifHandler.SetRxMode(1, &ifModel.Interface_RxModeSettings{ - RxMode: ifModel.Interface_RxModeSettings_DEFAULT, - QueueId: 1, - QueueIdValid: 2, + err := ifHandler.SetRxMode(1, &ifModel.Interface_RxMode{ + Mode: ifModel.Interface_RxMode_DEFAULT, + Queue: 1, + DefaultMode: false, }) Expect(err).ToNot(BeNil()) @@ -66,11 +66,33 @@ func TestSetRxModeRetval(t *testing.T) { Retval: 1, }) - err := ifHandler.SetRxMode(1, &ifModel.Interface_RxModeSettings{ - RxMode: ifModel.Interface_RxModeSettings_DEFAULT, - QueueId: 1, - QueueIdValid: 2, + err := ifHandler.SetRxMode(1, &ifModel.Interface_RxMode{ + Mode: ifModel.Interface_RxMode_DEFAULT, + Queue: 1, + DefaultMode: false, }) Expect(err).ToNot(BeNil()) } + + +func TestSetDefaultRxMode(t *testing.T) { + ctx, ifHandler := ifTestSetup(t) + defer ctx.TeardownTestCtx() + + ctx.MockVpp.MockReply(&interfaces.SwInterfaceSetRxModeReply{}) + + err := ifHandler.SetRxMode(5, &ifModel.Interface_RxMode{ + Mode: ifModel.Interface_RxMode_POLLING, + Queue: 10, // ignored on the VPP side + DefaultMode: true, + }) + + Expect(err).To(BeNil()) + vppMsg, ok := ctx.MockChannel.Msg.(*interfaces.SwInterfaceSetRxMode) + Expect(ok).To(BeTrue()) + Expect(vppMsg.SwIfIndex).To(BeEquivalentTo(5)) + Expect(vppMsg.Mode).To(BeEquivalentTo(1)) + Expect(vppMsg.QueueID).To(BeEquivalentTo(10)) + Expect(vppMsg.QueueIDValid).To(BeEquivalentTo(0)) +} \ No newline at end of file diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_placement_vppcalls_test.go b/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_placement_vppcalls_test.go index 3985d7049b..5886d5db2d 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_placement_vppcalls_test.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1901/rx_placement_vppcalls_test.go @@ -23,23 +23,45 @@ import ( . "github.com/onsi/gomega" ) -func TestSetRxPlacement(t *testing.T) { +func TestSetRxPlacementForWorker(t *testing.T) { ctx, ifHandler := ifTestSetup(t) defer ctx.TeardownTestCtx() ctx.MockVpp.MockReply(&ifApi.SwInterfaceSetRxPlacementReply{}) - err := ifHandler.SetRxPlacement(1, &interfaces.Interface_RxPlacementSettings{ - Queue: 1, - Worker: 2, - IsMain: true, + err := ifHandler.SetRxPlacement(1, &interfaces.Interface_RxPlacement{ + Queue: 1, + Worker: 2, + MainThread: false, }) Expect(err).To(BeNil()) vppMsg, ok := ctx.MockChannel.Msg.(*ifApi.SwInterfaceSetRxPlacement) Expect(ok).To(BeTrue()) + Expect(vppMsg.SwIfIndex).To(BeEquivalentTo(1)) Expect(vppMsg.QueueID).To(BeEquivalentTo(1)) Expect(vppMsg.WorkerID).To(BeEquivalentTo(uint32(2))) + Expect(vppMsg.IsMain).To(BeEquivalentTo(uint32(0))) +} + +func TestSetRxPlacementForMainThread(t *testing.T) { + ctx, ifHandler := ifTestSetup(t) + defer ctx.TeardownTestCtx() + + ctx.MockVpp.MockReply(&ifApi.SwInterfaceSetRxPlacementReply{}) + + err := ifHandler.SetRxPlacement(3, &interfaces.Interface_RxPlacement{ + Queue: 6, + Worker: 2, // ignored on the VPP side + MainThread: true, + }) + + Expect(err).To(BeNil()) + vppMsg, ok := ctx.MockChannel.Msg.(*ifApi.SwInterfaceSetRxPlacement) + Expect(ok).To(BeTrue()) + Expect(vppMsg.SwIfIndex).To(BeEquivalentTo(3)) + Expect(vppMsg.QueueID).To(BeEquivalentTo(6)) + Expect(vppMsg.WorkerID).To(BeEquivalentTo(uint32(2))) Expect(vppMsg.IsMain).To(BeEquivalentTo(uint32(1))) } @@ -51,9 +73,10 @@ func TestSetRxPlacementRetval(t *testing.T) { Retval: 1, }) - err := ifHandler.SetRxPlacement(1, &interfaces.Interface_RxPlacementSettings{ - Queue: 1, - Worker: 2, + err := ifHandler.SetRxPlacement(1, &interfaces.Interface_RxPlacement{ + Queue: 1, + Worker: 2, + MainThread: false, }) Expect(err).ToNot(BeNil()) @@ -65,9 +88,10 @@ func TestSetRxPlacementError(t *testing.T) { ctx.MockVpp.MockReply(&ifApi.SwInterfaceSetRxPlacement{}) - err := ifHandler.SetRxPlacement(1, &interfaces.Interface_RxPlacementSettings{ - Queue: 1, - Worker: 2, + err := ifHandler.SetRxPlacement(1, &interfaces.Interface_RxPlacement{ + Queue: 1, + Worker: 2, + MainThread: false, }) Expect(err).ToNot(BeNil()) diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_mode_vppcalls_test.go b/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_mode_vppcalls_test.go index 974676a5eb..a486b941f5 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_mode_vppcalls_test.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_mode_vppcalls_test.go @@ -28,10 +28,10 @@ func TestSetRxMode(t *testing.T) { ctx.MockVpp.MockReply(&interfaces.SwInterfaceSetRxModeReply{}) - err := ifHandler.SetRxMode(1, &ifModel.Interface_RxModeSettings{ - RxMode: ifModel.Interface_RxModeSettings_DEFAULT, - QueueId: 1, - QueueIdValid: 2, + err := ifHandler.SetRxMode(1, &ifModel.Interface_RxMode{ + Mode: ifModel.Interface_RxMode_DEFAULT, + Queue: 1, + DefaultMode: false, }) Expect(err).To(BeNil()) @@ -40,7 +40,7 @@ func TestSetRxMode(t *testing.T) { Expect(vppMsg.SwIfIndex).To(BeEquivalentTo(1)) Expect(vppMsg.Mode).To(BeEquivalentTo(4)) Expect(vppMsg.QueueID).To(BeEquivalentTo(1)) - Expect(vppMsg.QueueIDValid).To(BeEquivalentTo(2)) + Expect(vppMsg.QueueIDValid).To(BeEquivalentTo(1)) } func TestSetRxModeError(t *testing.T) { @@ -49,10 +49,10 @@ func TestSetRxModeError(t *testing.T) { ctx.MockVpp.MockReply(&interfaces.SwInterfaceSetRxMode{}) - err := ifHandler.SetRxMode(1, &ifModel.Interface_RxModeSettings{ - RxMode: ifModel.Interface_RxModeSettings_DEFAULT, - QueueId: 1, - QueueIdValid: 2, + err := ifHandler.SetRxMode(1, &ifModel.Interface_RxMode{ + Mode: ifModel.Interface_RxMode_DEFAULT, + Queue: 1, + DefaultMode: false, }) Expect(err).ToNot(BeNil()) @@ -66,11 +66,33 @@ func TestSetRxModeRetval(t *testing.T) { Retval: 1, }) - err := ifHandler.SetRxMode(1, &ifModel.Interface_RxModeSettings{ - RxMode: ifModel.Interface_RxModeSettings_DEFAULT, - QueueId: 1, - QueueIdValid: 2, + err := ifHandler.SetRxMode(1, &ifModel.Interface_RxMode{ + Mode: ifModel.Interface_RxMode_DEFAULT, + Queue: 1, + DefaultMode: false, }) Expect(err).ToNot(BeNil()) } + + +func TestSetDefaultRxMode(t *testing.T) { + ctx, ifHandler := ifTestSetup(t) + defer ctx.TeardownTestCtx() + + ctx.MockVpp.MockReply(&interfaces.SwInterfaceSetRxModeReply{}) + + err := ifHandler.SetRxMode(5, &ifModel.Interface_RxMode{ + Mode: ifModel.Interface_RxMode_POLLING, + Queue: 10, // ignored on the VPP side + DefaultMode: true, + }) + + Expect(err).To(BeNil()) + vppMsg, ok := ctx.MockChannel.Msg.(*interfaces.SwInterfaceSetRxMode) + Expect(ok).To(BeTrue()) + Expect(vppMsg.SwIfIndex).To(BeEquivalentTo(5)) + Expect(vppMsg.Mode).To(BeEquivalentTo(1)) + Expect(vppMsg.QueueID).To(BeEquivalentTo(10)) + Expect(vppMsg.QueueIDValid).To(BeEquivalentTo(0)) +} \ No newline at end of file diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_placement_vppcalls_test.go b/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_placement_vppcalls_test.go index d86f544d36..d1db7af174 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_placement_vppcalls_test.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1904/rx_placement_vppcalls_test.go @@ -23,23 +23,45 @@ import ( . "github.com/onsi/gomega" ) -func TestSetRxPlacement(t *testing.T) { +func TestSetRxPlacementForWorker(t *testing.T) { ctx, ifHandler := ifTestSetup(t) defer ctx.TeardownTestCtx() ctx.MockVpp.MockReply(&ifApi.SwInterfaceSetRxPlacementReply{}) - err := ifHandler.SetRxPlacement(1, &interfaces.Interface_RxPlacementSettings{ - Queue: 1, - Worker: 2, - IsMain: true, + err := ifHandler.SetRxPlacement(1, &interfaces.Interface_RxPlacement{ + Queue: 1, + Worker: 2, + MainThread: false, }) Expect(err).To(BeNil()) vppMsg, ok := ctx.MockChannel.Msg.(*ifApi.SwInterfaceSetRxPlacement) Expect(ok).To(BeTrue()) + Expect(vppMsg.SwIfIndex).To(BeEquivalentTo(1)) Expect(vppMsg.QueueID).To(BeEquivalentTo(1)) Expect(vppMsg.WorkerID).To(BeEquivalentTo(uint32(2))) + Expect(vppMsg.IsMain).To(BeEquivalentTo(uint32(0))) +} + +func TestSetRxPlacementForMainThread(t *testing.T) { + ctx, ifHandler := ifTestSetup(t) + defer ctx.TeardownTestCtx() + + ctx.MockVpp.MockReply(&ifApi.SwInterfaceSetRxPlacementReply{}) + + err := ifHandler.SetRxPlacement(3, &interfaces.Interface_RxPlacement{ + Queue: 6, + Worker: 2, // ignored on the VPP side + MainThread: true, + }) + + Expect(err).To(BeNil()) + vppMsg, ok := ctx.MockChannel.Msg.(*ifApi.SwInterfaceSetRxPlacement) + Expect(ok).To(BeTrue()) + Expect(vppMsg.SwIfIndex).To(BeEquivalentTo(3)) + Expect(vppMsg.QueueID).To(BeEquivalentTo(6)) + Expect(vppMsg.WorkerID).To(BeEquivalentTo(uint32(2))) Expect(vppMsg.IsMain).To(BeEquivalentTo(uint32(1))) } @@ -51,9 +73,10 @@ func TestSetRxPlacementRetval(t *testing.T) { Retval: 1, }) - err := ifHandler.SetRxPlacement(1, &interfaces.Interface_RxPlacementSettings{ - Queue: 1, - Worker: 2, + err := ifHandler.SetRxPlacement(1, &interfaces.Interface_RxPlacement{ + Queue: 1, + Worker: 2, + MainThread: false, }) Expect(err).ToNot(BeNil()) @@ -65,9 +88,10 @@ func TestSetRxPlacementError(t *testing.T) { ctx.MockVpp.MockReply(&ifApi.SwInterfaceSetRxPlacement{}) - err := ifHandler.SetRxPlacement(1, &interfaces.Interface_RxPlacementSettings{ - Queue: 1, - Worker: 2, + err := ifHandler.SetRxPlacement(1, &interfaces.Interface_RxPlacement{ + Queue: 1, + Worker: 2, + MainThread: false, }) Expect(err).ToNot(BeNil()) diff --git a/plugins/vpp/vppcallmock/vpp_ctx_mock.go b/plugins/vpp/vppcallmock/vpp_ctx_mock.go index a95157444c..1693587cc5 100644 --- a/plugins/vpp/vppcallmock/vpp_ctx_mock.go +++ b/plugins/vpp/vppcallmock/vpp_ctx_mock.go @@ -165,9 +165,7 @@ func (ctx *TestCtx) MockReplies(dataList []*HandleReplies) { sendControlPing = dataMock.Ping if len(dataMock.Messages) > 0 { log.DefaultLogger().Infof(" MOCK HANDLER: mocking %d messages", len(dataMock.Messages)) - for _, msg := range dataMock.Messages { - ctx.MockVpp.MockReply(msg) - } + ctx.MockVpp.MockReply(dataMock.Messages...) return nil, 0, false } if dataMock.Message == nil { From c79e9a0f6ba478f130c257e0ce68efe705d470b1 Mon Sep 17 00:00:00 2001 From: Milan Lenco Date: Thu, 16 May 2019 08:00:03 +0200 Subject: [PATCH 07/13] Adapter for rx mode descriptor Signed-off-by: Milan Lenco --- .../vpp/ifplugin/descriptor/adapter/rxmode.go | 233 ++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100644 plugins/vpp/ifplugin/descriptor/adapter/rxmode.go diff --git a/plugins/vpp/ifplugin/descriptor/adapter/rxmode.go b/plugins/vpp/ifplugin/descriptor/adapter/rxmode.go new file mode 100644 index 0000000000..93612a9c6a --- /dev/null +++ b/plugins/vpp/ifplugin/descriptor/adapter/rxmode.go @@ -0,0 +1,233 @@ +// Code generated by adapter-generator. DO NOT EDIT. + +package adapter + +import ( + "github.com/gogo/protobuf/proto" + . "github.com/ligato/vpp-agent/plugins/kvscheduler/api" + "github.com/ligato/vpp-agent/api/models/vpp/interfaces" +) + +////////// type-safe key-value pair with metadata ////////// + +type RxModeKVWithMetadata struct { + Key string + Value *vpp_interfaces.Interface + Metadata interface{} + Origin ValueOrigin +} + +////////// type-safe Descriptor structure ////////// + +type RxModeDescriptor struct { + Name string + KeySelector KeySelector + ValueTypeName string + KeyLabel func(key string) string + ValueComparator func(key string, oldValue, newValue *vpp_interfaces.Interface) bool + NBKeyPrefix string + WithMetadata bool + MetadataMapFactory MetadataMapFactory + Validate func(key string, value *vpp_interfaces.Interface) error + Create func(key string, value *vpp_interfaces.Interface) (metadata interface{}, err error) + Delete func(key string, value *vpp_interfaces.Interface, metadata interface{}) error + Update func(key string, oldValue, newValue *vpp_interfaces.Interface, oldMetadata interface{}) (newMetadata interface{}, err error) + UpdateWithRecreate func(key string, oldValue, newValue *vpp_interfaces.Interface, metadata interface{}) bool + Retrieve func(correlate []RxModeKVWithMetadata) ([]RxModeKVWithMetadata, error) + IsRetriableFailure func(err error) bool + DerivedValues func(key string, value *vpp_interfaces.Interface) []KeyValuePair + Dependencies func(key string, value *vpp_interfaces.Interface) []Dependency + RetrieveDependencies []string /* descriptor name */ +} + +////////// Descriptor adapter ////////// + +type RxModeDescriptorAdapter struct { + descriptor *RxModeDescriptor +} + +func NewRxModeDescriptor(typedDescriptor *RxModeDescriptor) *KVDescriptor { + adapter := &RxModeDescriptorAdapter{descriptor: typedDescriptor} + descriptor := &KVDescriptor{ + Name: typedDescriptor.Name, + KeySelector: typedDescriptor.KeySelector, + ValueTypeName: typedDescriptor.ValueTypeName, + KeyLabel: typedDescriptor.KeyLabel, + NBKeyPrefix: typedDescriptor.NBKeyPrefix, + WithMetadata: typedDescriptor.WithMetadata, + MetadataMapFactory: typedDescriptor.MetadataMapFactory, + IsRetriableFailure: typedDescriptor.IsRetriableFailure, + RetrieveDependencies: typedDescriptor.RetrieveDependencies, + } + if typedDescriptor.ValueComparator != nil { + descriptor.ValueComparator = adapter.ValueComparator + } + if typedDescriptor.Validate != nil { + descriptor.Validate = adapter.Validate + } + if typedDescriptor.Create != nil { + descriptor.Create = adapter.Create + } + if typedDescriptor.Delete != nil { + descriptor.Delete = adapter.Delete + } + if typedDescriptor.Update != nil { + descriptor.Update = adapter.Update + } + if typedDescriptor.UpdateWithRecreate != nil { + descriptor.UpdateWithRecreate = adapter.UpdateWithRecreate + } + if typedDescriptor.Retrieve != nil { + descriptor.Retrieve = adapter.Retrieve + } + if typedDescriptor.Dependencies != nil { + descriptor.Dependencies = adapter.Dependencies + } + if typedDescriptor.DerivedValues != nil { + descriptor.DerivedValues = adapter.DerivedValues + } + return descriptor +} + +func (da *RxModeDescriptorAdapter) ValueComparator(key string, oldValue, newValue proto.Message) bool { + typedOldValue, err1 := castRxModeValue(key, oldValue) + typedNewValue, err2 := castRxModeValue(key, newValue) + if err1 != nil || err2 != nil { + return false + } + return da.descriptor.ValueComparator(key, typedOldValue, typedNewValue) +} + +func (da *RxModeDescriptorAdapter) Validate(key string, value proto.Message) (err error) { + typedValue, err := castRxModeValue(key, value) + if err != nil { + return err + } + return da.descriptor.Validate(key, typedValue) +} + +func (da *RxModeDescriptorAdapter) Create(key string, value proto.Message) (metadata Metadata, err error) { + typedValue, err := castRxModeValue(key, value) + if err != nil { + return nil, err + } + return da.descriptor.Create(key, typedValue) +} + +func (da *RxModeDescriptorAdapter) Update(key string, oldValue, newValue proto.Message, oldMetadata Metadata) (newMetadata Metadata, err error) { + oldTypedValue, err := castRxModeValue(key, oldValue) + if err != nil { + return nil, err + } + newTypedValue, err := castRxModeValue(key, newValue) + if err != nil { + return nil, err + } + typedOldMetadata, err := castRxModeMetadata(key, oldMetadata) + if err != nil { + return nil, err + } + return da.descriptor.Update(key, oldTypedValue, newTypedValue, typedOldMetadata) +} + +func (da *RxModeDescriptorAdapter) Delete(key string, value proto.Message, metadata Metadata) error { + typedValue, err := castRxModeValue(key, value) + if err != nil { + return err + } + typedMetadata, err := castRxModeMetadata(key, metadata) + if err != nil { + return err + } + return da.descriptor.Delete(key, typedValue, typedMetadata) +} + +func (da *RxModeDescriptorAdapter) UpdateWithRecreate(key string, oldValue, newValue proto.Message, metadata Metadata) bool { + oldTypedValue, err := castRxModeValue(key, oldValue) + if err != nil { + return true + } + newTypedValue, err := castRxModeValue(key, newValue) + if err != nil { + return true + } + typedMetadata, err := castRxModeMetadata(key, metadata) + if err != nil { + return true + } + return da.descriptor.UpdateWithRecreate(key, oldTypedValue, newTypedValue, typedMetadata) +} + +func (da *RxModeDescriptorAdapter) Retrieve(correlate []KVWithMetadata) ([]KVWithMetadata, error) { + var correlateWithType []RxModeKVWithMetadata + for _, kvpair := range correlate { + typedValue, err := castRxModeValue(kvpair.Key, kvpair.Value) + if err != nil { + continue + } + typedMetadata, err := castRxModeMetadata(kvpair.Key, kvpair.Metadata) + if err != nil { + continue + } + correlateWithType = append(correlateWithType, + RxModeKVWithMetadata{ + Key: kvpair.Key, + Value: typedValue, + Metadata: typedMetadata, + Origin: kvpair.Origin, + }) + } + + typedValues, err := da.descriptor.Retrieve(correlateWithType) + if err != nil { + return nil, err + } + var values []KVWithMetadata + for _, typedKVWithMetadata := range typedValues { + kvWithMetadata := KVWithMetadata{ + Key: typedKVWithMetadata.Key, + Metadata: typedKVWithMetadata.Metadata, + Origin: typedKVWithMetadata.Origin, + } + kvWithMetadata.Value = typedKVWithMetadata.Value + values = append(values, kvWithMetadata) + } + return values, err +} + +func (da *RxModeDescriptorAdapter) DerivedValues(key string, value proto.Message) []KeyValuePair { + typedValue, err := castRxModeValue(key, value) + if err != nil { + return nil + } + return da.descriptor.DerivedValues(key, typedValue) +} + +func (da *RxModeDescriptorAdapter) Dependencies(key string, value proto.Message) []Dependency { + typedValue, err := castRxModeValue(key, value) + if err != nil { + return nil + } + return da.descriptor.Dependencies(key, typedValue) +} + +////////// Helper methods ////////// + +func castRxModeValue(key string, value proto.Message) (*vpp_interfaces.Interface, error) { + typedValue, ok := value.(*vpp_interfaces.Interface) + if !ok { + return nil, ErrInvalidValueType(key, value) + } + return typedValue, nil +} + +func castRxModeMetadata(key string, metadata Metadata) (interface{}, error) { + if metadata == nil { + return nil, nil + } + typedMetadata, ok := metadata.(interface{}) + if !ok { + return nil, ErrInvalidMetadataType(key) + } + return typedMetadata, nil +} From bac1fe918161d3221b9dfd72bf6ad42bce636102 Mon Sep 17 00:00:00 2001 From: Milan Lenco Date: Thu, 16 May 2019 15:39:15 +0200 Subject: [PATCH 08/13] Bug fixing txn post-processing in kvscheduler. Signed-off-by: Milan Lenco --- docs/kvscheduler/cfd/af_packet_interface.md | 2 +- plugins/kvscheduler/api/kv_scheduler_api.go | 4 +- plugins/kvscheduler/notification_test.go | 26 +- plugins/kvscheduler/plugin_scheduler.go | 20 +- plugins/kvscheduler/txn_exec.go | 1 + plugins/kvscheduler/txn_process.go | 222 +++++++++--------- plugins/linux/ifplugin/descriptor/watcher.go | 9 +- .../linux/nsplugin/descriptor/microservice.go | 19 +- plugins/vpp/ifplugin/descriptor/dhcp.go | 16 +- .../vpp/ifplugin/descriptor/interface_crud.go | 25 ++ plugins/vpp/ifplugin/descriptor/link_state.go | 100 ++++++-- plugins/vpp/ifplugin/descriptor/rx_mode.go | 3 +- plugins/vpp/ifplugin/ifplugin.go | 2 +- plugins/vpp/ifplugin/vppcalls/if_vppcalls.go | 8 + .../vpp1901/dump_interface_vppcalls.go | 38 +++ .../vpp1904/dump_interface_vppcalls.go | 38 +++ 16 files changed, 364 insertions(+), 169 deletions(-) diff --git a/docs/kvscheduler/cfd/af_packet_interface.md b/docs/kvscheduler/cfd/af_packet_interface.md index 145b59ce5b..085a763862 100644 --- a/docs/kvscheduler/cfd/af_packet_interface.md +++ b/docs/kvscheduler/cfd/af_packet_interface.md @@ -13,7 +13,7 @@ a pre-existing physical device or interface created by an external process or an administrator during the agent run-time. In such cases, however, there would be no key-value pair to reference from within `AF-Packet` dependencies. Therefore, KVScheduler allows to notify about external objects through -`PushSBNotification(key, value, metadata)` method. Values received through +`PushSBNotification(notification...)` method. Values received through notifications are denoted as `OBTAINED` and will not be removed by resync even though they are not requested to be configured by NB. Obtained values are allowed to have their own descriptors, but from the CRUD operations only diff --git a/plugins/kvscheduler/api/kv_scheduler_api.go b/plugins/kvscheduler/api/kv_scheduler_api.go index bf15d7430f..97219b05aa 100644 --- a/plugins/kvscheduler/api/kv_scheduler_api.go +++ b/plugins/kvscheduler/api/kv_scheduler_api.go @@ -225,7 +225,9 @@ type KVScheduler interface { // however. For example, notifications for values already created by NB // are ignored. But otherwise, SB values (not managed by NB) are untouched // by reconciliation or any other operation of the scheduler/descriptor. - PushSBNotification(key string, value proto.Message, metadata Metadata) error + // Note: Origin in KVWithMetadata is ignored and can be left unset + // (automatically assumed to be FromSB). + PushSBNotification(notif... KVWithMetadata) error // GetMetadataMap returns (read-only) map associating value label with value // metadata of a given descriptor. diff --git a/plugins/kvscheduler/notification_test.go b/plugins/kvscheduler/notification_test.go index 2d12769e11..68afd16185 100644 --- a/plugins/kvscheduler/notification_test.go +++ b/plugins/kvscheduler/notification_test.go @@ -215,8 +215,11 @@ func TestNotifications(t *testing.T) { // send notification startTime = time.Now() mockSB.SetValue(prefixA+baseValue1, test.NewArrayValue("item1"), &test.OnlyInteger{Integer: 10}, FromSB, false) - notifError := scheduler.PushSBNotification(prefixA+baseValue1, test.NewArrayValue("item1"), - &test.OnlyInteger{Integer: 10}) + notifError := scheduler.PushSBNotification(KVWithMetadata{ + Key: prefixA+baseValue1, + Value: test.NewArrayValue("item1"), + Metadata: &test.OnlyInteger{Integer: 10}, + }) Expect(notifError).ShouldNot(HaveOccurred()) // wait until the notification is processed @@ -434,8 +437,10 @@ func TestNotifications(t *testing.T) { // send 2nd notification startTime = time.Now() mockSB.SetValue(prefixA+baseValue1, test.NewArrayValue("item1", "item2"), &test.OnlyInteger{Integer: 11}, FromSB, false) - notifError = scheduler.PushSBNotification(prefixA+baseValue1, test.NewArrayValue("item1", "item2"), - &test.OnlyInteger{Integer: 11}) + notifError = scheduler.PushSBNotification(KVWithMetadata{ + Key: prefixA+baseValue1, + Value: test.NewArrayValue("item1", "item2"), + Metadata: &test.OnlyInteger{Integer: 11}}) Expect(notifError).ShouldNot(HaveOccurred()) // wait until the notification is processed @@ -589,7 +594,11 @@ func TestNotifications(t *testing.T) { // send 3rd notification startTime = time.Now() mockSB.SetValue(prefixA+baseValue1, nil, nil, FromSB, false) - notifError = scheduler.PushSBNotification(prefixA+baseValue1, nil, nil) + notifError = scheduler.PushSBNotification(KVWithMetadata{ + Key: prefixA+baseValue1, + Value: nil, + Metadata: nil, + }) Expect(notifError).ShouldNot(HaveOccurred()) // wait until the notification is processed @@ -847,8 +856,11 @@ func TestNotificationsWithRetry(t *testing.T) { // send notification startTime := time.Now() - notifError := scheduler.PushSBNotification(prefixA+baseValue1, test.NewArrayValue("item1", "item2"), - &test.OnlyInteger{Integer: 10}) + notifError := scheduler.PushSBNotification(KVWithMetadata{ + Key: prefixA+baseValue1, + Value: test.NewArrayValue("item1", "item2"), + Metadata: &test.OnlyInteger{Integer: 10}, + }) Expect(notifError).ShouldNot(HaveOccurred()) // wait until the notification is processed diff --git a/plugins/kvscheduler/plugin_scheduler.go b/plugins/kvscheduler/plugin_scheduler.go index c29d6b6b7e..c5e9bcaaa2 100644 --- a/plugins/kvscheduler/plugin_scheduler.go +++ b/plugins/kvscheduler/plugin_scheduler.go @@ -286,19 +286,19 @@ func (s *Scheduler) TransactionBarrier() { s.txnLock.Unlock() } -// PushSBNotification notifies about a spontaneous value change in the SB +// PushSBNotification notifies about a spontaneous value change(s) in the SB // plane (i.e. not triggered by NB transaction). -func (s *Scheduler) PushSBNotification(key string, value proto.Message, metadata kvs.Metadata) error { +func (s *Scheduler) PushSBNotification(notif... kvs.KVWithMetadata) error { txn := &transaction{ txnType: kvs.SBNotification, - values: []kvForTxn{ - { - key: key, - value: value, - metadata: metadata, - origin: kvs.FromSB, - }, - }, + } + for _, value := range notif { + txn.values = append(txn.values, kvForTxn{ + key: value.Key, + value: value.Value, + metadata: value.Metadata, + origin: kvs.FromSB, + }) } return s.enqueueTxn(txn) } diff --git a/plugins/kvscheduler/txn_exec.go b/plugins/kvscheduler/txn_exec.go index b7d666a466..794f94d023 100644 --- a/plugins/kvscheduler/txn_exec.go +++ b/plugins/kvscheduler/txn_exec.go @@ -558,6 +558,7 @@ func (s *Scheduler) applyUpdate(node graph.NodeRW, txnOp *kvs.RecordedTxnOp, arg return } // create the new revision of the value + node = args.graphW.SetNode(args.kv.key) createOp := s.preRecordTxnOp(args, node) createOp.Operation = kvs.TxnOperation_CREATE createOp.PrevValue = nil diff --git a/plugins/kvscheduler/txn_process.go b/plugins/kvscheduler/txn_process.go index 747f78cab5..fae5ff1ec9 100644 --- a/plugins/kvscheduler/txn_process.go +++ b/plugins/kvscheduler/txn_process.go @@ -311,7 +311,8 @@ func (s *Scheduler) postProcessTransaction(txn *transaction, executed kvs.Record toRetry := utils.NewSliceBasedKeySet() toRefresh := utils.NewSliceBasedKeySet() - var verboseRefresh bool + var afterErrRefresh bool + var kvErrors []kvs.KeyWithError graphR := s.graph.Read() for _, op := range executed { node := graphR.GetNode(op.Key) @@ -325,12 +326,12 @@ func (s *Scheduler) postProcessTransaction(txn *transaction, executed kvs.Record } if state == kvs.ValueState_FAILED { toRefresh.Add(baseKey) - verboseRefresh = true + afterErrRefresh = true } if state == kvs.ValueState_RETRYING { toRefresh.Add(baseKey) toRetry.Add(baseKey) - verboseRefresh = true + afterErrRefresh = true } if s.verifyMode { toRefresh.Add(baseKey) @@ -341,52 +342,15 @@ func (s *Scheduler) postProcessTransaction(txn *transaction, executed kvs.Record // refresh base values which themselves are in a failed state or have derived failed values // - in verifyMode all updated values are re-freshed if toRefresh.Length() > 0 { - graphW := s.graph.Write(true,false) - s.refreshGraph(graphW, toRefresh, nil, verboseRefresh) - - // split values based on the retry metadata - retryTxns := make(map[retryTxnMeta]*retryTxn) - for _, retryKey := range toRetry.Iterate() { - node := graphW.GetNode(retryKey) - lastUpdate := getNodeLastUpdate(node) - // did retry fail? - var alreadyRetried bool - if txn.txnType == kvs.RetryFailedOps { - _, alreadyRetried = txn.retry.keys[retryKey] - } - // determine how long to delay the retry - delay := lastUpdate.retryArgs.Period - if alreadyRetried && lastUpdate.retryArgs.ExpBackoff { - delay = txn.retry.delay * 2 - } - // determine which attempt this is - attempt := 1 - if alreadyRetried { - attempt = txn.retry.attempt + 1 - } - // determine which transaction this retry is for - seqNum := txn.seqNum - if alreadyRetried { - seqNum = txn.retry.txnSeqNum - } - // add key into the set to retry within a single transaction - retryMeta := retryTxnMeta{ - txnSeqNum: seqNum, - delay: delay, - attempt: attempt, - } - if _, has := retryTxns[retryMeta]; !has { - retryTxns[retryMeta] = &retryTxn{ - retryTxnMeta: retryMeta, - keys: make(map[string]uint64), - } - } - retryTxns[retryMeta].keys[retryKey] = lastUpdate.txnSeqNum - } + // changes brought by refresh triggered solely for the verification are + // not saved into the graph + graphW := s.graph.Write(afterErrRefresh,false) + s.refreshGraph(graphW, toRefresh, nil, afterErrRefresh) + s.scheduleRetries(txn, graphW, toRetry) - // schedule a series of re-try transactions for failed values - for _, retryTxn := range retryTxns { - s.enqueueRetry(retryTxn) + // if enabled, verify transaction effects + if s.verifyMode { + kvErrors = s.verifyTransaction(graphW, executed) } graphW.Release() } @@ -407,63 +371,6 @@ func (s *Scheduler) postProcessTransaction(txn *transaction, executed kvs.Record // clear the set of updated states s.updatedStates = utils.NewSliceBasedKeySet() - // if enabled, verify transaction effects - var kvErrors []kvs.KeyWithError - if s.verifyMode { - graphR = s.graph.Read() - for _, op := range executed { - key := op.Key - node := graphR.GetNode(key) - if node == nil { - continue - } - state := getNodeState(node) - if state == kvs.ValueState_RETRYING || state == kvs.ValueState_FAILED { - // effects of failed operations are uncertain and cannot be therefore verified - continue - } - expValue := getNodeLastAppliedValue(node) - lastOp := getNodeLastOperation(node) - expToNotExist := expValue == nil || state == kvs.ValueState_PENDING || state == kvs.ValueState_INVALID - if expToNotExist && isNodeAvailable(node) { - kvErrors = append(kvErrors, kvs.KeyWithError{ - Key: key, - Error: kvs.NewVerificationError(key, kvs.ExpectedToNotExist), - TxnOperation: lastOp, - }) - continue - } - if expValue == nil { - // properly removed - continue - } - if !expToNotExist && !isNodeAvailable(node) { - kvErrors = append(kvErrors, kvs.KeyWithError{ - Key: key, - Error: kvs.NewVerificationError(key, kvs.ExpectedToExist), - TxnOperation: lastOp, - }) - continue - } - descriptor := s.registry.GetDescriptorForKey(key) - handler := newDescriptorHandler(descriptor) - equivalent := handler.equivalentValues(key, node.GetValue(), expValue) - if !equivalent { - kvErrors = append(kvErrors, kvs.KeyWithError{ - Key: key, - Error: kvs.NewVerificationError(key, kvs.NotEquivalent), - TxnOperation: lastOp, - }) - s.Log.WithFields( - logging.Fields{ - "applied": expValue, - "refreshed": node.GetValue(), - }).Warn("Detected non-equivalent applied vs. refreshed values") - } - } - graphR.Release() - } - // build transaction error var txnErr error for _, txnOp := range executed { @@ -521,6 +428,111 @@ func (s *Scheduler) postProcessTransaction(txn *transaction, executed kvs.Record } } +// scheduleRetries schedules a series of re-try transactions for failed values +func (s *Scheduler) scheduleRetries(txn *transaction, graphR graph.ReadAccess, toRetry utils.KeySet,) { + // split values based on the retry metadata + retryTxns := make(map[retryTxnMeta]*retryTxn) + for _, retryKey := range toRetry.Iterate() { + node := graphR.GetNode(retryKey) + lastUpdate := getNodeLastUpdate(node) + // did retry fail? + var alreadyRetried bool + if txn.txnType == kvs.RetryFailedOps { + _, alreadyRetried = txn.retry.keys[retryKey] + } + // determine how long to delay the retry + delay := lastUpdate.retryArgs.Period + if alreadyRetried && lastUpdate.retryArgs.ExpBackoff { + delay = txn.retry.delay * 2 + } + // determine which attempt this is + attempt := 1 + if alreadyRetried { + attempt = txn.retry.attempt + 1 + } + // determine which transaction this retry is for + seqNum := txn.seqNum + if alreadyRetried { + seqNum = txn.retry.txnSeqNum + } + // add key into the set to retry within a single transaction + retryMeta := retryTxnMeta{ + txnSeqNum: seqNum, + delay: delay, + attempt: attempt, + } + if _, has := retryTxns[retryMeta]; !has { + retryTxns[retryMeta] = &retryTxn{ + retryTxnMeta: retryMeta, + keys: make(map[string]uint64), + } + } + retryTxns[retryMeta].keys[retryKey] = lastUpdate.txnSeqNum + } + + // schedule a series of re-try transactions for failed values + for _, retryTxn := range retryTxns { + s.enqueueRetry(retryTxn) + } +} + +// verifyTransaction verifies if the effect of the transaction is as expected. +func (s *Scheduler) verifyTransaction(graphR graph.ReadAccess, executed kvs.RecordedTxnOps) (kvErrors []kvs.KeyWithError) { + for _, op := range executed { + key := op.Key + node := graphR.GetNode(key) + if node == nil { + continue + } + state := getNodeState(node) + if state == kvs.ValueState_RETRYING || state == kvs.ValueState_FAILED { + // effects of failed operations are uncertain and cannot be therefore verified + continue + } + + expValue := getNodeLastAppliedValue(node) + lastOp := getNodeLastOperation(node) + + expToNotExist := expValue == nil || state == kvs.ValueState_PENDING || state == kvs.ValueState_INVALID + if expToNotExist && isNodeAvailable(node) { + kvErrors = append(kvErrors, kvs.KeyWithError{ + Key: key, + Error: kvs.NewVerificationError(key, kvs.ExpectedToNotExist), + TxnOperation: lastOp, + }) + continue + } + if expValue == nil { + // properly removed + continue + } + if !expToNotExist && !isNodeAvailable(node) { + kvErrors = append(kvErrors, kvs.KeyWithError{ + Key: key, + Error: kvs.NewVerificationError(key, kvs.ExpectedToExist), + TxnOperation: lastOp, + }) + continue + } + descriptor := s.registry.GetDescriptorForKey(key) + handler := newDescriptorHandler(descriptor) + equivalent := handler.equivalentValues(key, node.GetValue(), expValue) + if !equivalent { + kvErrors = append(kvErrors, kvs.KeyWithError{ + Key: key, + Error: kvs.NewVerificationError(key, kvs.NotEquivalent), + TxnOperation: lastOp, + }) + s.Log.WithFields( + logging.Fields{ + "applied": expValue, + "refreshed": node.GetValue(), + }).Warn("Detected non-equivalent applied vs. refreshed values") + } + } + return +} + // filterNotification checks if the received notification should be filtered // or normally applied. func (s *Scheduler) filterNotification(graphR graph.ReadAccess, key string, value proto.Message, txnSeqNum uint64) bool { diff --git a/plugins/linux/ifplugin/descriptor/watcher.go b/plugins/linux/ifplugin/descriptor/watcher.go index 7a09288fcb..f1bd40e5dc 100644 --- a/plugins/linux/ifplugin/descriptor/watcher.go +++ b/plugins/linux/ifplugin/descriptor/watcher.go @@ -251,10 +251,11 @@ func (w *InterfaceWatcher) notifyScheduler(ifName string, enabled bool) { delete(w.ifaces, ifName) } - w.kvscheduler.PushSBNotification( - ifmodel.InterfaceHostNameKey(ifName), - value, - nil) + w.kvscheduler.PushSBNotification(kvs.KVWithMetadata{ + Key: ifmodel.InterfaceHostNameKey(ifName), + Value: value, + Metadata: nil, + }) } func (w *InterfaceWatcher) needsUpdate(ifName string, isEnabled bool) bool { diff --git a/plugins/linux/nsplugin/descriptor/microservice.go b/plugins/linux/nsplugin/descriptor/microservice.go index a40c857026..ad3708ae80 100644 --- a/plugins/linux/nsplugin/descriptor/microservice.go +++ b/plugins/linux/nsplugin/descriptor/microservice.go @@ -297,10 +297,12 @@ func (d *MicroserviceDescriptor) processNewMicroservice(microserviceLabel string // Notify scheduler about new microservice if d.msStateInSync { - d.kvscheduler.PushSBNotification( - nsmodel.MicroserviceKey(ms.Label), - &prototypes.Empty{}, - nil) + d.kvscheduler.PushSBNotification(kvs.KVWithMetadata{ + Key: nsmodel.MicroserviceKey(ms.Label), + Value: &prototypes.Empty{}, + Metadata: nil, + + }) } } @@ -321,10 +323,11 @@ func (d *MicroserviceDescriptor) processTerminatedMicroservice(id string) { // Notify scheduler about terminated microservice if d.msStateInSync { - d.kvscheduler.PushSBNotification( - nsmodel.MicroserviceKey(ms.Label), - nil, - nil) + d.kvscheduler.PushSBNotification(kvs.KVWithMetadata{ + Key: nsmodel.MicroserviceKey(ms.Label), + Value: nil, + Metadata: nil, + }) } } diff --git a/plugins/vpp/ifplugin/descriptor/dhcp.go b/plugins/vpp/ifplugin/descriptor/dhcp.go index ca469820ed..06486e7b28 100644 --- a/plugins/vpp/ifplugin/descriptor/dhcp.go +++ b/plugins/vpp/ifplugin/descriptor/dhcp.go @@ -150,8 +150,11 @@ func (d *DHCPDescriptor) Delete(key string, emptyVal proto.Message, metadata kvs } // notify about the unconfigured client by removing the lease notification - return d.kvscheduler.PushSBNotification( - interfaces.DHCPLeaseKey(ifName), nil, nil) + return d.kvscheduler.PushSBNotification(kvs.KVWithMetadata{ + Key: interfaces.DHCPLeaseKey(ifName), + Value: nil, + Metadata: nil, + }) } // Retrieve returns all existing DHCP leases. @@ -239,10 +242,11 @@ func (d *DHCPDescriptor) watchDHCPNotifications(ctx context.Context) { HostIpAddress: lease.HostAddress, RouterIpAddress: lease.RouterAddress, } - if err := d.kvscheduler.PushSBNotification( - interfaces.DHCPLeaseKey(ifName), - dhcpLease, - dhcpLease); err != nil { + if err := d.kvscheduler.PushSBNotification(kvs.KVWithMetadata{ + Key: interfaces.DHCPLeaseKey(ifName), + Value: dhcpLease, + Metadata: dhcpLease, + }); err != nil { d.log.Error(err) } case <-ctx.Done(): diff --git a/plugins/vpp/ifplugin/descriptor/interface_crud.go b/plugins/vpp/ifplugin/descriptor/interface_crud.go index e8a6071056..fb9e2cfd17 100644 --- a/plugins/vpp/ifplugin/descriptor/interface_crud.go +++ b/plugins/vpp/ifplugin/descriptor/interface_crud.go @@ -419,6 +419,31 @@ func (d *InterfaceDescriptor) Retrieve(correlate []adapter.InterfaceKVWithMetada intf.Interface.GetMemif().BufferSize = expCfg.GetMemif().GetBufferSize() } } + + // remove rx-placement entries for queues with configuration not defined by NB + rxPlacementDump := intf.Interface.GetRxPlacement() + rxPlacementCfg := expCfg.GetRxPlacement() + for i := 0; i < len(rxPlacementDump); { + queue := rxPlacementDump[i].Queue + found := false + for j := 0; j < len(rxPlacementCfg); j++ { + if rxPlacementCfg[j].Queue == queue { + found = true + break + } + } + if found { + i++ + } else { + rxPlacementDump = append(rxPlacementDump[:i], rxPlacementDump[i+1:]...) + } + } + intf.Interface.RxPlacement = rxPlacementDump + + // remove rx-mode from the dump if it is not configured by NB + if len(expCfg.GetRxMode()) == 0 { + intf.Interface.RxMode = []*interfaces.Interface_RxMode{} + } } // verify links between VPP and Linux side diff --git a/plugins/vpp/ifplugin/descriptor/link_state.go b/plugins/vpp/ifplugin/descriptor/link_state.go index 0120a2c1f9..9129d295b4 100644 --- a/plugins/vpp/ifplugin/descriptor/link_state.go +++ b/plugins/vpp/ifplugin/descriptor/link_state.go @@ -15,12 +15,15 @@ package descriptor import ( + "sync" + prototypes "github.com/gogo/protobuf/types" "github.com/ligato/cn-infra/logging" interfaces "github.com/ligato/vpp-agent/api/models/vpp/interfaces" kvs "github.com/ligato/vpp-agent/plugins/kvscheduler/api" "github.com/ligato/vpp-agent/plugins/vpp/ifplugin/ifaceidx" + "github.com/ligato/vpp-agent/plugins/vpp/ifplugin/vppcalls" ) const ( @@ -33,25 +36,33 @@ const ( // interfaces. type LinkStateDescriptor struct { // input arguments - log logging.Logger - kvscheduler kvs.KVScheduler - ifaceIdx ifaceidx.IfaceMetadataIndex + log logging.Logger + kvscheduler kvs.KVScheduler + ifaceHandler vppcalls.InterfaceVppAPI + ifaceIdx ifaceidx.IfaceMetadataIndex + + linkStatesMx sync.Mutex + linkStates map[string]bool // interface name -> link is up } // NewLinkStateDescriptor creates a new instance of the Link-State descriptor. -func NewLinkStateDescriptor(kvscheduler kvs.KVScheduler, ifaceIdx ifaceidx.IfaceMetadataIndex, - log logging.PluginLogger) (descr *kvs.KVDescriptor, ctx *LinkStateDescriptor) { +func NewLinkStateDescriptor(kvscheduler kvs.KVScheduler, ifaceHandler vppcalls.InterfaceVppAPI, + ifaceIdx ifaceidx.IfaceMetadataIndex, log logging.PluginLogger) (descr *kvs.KVDescriptor, ctx *LinkStateDescriptor) { descrCtx := &LinkStateDescriptor{ log: log.NewLogger("interface-link-state"), kvscheduler: kvscheduler, + ifaceHandler: ifaceHandler, ifaceIdx: ifaceIdx, + linkStates: make(map[string]bool), } return &kvs.KVDescriptor{ Name: LinkStateDescriptorName, KeySelector: descrCtx.IsInterfaceLinkStateKey, Retrieve: descrCtx.Retrieve, - RetrieveDependencies: []string{InterfaceDescriptorName}, // link state read from interface metadata + // Retrieve depends on the interface descriptor: interface index is used + // to convert sw_if_index to logical interface name + RetrieveDependencies: []string{InterfaceDescriptorName}, }, descrCtx } @@ -65,10 +76,30 @@ func (w *LinkStateDescriptor) IsInterfaceLinkStateKey(key string) bool { // Retrieve returns key for every VPP interface describing the state of the link // (value is empty). func (w *LinkStateDescriptor) Retrieve(correlate []kvs.KVWithMetadata) (values []kvs.KVWithMetadata, err error) { - for _, ifaceName := range w.ifaceIdx.ListAllInterfaces() { - ifaceMeta, _ := w.ifaceIdx.LookupByName(ifaceName) + // TODO: avoid dumping interface details when it was already done in the interface + // descriptor within the same Refresh (e.g. during full resync) + // - e.g. add context to allow sharing of information across Retrieve-s of the same Refresh + + ifaceStates, err := w.ifaceHandler.DumpInterfaceStates() + if err != nil { + w.log.Error(err) + return nil, err + } + + w.linkStatesMx.Lock() + defer w.linkStatesMx.Unlock() + w.linkStates = make(map[string]bool) // clear the map + + for ifaceIdx, ifaceState := range ifaceStates { + ifaceName, _, found := w.ifaceIdx.LookupBySwIfIndex(ifaceIdx) + if !found { + // skip interface not configured by NB (e.g. untouched Gbe interface) + continue + } + linkIsUp := ifaceState.LinkState == interfaces.InterfaceState_UP + w.linkStates[ifaceName] = linkIsUp values = append(values, kvs.KVWithMetadata{ - Key: interfaces.LinkStateKey(ifaceName, ifaceMeta.LinkIsUp), + Key: interfaces.LinkStateKey(ifaceName, linkIsUp), Value: &prototypes.Empty{}, Origin: kvs.FromSB, }) @@ -79,24 +110,43 @@ func (w *LinkStateDescriptor) Retrieve(correlate []kvs.KVWithMetadata) (values [ // UpdateLinkState notifies scheduler about a change in the link state of an interface. func (w *LinkStateDescriptor) UpdateLinkState(ifaceState *interfaces.InterfaceNotification) { + w.linkStatesMx.Lock() + defer w.linkStatesMx.Unlock() + + var notifs []kvs.KVWithMetadata operStatus := ifaceState.State.OperStatus - if operStatus == interfaces.InterfaceState_DELETED || - operStatus == interfaces.InterfaceState_UNKNOWN_STATUS { - // interface link is neither up nor down - w.kvscheduler.PushSBNotification( - interfaces.LinkStateKey(ifaceState.State.Name, true), - nil, - nil) - w.kvscheduler.PushSBNotification( - interfaces.LinkStateKey(ifaceState.State.Name, false), - nil, - nil) - return + ifaceName := ifaceState.State.Name + linkWasUp, hadLinkState := w.linkStates[ifaceName] + linkIsUp := operStatus == interfaces.InterfaceState_UP + toDelete := operStatus == interfaces.InterfaceState_DELETED || + operStatus == interfaces.InterfaceState_UNKNOWN_STATUS + + if toDelete || (hadLinkState && (linkIsUp != linkWasUp)) { + if hadLinkState { + // remove now obsolete key-value pair + notifs = append(notifs, kvs.KVWithMetadata{ + Key: interfaces.LinkStateKey(ifaceState.State.Name, linkWasUp), + Value: nil, + Metadata: nil, + }) + } + } + + if !toDelete && (!hadLinkState || (linkIsUp != linkWasUp)) { + // push new key-value pair + notifs = append(notifs, kvs.KVWithMetadata{ + Key: interfaces.LinkStateKey(ifaceState.State.Name, linkIsUp), + Value: &prototypes.Empty{}, + Metadata: nil, + }) + w.linkStates[ifaceName] = linkIsUp } - w.kvscheduler.PushSBNotification( - interfaces.LinkStateKey(ifaceState.State.Name, operStatus == interfaces.InterfaceState_UP), - &prototypes.Empty{}, - nil) + if len(notifs) != 0 { + err := w.kvscheduler.PushSBNotification(notifs...) + if err != nil { + w.log.Errorf("failed to send notifications to KVScheduler: %v", err) + } + } } \ No newline at end of file diff --git a/plugins/vpp/ifplugin/descriptor/rx_mode.go b/plugins/vpp/ifplugin/descriptor/rx_mode.go index 3360b37d66..f416218cde 100644 --- a/plugins/vpp/ifplugin/descriptor/rx_mode.go +++ b/plugins/vpp/ifplugin/descriptor/rx_mode.go @@ -211,7 +211,8 @@ func (d *RxModeDescriptor) configureRxMode(iface *interfaces.Interface, op kvs.T }) if err != nil { // treat error as warning here - d.log.Warn(err) + d.log.Warnf("failed to un-configure Rx-mode (%v) - most likely "+ + "the interface is already without a link", err) err = nil } } diff --git a/plugins/vpp/ifplugin/ifplugin.go b/plugins/vpp/ifplugin/ifplugin.go index 782beca639..a0e41ba3de 100644 --- a/plugins/vpp/ifplugin/ifplugin.go +++ b/plugins/vpp/ifplugin/ifplugin.go @@ -178,7 +178,7 @@ func (p *IfPlugin) Init() error { dhcpDescriptor, p.dhcpDescriptor = descriptor.NewDHCPDescriptor(p.KVScheduler, p.ifHandler, p.intfIndex, p.Log) linkStateDescriptor, p.linkStateDescriptor = descriptor.NewLinkStateDescriptor( - p.KVScheduler, p.intfIndex, p.Log) + p.KVScheduler, p.ifHandler, p.intfIndex, p.Log) rxModeDescriptor := descriptor.NewRxModeDescriptor(p.ifHandler, p.intfIndex, p.Log) rxPlacementDescriptor := descriptor.NewRxPlacementDescriptor(p.ifHandler, p.intfIndex, p.Log) addrDescriptor := descriptor.NewInterfaceAddressDescriptor(p.ifHandler, p.intfIndex, p.Log) diff --git a/plugins/vpp/ifplugin/vppcalls/if_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/if_vppcalls.go index 08ff520df8..04d84dd4e2 100644 --- a/plugins/vpp/ifplugin/vppcalls/if_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/if_vppcalls.go @@ -87,6 +87,12 @@ type Lease struct { HostMac string } +// InterfaceState is a helper function grouping interface state data. +type InterfaceState struct { + AdminState interfaces.InterfaceState_Status + LinkState interfaces.InterfaceState_Status +} + // InterfaceVppAPI provides methods for creating and managing interface plugin type InterfaceVppAPI interface { InterfaceVppRead @@ -191,6 +197,8 @@ type InterfaceVppRead interface { DumpMemifSocketDetails() (map[string]uint32, error) // DumpDhcpClients dumps DHCP-related information for all interfaces. DumpDhcpClients() (map[uint32]*Dhcp, error) + // DumpInterfaceStates dumps link and administrative state of every interface. + DumpInterfaceStates() (map[uint32]*InterfaceState, error) // WatchInterfaceEvents starts watching for interface events. WatchInterfaceEvents(ch chan<- *InterfaceEvent) error // WatchDHCPLeases starts watching for DHCP leases. diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go index ec97d5b39d..4afd6067f4 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go @@ -336,6 +336,44 @@ func (h *InterfaceVppHandler) DumpDhcpClients() (map[uint32]*vppcalls.Dhcp, erro return dhcpData, nil } +// DumpInterfaceStates dumps link and administrative state of every interface. +func (h *InterfaceVppHandler) DumpInterfaceStates() (map[uint32]*vppcalls.InterfaceState, error) { + ifs := make(map[uint32]*vppcalls.InterfaceState) + + reqCtx := h.callsChannel.SendMultiRequest(&binapi_interface.SwInterfaceDump{}) + for { + ifDetails := &binapi_interface.SwInterfaceDetails{} + stop, err := reqCtx.ReceiveReply(ifDetails) + if stop { + break // Break from the loop. + } + if err != nil { + return nil, fmt.Errorf("failed to dump interface: %v", err) + } + + ifaceState := &vppcalls.InterfaceState{} + switch ifDetails.AdminUpDown { + case 0: + ifaceState.AdminState = interfaces.InterfaceState_DOWN + case 1: + ifaceState.AdminState = interfaces.InterfaceState_UP + default: + ifaceState.AdminState = interfaces.InterfaceState_UNKNOWN_STATUS + } + switch ifDetails.LinkUpDown { + case 0: + ifaceState.LinkState = interfaces.InterfaceState_DOWN + case 1: + ifaceState.LinkState = interfaces.InterfaceState_UP + default: + ifaceState.LinkState = interfaces.InterfaceState_UNKNOWN_STATUS + } + ifs[ifDetails.SwIfIndex] = ifaceState + } + + return ifs, nil +} + // Returns true if given interface contains at least one IPv6 address. For VxLAN, source and destination // addresses are also checked func (h *InterfaceVppHandler) isIpv6Interface(iface *interfaces.Interface) (bool, error) { diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls.go index 53eb4e7bad..522d02ad24 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls.go @@ -335,6 +335,44 @@ func (h *InterfaceVppHandler) DumpDhcpClients() (map[uint32]*vppcalls.Dhcp, erro return dhcpData, nil } +// DumpInterfaceStates dumps link and administrative state of every interface. +func (h *InterfaceVppHandler) DumpInterfaceStates() (map[uint32]*vppcalls.InterfaceState, error) { + ifs := make(map[uint32]*vppcalls.InterfaceState) + + reqCtx := h.callsChannel.SendMultiRequest(&binapi_interface.SwInterfaceDump{}) + for { + ifDetails := &binapi_interface.SwInterfaceDetails{} + stop, err := reqCtx.ReceiveReply(ifDetails) + if stop { + break // Break from the loop. + } + if err != nil { + return nil, fmt.Errorf("failed to dump interface: %v", err) + } + + ifaceState := &vppcalls.InterfaceState{} + switch ifDetails.AdminUpDown { + case 0: + ifaceState.AdminState = interfaces.InterfaceState_DOWN + case 1: + ifaceState.AdminState = interfaces.InterfaceState_UP + default: + ifaceState.AdminState = interfaces.InterfaceState_UNKNOWN_STATUS + } + switch ifDetails.LinkUpDown { + case 0: + ifaceState.LinkState = interfaces.InterfaceState_DOWN + case 1: + ifaceState.LinkState = interfaces.InterfaceState_UP + default: + ifaceState.LinkState = interfaces.InterfaceState_UNKNOWN_STATUS + } + ifs[ifDetails.SwIfIndex] = ifaceState + } + + return ifs, nil +} + // Returns true if given interface contains at least one IPv6 address. For VxLAN, source and destination // addresses are also checked func (h *InterfaceVppHandler) isIpv6Interface(iface *interfaces.Interface) (bool, error) { From b701372db6514108d8b0a52949aeebdca43b360b Mon Sep 17 00:00:00 2001 From: Milan Lenco Date: Thu, 16 May 2019 20:45:44 +0200 Subject: [PATCH 09/13] Add example for rx-placement and rx-mode. Signed-off-by: Milan Lenco --- examples/kvscheduler/rxplacement/govpp.conf | 4 + .../kvscheduler/rxplacement/kvscheduler.conf | 3 + examples/kvscheduler/rxplacement/main.go | 264 ++++++++++++++++++ 3 files changed, 271 insertions(+) create mode 100644 examples/kvscheduler/rxplacement/govpp.conf create mode 100644 examples/kvscheduler/rxplacement/kvscheduler.conf create mode 100644 examples/kvscheduler/rxplacement/main.go diff --git a/examples/kvscheduler/rxplacement/govpp.conf b/examples/kvscheduler/rxplacement/govpp.conf new file mode 100644 index 0000000000..35870c51bc --- /dev/null +++ b/examples/kvscheduler/rxplacement/govpp.conf @@ -0,0 +1,4 @@ +# Path to a Unix-domain socket through which configuration requests are sent to VPP. +# Used if connect-via-shm is set to false and env. variable GOVPPMUX_NOSOCK is not defined. +# Default is "/run/vpp-api.sock". +binapi-socket-path: /tmp/vpp1.sock diff --git a/examples/kvscheduler/rxplacement/kvscheduler.conf b/examples/kvscheduler/rxplacement/kvscheduler.conf new file mode 100644 index 0000000000..557749f3f4 --- /dev/null +++ b/examples/kvscheduler/rxplacement/kvscheduler.conf @@ -0,0 +1,3 @@ +enable-txn-simulation: true +record-transaction-history: true +print-txn-summary: true diff --git a/examples/kvscheduler/rxplacement/main.go b/examples/kvscheduler/rxplacement/main.go new file mode 100644 index 0000000000..60888ff4f0 --- /dev/null +++ b/examples/kvscheduler/rxplacement/main.go @@ -0,0 +1,264 @@ +// Copyright (c) 2019 Cisco and/or its affiliates. +// +// 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 main + +import ( + "fmt" + "log" + "time" + + "github.com/ligato/cn-infra/agent" + + "github.com/ligato/vpp-agent/api/models/vpp/interfaces" + "github.com/ligato/vpp-agent/clientv2/linux/localclient" + kvs "github.com/ligato/vpp-agent/plugins/kvscheduler" + kvs_api "github.com/ligato/vpp-agent/plugins/kvscheduler/api" + "github.com/ligato/vpp-agent/plugins/orchestrator" + vpp_ifplugin "github.com/ligato/vpp-agent/plugins/vpp/ifplugin" +) + +/* + * VPP1 (configured by this example): + - startup config: + unix { + interactive + cli-listen 0.0.0.0:5002 + cli-no-pager + coredump-size unlimited + full-coredump + poll-sleep-usec 50 + } + api-trace { + on + } + socksvr { + socket-name "/tmp/vpp1.sock" + } + statseg { + default + per-node-counters on + } + cpu { + workers 2 + } + + * VPP2 (configured manually to connect with myMemif): + - startup config: + unix { + interactive + cli-listen 0.0.0.0:5003 + cli-no-pager + coredump-size unlimited + full-coredump + poll-sleep-usec 50 + } + api-trace { + on + } + socksvr { + socket-name "/tmp/vpp2.sock" + } + statseg { + default + per-node-counters on + } + cpu { + workers 2 + } + + - configuration to be applied via CLI: + $ create interface memif id 0 slave rx-queues 5 tx-queues 5 + $ set int state memif0/0 up + $ set int ip address memif0/0 192.168.1.2/24 +*/ +func main() { + //vpp_ifplugin.DefaultPlugin.PublishStatistics = &Publisher{} + ep := &ExamplePlugin{ + KVScheduler: &kvs.DefaultPlugin, + VPPIfPlugin: &vpp_ifplugin.DefaultPlugin, + Orchestrator: &orchestrator.DefaultPlugin, + } + + a := agent.NewAgent( + agent.AllPlugins(ep), + ) + if err := a.Run(); err != nil { + log.Fatal(err) + } +} + +// ExamplePlugin is the main plugin which +// handles resync and changes in this example. +type ExamplePlugin struct { + KVScheduler *kvs.Scheduler + VPPIfPlugin *vpp_ifplugin.IfPlugin + Orchestrator *orchestrator.Plugin +} + +/* +type Publisher struct { +} + +func (p *Publisher) Put(key string, data proto.Message, opts ...datasync.PutOption) error { + fmt.Printf("Publishing key=%s, data=%+v\n", key, data) + return nil +} +*/ + +// String returns plugin name +func (p *ExamplePlugin) String() string { + return "rx-placement-example" +} + +// Init handles initialization phase. +func (p *ExamplePlugin) Init() error { + return nil +} + +// AfterInit handles phase after initialization. +func (p *ExamplePlugin) AfterInit() error { + ch := make(chan *kvs_api.BaseValueStatus, 100) + p.KVScheduler.WatchValueStatus(ch, nil) + go watchValueStatus(ch) + go testLocalClientWithScheduler(p.KVScheduler) + return nil +} + +// Close cleans up the resources. +func (p *ExamplePlugin) Close() error { + return nil +} + +func watchValueStatus(ch <-chan *kvs_api.BaseValueStatus) { + for { + select { + case status := <-ch: + fmt.Printf("Value status change: %v\n", status.String()) + } + } +} + +func testLocalClientWithScheduler(kvscheduler kvs_api.KVScheduler) { + // initial resync + time.Sleep(time.Second * 2) + fmt.Println("=== RESYNC WITH MEMIF ===") + + txn := localclient.DataResyncRequest("example") + err := txn. + VppInterface(myMemif). + Send().ReceiveReply() + if err != nil { + fmt.Println(err) + return + } + + // data change #1 + time.Sleep(time.Second * 10) + fmt.Println("=== CHANGE ===") + + myMemif.RxMode[0].Mode = vpp_interfaces.Interface_RxMode_INTERRUPT // change default + myMemif.RxMode = append(myMemif.RxMode, &vpp_interfaces.Interface_RxMode{ + Queue: 3, + Mode: vpp_interfaces.Interface_RxMode_POLLING, + }) + myMemif.RxPlacement = append(myMemif.RxPlacement, &vpp_interfaces.Interface_RxPlacement{ + Queue: 3, + MainThread: true, + Worker: 100, // ignored + }) + + txn2 := localclient.DataChangeRequest("example") + err = txn2.Put(). + VppInterface(myMemif). + Send().ReceiveReply() + if err != nil { + fmt.Println(err) + return + } + + // data change #2 + time.Sleep(time.Second * 20) + fmt.Println("=== CHANGE ===") + + myMemif.GetMemif().RxQueues = 5 + myMemif.GetMemif().TxQueues = 5 + myMemif.RxPlacement = append(myMemif.RxPlacement, &vpp_interfaces.Interface_RxPlacement{ + Queue: 4, + MainThread: true, + }) + + /* Re-create will fail - that is expected and it is due to the link-state key + being updated AFTER the transaction, not during. The subsequent retry/notification + should fix all the errors. + */ + + txn3 := localclient.DataChangeRequest("example") + err = txn3.Put(). + VppInterface(myMemif). // re-create + Send().ReceiveReply() + if err != nil { + fmt.Println(err) + return + } +} + +var ( + myMemif = &vpp_interfaces.Interface{ + Name: "my-memif", + Type: vpp_interfaces.Interface_MEMIF, + Enabled: true, + IpAddresses: []string{"192.168.1.1/24"}, + + RxPlacement: []*vpp_interfaces.Interface_RxPlacement{ + { + Queue: 0, + Worker: 0, + }, + { + Queue: 1, + MainThread: true, + }, + { + Queue: 2, + Worker: 1, + }, + }, + + RxMode: []*vpp_interfaces.Interface_RxMode{ + { + DefaultMode: true, + Mode: vpp_interfaces.Interface_RxMode_POLLING, + }, + { + Queue: 1, + Mode: vpp_interfaces.Interface_RxMode_INTERRUPT, + }, + { + Queue: 2, + Mode: vpp_interfaces.Interface_RxMode_INTERRUPT, + }, + }, + + Link: &vpp_interfaces.Interface_Memif{ + Memif: &vpp_interfaces.MemifLink{ + Mode: vpp_interfaces.MemifLink_ETHERNET, + Master: true, + Id: 0, + RxQueues: 4, + TxQueues: 4, + }, + }, + } +) From 9875d2bd6caf4b53bd1a512f091aa5ba0f0fddb8 Mon Sep 17 00:00:00 2001 From: Milan Lenco Date: Fri, 17 May 2019 10:49:54 +0200 Subject: [PATCH 10/13] Pluralize rx-mode and rx-placement Signed-off-by: Milan Lenco --- Makefile | 2 + api/models/vpp/interfaces/interface.pb.go | 248 +++++++++--------- api/models/vpp/interfaces/interface.proto | 4 +- examples/kvscheduler/rxplacement/main.go | 12 +- plugins/vpp/ifplugin/descriptor/interface.go | 16 +- .../vpp/ifplugin/descriptor/interface_crud.go | 10 +- plugins/vpp/ifplugin/descriptor/rx_mode.go | 18 +- .../vpp1901/dump_interface_vppcalls.go | 4 +- .../vpp1901/dump_interface_vppcalls_test.go | 4 +- .../vpp1904/dump_interface_vppcalls.go | 4 +- .../vpp1904/dump_interface_vppcalls_test.go | 112 ++++++++ 11 files changed, 274 insertions(+), 160 deletions(-) diff --git a/Makefile b/Makefile index 4d0101edf5..99607c3bde 100644 --- a/Makefile +++ b/Makefile @@ -66,7 +66,9 @@ examples: cd examples/kvscheduler/l2 && go build -tags="${GO_BUILD_TAGS}" ${GO_BUILD_ARGS} cd examples/kvscheduler/acl && go build -tags="${GO_BUILD_TAGS}" ${GO_BUILD_ARGS} cd examples/kvscheduler/nat && go build -tags="${GO_BUILD_TAGS}" ${GO_BUILD_ARGS} + cd examples/kvscheduler/rxplacement && go build -tags="${GO_BUILD_TAGS}" ${GO_BUILD_ARGS} cd examples/kvscheduler/vpp-l3 && go build -tags="${GO_BUILD_TAGS}" ${GO_BUILD_ARGS} + cd examples/kvscheduler/vrf && go build -tags="${GO_BUILD_TAGS}" ${GO_BUILD_ARGS} cd examples/localclient_linux/tap && go build -tags="${GO_BUILD_TAGS}" ${GO_BUILD_ARGS} cd examples/localclient_linux/veth && go build -tags="${GO_BUILD_TAGS}" ${GO_BUILD_ARGS} cd examples/localclient_vpp/nat && go build -tags="${GO_BUILD_TAGS}" ${GO_BUILD_ARGS} diff --git a/api/models/vpp/interfaces/interface.pb.go b/api/models/vpp/interfaces/interface.pb.go index d242cacf4b..fe6ddd4593 100644 --- a/api/models/vpp/interfaces/interface.pb.go +++ b/api/models/vpp/interfaces/interface.pb.go @@ -258,8 +258,8 @@ type Interface struct { SetDhcpClient bool `protobuf:"varint,7,opt,name=set_dhcp_client,json=setDhcpClient,proto3" json:"set_dhcp_client,omitempty"` Mtu uint32 `protobuf:"varint,8,opt,name=mtu,proto3" json:"mtu,omitempty"` Unnumbered *Interface_Unnumbered `protobuf:"bytes,9,opt,name=unnumbered,proto3" json:"unnumbered,omitempty"` - RxMode []*Interface_RxMode `protobuf:"bytes,10,rep,name=rx_mode,json=rxMode,proto3" json:"rx_mode,omitempty"` - RxPlacement []*Interface_RxPlacement `protobuf:"bytes,11,rep,name=rx_placement,json=rxPlacement,proto3" json:"rx_placement,omitempty"` + RxModes []*Interface_RxMode `protobuf:"bytes,10,rep,name=rx_modes,json=rxModes,proto3" json:"rx_modes,omitempty"` + RxPlacements []*Interface_RxPlacement `protobuf:"bytes,11,rep,name=rx_placements,json=rxPlacements,proto3" json:"rx_placements,omitempty"` // Types that are valid to be assigned to Link: // *Interface_Sub // *Interface_Memif @@ -407,16 +407,16 @@ func (m *Interface) GetUnnumbered() *Interface_Unnumbered { return nil } -func (m *Interface) GetRxMode() []*Interface_RxMode { +func (m *Interface) GetRxModes() []*Interface_RxMode { if m != nil { - return m.RxMode + return m.RxModes } return nil } -func (m *Interface) GetRxPlacement() []*Interface_RxPlacement { +func (m *Interface) GetRxPlacements() []*Interface_RxPlacement { if m != nil { - return m.RxPlacement + return m.RxPlacements } return nil } @@ -1554,123 +1554,123 @@ func init() { } var fileDescriptor_1ac7cab935c1dc4d = []byte{ - // 1875 bytes of a gzipped FileDescriptorProto + // 1880 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x57, 0xcd, 0x72, 0xe3, 0xc6, - 0x11, 0x16, 0x7f, 0x44, 0x12, 0xcd, 0x1f, 0x41, 0x13, 0xdb, 0xc1, 0xca, 0xbb, 0x36, 0xc3, 0x64, - 0x63, 0x55, 0x52, 0xa6, 0x56, 0x94, 0xab, 0x62, 0x27, 0x27, 0x90, 0x84, 0x2c, 0xae, 0x28, 0x90, - 0x01, 0xc1, 0xdd, 0x75, 0x2a, 0x55, 0x28, 0x10, 0x18, 0x82, 0x88, 0x40, 0x00, 0x0b, 0x0c, 0x29, - 0xca, 0x55, 0x79, 0x86, 0xdc, 0xf2, 0x3c, 0x39, 0xfa, 0x90, 0x4b, 0x8e, 0x39, 0xe7, 0x98, 0x63, - 0x5e, 0x20, 0x35, 0x3f, 0xa0, 0x28, 0xad, 0x64, 0x5f, 0xa4, 0xe9, 0xaf, 0xfb, 0x9b, 0x69, 0xf4, - 0x74, 0xf7, 0x34, 0xe1, 0xe5, 0x32, 0x72, 0x71, 0x90, 0x9e, 0xac, 0xe3, 0xf8, 0xc4, 0x0f, 0x09, - 0x4e, 0xe6, 0xb6, 0x83, 0xd3, 0xbb, 0x65, 0x3b, 0x4e, 0x22, 0x12, 0xa1, 0xc6, 0x3a, 0x8e, 0xdb, - 0x77, 0xfa, 0xa3, 0x2f, 0x3d, 0x9f, 0x2c, 0x56, 0xb3, 0xb6, 0x13, 0x2d, 0x4f, 0xbc, 0xc8, 0x8b, - 0x4e, 0x98, 0xd9, 0x6c, 0x35, 0x67, 0x12, 0x13, 0xd8, 0x8a, 0xd3, 0x8f, 0x9e, 0xef, 0x9e, 0x12, - 0xa7, 0xd8, 0xe1, 0x7f, 0xb9, 0xb6, 0xf5, 0xf7, 0x2a, 0x48, 0x83, 0x6c, 0x6f, 0x84, 0xa0, 0x18, - 0xda, 0x4b, 0xac, 0xe4, 0x9a, 0xb9, 0x63, 0xc9, 0x60, 0x6b, 0xd4, 0x81, 0x22, 0xb9, 0x8d, 0xb1, - 0x92, 0x6f, 0xe6, 0x8e, 0x1b, 0x9d, 0xcf, 0xda, 0xf7, 0xbd, 0x69, 0x6f, 0xc9, 0x6d, 0xf3, 0x36, - 0xc6, 0x06, 0xb3, 0x45, 0x0a, 0x94, 0x71, 0x68, 0xcf, 0x02, 0xec, 0x2a, 0x85, 0x66, 0xee, 0xb8, - 0x62, 0x64, 0x22, 0xfa, 0x05, 0xd4, 0xe2, 0xc5, 0x6d, 0x6a, 0xd9, 0xae, 0x9b, 0xe0, 0x34, 0x55, - 0x8a, 0xec, 0xa4, 0x2a, 0xc5, 0x54, 0x0e, 0x51, 0x13, 0x3f, 0xce, 0x0c, 0x70, 0xaa, 0xec, 0x37, - 0x0b, 0xd4, 0xc4, 0x8f, 0xd5, 0x0c, 0x42, 0x32, 0x14, 0xd6, 0xc9, 0x5c, 0x29, 0x35, 0x73, 0xc7, - 0x75, 0x83, 0x2e, 0xd1, 0xaf, 0xe1, 0x20, 0xc5, 0xc4, 0x72, 0x17, 0x4e, 0x6c, 0x39, 0x81, 0x8f, - 0x43, 0xa2, 0x94, 0xd9, 0xc9, 0xf5, 0x14, 0x93, 0xfe, 0xc2, 0x89, 0x7b, 0x0c, 0xa4, 0xcc, 0x25, - 0x59, 0x29, 0x15, 0xce, 0x5c, 0x92, 0x15, 0xea, 0x03, 0xac, 0xc2, 0x70, 0xb5, 0x9c, 0xe1, 0x04, - 0xbb, 0x8a, 0xd4, 0xcc, 0x1d, 0x57, 0x3b, 0xbf, 0x7a, 0xfa, 0x2b, 0xa7, 0x5b, 0x5b, 0x63, 0x87, - 0x87, 0xbe, 0x81, 0x72, 0xb2, 0xb1, 0x68, 0xa8, 0x15, 0x68, 0x16, 0x8e, 0xab, 0x9d, 0xe6, 0xd3, - 0x5b, 0x18, 0x9b, 0xab, 0xc8, 0xc5, 0x46, 0x29, 0x61, 0xff, 0xd1, 0x05, 0xd4, 0x92, 0x8d, 0x15, - 0x07, 0xb6, 0x83, 0x97, 0xd4, 0xef, 0x2a, 0xe3, 0xbf, 0xfc, 0x31, 0xfe, 0x38, 0x33, 0x36, 0xaa, - 0xc9, 0x9d, 0x80, 0x5e, 0x41, 0x21, 0x5d, 0xcd, 0x14, 0x97, 0x7d, 0xc3, 0xf3, 0x87, 0x1b, 0x4c, - 0x56, 0xb3, 0xed, 0x1e, 0x17, 0x7b, 0x06, 0x35, 0x45, 0xa7, 0xb0, 0xbf, 0xc4, 0x4b, 0x7f, 0xae, - 0x60, 0xc6, 0x79, 0xf6, 0x90, 0x73, 0x45, 0x95, 0x43, 0x3f, 0xbc, 0xbe, 0xd8, 0x33, 0xb8, 0x25, - 0xfa, 0x3d, 0x54, 0xec, 0x79, 0x6c, 0x3b, 0xd7, 0x98, 0x28, 0xf3, 0xc7, 0x4f, 0x52, 0x85, 0x5e, - 0x10, 0xb7, 0xf6, 0xe8, 0xb7, 0x50, 0x20, 0x76, 0xac, 0x78, 0x8c, 0xf6, 0xf3, 0x87, 0x34, 0xd3, - 0x8e, 0x05, 0x83, 0x5a, 0x51, 0xdf, 0xd6, 0x9b, 0xc0, 0x0e, 0x95, 0xc5, 0xe3, 0xbe, 0xbd, 0xa1, - 0xca, 0xcc, 0x37, 0x66, 0x49, 0x29, 0x2c, 0xb9, 0x15, 0xff, 0x71, 0xca, 0x60, 0x3c, 0xc1, 0x4e, - 0x46, 0x61, 0x96, 0xe8, 0x6b, 0xa8, 0xac, 0x97, 0x1b, 0x2b, 0xc4, 0xe4, 0x4c, 0xf9, 0x0b, 0x63, - 0x7d, 0xfa, 0xc1, 0x41, 0xcb, 0x8d, 0x8e, 0xc9, 0x99, 0xe0, 0x95, 0xd7, 0x5c, 0x44, 0x6d, 0x28, - 0xce, 0xa2, 0xd0, 0x55, 0xae, 0x19, 0x4b, 0x79, 0xc8, 0xea, 0x46, 0xa1, 0x2b, 0x28, 0xcc, 0xee, - 0xe8, 0x6b, 0x80, 0xbb, 0xe4, 0x41, 0xbf, 0x81, 0xc3, 0xad, 0xb1, 0x75, 0xe3, 0x93, 0x85, 0xe5, - 0xc7, 0xa2, 0xee, 0x0e, 0xb6, 0x8a, 0xb7, 0x3e, 0x59, 0x0c, 0xe2, 0xa3, 0x1f, 0x72, 0x50, 0xe2, - 0x49, 0x83, 0x3e, 0x82, 0xfd, 0xf7, 0x2b, 0xbc, 0xe2, 0x25, 0x5a, 0x37, 0xb8, 0x80, 0xbe, 0x81, - 0x22, 0x4b, 0x3d, 0x5e, 0xa3, 0x2f, 0x7f, 0x2a, 0xf5, 0x44, 0xa9, 0x52, 0x0a, 0xad, 0x36, 0x17, - 0xcf, 0xed, 0x55, 0x40, 0x78, 0xf6, 0xf2, 0x7a, 0xad, 0x0a, 0x8c, 0x5a, 0xb7, 0x5e, 0x43, 0x91, - 0x12, 0x50, 0x15, 0xca, 0x53, 0xfd, 0x52, 0x1f, 0xbd, 0xd5, 0xe5, 0x3d, 0x2a, 0x8c, 0x47, 0xc3, - 0xe1, 0x40, 0xff, 0x56, 0xce, 0xa1, 0x3a, 0x48, 0x03, 0xdd, 0xd4, 0x0c, 0x63, 0x3a, 0x36, 0xe5, - 0x3c, 0xaa, 0x41, 0x45, 0xed, 0xab, 0x63, 0x73, 0xf0, 0x46, 0x93, 0x0b, 0xd4, 0xb2, 0xaf, 0x9d, - 0xab, 0xd3, 0xa1, 0x29, 0x17, 0x8f, 0xfe, 0x0c, 0xd5, 0x9d, 0xf4, 0x7d, 0xe2, 0x73, 0x3e, 0x81, - 0xd2, 0x4d, 0x94, 0x5c, 0xe3, 0x84, 0x7d, 0x50, 0xdd, 0x10, 0x12, 0xfa, 0x1c, 0xaa, 0x4b, 0xdb, - 0x0f, 0x2d, 0xb2, 0x48, 0xb0, 0x9d, 0xb5, 0x16, 0xa0, 0x90, 0xc9, 0x90, 0xd6, 0x3f, 0x72, 0xc2, - 0x55, 0x04, 0x8d, 0xa9, 0xde, 0xd7, 0xce, 0x07, 0xba, 0xd6, 0xb7, 0xcc, 0xef, 0xc6, 0x9a, 0xbc, - 0x87, 0x0e, 0xa1, 0x3e, 0x99, 0x76, 0x2d, 0xe6, 0xe8, 0xb9, 0xda, 0xd3, 0xe4, 0x1c, 0xfa, 0x18, - 0x0e, 0x27, 0xa3, 0x73, 0xf3, 0xad, 0x6a, 0x68, 0xd6, 0x70, 0x34, 0x1a, 0x77, 0xd5, 0xde, 0xa5, - 0x9c, 0x47, 0x15, 0x28, 0xf6, 0xc7, 0xfd, 0x4b, 0xb9, 0x80, 0x24, 0xd8, 0xbf, 0xd2, 0xae, 0x06, - 0xe7, 0x72, 0x11, 0x95, 0xa1, 0x60, 0xaa, 0x63, 0x79, 0x9f, 0x7e, 0xac, 0x7a, 0x6e, 0x8d, 0xd5, - 0xde, 0xa5, 0x66, 0xca, 0x25, 0x24, 0x43, 0xed, 0xcd, 0xbb, 0xa1, 0xaa, 0x5b, 0xe6, 0x54, 0xd7, - 0xb5, 0xa1, 0x5c, 0xa6, 0xc8, 0x60, 0x3c, 0xd1, 0x7a, 0x19, 0x52, 0xa1, 0xe7, 0xbc, 0xb9, 0x7a, - 0xa7, 0x6b, 0xe6, 0xd9, 0xce, 0xf1, 0x12, 0xf5, 0xb2, 0x3b, 0xd2, 0xfb, 0x3b, 0x18, 0x74, 0x4b, - 0x50, 0x0c, 0xfc, 0xf0, 0xba, 0xf5, 0xbf, 0x3c, 0xd4, 0x76, 0x2b, 0x96, 0x7e, 0x7c, 0x6c, 0x27, - 0x38, 0x24, 0xd6, 0x4e, 0x8b, 0x06, 0x0e, 0xe9, 0xb4, 0x51, 0x7f, 0x0c, 0xa5, 0x74, 0x35, 0xb3, - 0x7c, 0x57, 0x44, 0x6d, 0x3f, 0x5d, 0xcd, 0x06, 0x2e, 0x32, 0xa0, 0x4e, 0x6c, 0xcf, 0x4a, 0x6e, - 0xac, 0x28, 0x26, 0x7e, 0x14, 0xb2, 0xb0, 0x35, 0x3a, 0xed, 0x1f, 0x6b, 0x0f, 0x6d, 0xd3, 0xf6, - 0x0c, 0x7c, 0x93, 0xf8, 0x04, 0x8f, 0x18, 0x29, 0x35, 0xaa, 0xc4, 0xf6, 0x8c, 0x1b, 0x2e, 0xa1, - 0x17, 0x00, 0xf1, 0x2a, 0x5d, 0x58, 0x6e, 0x44, 0x4e, 0xdf, 0xb3, 0x1e, 0x5e, 0x31, 0x24, 0x8a, - 0xf4, 0x29, 0x40, 0x9f, 0x11, 0x62, 0x7b, 0xa7, 0xca, 0x3e, 0xf3, 0x83, 0xad, 0x05, 0xd6, 0x11, - 0x3d, 0x9b, 0xad, 0x5b, 0x7f, 0xcb, 0xc1, 0xe1, 0x07, 0x27, 0xd1, 0xec, 0xe9, 0x0f, 0x26, 0x6a, - 0x77, 0xa8, 0xf5, 0xe5, 0x3d, 0x7a, 0x03, 0xe3, 0xe9, 0xe4, 0xe2, 0x54, 0xce, 0x65, 0xcb, 0x0e, - 0xbf, 0xa1, 0xf1, 0x68, 0x7c, 0x2a, 0x17, 0xc4, 0xaa, 0x23, 0x17, 0xd1, 0x01, 0x54, 0x4d, 0x43, - 0xd5, 0x27, 0x43, 0xd5, 0xd4, 0x4e, 0x4f, 0xe5, 0xfd, 0xfb, 0x40, 0x47, 0x2e, 0xdd, 0x03, 0x3a, - 0xa7, 0x72, 0xf9, 0x3e, 0xd0, 0x91, 0x2b, 0xad, 0x7f, 0xe7, 0x41, 0xda, 0xf6, 0x3c, 0xf4, 0x3b, - 0x51, 0x56, 0x39, 0x16, 0xb1, 0x5f, 0x3e, 0xd9, 0x1c, 0xf9, 0x8a, 0x35, 0x75, 0x5e, 0x54, 0x9f, - 0x40, 0x69, 0x69, 0xa7, 0x44, 0x24, 0x70, 0xc5, 0x10, 0x12, 0x6a, 0x40, 0xde, 0xe7, 0x79, 0x5b, - 0x37, 0xf2, 0xbe, 0x8b, 0xbe, 0x80, 0x83, 0x34, 0xa2, 0x9d, 0xd1, 0x9a, 0xfb, 0x01, 0x66, 0xf7, - 0xca, 0x1f, 0xc4, 0x06, 0x87, 0xcf, 0x05, 0x4a, 0x37, 0x4c, 0xb1, 0x93, 0x60, 0xc2, 0x62, 0x2a, - 0x19, 0x42, 0x42, 0x9f, 0x82, 0x94, 0xf8, 0xa1, 0x67, 0xa5, 0xfe, 0xf7, 0x58, 0x84, 0xb6, 0x42, - 0x81, 0x89, 0xff, 0x3d, 0xcb, 0x98, 0xd9, 0x6a, 0x3e, 0xc7, 0x09, 0x57, 0x97, 0x99, 0x1a, 0x38, - 0xc4, 0x0c, 0x28, 0x7b, 0x63, 0xb1, 0x9a, 0x4b, 0xc5, 0x93, 0x58, 0x49, 0x36, 0x7f, 0x64, 0x32, - 0x55, 0x92, 0xad, 0x52, 0xe2, 0x4a, 0x22, 0x94, 0xad, 0x8e, 0x08, 0x13, 0xeb, 0x49, 0x35, 0xa8, - 0x68, 0xe6, 0x85, 0x66, 0xe8, 0x9a, 0x29, 0xef, 0xa1, 0x12, 0xe4, 0x07, 0x63, 0x39, 0x47, 0x63, - 0x3b, 0x9e, 0xea, 0xa6, 0x35, 0xd0, 0x5f, 0x6b, 0x3d, 0x53, 0xce, 0xb7, 0xfe, 0x0a, 0xd2, 0xb6, - 0x65, 0x53, 0xdf, 0xd2, 0xc4, 0xd9, 0x8e, 0x01, 0x22, 0x9b, 0xd3, 0xc4, 0xc9, 0xa6, 0x80, 0xcf, - 0xa1, 0xea, 0xa6, 0x64, 0x6b, 0x90, 0xe7, 0x06, 0x6e, 0x4a, 0x32, 0x03, 0x3a, 0x03, 0x84, 0xbe, - 0x08, 0x26, 0x5d, 0xa2, 0xe7, 0x20, 0x2d, 0x57, 0x01, 0xf1, 0x1d, 0x3b, 0x25, 0x22, 0x8e, 0x77, - 0x40, 0xeb, 0x15, 0xd4, 0x76, 0xdf, 0x25, 0xd4, 0x84, 0xda, 0x22, 0x4a, 0x89, 0xe5, 0xcf, 0xef, - 0x15, 0x14, 0xc5, 0x06, 0x73, 0x5a, 0x50, 0xad, 0x7f, 0xe5, 0xa0, 0x2c, 0xde, 0x24, 0x3a, 0xd1, - 0xac, 0x71, 0x92, 0xd2, 0xfa, 0xe1, 0xad, 0x2a, 0x13, 0x3f, 0xd8, 0x27, 0xff, 0x70, 0x1f, 0x7a, - 0xcb, 0x24, 0xb2, 0x96, 0xbe, 0x93, 0x44, 0x29, 0x4e, 0xd6, 0xbe, 0xc3, 0xbb, 0xac, 0x64, 0x34, - 0x48, 0x74, 0xb5, 0x83, 0xd2, 0xad, 0x92, 0x8d, 0x75, 0x77, 0xa1, 0x45, 0x7e, 0x63, 0xc9, 0xc6, - 0xc8, 0xae, 0xb4, 0x09, 0x35, 0xb2, 0x6b, 0xc1, 0x2b, 0x0c, 0xc8, 0x9d, 0xc5, 0x0b, 0x00, 0x3e, - 0x6b, 0x59, 0x5e, 0x1a, 0xb1, 0x94, 0xa8, 0x18, 0x12, 0x47, 0xbe, 0x4d, 0xa3, 0xd6, 0x7f, 0x0b, - 0x20, 0x6d, 0x5f, 0x41, 0x1a, 0x43, 0x9c, 0x86, 0x22, 0x49, 0xe9, 0x92, 0x86, 0xdd, 0x0e, 0x89, - 0x6f, 0x25, 0x38, 0x0e, 0xec, 0xdb, 0xac, 0xc5, 0x52, 0xc8, 0x60, 0x08, 0x7a, 0x06, 0x95, 0x20, - 0x72, 0xec, 0x80, 0x3e, 0x57, 0x3c, 0xc6, 0x65, 0x26, 0x0f, 0x62, 0x96, 0x4e, 0x78, 0x19, 0x11, - 0x4c, 0x75, 0x3c, 0x4f, 0x2b, 0x1c, 0xe0, 0x4a, 0xce, 0x4b, 0x63, 0x3f, 0xcb, 0x54, 0x06, 0x4c, - 0x62, 0x9f, 0x3a, 0x2d, 0x98, 0x54, 0xcb, 0x13, 0x55, 0xec, 0x45, 0xd5, 0x67, 0x00, 0x4e, 0x72, - 0x1b, 0x93, 0xc8, 0xb2, 0x03, 0x8f, 0x25, 0x6a, 0xa3, 0xf3, 0x11, 0xaf, 0x46, 0x36, 0xca, 0xf6, - 0x98, 0x52, 0x0d, 0x3c, 0x43, 0x72, 0xb2, 0x25, 0x3a, 0x06, 0x99, 0x1f, 0x28, 0xa8, 0xd7, 0xf8, - 0x96, 0xa5, 0xb1, 0x64, 0x34, 0x18, 0xce, 0x49, 0x97, 0xf8, 0x96, 0x3e, 0xc5, 0xe2, 0xf4, 0x1d, - 0x53, 0xe0, 0x4f, 0x31, 0x57, 0xdc, 0xd9, 0xbe, 0x02, 0x89, 0x76, 0x00, 0x8f, 0x79, 0x52, 0x65, - 0x9e, 0xfc, 0x6c, 0xc7, 0x13, 0xda, 0x41, 0x3d, 0xea, 0x48, 0xc5, 0x17, 0x2b, 0x3a, 0x99, 0x8a, - 0x80, 0x31, 0x1e, 0xdd, 0xbb, 0xc6, 0xf6, 0xae, 0xf3, 0xb8, 0x51, 0x94, 0xee, 0x7c, 0x0c, 0x72, - 0x16, 0xbd, 0xad, 0x61, 0x9d, 0xfb, 0x2b, 0x82, 0xb8, 0x63, 0x29, 0xae, 0x78, 0xe5, 0xc6, 0x16, - 0x0e, 0x1d, 0x3b, 0x56, 0x1a, 0xec, 0xa2, 0x1a, 0x1c, 0x9f, 0xba, 0xb1, 0x46, 0xd1, 0x96, 0x0b, - 0xd5, 0x9d, 0xe1, 0x85, 0x5e, 0xae, 0x20, 0xe2, 0x20, 0xf2, 0xc4, 0xb5, 0x8b, 0x74, 0xd1, 0x82, - 0xc8, 0xa3, 0x97, 0x9b, 0x6c, 0xde, 0xf3, 0xd4, 0xe2, 0x85, 0x55, 0x4e, 0x36, 0xef, 0x59, 0x5e, - 0x3d, 0x83, 0x0a, 0xc9, 0x54, 0x3c, 0x2f, 0xcb, 0x84, 0xab, 0x5a, 0xff, 0x2c, 0x40, 0x25, 0x9b, - 0x76, 0x44, 0x8b, 0xcb, 0x6d, 0x5b, 0xdc, 0xa9, 0xe8, 0xa1, 0xfc, 0xd5, 0x79, 0xf1, 0xd4, 0x94, - 0xd4, 0xde, 0xe9, 0x9e, 0x5f, 0x41, 0x3e, 0x98, 0xb1, 0x43, 0x1a, 0x1f, 0x4e, 0xe2, 0x5b, 0xc2, - 0x30, 0xb2, 0xdd, 0xae, 0x1d, 0xd8, 0xa1, 0x83, 0x8d, 0x7c, 0x30, 0x43, 0x53, 0x38, 0xa4, 0x63, - 0x16, 0x76, 0xad, 0x3b, 0x6b, 0xa5, 0xc6, 0x66, 0xe9, 0xe3, 0x27, 0x37, 0xe9, 0x32, 0xc6, 0xf6, - 0xdd, 0x33, 0xe4, 0xd9, 0x7d, 0x20, 0x3d, 0x0a, 0xe0, 0xe0, 0x81, 0xd1, 0xa3, 0xbf, 0x92, 0x5e, - 0x00, 0xf8, 0xa9, 0x15, 0xdb, 0x69, 0xea, 0xaf, 0xb1, 0x88, 0xac, 0xe4, 0xa7, 0x63, 0x0e, 0xd0, - 0x24, 0xf0, 0x53, 0x2b, 0x88, 0x42, 0xcf, 0x22, 0xfe, 0x12, 0x47, 0x2b, 0x22, 0x4a, 0xab, 0xee, - 0xa7, 0xc3, 0x28, 0xf4, 0x4c, 0x0e, 0xb6, 0xbe, 0x83, 0x22, 0x6b, 0xa9, 0xf7, 0x46, 0xad, 0x03, - 0xa8, 0x1a, 0xa3, 0xa9, 0xde, 0xb7, 0x8c, 0x51, 0x77, 0xa0, 0xcb, 0x39, 0x3a, 0xc9, 0xa8, 0x3d, - 0x3a, 0x5d, 0x59, 0x74, 0x60, 0x99, 0x8e, 0xe5, 0x3c, 0x9d, 0x4e, 0xde, 0x8d, 0x0c, 0xb9, 0x40, - 0xa7, 0x93, 0xae, 0x31, 0x52, 0xfb, 0x3d, 0x75, 0x62, 0xca, 0x45, 0xfa, 0x3c, 0x0e, 0xd5, 0xde, - 0x58, 0xde, 0x6f, 0x7d, 0x01, 0xd5, 0x9d, 0x90, 0xd1, 0x36, 0x3d, 0xec, 0xc8, 0x7b, 0x94, 0x38, - 0x3c, 0xfb, 0x4a, 0xce, 0xb1, 0x45, 0xe7, 0x4c, 0xce, 0x77, 0x5f, 0xff, 0xf0, 0x9f, 0xcf, 0x72, - 0x7f, 0xea, 0xef, 0xfc, 0xca, 0x0c, 0x7c, 0xcf, 0x26, 0x11, 0xfd, 0x05, 0xf9, 0xa5, 0xed, 0xe1, - 0x90, 0x9c, 0xd8, 0xb1, 0x7f, 0xf2, 0xe8, 0x8f, 0xd7, 0x3f, 0xac, 0xe3, 0x78, 0x27, 0xfe, 0xb3, - 0x12, 0xfb, 0x95, 0x79, 0xf6, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7e, 0xc9, 0xc7, 0xfb, 0xeb, - 0x0e, 0x00, 0x00, + 0x11, 0x16, 0x7f, 0x24, 0x02, 0xcd, 0x1f, 0x61, 0x27, 0xb6, 0x83, 0x95, 0x77, 0x6d, 0x85, 0xc9, + 0xc6, 0xaa, 0xa4, 0x2c, 0xad, 0x28, 0x57, 0xc5, 0x89, 0x4f, 0xa0, 0x08, 0x79, 0xb9, 0x4b, 0x81, + 0x0c, 0x08, 0xee, 0xae, 0x53, 0xa9, 0x42, 0x81, 0xc0, 0x10, 0x44, 0x04, 0x02, 0x58, 0xcc, 0x90, + 0x4b, 0xb9, 0x2a, 0xcf, 0x90, 0x7b, 0x9e, 0x26, 0x47, 0x1f, 0x72, 0xc9, 0x31, 0xe7, 0x1c, 0x73, + 0xcc, 0x0b, 0xa4, 0xe6, 0x07, 0x14, 0xa5, 0x95, 0xec, 0x8b, 0x34, 0xf3, 0x75, 0x7f, 0x3d, 0x8d, + 0x9e, 0xee, 0x9e, 0x26, 0x3c, 0x5b, 0xa4, 0x01, 0x8e, 0xc9, 0xc9, 0x2a, 0xcb, 0x4e, 0xa2, 0x84, + 0xe2, 0x7c, 0xe6, 0xf9, 0x98, 0xdc, 0x2c, 0x8f, 0xb3, 0x3c, 0xa5, 0x29, 0x6a, 0xad, 0xb2, 0xec, + 0xf8, 0x46, 0x7e, 0xf0, 0x65, 0x18, 0xd1, 0xf9, 0x72, 0x7a, 0xec, 0xa7, 0x8b, 0x93, 0x30, 0x0d, + 0xd3, 0x13, 0xae, 0x36, 0x5d, 0xce, 0xf8, 0x8e, 0x6f, 0xf8, 0x4a, 0xd0, 0x0f, 0x9e, 0x6c, 0x9f, + 0x92, 0x11, 0xec, 0x8b, 0xbf, 0x42, 0xda, 0xfe, 0x7b, 0x1d, 0xd4, 0x7e, 0x61, 0x1b, 0x21, 0xa8, + 0x26, 0xde, 0x02, 0xeb, 0xa5, 0xc3, 0xd2, 0x91, 0x6a, 0xf3, 0x35, 0xea, 0x40, 0x95, 0x5e, 0x67, + 0x58, 0x2f, 0x1f, 0x96, 0x8e, 0x5a, 0x9d, 0xcf, 0x8e, 0x6f, 0x7b, 0x73, 0xbc, 0x21, 0x1f, 0x3b, + 0xd7, 0x19, 0xb6, 0xb9, 0x2e, 0xd2, 0xa1, 0x86, 0x13, 0x6f, 0x1a, 0xe3, 0x40, 0xaf, 0x1c, 0x96, + 0x8e, 0x14, 0xbb, 0xd8, 0xa2, 0x5f, 0x40, 0x23, 0x9b, 0x5f, 0x13, 0xd7, 0x0b, 0x82, 0x1c, 0x13, + 0xa2, 0x57, 0xf9, 0x49, 0x75, 0x86, 0x19, 0x02, 0x62, 0x2a, 0x51, 0x56, 0x28, 0x60, 0xa2, 0xef, + 0x1e, 0x56, 0x98, 0x4a, 0x94, 0x19, 0x05, 0x84, 0x34, 0xa8, 0xac, 0xf2, 0x99, 0xbe, 0x77, 0x58, + 0x3a, 0x6a, 0xda, 0x6c, 0x89, 0x7e, 0x0d, 0xfb, 0x04, 0x53, 0x37, 0x98, 0xfb, 0x99, 0xeb, 0xc7, + 0x11, 0x4e, 0xa8, 0x5e, 0xe3, 0x27, 0x37, 0x09, 0xa6, 0xbd, 0xb9, 0x9f, 0x9d, 0x73, 0x90, 0x31, + 0x17, 0x74, 0xa9, 0x2b, 0x82, 0xb9, 0xa0, 0x4b, 0xd4, 0x03, 0x58, 0x26, 0xc9, 0x72, 0x31, 0xc5, + 0x39, 0x0e, 0x74, 0xf5, 0xb0, 0x74, 0x54, 0xef, 0xfc, 0xea, 0xe1, 0xaf, 0x9c, 0x6c, 0x74, 0xed, + 0x2d, 0x1e, 0xfa, 0x06, 0x94, 0x7c, 0xed, 0xb2, 0x50, 0x13, 0x1d, 0x0e, 0x2b, 0x47, 0xf5, 0xce, + 0xe1, 0xc3, 0x36, 0xec, 0xf5, 0x65, 0x1a, 0x60, 0xbb, 0x96, 0xf3, 0xff, 0x04, 0xbd, 0x84, 0x66, + 0xbe, 0x76, 0xb3, 0xd8, 0xf3, 0xf1, 0x02, 0x27, 0x94, 0xe8, 0x75, 0x6e, 0xe1, 0xd9, 0x8f, 0x59, + 0x18, 0x15, 0xda, 0x76, 0x23, 0xbf, 0xd9, 0x10, 0xf4, 0x1c, 0x2a, 0x64, 0x39, 0xd5, 0x03, 0xfe, + 0x1d, 0x4f, 0xee, 0x5a, 0x18, 0x2f, 0xa7, 0x1b, 0x23, 0x2f, 0x76, 0x6c, 0xa6, 0x8a, 0x4e, 0x61, + 0x77, 0x81, 0x17, 0xd1, 0x4c, 0xc7, 0x9c, 0xf3, 0xf8, 0x2e, 0xe7, 0x92, 0x09, 0x07, 0x51, 0x72, + 0xf5, 0x62, 0xc7, 0x16, 0x9a, 0xe8, 0x0f, 0xa0, 0x78, 0xb3, 0xcc, 0xf3, 0xaf, 0x30, 0xd5, 0x67, + 0xf7, 0x9f, 0x64, 0x48, 0xb9, 0x24, 0x6e, 0xf4, 0xd1, 0x6f, 0xa1, 0x42, 0xbd, 0x4c, 0x0f, 0x39, + 0xed, 0xe7, 0x77, 0x69, 0x8e, 0x97, 0x49, 0x06, 0xd3, 0x62, 0xbe, 0xad, 0xd6, 0xb1, 0x97, 0xe8, + 0xf3, 0xfb, 0x7d, 0x7b, 0xcd, 0x84, 0x85, 0x6f, 0x5c, 0x93, 0x51, 0x78, 0x82, 0xeb, 0xd1, 0xfd, + 0x94, 0xfe, 0x68, 0x8c, 0xfd, 0x82, 0xc2, 0x35, 0xd1, 0xd7, 0xa0, 0xac, 0x16, 0x6b, 0x37, 0xc1, + 0xf4, 0x4c, 0xff, 0x0b, 0x67, 0x7d, 0xfa, 0xc1, 0x41, 0x8b, 0xb5, 0x85, 0xe9, 0x99, 0xe4, 0xd5, + 0x56, 0x62, 0x8b, 0x8e, 0xa1, 0x3a, 0x4d, 0x93, 0x40, 0xbf, 0xe2, 0x2c, 0xfd, 0x2e, 0xab, 0x9b, + 0x26, 0x81, 0xa4, 0x70, 0xbd, 0x83, 0xaf, 0x01, 0x6e, 0x12, 0x08, 0xfd, 0x06, 0x1e, 0x6d, 0x94, + 0xdd, 0xf7, 0x11, 0x9d, 0xbb, 0x51, 0x26, 0x6b, 0x6f, 0x7f, 0x23, 0x78, 0x13, 0xd1, 0x79, 0x3f, + 0x3b, 0xf8, 0xa1, 0x04, 0x7b, 0x22, 0x6f, 0xd0, 0x47, 0xb0, 0xfb, 0x6e, 0x89, 0x97, 0xa2, 0x4c, + 0x9b, 0xb6, 0xd8, 0xa0, 0xdf, 0x43, 0x95, 0xa5, 0x9f, 0xac, 0xd3, 0x67, 0x3f, 0x95, 0x7d, 0xb2, + 0x5c, 0x19, 0x85, 0x55, 0x5c, 0x80, 0x67, 0xde, 0x32, 0xa6, 0x3c, 0x83, 0x65, 0xcd, 0xd6, 0x25, + 0xc6, 0xb4, 0xdb, 0x2f, 0xa1, 0xca, 0x08, 0xa8, 0x0e, 0xb5, 0x89, 0xf5, 0xca, 0x1a, 0xbe, 0xb1, + 0xb4, 0x1d, 0xb6, 0x19, 0x0d, 0x07, 0x83, 0xbe, 0xf5, 0xad, 0x56, 0x42, 0x4d, 0x50, 0xfb, 0x96, + 0x63, 0xda, 0xf6, 0x64, 0xe4, 0x68, 0x65, 0xd4, 0x00, 0xc5, 0xe8, 0x19, 0x23, 0xa7, 0xff, 0xda, + 0xd4, 0x2a, 0x4c, 0xb3, 0x67, 0x5e, 0x18, 0x93, 0x81, 0xa3, 0x55, 0x0f, 0xfe, 0x0c, 0xf5, 0xad, + 0xfc, 0x7d, 0xe0, 0x73, 0x3e, 0x81, 0xbd, 0xf7, 0x69, 0x7e, 0x85, 0x73, 0xfe, 0x41, 0x4d, 0x5b, + 0xee, 0xd0, 0xe7, 0x50, 0x5f, 0x78, 0x51, 0xe2, 0xd2, 0x79, 0x8e, 0xbd, 0xa2, 0xbd, 0x00, 0x83, + 0x1c, 0x8e, 0xb4, 0xff, 0x51, 0x92, 0xae, 0x22, 0x68, 0x4d, 0xac, 0x9e, 0x79, 0xd1, 0xb7, 0xcc, + 0x9e, 0xeb, 0x7c, 0x37, 0x32, 0xb5, 0x1d, 0xf4, 0x08, 0x9a, 0xe3, 0x49, 0xd7, 0xe5, 0x8e, 0x5e, + 0x18, 0xe7, 0xa6, 0x56, 0x42, 0x1f, 0xc3, 0xa3, 0xf1, 0xf0, 0xc2, 0x79, 0x63, 0xd8, 0xa6, 0x3b, + 0x18, 0x0e, 0x47, 0x5d, 0xe3, 0xfc, 0x95, 0x56, 0x46, 0x0a, 0x54, 0x7b, 0xa3, 0xde, 0x2b, 0xad, + 0x82, 0x54, 0xd8, 0xbd, 0x34, 0x2f, 0xfb, 0x17, 0x5a, 0x15, 0xd5, 0xa0, 0xe2, 0x18, 0x23, 0x6d, + 0x97, 0x7d, 0xac, 0x71, 0xe1, 0x8e, 0x8c, 0xf3, 0x57, 0xa6, 0xa3, 0xed, 0x21, 0x0d, 0x1a, 0xaf, + 0xdf, 0x0e, 0x0c, 0xcb, 0x75, 0x26, 0x96, 0x65, 0x0e, 0xb4, 0x1a, 0x43, 0xfa, 0xa3, 0xb1, 0x79, + 0x5e, 0x20, 0x0a, 0x3b, 0xe7, 0xf5, 0xe5, 0x5b, 0xcb, 0x74, 0xce, 0xb6, 0x8e, 0x57, 0x99, 0x97, + 0xdd, 0xa1, 0xd5, 0xdb, 0xc2, 0xa0, 0xbb, 0x07, 0xd5, 0x38, 0x4a, 0xae, 0xda, 0xff, 0x2b, 0x43, + 0x63, 0xbb, 0x62, 0xd9, 0xc7, 0x67, 0x5e, 0x8e, 0x13, 0xea, 0x6e, 0xb5, 0x69, 0x10, 0x90, 0xc5, + 0x9a, 0xf5, 0xc7, 0xb0, 0x47, 0x96, 0x53, 0x37, 0x0a, 0x64, 0xd4, 0x76, 0xc9, 0x72, 0xda, 0x0f, + 0x90, 0x0d, 0x4d, 0xea, 0x85, 0x6e, 0xfe, 0xde, 0x4d, 0x33, 0x1a, 0xa5, 0x09, 0x0f, 0x5b, 0xab, + 0x73, 0xfc, 0x63, 0xed, 0xe1, 0xd8, 0xf1, 0x42, 0x1b, 0xbf, 0xcf, 0x23, 0x8a, 0x87, 0x9c, 0x44, + 0xec, 0x3a, 0xf5, 0x42, 0xfb, 0xbd, 0xd8, 0xa1, 0xa7, 0x00, 0xd9, 0x92, 0xcc, 0xdd, 0x20, 0xa5, + 0xa7, 0xef, 0x78, 0x1f, 0x57, 0x6c, 0x95, 0x21, 0x3d, 0x06, 0xb0, 0xa7, 0x84, 0x7a, 0xe1, 0xa9, + 0xbe, 0xcb, 0xfd, 0xe0, 0x6b, 0x89, 0x75, 0x64, 0xdf, 0xe6, 0xeb, 0xf6, 0xdf, 0x4a, 0xf0, 0xe8, + 0x83, 0x93, 0x58, 0xf6, 0xf4, 0xfa, 0x63, 0xa3, 0x3b, 0x30, 0x7b, 0xda, 0x0e, 0xbb, 0x81, 0xd1, + 0x64, 0xfc, 0xe2, 0x54, 0x2b, 0x15, 0xcb, 0x8e, 0xb8, 0xa1, 0xd1, 0x70, 0x74, 0xaa, 0x55, 0xe4, + 0xaa, 0xa3, 0x55, 0xd1, 0x3e, 0xd4, 0x1d, 0xdb, 0xb0, 0xc6, 0x03, 0xc3, 0x31, 0x4f, 0x4f, 0xb5, + 0xdd, 0xdb, 0x40, 0x47, 0xdb, 0xbb, 0x05, 0x74, 0x4e, 0xb5, 0xda, 0x6d, 0xa0, 0xa3, 0x29, 0xed, + 0x7f, 0x97, 0x41, 0xdd, 0xf4, 0x3c, 0xf4, 0x3b, 0x59, 0x56, 0x25, 0x1e, 0xb1, 0x5f, 0x3e, 0xd8, + 0x1c, 0xc5, 0x8a, 0xf7, 0x75, 0x51, 0x54, 0x9f, 0xc0, 0xde, 0xc2, 0x23, 0x54, 0x26, 0xb0, 0x62, + 0xcb, 0x1d, 0x6a, 0x41, 0x39, 0x12, 0x79, 0xdb, 0xb4, 0xcb, 0x51, 0x80, 0xbe, 0x80, 0x7d, 0x92, + 0xb2, 0xce, 0xe8, 0xce, 0xa2, 0x18, 0xf3, 0x7b, 0x15, 0x8f, 0x62, 0x4b, 0xc0, 0x17, 0x12, 0x65, + 0x06, 0x09, 0xf6, 0x73, 0x4c, 0x79, 0x4c, 0x55, 0x5b, 0xee, 0xd0, 0xa7, 0xa0, 0xe6, 0x51, 0x12, + 0xba, 0x24, 0xfa, 0x1e, 0xcb, 0xd0, 0x2a, 0x0c, 0x18, 0x47, 0xdf, 0xf3, 0x8c, 0x99, 0x2e, 0x67, + 0x33, 0x9c, 0x0b, 0x71, 0x8d, 0x8b, 0x41, 0x40, 0x5c, 0x81, 0xb1, 0xd7, 0x2e, 0xaf, 0x39, 0x22, + 0x9f, 0x45, 0x25, 0x5f, 0xff, 0x91, 0xef, 0x99, 0x90, 0x6e, 0x84, 0xaa, 0x10, 0x52, 0x29, 0x6c, + 0x77, 0x64, 0x98, 0x78, 0x4f, 0x6a, 0x80, 0x62, 0x3a, 0x2f, 0x4c, 0xdb, 0x32, 0x1d, 0x6d, 0x07, + 0xed, 0x41, 0xb9, 0x3f, 0xd2, 0x4a, 0x2c, 0xb6, 0xa3, 0x89, 0xe5, 0xb8, 0x7d, 0xeb, 0xa5, 0x79, + 0xee, 0x68, 0xe5, 0xf6, 0x5f, 0x41, 0xdd, 0xb4, 0x6c, 0xe6, 0x1b, 0xc9, 0xfd, 0xcd, 0x28, 0x20, + 0xb3, 0x99, 0xe4, 0x7e, 0x31, 0x09, 0x7c, 0x0e, 0xf5, 0x80, 0xd0, 0x8d, 0x42, 0x59, 0x28, 0x04, + 0x84, 0x16, 0x0a, 0x6c, 0x0e, 0x48, 0x22, 0x19, 0x4c, 0xb6, 0x44, 0x4f, 0x40, 0x5d, 0x2c, 0x63, + 0x1a, 0xf9, 0x1e, 0xa1, 0x32, 0x8e, 0x37, 0x40, 0xfb, 0x39, 0x34, 0xb6, 0xdf, 0x25, 0x74, 0x08, + 0x8d, 0x79, 0x4a, 0xa8, 0x1b, 0xcd, 0x6e, 0x15, 0x14, 0xc3, 0xfa, 0x33, 0x56, 0x50, 0xed, 0x7f, + 0x95, 0xa0, 0x26, 0xdf, 0x24, 0x36, 0xd5, 0xac, 0x70, 0x4e, 0x58, 0xfd, 0x88, 0x56, 0x55, 0x6c, + 0x3f, 0xb0, 0x53, 0xbe, 0x6b, 0x87, 0xdd, 0x32, 0x4d, 0xdd, 0x45, 0xe4, 0xe7, 0x29, 0xc1, 0xf9, + 0x2a, 0xf2, 0x45, 0x97, 0x55, 0xed, 0x16, 0x4d, 0x2f, 0xb7, 0x50, 0x66, 0x2a, 0x5f, 0xbb, 0x37, + 0x17, 0x5a, 0x15, 0x37, 0x96, 0xaf, 0xed, 0xe2, 0x4a, 0x0f, 0xa1, 0x41, 0xb7, 0x35, 0x44, 0x85, + 0x01, 0xbd, 0xd1, 0x78, 0x0a, 0x20, 0xe6, 0x2d, 0x37, 0x24, 0x29, 0x4f, 0x09, 0xc5, 0x56, 0x05, + 0xf2, 0x2d, 0x49, 0xdb, 0xff, 0xad, 0x80, 0xba, 0x79, 0x05, 0x59, 0x0c, 0x31, 0x49, 0x64, 0x92, + 0xb2, 0x25, 0x0b, 0xbb, 0x97, 0xd0, 0xc8, 0xcd, 0x71, 0x16, 0x7b, 0xd7, 0x45, 0x8b, 0x65, 0x90, + 0xcd, 0x11, 0xf4, 0x18, 0x94, 0x38, 0xf5, 0xbd, 0x98, 0x3d, 0x57, 0x22, 0xc6, 0x35, 0xbe, 0xef, + 0x67, 0x3c, 0x9d, 0xf0, 0x22, 0xa5, 0x98, 0xc9, 0x44, 0x9e, 0x2a, 0x02, 0x10, 0x42, 0xc1, 0x23, + 0x59, 0x54, 0x64, 0x2a, 0x07, 0xc6, 0x59, 0xc4, 0x9c, 0x96, 0x4c, 0x26, 0x15, 0x89, 0x2a, 0x6d, + 0x31, 0xf1, 0x19, 0x80, 0x9f, 0x5f, 0x67, 0x34, 0x75, 0xbd, 0x38, 0xe4, 0x89, 0xda, 0xea, 0x7c, + 0x24, 0xaa, 0x91, 0x8f, 0xb3, 0xe7, 0x5c, 0x68, 0xc4, 0xa1, 0xad, 0xfa, 0xc5, 0x12, 0x1d, 0x81, + 0x26, 0x0e, 0x94, 0xd4, 0x2b, 0x7c, 0xcd, 0xd3, 0x58, 0xb5, 0x5b, 0x1c, 0x17, 0xa4, 0x57, 0xf8, + 0x9a, 0x3d, 0xc5, 0xf2, 0xf4, 0x2d, 0x55, 0x10, 0x4f, 0xb1, 0x10, 0xdc, 0xe8, 0x3e, 0x07, 0x95, + 0x75, 0x80, 0x90, 0x7b, 0x52, 0xe7, 0x9e, 0xfc, 0x6c, 0xcb, 0x13, 0xd6, 0x41, 0x43, 0xe6, 0x88, + 0x12, 0xc9, 0x15, 0x9b, 0x4e, 0x65, 0xc0, 0x38, 0x8f, 0xd9, 0x6e, 0x70, 0xdb, 0x4d, 0x11, 0x37, + 0x86, 0x32, 0xcb, 0x47, 0xa0, 0x15, 0xd1, 0xdb, 0x28, 0x36, 0x85, 0xbf, 0x32, 0x88, 0x5b, 0x9a, + 0xf2, 0x8a, 0x97, 0x41, 0xe6, 0xe2, 0xc4, 0xf7, 0x32, 0xbd, 0xc5, 0x2f, 0xaa, 0x25, 0xf0, 0x49, + 0x90, 0x99, 0x0c, 0x6d, 0x07, 0x50, 0xdf, 0x1a, 0x5e, 0xd8, 0xe5, 0x4a, 0x22, 0x8e, 0xd3, 0x50, + 0x5e, 0xbb, 0x4c, 0x17, 0x33, 0x4e, 0x43, 0x76, 0xb9, 0xf9, 0xfa, 0x9d, 0x48, 0x2d, 0x51, 0x58, + 0xb5, 0x7c, 0xfd, 0x8e, 0xe7, 0xd5, 0x63, 0x50, 0x68, 0x21, 0x12, 0x79, 0x59, 0xa3, 0x42, 0xd4, + 0xfe, 0x67, 0x05, 0x94, 0x62, 0xda, 0x91, 0x2d, 0xae, 0xb4, 0x69, 0x71, 0xa7, 0xb2, 0x87, 0x8a, + 0x57, 0xe7, 0xe9, 0x43, 0x53, 0xd2, 0xf1, 0x56, 0xf7, 0xfc, 0x0a, 0xca, 0xf1, 0x94, 0x1f, 0xd2, + 0xfa, 0x70, 0x1a, 0xdf, 0x10, 0x06, 0xa9, 0x17, 0x74, 0xbd, 0xd8, 0x4b, 0x7c, 0x6c, 0x97, 0xe3, + 0x29, 0x9a, 0xc0, 0x23, 0x36, 0x66, 0xe1, 0xc0, 0xbd, 0xd1, 0xd6, 0x1b, 0x7c, 0x98, 0x3e, 0x7a, + 0xd0, 0x48, 0x97, 0x33, 0x36, 0xef, 0x9e, 0xad, 0x4d, 0x6f, 0x03, 0xe4, 0x20, 0x86, 0xfd, 0x3b, + 0x4a, 0xf7, 0xfe, 0x52, 0x7a, 0x0a, 0x10, 0x11, 0x37, 0xf3, 0x08, 0x89, 0x56, 0x58, 0x46, 0x56, + 0x8d, 0xc8, 0x48, 0x00, 0x2c, 0x09, 0x22, 0xe2, 0xc6, 0x69, 0x12, 0xba, 0x34, 0x5a, 0xe0, 0x74, + 0x49, 0x65, 0x69, 0x35, 0x23, 0x32, 0x48, 0x93, 0xd0, 0x11, 0x60, 0xfb, 0x3b, 0xa8, 0xf2, 0x96, + 0x7a, 0x6b, 0xd4, 0xda, 0x87, 0xba, 0x3d, 0x9c, 0x58, 0x3d, 0xd7, 0x1e, 0x76, 0xfb, 0x96, 0x56, + 0x62, 0x93, 0x8c, 0x71, 0xce, 0xa6, 0x2b, 0x97, 0x0d, 0x2c, 0x93, 0x91, 0x56, 0x66, 0xd3, 0xc9, + 0xdb, 0xa1, 0xad, 0x55, 0xd8, 0x74, 0xd2, 0xb5, 0x87, 0x46, 0xef, 0xdc, 0x18, 0x3b, 0x5a, 0x95, + 0x3d, 0x8f, 0x03, 0xe3, 0x7c, 0xa4, 0xed, 0xb6, 0xbf, 0x80, 0xfa, 0x56, 0xc8, 0x58, 0x9b, 0x1e, + 0x74, 0xb4, 0x1d, 0x46, 0x1c, 0x9c, 0x7d, 0xa5, 0x95, 0xf8, 0xa2, 0x73, 0xa6, 0x95, 0xbb, 0x2f, + 0x7f, 0xf8, 0xcf, 0x67, 0xa5, 0x3f, 0xf5, 0xb6, 0x7e, 0x69, 0xc6, 0x51, 0xe8, 0xd1, 0x94, 0xfd, + 0x8a, 0xfc, 0xd2, 0x0b, 0x71, 0x42, 0x4f, 0xbc, 0x2c, 0x3a, 0xb9, 0xf7, 0x07, 0xec, 0x37, 0xab, + 0x2c, 0xdb, 0x8a, 0xff, 0x74, 0x8f, 0xff, 0xd2, 0x3c, 0xfb, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x6f, 0x77, 0x95, 0x46, 0xef, 0x0e, 0x00, 0x00, } diff --git a/api/models/vpp/interfaces/interface.proto b/api/models/vpp/interfaces/interface.proto index 7fe566525b..0b1a73cf8d 100644 --- a/api/models/vpp/interfaces/interface.proto +++ b/api/models/vpp/interfaces/interface.proto @@ -55,7 +55,7 @@ message Interface { // will be used for all queues without explicitly // selected Rx mode } - repeated RxMode rx_mode = 10; + repeated RxMode rx_modes = 10; message RxPlacement { uint32 queue = 1; // select from interval <0, number-of-queues) @@ -63,7 +63,7 @@ message Interface { bool main_thread = 3; // let the main thread to process the given queue // - if enabled, value of is ignored } - repeated RxPlacement rx_placement = 11; + repeated RxPlacement rx_placements = 11; oneof link { SubInterface sub = 100; /* sub-interface configuration */ diff --git a/examples/kvscheduler/rxplacement/main.go b/examples/kvscheduler/rxplacement/main.go index 60888ff4f0..74660b0d76 100644 --- a/examples/kvscheduler/rxplacement/main.go +++ b/examples/kvscheduler/rxplacement/main.go @@ -168,12 +168,12 @@ func testLocalClientWithScheduler(kvscheduler kvs_api.KVScheduler) { time.Sleep(time.Second * 10) fmt.Println("=== CHANGE ===") - myMemif.RxMode[0].Mode = vpp_interfaces.Interface_RxMode_INTERRUPT // change default - myMemif.RxMode = append(myMemif.RxMode, &vpp_interfaces.Interface_RxMode{ + myMemif.RxModes[0].Mode = vpp_interfaces.Interface_RxMode_INTERRUPT // change default + myMemif.RxModes = append(myMemif.RxModes, &vpp_interfaces.Interface_RxMode{ Queue: 3, Mode: vpp_interfaces.Interface_RxMode_POLLING, }) - myMemif.RxPlacement = append(myMemif.RxPlacement, &vpp_interfaces.Interface_RxPlacement{ + myMemif.RxPlacements = append(myMemif.RxPlacements, &vpp_interfaces.Interface_RxPlacement{ Queue: 3, MainThread: true, Worker: 100, // ignored @@ -194,7 +194,7 @@ func testLocalClientWithScheduler(kvscheduler kvs_api.KVScheduler) { myMemif.GetMemif().RxQueues = 5 myMemif.GetMemif().TxQueues = 5 - myMemif.RxPlacement = append(myMemif.RxPlacement, &vpp_interfaces.Interface_RxPlacement{ + myMemif.RxPlacements = append(myMemif.RxPlacements, &vpp_interfaces.Interface_RxPlacement{ Queue: 4, MainThread: true, }) @@ -221,7 +221,7 @@ var ( Enabled: true, IpAddresses: []string{"192.168.1.1/24"}, - RxPlacement: []*vpp_interfaces.Interface_RxPlacement{ + RxPlacements: []*vpp_interfaces.Interface_RxPlacement{ { Queue: 0, Worker: 0, @@ -236,7 +236,7 @@ var ( }, }, - RxMode: []*vpp_interfaces.Interface_RxMode{ + RxModes: []*vpp_interfaces.Interface_RxMode{ { DefaultMode: true, Mode: vpp_interfaces.Interface_RxMode_POLLING, diff --git a/plugins/vpp/ifplugin/descriptor/interface.go b/plugins/vpp/ifplugin/descriptor/interface.go index c8d6f2d3ff..cbc5059b08 100644 --- a/plugins/vpp/ifplugin/descriptor/interface.go +++ b/plugins/vpp/ifplugin/descriptor/interface.go @@ -434,9 +434,9 @@ func (d *InterfaceDescriptor) Validate(key string, intf *interfaces.Interface) e } // validate Rx Placement before it gets derived out - for i, rxPlacement1 := range intf.GetRxPlacement() { - for j := i + 1; j < len(intf.GetRxPlacement()); j++ { - rxPlacement2 := intf.GetRxPlacement()[j] + for i, rxPlacement1 := range intf.GetRxPlacements() { + for j := i + 1; j < len(intf.GetRxPlacements()); j++ { + rxPlacement2 := intf.GetRxPlacements()[j] if rxPlacement1.Queue == rxPlacement2.Queue { return kvs.NewInvalidValueError(ErrRedefinedRxPlacement, fmt.Sprintf("rx_placement[.queue=%d]", rxPlacement1.Queue)) @@ -603,19 +603,19 @@ func (d *InterfaceDescriptor) DerivedValues(key string, intf *interfaces.Interfa } // Rx mode - if len(intf.GetRxMode()) > 0 { + if len(intf.GetRxModes()) > 0 { derValues = append(derValues, kvs.KeyValuePair{ Key: interfaces.RxModeKey(intf.GetName()), Value: &interfaces.Interface{ - Name: intf.GetName(), - Type: intf.GetType(), - RxMode: intf.GetRxMode(), + Name: intf.GetName(), + Type: intf.GetType(), + RxModes: intf.GetRxModes(), }, }) } // Rx placement - for _, rxPlacement := range intf.GetRxPlacement() { + for _, rxPlacement := range intf.GetRxPlacements() { derValues = append(derValues, kvs.KeyValuePair{ Key: interfaces.RxPlacementKey(intf.GetName(), rxPlacement.GetQueue()), Value: rxPlacement, diff --git a/plugins/vpp/ifplugin/descriptor/interface_crud.go b/plugins/vpp/ifplugin/descriptor/interface_crud.go index fb9e2cfd17..8078a23639 100644 --- a/plugins/vpp/ifplugin/descriptor/interface_crud.go +++ b/plugins/vpp/ifplugin/descriptor/interface_crud.go @@ -421,8 +421,8 @@ func (d *InterfaceDescriptor) Retrieve(correlate []adapter.InterfaceKVWithMetada } // remove rx-placement entries for queues with configuration not defined by NB - rxPlacementDump := intf.Interface.GetRxPlacement() - rxPlacementCfg := expCfg.GetRxPlacement() + rxPlacementDump := intf.Interface.GetRxPlacements() + rxPlacementCfg := expCfg.GetRxPlacements() for i := 0; i < len(rxPlacementDump); { queue := rxPlacementDump[i].Queue found := false @@ -438,11 +438,11 @@ func (d *InterfaceDescriptor) Retrieve(correlate []adapter.InterfaceKVWithMetada rxPlacementDump = append(rxPlacementDump[:i], rxPlacementDump[i+1:]...) } } - intf.Interface.RxPlacement = rxPlacementDump + intf.Interface.RxPlacements = rxPlacementDump // remove rx-mode from the dump if it is not configured by NB - if len(expCfg.GetRxMode()) == 0 { - intf.Interface.RxMode = []*interfaces.Interface_RxMode{} + if len(expCfg.GetRxModes()) == 0 { + intf.Interface.RxModes = []*interfaces.Interface_RxMode{} } } diff --git a/plugins/vpp/ifplugin/descriptor/rx_mode.go b/plugins/vpp/ifplugin/descriptor/rx_mode.go index f416218cde..f50d5a09eb 100644 --- a/plugins/vpp/ifplugin/descriptor/rx_mode.go +++ b/plugins/vpp/ifplugin/descriptor/rx_mode.go @@ -103,7 +103,7 @@ func (d *RxModeDescriptor) EquivalentRxMode(key string, oldIntf, newIntf *interf } } // compare queue-specific RX modes - for _, rxMode := range oldIntf.GetRxMode() { + for _, rxMode := range oldIntf.GetRxModes() { if rxMode.DefaultMode { continue } @@ -113,7 +113,7 @@ func (d *RxModeDescriptor) EquivalentRxMode(key string, oldIntf, newIntf *interf return false } } - for _, rxMode := range newIntf.GetRxMode() { + for _, rxMode := range newIntf.GetRxModes() { if rxMode.DefaultMode { continue } @@ -128,7 +128,7 @@ func (d *RxModeDescriptor) EquivalentRxMode(key string, oldIntf, newIntf *interf // Validate validates Rx mode configuration. func (d *RxModeDescriptor) Validate(key string, ifaceWithRxMode *interfaces.Interface) error { - for i, rxMode1 := range ifaceWithRxMode.GetRxMode() { + for i, rxMode1 := range ifaceWithRxMode.GetRxModes() { if rxMode1.Mode == interfaces.Interface_RxMode_UNKNOWN { if rxMode1.DefaultMode { return kvs.NewInvalidValueError(ErrUndefinedRxMode,"rx_mode[default]") @@ -136,8 +136,8 @@ func (d *RxModeDescriptor) Validate(key string, ifaceWithRxMode *interfaces.Inte return kvs.NewInvalidValueError(ErrUndefinedRxMode, fmt.Sprintf("rx_mode[.queue=%d]", rxMode1.Queue)) } - for j := i + 1; j < len(ifaceWithRxMode.GetRxMode()); j++ { - rxMode2 := ifaceWithRxMode.GetRxMode()[j] + for j := i + 1; j < len(ifaceWithRxMode.GetRxModes()); j++ { + rxMode2 := ifaceWithRxMode.GetRxModes()[j] if rxMode1.DefaultMode != rxMode2.DefaultMode { continue } @@ -152,7 +152,7 @@ func (d *RxModeDescriptor) Validate(key string, ifaceWithRxMode *interfaces.Inte } if ifaceWithRxMode.GetType() == interfaces.Interface_DPDK { - for _, rxMode := range ifaceWithRxMode.GetRxMode() { + for _, rxMode := range ifaceWithRxMode.GetRxModes() { mode := normalizeRxMode(rxMode.Mode, ifaceWithRxMode) if mode != interfaces.Interface_RxMode_POLLING { if rxMode.DefaultMode { @@ -235,7 +235,7 @@ func (d *RxModeDescriptor) configureRxMode(iface *interfaces.Interface, op kvs.T } // configure per-queue RX mode - for _, rxMode := range iface.GetRxMode() { + for _, rxMode := range iface.GetRxModes() { if rxMode.DefaultMode || rxMode.Mode == defRxMode { continue } @@ -264,7 +264,7 @@ func (d *RxModeDescriptor) Dependencies(key string, ifaceWithRxMode *interfaces. // getDefaultRxMode reads default RX mode from the interface configuration. func getDefaultRxMode(iface *interfaces.Interface) (rxMode interfaces.Interface_RxMode_Type) { - for _, rxMode := range iface.GetRxMode() { + for _, rxMode := range iface.GetRxModes() { if rxMode.DefaultMode { return normalizeRxMode(rxMode.Mode, iface) } @@ -274,7 +274,7 @@ func getDefaultRxMode(iface *interfaces.Interface) (rxMode interfaces.Interface_ // getQueueRxMode reads RX mode for the given queue from the interface configuration. func getQueueRxMode(queue uint32, iface *interfaces.Interface) (mode interfaces.Interface_RxMode_Type) { - for _, rxMode := range iface.GetRxMode() { + for _, rxMode := range iface.GetRxModes() { if rxMode.DefaultMode { mode = rxMode.Mode continue // keep looking for a queue-specific RX mode diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go index 4afd6067f4..1f89e22f74 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go @@ -794,7 +794,7 @@ func (h *InterfaceVppHandler) dumpRxPlacement(ifs map[uint32]*vppcalls.Interface continue } - ifData.Interface.RxMode = append(ifData.Interface.RxMode, + ifData.Interface.RxModes = append(ifData.Interface.RxModes, &interfaces.Interface_RxMode{ Queue: rxDetails.QueueID, Mode: getRxModeType(rxDetails.Mode), @@ -804,7 +804,7 @@ func (h *InterfaceVppHandler) dumpRxPlacement(ifs map[uint32]*vppcalls.Interface if rxDetails.WorkerID > 0 { worker = rxDetails.WorkerID - 1 } - ifData.Interface.RxPlacement = append(ifData.Interface.RxPlacement, + ifData.Interface.RxPlacements = append(ifData.Interface.RxPlacements, &interfaces.Interface_RxPlacement{ Queue: rxDetails.QueueID, Worker: worker, diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls_test.go b/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls_test.go index a962e1a3e7..e19c1d2e27 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls_test.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls_test.go @@ -494,7 +494,7 @@ func TestDumpInterfacesRxPlacement(t *testing.T) { Expect(intface.GetMemif().Mode).To(Equal(interfaces2.MemifLink_IP)) Expect(intface.GetMemif().Master).To(BeFalse()) - rxMode := intface.GetRxMode() + rxMode := intface.GetRxModes() Expect(rxMode).To(HaveLen(3)) Expect(rxMode[0].Queue).To(BeEquivalentTo(0)) Expect(rxMode[0].Mode).To(BeEquivalentTo(interfaces2.Interface_RxMode_ADAPTIVE)) @@ -503,7 +503,7 @@ func TestDumpInterfacesRxPlacement(t *testing.T) { Expect(rxMode[2].Queue).To(BeEquivalentTo(2)) Expect(rxMode[2].Mode).To(BeEquivalentTo(interfaces2.Interface_RxMode_POLLING)) - rxPlacement := intface.GetRxPlacement() + rxPlacement := intface.GetRxPlacements() Expect(rxPlacement).To(HaveLen(3)) Expect(rxPlacement[0].Queue).To(BeEquivalentTo(0)) Expect(rxPlacement[0].MainThread).To(BeTrue()) diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls.go index 522d02ad24..9117dff74d 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls.go @@ -810,7 +810,7 @@ func (h *InterfaceVppHandler) dumpRxPlacement(ifs map[uint32]*vppcalls.Interface continue } - ifData.Interface.RxMode = append(ifData.Interface.RxMode, + ifData.Interface.RxModes = append(ifData.Interface.RxModes, &interfaces.Interface_RxMode{ Queue: rxDetails.QueueID, Mode: getRxModeType(rxDetails.Mode), @@ -820,7 +820,7 @@ func (h *InterfaceVppHandler) dumpRxPlacement(ifs map[uint32]*vppcalls.Interface if rxDetails.WorkerID > 0 { worker = rxDetails.WorkerID - 1 } - ifData.Interface.RxPlacement = append(ifData.Interface.RxPlacement, + ifData.Interface.RxPlacements = append(ifData.Interface.RxPlacements, &interfaces.Interface_RxPlacement{ Queue: rxDetails.QueueID, Worker: worker, diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls_test.go b/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls_test.go index b137fd8903..402e099b08 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls_test.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls_test.go @@ -18,6 +18,8 @@ import ( "net" "testing" + govppapi "git.fd.io/govpp.git/api" + interfaces2 "github.com/ligato/vpp-agent/api/models/vpp/interfaces" "github.com/ligato/vpp-agent/plugins/vpp/binapi/vpp1904/dhcp" "github.com/ligato/vpp-agent/plugins/vpp/binapi/vpp1904/interfaces" @@ -304,3 +306,113 @@ func TestDumpMemifSocketDetails(t *testing.T) { Expect(ok).To(BeTrue()) Expect(socketID).To(Equal(uint32(1))) } + +func TestDumpInterfacesRxPlacement(t *testing.T) { + ctx, ifHandler := ifTestSetup(t) + defer ctx.TeardownTestCtx() + + ctx.MockReplies([]*vppcallmock.HandleReplies{ + { + Name: (&interfaces.SwInterfaceDump{}).GetMessageName(), + Ping: true, + Message: &interfaces.SwInterfaceDetails{ + InterfaceName: []byte("memif1"), + }, + }, + { + Name: (&interfaces.SwInterfaceGetTable{}).GetMessageName(), + Ping: false, + Message: &interfaces.SwInterfaceGetTableReply{}, + }, + { + Name: (&ip.IPAddressDump{}).GetMessageName(), + Ping: true, + Message: &ip.IPAddressDetails{}, + }, + { + Name: (&memif.MemifSocketFilenameDump{}).GetMessageName(), + Ping: true, + Message: &memif.MemifSocketFilenameDetails{ + SocketID: 1, + SocketFilename: []byte("test"), + }, + }, + { + Name: (&memif.MemifDump{}).GetMessageName(), + Ping: true, + Message: &memif.MemifDetails{ + ID: 2, + SwIfIndex: 0, + Role: 1, // Slave + Mode: 1, // IP + SocketID: 1, + RingSize: 0, + BufferSize: 0, + }, + }, + { + Name: (&tapv2.SwInterfaceTapV2Dump{}).GetMessageName(), + Ping: true, + }, + { + Name: (&vxlan.VxlanTunnelDump{}).GetMessageName(), + Ping: true, + }, + { + Name: (&interfaces.SwInterfaceRxPlacementDump{}).GetMessageName(), + Ping: true, + Messages: []govppapi.Message{ + &interfaces.SwInterfaceRxPlacementDetails{ + SwIfIndex: 0, + QueueID: 0, + WorkerID: 0, // main thread + Mode: 3, // adaptive + }, + &interfaces.SwInterfaceRxPlacementDetails{ + SwIfIndex: 0, + QueueID: 1, + WorkerID: 1, // worker 0 + Mode: 2, // interrupt + }, + &interfaces.SwInterfaceRxPlacementDetails{ + SwIfIndex: 0, + QueueID: 2, + WorkerID: 2, // worker 1 + Mode: 1, // polling + }, + }, + }, + }) + + intfs, err := ifHandler.DumpInterfaces() + Expect(err).To(BeNil()) + Expect(intfs).To(HaveLen(1)) + intface := intfs[0].Interface + + // Check memif + Expect(intface.GetMemif().SocketFilename).To(Equal("test")) + Expect(intface.GetMemif().Id).To(Equal(uint32(2))) + Expect(intface.GetMemif().Mode).To(Equal(interfaces2.MemifLink_IP)) + Expect(intface.GetMemif().Master).To(BeFalse()) + + rxMode := intface.GetRxModes() + Expect(rxMode).To(HaveLen(3)) + Expect(rxMode[0].Queue).To(BeEquivalentTo(0)) + Expect(rxMode[0].Mode).To(BeEquivalentTo(interfaces2.Interface_RxMode_ADAPTIVE)) + Expect(rxMode[1].Queue).To(BeEquivalentTo(1)) + Expect(rxMode[1].Mode).To(BeEquivalentTo(interfaces2.Interface_RxMode_INTERRUPT)) + Expect(rxMode[2].Queue).To(BeEquivalentTo(2)) + Expect(rxMode[2].Mode).To(BeEquivalentTo(interfaces2.Interface_RxMode_POLLING)) + + rxPlacement := intface.GetRxPlacements() + Expect(rxPlacement).To(HaveLen(3)) + Expect(rxPlacement[0].Queue).To(BeEquivalentTo(0)) + Expect(rxPlacement[0].MainThread).To(BeTrue()) + Expect(rxPlacement[0].Worker).To(BeEquivalentTo(0)) + Expect(rxPlacement[1].Queue).To(BeEquivalentTo(1)) + Expect(rxPlacement[1].MainThread).To(BeFalse()) + Expect(rxPlacement[1].Worker).To(BeEquivalentTo(0)) + Expect(rxPlacement[2].Queue).To(BeEquivalentTo(2)) + Expect(rxPlacement[2].MainThread).To(BeFalse()) + Expect(rxPlacement[2].Worker).To(BeEquivalentTo(1)) +} \ No newline at end of file From 36a4186b460007f3327d1c37239df2447b9d5936 Mon Sep 17 00:00:00 2001 From: Milan Lenco Date: Fri, 17 May 2019 10:50:19 +0200 Subject: [PATCH 11/13] Add check for multiple descriptors matching the same key. Signed-off-by: Milan Lenco --- plugins/kvscheduler/internal/registry/registry_impl.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/kvscheduler/internal/registry/registry_impl.go b/plugins/kvscheduler/internal/registry/registry_impl.go index d403e6f986..898e1a321a 100644 --- a/plugins/kvscheduler/internal/registry/registry_impl.go +++ b/plugins/kvscheduler/internal/registry/registry_impl.go @@ -19,6 +19,7 @@ import ( . "github.com/ligato/vpp-agent/plugins/kvscheduler/api" "github.com/ligato/vpp-agent/plugins/kvscheduler/internal/utils" + "fmt" ) const ( @@ -111,8 +112,11 @@ func (reg *registry) GetDescriptorForKey(key string) *KVDescriptor { var keyDescriptor *KVDescriptor for _, descriptor := range reg.descriptors { if descriptor.KeySelector(key) { + if keyDescriptor != nil { + panic(fmt.Sprintf("key %s is selected by both %s and %s descriptors", + key, keyDescriptor.Name, descriptor.Name)) + } keyDescriptor = descriptor - break } } // add entry to cache From d06757fe56b24fea7a0a36adc94b03fb0dd5cbcb Mon Sep 17 00:00:00 2001 From: Milan Lenco Date: Fri, 17 May 2019 11:02:25 +0200 Subject: [PATCH 12/13] Pluralize also key for all rx-modes of an interface Signed-off-by: Milan Lenco --- api/models/vpp/interfaces/keys.go | 21 +++--- api/models/vpp/interfaces/keys_test.go | 76 ++++++++++---------- plugins/vpp/ifplugin/descriptor/interface.go | 2 +- plugins/vpp/ifplugin/descriptor/rx_mode.go | 2 +- 4 files changed, 49 insertions(+), 52 deletions(-) diff --git a/api/models/vpp/interfaces/keys.go b/api/models/vpp/interfaces/keys.go index a659fbc197..e13ac15520 100644 --- a/api/models/vpp/interfaces/keys.go +++ b/api/models/vpp/interfaces/keys.go @@ -128,11 +128,11 @@ const ( rxPlacementKeyTemplate = "vpp/interface/{iface}/rx-placement/queue/{queue}" ) -/* Interface Rx-mode (derived) */ +/* Interface Rx-modes (derived) */ const ( // rxModeKeyTemplate is a template for (derived) key representing // rx-mode configuration for all queues of a given interface. - rxModeKeyTemplate = "vpp/interface/{iface}/rx-mode" + rxModesKeyTemplate = "vpp/interface/{iface}/rx-modes" ) const ( @@ -527,24 +527,23 @@ func ParseRxPlacementKey(key string) (ifaceName string, queue uint32, isRxPlacem return } -/* Rx mode (derived) */ +/* Rx modes (derived) */ -// RxModeKey returns a key representing rx-mode configuration for all queues +// RxModesKey returns a key representing rx-mode configuration for all queues // of a given interface. -func RxModeKey(ifaceName string) string { +func RxModesKey(ifaceName string) string { if ifaceName == "" { ifaceName = InvalidKeyPart } - return strings.Replace(rxModeKeyTemplate, "{iface}", ifaceName, 1) + return strings.Replace(rxModesKeyTemplate, "{iface}", ifaceName, 1) } -// ParseRxModeKey parses key representing rx-mode configuration for all queues +// ParseRxModesKey parses key representing rx-mode configuration for all queues // of a given interface. -func ParseRxModeKey(key string) (ifaceName string, isRxModeKey bool) { +func ParseRxModesKey(key string) (ifaceName string, isRxModesKey bool) { if suffix := strings.TrimPrefix(key, "vpp/interface/"); suffix != key { parts := strings.Split(suffix, "/") - if len(parts) == 0 || parts[len(parts)-1] != "rx-mode" { - isRxModeKey = false + if len(parts) == 0 || parts[len(parts)-1] != "rx-modes" { return } @@ -555,7 +554,7 @@ func ParseRxModeKey(key string) (ifaceName string, isRxModeKey bool) { return } - isRxModeKey = true + isRxModesKey = true } return } diff --git a/api/models/vpp/interfaces/keys_test.go b/api/models/vpp/interfaces/keys_test.go index 92239d1e42..e166f65aad 100644 --- a/api/models/vpp/interfaces/keys_test.go +++ b/api/models/vpp/interfaces/keys_test.go @@ -889,11 +889,11 @@ func TestLinkStateKey(t *testing.T) { func TestParseLinkStateKey(t *testing.T) { tests := []struct { - name string - key string - expectedIface string - expectedIsLinkUp bool - expectedIsLinkStateKey bool + name string + key string + expectedIface string + expectedIsLinkUp bool + expectedIsLinkStateKey bool }{ { name: "link is UP", @@ -936,7 +936,6 @@ func TestParseLinkStateKey(t *testing.T) { key: "vpp/interface/unnumbered/GigabitEthernet0/8/0", expectedIsLinkStateKey: false, }, - } for _, test := range tests { t.Run(test.name, func(t *testing.T) { @@ -1032,7 +1031,7 @@ func TestParseRxPlacementKey(t *testing.T) { expectedIsRxPlacementKey: false, }, { - name: "missing queue", + name: "missing queue", key: "vpp/interface/memif0/rx-placement/", expectedIsRxPlacementKey: false, }, @@ -1053,7 +1052,6 @@ func TestParseRxPlacementKey(t *testing.T) { key: "vpp/interface/memif0/link-state/DOWN", expectedIsRxPlacementKey: false, }, - } for _, test := range tests { t.Run(test.name, func(t *testing.T) { @@ -1072,7 +1070,7 @@ func TestParseRxPlacementKey(t *testing.T) { } } -func TestRxModeKey(t *testing.T) { +func TestRxModesKey(t *testing.T) { tests := []struct { name string iface string @@ -1081,22 +1079,22 @@ func TestRxModeKey(t *testing.T) { { name: "memif", iface: "memif0", - expectedKey: "vpp/interface/memif0/rx-mode", + expectedKey: "vpp/interface/memif0/rx-modes", }, { name: "Gbe", iface: "GigabitEthernet0/8/0", - expectedKey: "vpp/interface/GigabitEthernet0/8/0/rx-mode", + expectedKey: "vpp/interface/GigabitEthernet0/8/0/rx-modes", }, { name: "invalid interface name", iface: "", - expectedKey: "vpp/interface//rx-mode", + expectedKey: "vpp/interface//rx-modes", }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - key := RxModeKey(test.iface) + key := RxModesKey(test.iface) if key != test.expectedKey { t.Errorf("failed for: iface=%s\n"+ "expected key:\n\t%q\ngot key:\n\t%q", @@ -1106,47 +1104,47 @@ func TestRxModeKey(t *testing.T) { } } -func TestParseRxModeKey(t *testing.T) { +func TestParseRxModesKey(t *testing.T) { tests := []struct { - name string - key string - expectedIface string - expectedIsRxModeKey bool + name string + key string + expectedIface string + expectedIsRxModesKey bool }{ { - name: "memif", - key: "vpp/interface/memif0/rx-mode", - expectedIface: "memif0", - expectedIsRxModeKey: true, + name: "memif", + key: "vpp/interface/memif0/rx-modes", + expectedIface: "memif0", + expectedIsRxModesKey: true, }, { - name: "Gbe", - key: "vpp/interface/GigabitEthernet0/8/0/rx-mode", - expectedIface: "GigabitEthernet0/8/0", - expectedIsRxModeKey: true, + name: "Gbe", + key: "vpp/interface/GigabitEthernet0/8/0/rx-modes", + expectedIface: "GigabitEthernet0/8/0", + expectedIsRxModesKey: true, }, { - name: "invalid interface name", - key: "vpp/interface//rx-mode", - expectedIsRxModeKey: false, + name: "invalid interface name", + key: "vpp/interface//rx-modes", + expectedIsRxModesKey: false, }, { - name: "missing rx-mode suffix", - key: "vpp/interface/", - expectedIsRxModeKey: false, + name: "missing rx-mode suffix", + key: "vpp/interface/", + expectedIsRxModesKey: false, }, { - name: "not rx-mode key", - key: "vpp/interface/memif0/address/192.168.1.12/24", - expectedIsRxModeKey: false, + name: "not rx-mode key", + key: "vpp/interface/memif0/address/192.168.1.12/24", + expectedIsRxModesKey: false, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - iface, isRxModeKey := ParseRxModeKey(test.key) - if isRxModeKey != test.expectedIsRxModeKey { - t.Errorf("expected isRxModeKey: %v\tgot: %v", - test.expectedIsRxModeKey, isRxModeKey) + iface, isRxModesKey := ParseRxModesKey(test.key) + if isRxModesKey != test.expectedIsRxModesKey { + t.Errorf("expected isRxModesKey: %v\tgot: %v", + test.expectedIsRxModesKey, isRxModesKey) } if iface != test.expectedIface { t.Errorf("expected iface: %s\tgot: %s", test.expectedIface, iface) diff --git a/plugins/vpp/ifplugin/descriptor/interface.go b/plugins/vpp/ifplugin/descriptor/interface.go index cbc5059b08..7e7978a5d9 100644 --- a/plugins/vpp/ifplugin/descriptor/interface.go +++ b/plugins/vpp/ifplugin/descriptor/interface.go @@ -605,7 +605,7 @@ func (d *InterfaceDescriptor) DerivedValues(key string, intf *interfaces.Interfa // Rx mode if len(intf.GetRxModes()) > 0 { derValues = append(derValues, kvs.KeyValuePair{ - Key: interfaces.RxModeKey(intf.GetName()), + Key: interfaces.RxModesKey(intf.GetName()), Value: &interfaces.Interface{ Name: intf.GetName(), Type: intf.GetType(), diff --git a/plugins/vpp/ifplugin/descriptor/rx_mode.go b/plugins/vpp/ifplugin/descriptor/rx_mode.go index f50d5a09eb..59130aafc5 100644 --- a/plugins/vpp/ifplugin/descriptor/rx_mode.go +++ b/plugins/vpp/ifplugin/descriptor/rx_mode.go @@ -85,7 +85,7 @@ func NewRxModeDescriptor(ifHandler vppcalls.InterfaceVppAPI, ifIndex ifaceidx.If // IsInterfaceRxModeKey returns true if the key is identifying RxMode configuration. func (d *RxModeDescriptor) IsInterfaceRxModeKey(key string) bool { - _, isValid := interfaces.ParseRxModeKey(key) + _, isValid := interfaces.ParseRxModesKey(key) return isValid } From a6c48034492efdc17cf2386341b237f00408267d Mon Sep 17 00:00:00 2001 From: Milan Lenco Date: Fri, 17 May 2019 11:10:17 +0200 Subject: [PATCH 13/13] Remove unnecessary LinkIsUp from interface metadata Signed-off-by: Milan Lenco --- plugins/vpp/ifplugin/descriptor/interface_crud.go | 1 - plugins/vpp/ifplugin/ifaceidx/ifaceidx.go | 1 - 2 files changed, 2 deletions(-) diff --git a/plugins/vpp/ifplugin/descriptor/interface_crud.go b/plugins/vpp/ifplugin/descriptor/interface_crud.go index 8078a23639..bfb7d443a8 100644 --- a/plugins/vpp/ifplugin/descriptor/interface_crud.go +++ b/plugins/vpp/ifplugin/descriptor/interface_crud.go @@ -478,7 +478,6 @@ func (d *InterfaceDescriptor) Retrieve(correlate []adapter.InterfaceKVWithMetada Vrf: intf.Interface.Vrf, IPAddresses: intf.Interface.IpAddresses, TAPHostIfName: tapHostIfName, - LinkIsUp: intf.Meta.LinkState == 1, } retrieved = append(retrieved, adapter.InterfaceKVWithMetadata{ Key: models.Key(intf.Interface), diff --git a/plugins/vpp/ifplugin/ifaceidx/ifaceidx.go b/plugins/vpp/ifplugin/ifaceidx/ifaceidx.go index 5c19ceafcc..58c2d1da3a 100644 --- a/plugins/vpp/ifplugin/ifaceidx/ifaceidx.go +++ b/plugins/vpp/ifplugin/ifaceidx/ifaceidx.go @@ -63,7 +63,6 @@ type IfaceMetadata struct { Vrf uint32 IPAddresses []string TAPHostIfName string /* host interface name set for the Linux-side of the TAP interface; empty for non-TAPs */ - LinkIsUp bool // Note: this is updated only on refresh! (i.e. suitable to use for Retrieve) } // GetIndex returns sw_if_index assigned to the interface.