diff --git a/dataplane/kernel/genetlink/genetlink.go b/dataplane/kernel/genetlink/genetlink.go index c52afe51..6e9450e5 100644 --- a/dataplane/kernel/genetlink/genetlink.go +++ b/dataplane/kernel/genetlink/genetlink.go @@ -107,6 +107,10 @@ func (p GenetlinkPort) Delete() error { return nil } +func (t GenetlinkPort) SetAdminState(up bool) error { + return nil +} + func init() { pktiohandler.Register(pktiopb.PortType_PORT_TYPE_GENETLINK, New) } diff --git a/dataplane/kernel/tap/tap.go b/dataplane/kernel/tap/tap.go index 68e1bb6b..bd1c41b4 100644 --- a/dataplane/kernel/tap/tap.go +++ b/dataplane/kernel/tap/tap.go @@ -69,6 +69,17 @@ func (t *TapInterface) IfIndex() int { return t.ifIndex } +func (t *TapInterface) SetAdminState(up bool) error { + l, err := netlink.LinkByName(t.name) + if err != nil { + return err + } + if up { + return netlink.LinkSetUp(l) + } + return netlink.LinkSetDown(l) +} + func init() { pktiohandler.Register(pktiopb.PortType_PORT_TYPE_NETDEV, New) } diff --git a/dataplane/proto/packetio/packetio.pb.go b/dataplane/proto/packetio/packetio.pb.go index 491616ca..fca072ca 100755 --- a/dataplane/proto/packetio/packetio.pb.go +++ b/dataplane/proto/packetio/packetio.pb.go @@ -25,6 +25,61 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +type PortOperation int32 + +const ( + PortOperation_PORT_OPERATION_UNSPECIFIED PortOperation = 0 + PortOperation_PORT_OPERATION_CREATE PortOperation = 1 + PortOperation_PORT_OPERATION_DELETE PortOperation = 2 + PortOperation_PORT_OPERATION_SET_UP PortOperation = 3 + PortOperation_PORT_OPERATION_SET_DOWN PortOperation = 4 +) + +// Enum value maps for PortOperation. +var ( + PortOperation_name = map[int32]string{ + 0: "PORT_OPERATION_UNSPECIFIED", + 1: "PORT_OPERATION_CREATE", + 2: "PORT_OPERATION_DELETE", + 3: "PORT_OPERATION_SET_UP", + 4: "PORT_OPERATION_SET_DOWN", + } + PortOperation_value = map[string]int32{ + "PORT_OPERATION_UNSPECIFIED": 0, + "PORT_OPERATION_CREATE": 1, + "PORT_OPERATION_DELETE": 2, + "PORT_OPERATION_SET_UP": 3, + "PORT_OPERATION_SET_DOWN": 4, + } +) + +func (x PortOperation) Enum() *PortOperation { + p := new(PortOperation) + *p = x + return p +} + +func (x PortOperation) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (PortOperation) Descriptor() protoreflect.EnumDescriptor { + return file_dataplane_proto_packetio_packetio_proto_enumTypes[0].Descriptor() +} + +func (PortOperation) Type() protoreflect.EnumType { + return &file_dataplane_proto_packetio_packetio_proto_enumTypes[0] +} + +func (x PortOperation) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use PortOperation.Descriptor instead. +func (PortOperation) EnumDescriptor() ([]byte, []int) { + return file_dataplane_proto_packetio_packetio_proto_rawDescGZIP(), []int{0} +} + type PortType int32 const ( @@ -58,11 +113,11 @@ func (x PortType) String() string { } func (PortType) Descriptor() protoreflect.EnumDescriptor { - return file_dataplane_proto_packetio_packetio_proto_enumTypes[0].Descriptor() + return file_dataplane_proto_packetio_packetio_proto_enumTypes[1].Descriptor() } func (PortType) Type() protoreflect.EnumType { - return &file_dataplane_proto_packetio_packetio_proto_enumTypes[0] + return &file_dataplane_proto_packetio_packetio_proto_enumTypes[1] } func (x PortType) Number() protoreflect.EnumNumber { @@ -71,7 +126,7 @@ func (x PortType) Number() protoreflect.EnumNumber { // Deprecated: Use PortType.Descriptor instead. func (PortType) EnumDescriptor() ([]byte, []int) { - return file_dataplane_proto_packetio_packetio_proto_rawDescGZIP(), []int{0} + return file_dataplane_proto_packetio_packetio_proto_rawDescGZIP(), []int{1} } type HostPortControlInit struct { @@ -302,12 +357,14 @@ type HostPortControlMessage struct { PortId uint64 `protobuf:"varint,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty"` DataplanePort uint64 `protobuf:"varint,2,opt,name=dataplane_port,json=dataplanePort,proto3" json:"dataplane_port,omitempty"` - Create bool `protobuf:"varint,3,opt,name=create,proto3" json:"create,omitempty"` + // Deprecated: Marked as deprecated in dataplane/proto/packetio/packetio.proto. + Create bool `protobuf:"varint,3,opt,name=create,proto3" json:"create,omitempty"` // Types that are assignable to Port: // // *HostPortControlMessage_Netdev // *HostPortControlMessage_Genetlink Port isHostPortControlMessage_Port `protobuf_oneof:"port"` + Op PortOperation `protobuf:"varint,6,opt,name=op,proto3,enum=lucius.dataplane.packetio.PortOperation" json:"op,omitempty"` } func (x *HostPortControlMessage) Reset() { @@ -356,6 +413,7 @@ func (x *HostPortControlMessage) GetDataplanePort() uint64 { return 0 } +// Deprecated: Marked as deprecated in dataplane/proto/packetio/packetio.proto. func (x *HostPortControlMessage) GetCreate() bool { if x != nil { return x.Create @@ -384,6 +442,13 @@ func (x *HostPortControlMessage) GetGenetlink() *GenetlinkPort { return nil } +func (x *HostPortControlMessage) GetOp() PortOperation { + if x != nil { + return x.Op + } + return PortOperation_PORT_OPERATION_UNSPECIFIED +} + type isHostPortControlMessage_Port interface { isHostPortControlMessage_Port() } @@ -662,71 +727,85 @@ var file_dataplane_proto_packetio_packetio_proto_rawDesc = []byte{ 0x47, 0x65, 0x6e, 0x65, 0x74, 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x83, 0x02, 0x0a, 0x16, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x22, 0xc1, 0x02, 0x0a, 0x16, 0x48, 0x6f, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, - 0x6e, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x3f, - 0x0a, 0x06, 0x6e, 0x65, 0x74, 0x64, 0x65, 0x76, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, - 0x2e, 0x6c, 0x75, 0x63, 0x69, 0x75, 0x73, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, - 0x65, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x69, 0x6f, 0x2e, 0x4e, 0x65, 0x74, 0x64, 0x65, - 0x76, 0x50, 0x6f, 0x72, 0x74, 0x48, 0x00, 0x52, 0x06, 0x6e, 0x65, 0x74, 0x64, 0x65, 0x76, 0x12, - 0x48, 0x0a, 0x09, 0x67, 0x65, 0x6e, 0x65, 0x74, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x6c, 0x75, 0x63, 0x69, 0x75, 0x73, 0x2e, 0x64, 0x61, 0x74, 0x61, - 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x69, 0x6f, 0x2e, 0x47, - 0x65, 0x6e, 0x65, 0x74, 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x6f, 0x72, 0x74, 0x48, 0x00, 0x52, 0x09, - 0x67, 0x65, 0x6e, 0x65, 0x74, 0x6c, 0x69, 0x6e, 0x6b, 0x42, 0x06, 0x0a, 0x04, 0x70, 0x6f, 0x72, - 0x74, 0x22, 0x7b, 0x0a, 0x06, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x68, - 0x6f, 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, - 0x68, 0x6f, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x6e, 0x70, 0x75, - 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x69, 0x6e, - 0x70, 0x75, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x75, 0x74, 0x70, 0x75, - 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x6f, 0x75, - 0x74, 0x70, 0x75, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x72, 0x61, 0x6d, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x22, 0x12, - 0x0a, 0x10, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x6e, - 0x69, 0x74, 0x22, 0x91, 0x01, 0x0a, 0x08, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x49, 0x6e, 0x12, - 0x41, 0x0a, 0x04, 0x69, 0x6e, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, - 0x6c, 0x75, 0x63, 0x69, 0x75, 0x73, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, - 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x69, 0x6f, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, - 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x6e, 0x69, 0x74, 0x48, 0x00, 0x52, 0x04, 0x69, 0x6e, - 0x69, 0x74, 0x12, 0x3b, 0x0a, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6c, 0x75, 0x63, 0x69, 0x75, 0x73, 0x2e, 0x64, 0x61, 0x74, 0x61, - 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x69, 0x6f, 0x2e, 0x50, - 0x61, 0x63, 0x6b, 0x65, 0x74, 0x48, 0x00, 0x52, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x42, - 0x05, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x22, 0x46, 0x0a, 0x09, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, - 0x4f, 0x75, 0x74, 0x12, 0x39, 0x0a, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6c, 0x75, 0x63, 0x69, 0x75, 0x73, 0x2e, 0x64, 0x61, 0x74, - 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x69, 0x6f, 0x2e, - 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x2a, 0x54, - 0x0a, 0x08, 0x50, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x50, 0x4f, - 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, - 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x4e, 0x45, 0x54, 0x44, 0x45, 0x56, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x50, - 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x54, 0x4c, 0x49, - 0x4e, 0x4b, 0x10, 0x02, 0x32, 0xed, 0x01, 0x0a, 0x08, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x49, - 0x4f, 0x12, 0x7d, 0x0a, 0x0f, 0x48, 0x6f, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x31, 0x2e, 0x6c, 0x75, 0x63, 0x69, 0x75, 0x73, 0x2e, 0x64, 0x61, - 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x69, 0x6f, - 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x6c, 0x75, 0x63, 0x69, 0x75, 0x73, - 0x2e, 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x65, - 0x74, 0x69, 0x6f, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, - 0x72, 0x6f, 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, - 0x12, 0x62, 0x0a, 0x0f, 0x43, 0x50, 0x55, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x12, 0x23, 0x2e, 0x6c, 0x75, 0x63, 0x69, 0x75, 0x73, 0x2e, 0x64, 0x61, 0x74, - 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x69, 0x6f, 0x2e, - 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x49, 0x6e, 0x1a, 0x24, 0x2e, 0x6c, 0x75, 0x63, 0x69, 0x75, - 0x73, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x70, 0x61, 0x63, 0x6b, - 0x65, 0x74, 0x69, 0x6f, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x4f, 0x75, 0x74, 0x22, 0x00, - 0x28, 0x01, 0x30, 0x01, 0x42, 0x38, 0x5a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, - 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x6c, 0x65, - 0x6d, 0x6d, 0x69, 0x6e, 0x67, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x69, 0x6f, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1a, 0x0a, 0x06, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x42, 0x02, 0x18, 0x01, 0x52, 0x06, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x12, 0x3f, 0x0a, 0x06, 0x6e, 0x65, 0x74, 0x64, 0x65, 0x76, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6c, 0x75, 0x63, 0x69, 0x75, 0x73, 0x2e, 0x64, 0x61, 0x74, 0x61, + 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x69, 0x6f, 0x2e, 0x4e, + 0x65, 0x74, 0x64, 0x65, 0x76, 0x50, 0x6f, 0x72, 0x74, 0x48, 0x00, 0x52, 0x06, 0x6e, 0x65, 0x74, + 0x64, 0x65, 0x76, 0x12, 0x48, 0x0a, 0x09, 0x67, 0x65, 0x6e, 0x65, 0x74, 0x6c, 0x69, 0x6e, 0x6b, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x6c, 0x75, 0x63, 0x69, 0x75, 0x73, 0x2e, + 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, + 0x69, 0x6f, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x74, 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x6f, 0x72, 0x74, + 0x48, 0x00, 0x52, 0x09, 0x67, 0x65, 0x6e, 0x65, 0x74, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x38, 0x0a, + 0x02, 0x6f, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x6c, 0x75, 0x63, 0x69, + 0x75, 0x73, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x70, 0x61, 0x63, + 0x6b, 0x65, 0x74, 0x69, 0x6f, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x02, 0x6f, 0x70, 0x42, 0x06, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, + 0x7b, 0x0a, 0x06, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x6f, 0x73, + 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x68, 0x6f, + 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, + 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, + 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x6f, 0x75, 0x74, 0x70, + 0x75, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x22, 0x12, 0x0a, 0x10, + 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x6e, 0x69, 0x74, + 0x22, 0x91, 0x01, 0x0a, 0x08, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x49, 0x6e, 0x12, 0x41, 0x0a, + 0x04, 0x69, 0x6e, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x6c, 0x75, + 0x63, 0x69, 0x75, 0x73, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x70, + 0x61, 0x63, 0x6b, 0x65, 0x74, 0x69, 0x6f, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x49, 0x6e, 0x69, 0x74, 0x48, 0x00, 0x52, 0x04, 0x69, 0x6e, 0x69, 0x74, + 0x12, 0x3b, 0x0a, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x21, 0x2e, 0x6c, 0x75, 0x63, 0x69, 0x75, 0x73, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, + 0x61, 0x6e, 0x65, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x69, 0x6f, 0x2e, 0x50, 0x61, 0x63, + 0x6b, 0x65, 0x74, 0x48, 0x00, 0x52, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x42, 0x05, 0x0a, + 0x03, 0x6d, 0x73, 0x67, 0x22, 0x46, 0x0a, 0x09, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x4f, 0x75, + 0x74, 0x12, 0x39, 0x0a, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x21, 0x2e, 0x6c, 0x75, 0x63, 0x69, 0x75, 0x73, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x70, + 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x69, 0x6f, 0x2e, 0x50, 0x61, + 0x63, 0x6b, 0x65, 0x74, 0x52, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x2a, 0x9d, 0x01, 0x0a, + 0x0d, 0x50, 0x6f, 0x72, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, + 0x0a, 0x1a, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, + 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, + 0x0a, 0x15, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, + 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, 0x50, 0x4f, 0x52, + 0x54, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x44, 0x45, 0x4c, 0x45, + 0x54, 0x45, 0x10, 0x02, 0x12, 0x19, 0x0a, 0x15, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x4f, 0x50, 0x45, + 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x45, 0x54, 0x5f, 0x55, 0x50, 0x10, 0x03, 0x12, + 0x1b, 0x0a, 0x17, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x53, 0x45, 0x54, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x04, 0x2a, 0x54, 0x0a, 0x08, + 0x50, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x50, 0x4f, 0x52, 0x54, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, + 0x44, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x4e, 0x45, 0x54, 0x44, 0x45, 0x56, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x50, 0x4f, 0x52, + 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x54, 0x4c, 0x49, 0x4e, 0x4b, + 0x10, 0x02, 0x32, 0xed, 0x01, 0x0a, 0x08, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x49, 0x4f, 0x12, + 0x7d, 0x0a, 0x0f, 0x48, 0x6f, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x12, 0x31, 0x2e, 0x6c, 0x75, 0x63, 0x69, 0x75, 0x73, 0x2e, 0x64, 0x61, 0x74, 0x61, + 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x69, 0x6f, 0x2e, 0x48, + 0x6f, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x6c, 0x75, 0x63, 0x69, 0x75, 0x73, 0x2e, 0x64, + 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x69, + 0x6f, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, 0x62, + 0x0a, 0x0f, 0x43, 0x50, 0x55, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x12, 0x23, 0x2e, 0x6c, 0x75, 0x63, 0x69, 0x75, 0x73, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x70, + 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x69, 0x6f, 0x2e, 0x50, 0x61, + 0x63, 0x6b, 0x65, 0x74, 0x49, 0x6e, 0x1a, 0x24, 0x2e, 0x6c, 0x75, 0x63, 0x69, 0x75, 0x73, 0x2e, + 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, + 0x69, 0x6f, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x4f, 0x75, 0x74, 0x22, 0x00, 0x28, 0x01, + 0x30, 0x01, 0x42, 0x38, 0x5a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x6c, 0x65, 0x6d, 0x6d, + 0x69, 0x6e, 0x67, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x69, 0x6f, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -741,38 +820,40 @@ func file_dataplane_proto_packetio_packetio_proto_rawDescGZIP() []byte { return file_dataplane_proto_packetio_packetio_proto_rawDescData } -var file_dataplane_proto_packetio_packetio_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_dataplane_proto_packetio_packetio_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_dataplane_proto_packetio_packetio_proto_msgTypes = make([]protoimpl.MessageInfo, 9) var file_dataplane_proto_packetio_packetio_proto_goTypes = []interface{}{ - (PortType)(0), // 0: lucius.dataplane.packetio.PortType - (*HostPortControlInit)(nil), // 1: lucius.dataplane.packetio.HostPortControlInit - (*HostPortControlRequest)(nil), // 2: lucius.dataplane.packetio.HostPortControlRequest - (*NetdevPort)(nil), // 3: lucius.dataplane.packetio.NetdevPort - (*GenetlinkPort)(nil), // 4: lucius.dataplane.packetio.GenetlinkPort - (*HostPortControlMessage)(nil), // 5: lucius.dataplane.packetio.HostPortControlMessage - (*Packet)(nil), // 6: lucius.dataplane.packetio.Packet - (*PacketStreamInit)(nil), // 7: lucius.dataplane.packetio.PacketStreamInit - (*PacketIn)(nil), // 8: lucius.dataplane.packetio.PacketIn - (*PacketOut)(nil), // 9: lucius.dataplane.packetio.PacketOut - (*status.Status)(nil), // 10: google.rpc.Status + (PortOperation)(0), // 0: lucius.dataplane.packetio.PortOperation + (PortType)(0), // 1: lucius.dataplane.packetio.PortType + (*HostPortControlInit)(nil), // 2: lucius.dataplane.packetio.HostPortControlInit + (*HostPortControlRequest)(nil), // 3: lucius.dataplane.packetio.HostPortControlRequest + (*NetdevPort)(nil), // 4: lucius.dataplane.packetio.NetdevPort + (*GenetlinkPort)(nil), // 5: lucius.dataplane.packetio.GenetlinkPort + (*HostPortControlMessage)(nil), // 6: lucius.dataplane.packetio.HostPortControlMessage + (*Packet)(nil), // 7: lucius.dataplane.packetio.Packet + (*PacketStreamInit)(nil), // 8: lucius.dataplane.packetio.PacketStreamInit + (*PacketIn)(nil), // 9: lucius.dataplane.packetio.PacketIn + (*PacketOut)(nil), // 10: lucius.dataplane.packetio.PacketOut + (*status.Status)(nil), // 11: google.rpc.Status } var file_dataplane_proto_packetio_packetio_proto_depIdxs = []int32{ - 1, // 0: lucius.dataplane.packetio.HostPortControlRequest.init:type_name -> lucius.dataplane.packetio.HostPortControlInit - 10, // 1: lucius.dataplane.packetio.HostPortControlRequest.status:type_name -> google.rpc.Status - 3, // 2: lucius.dataplane.packetio.HostPortControlMessage.netdev:type_name -> lucius.dataplane.packetio.NetdevPort - 4, // 3: lucius.dataplane.packetio.HostPortControlMessage.genetlink:type_name -> lucius.dataplane.packetio.GenetlinkPort - 7, // 4: lucius.dataplane.packetio.PacketIn.init:type_name -> lucius.dataplane.packetio.PacketStreamInit - 6, // 5: lucius.dataplane.packetio.PacketIn.packet:type_name -> lucius.dataplane.packetio.Packet - 6, // 6: lucius.dataplane.packetio.PacketOut.packet:type_name -> lucius.dataplane.packetio.Packet - 2, // 7: lucius.dataplane.packetio.PacketIO.HostPortControl:input_type -> lucius.dataplane.packetio.HostPortControlRequest - 8, // 8: lucius.dataplane.packetio.PacketIO.CPUPacketStream:input_type -> lucius.dataplane.packetio.PacketIn - 5, // 9: lucius.dataplane.packetio.PacketIO.HostPortControl:output_type -> lucius.dataplane.packetio.HostPortControlMessage - 9, // 10: lucius.dataplane.packetio.PacketIO.CPUPacketStream:output_type -> lucius.dataplane.packetio.PacketOut - 9, // [9:11] is the sub-list for method output_type - 7, // [7:9] is the sub-list for method input_type - 7, // [7:7] is the sub-list for extension type_name - 7, // [7:7] is the sub-list for extension extendee - 0, // [0:7] is the sub-list for field type_name + 2, // 0: lucius.dataplane.packetio.HostPortControlRequest.init:type_name -> lucius.dataplane.packetio.HostPortControlInit + 11, // 1: lucius.dataplane.packetio.HostPortControlRequest.status:type_name -> google.rpc.Status + 4, // 2: lucius.dataplane.packetio.HostPortControlMessage.netdev:type_name -> lucius.dataplane.packetio.NetdevPort + 5, // 3: lucius.dataplane.packetio.HostPortControlMessage.genetlink:type_name -> lucius.dataplane.packetio.GenetlinkPort + 0, // 4: lucius.dataplane.packetio.HostPortControlMessage.op:type_name -> lucius.dataplane.packetio.PortOperation + 8, // 5: lucius.dataplane.packetio.PacketIn.init:type_name -> lucius.dataplane.packetio.PacketStreamInit + 7, // 6: lucius.dataplane.packetio.PacketIn.packet:type_name -> lucius.dataplane.packetio.Packet + 7, // 7: lucius.dataplane.packetio.PacketOut.packet:type_name -> lucius.dataplane.packetio.Packet + 3, // 8: lucius.dataplane.packetio.PacketIO.HostPortControl:input_type -> lucius.dataplane.packetio.HostPortControlRequest + 9, // 9: lucius.dataplane.packetio.PacketIO.CPUPacketStream:input_type -> lucius.dataplane.packetio.PacketIn + 6, // 10: lucius.dataplane.packetio.PacketIO.HostPortControl:output_type -> lucius.dataplane.packetio.HostPortControlMessage + 10, // 11: lucius.dataplane.packetio.PacketIO.CPUPacketStream:output_type -> lucius.dataplane.packetio.PacketOut + 10, // [10:12] is the sub-list for method output_type + 8, // [8:10] is the sub-list for method input_type + 8, // [8:8] is the sub-list for extension type_name + 8, // [8:8] is the sub-list for extension extendee + 0, // [0:8] is the sub-list for field type_name } func init() { file_dataplane_proto_packetio_packetio_proto_init() } @@ -907,7 +988,7 @@ func file_dataplane_proto_packetio_packetio_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_dataplane_proto_packetio_packetio_proto_rawDesc, - NumEnums: 1, + NumEnums: 2, NumMessages: 9, NumExtensions: 0, NumServices: 1, diff --git a/dataplane/proto/packetio/packetio.proto b/dataplane/proto/packetio/packetio.proto index e2c2470b..b1a734f7 100644 --- a/dataplane/proto/packetio/packetio.proto +++ b/dataplane/proto/packetio/packetio.proto @@ -38,15 +38,24 @@ message GenetlinkPort { string group = 2; } +enum PortOperation { + PORT_OPERATION_UNSPECIFIED = 0; + PORT_OPERATION_CREATE = 1; + PORT_OPERATION_DELETE = 2; + PORT_OPERATION_SET_UP = 3; + PORT_OPERATION_SET_DOWN = 4; +} + message HostPortControlMessage { uint64 port_id = 1; uint64 dataplane_port = 2; // ID of the dataplane port related to this one. // Set to true if an hostif should be created, false for delete. - bool create = 3; + bool create = 3 [deprecated=true]; oneof port { NetdevPort netdev = 4; GenetlinkPort genetlink = 5; } + PortOperation op = 6; } message Packet { diff --git a/dataplane/standalone/pkthandler/pktiohandler/pktiohandler.go b/dataplane/standalone/pkthandler/pktiohandler/pktiohandler.go index fad91a91..0de0ede1 100644 --- a/dataplane/standalone/pkthandler/pktiohandler/pktiohandler.go +++ b/dataplane/standalone/pkthandler/pktiohandler/pktiohandler.go @@ -68,6 +68,7 @@ type PortIO interface { Delete() error Write([]byte, *kernel.PacketMetadata) (int, error) Read([]byte) (int, error) + SetAdminState(bool) error } // StreamPackets sends and receives packets from a lucius CPU port. @@ -153,13 +154,14 @@ func (m *PacketIOMgr) ManagePorts(c pktiopb.PacketIO_HostPortControlClient) erro if err := c.Send(&pktiopb.HostPortControlRequest{Msg: &pktiopb.HostPortControlRequest_Init{}}); err != nil { return err } + for { resp, err := c.Recv() if err != nil { return err } log.Infof("received port control message: %+v", resp) - if resp.Create { + if (resp.Op == pktiopb.PortOperation_PORT_OPERATION_UNSPECIFIED && resp.Create) || resp.Op == pktiopb.PortOperation_PORT_OPERATION_CREATE { st := &status.Status{ Code: int32(codes.OK), } @@ -178,7 +180,7 @@ func (m *PacketIOMgr) ManagePorts(c pktiopb.PacketIO_HostPortControlClient) erro if err := m.writePorts(); err != nil { log.Warningf("failed to write file: %v", err) } - } else { + } else if resp.Op == pktiopb.PortOperation_PORT_OPERATION_UNSPECIFIED || resp.Op == pktiopb.PortOperation_PORT_OPERATION_DELETE { p, ok := m.hostifs[resp.GetPortId()] if !ok { sendErr := c.Send(&pktiopb.HostPortControlRequest{Msg: &pktiopb.HostPortControlRequest_Status{ @@ -192,9 +194,7 @@ func (m *PacketIOMgr) ManagePorts(c pktiopb.PacketIO_HostPortControlClient) erro } continue } - m.hostifs[resp.GetPortId()].cancelFn() - if err := p.Delete(); err != nil { sendErr := c.Send(&pktiopb.HostPortControlRequest{Msg: &pktiopb.HostPortControlRequest_Status{ Status: &status.Status{ @@ -206,7 +206,6 @@ func (m *PacketIOMgr) ManagePorts(c pktiopb.PacketIO_HostPortControlClient) erro return sendErr } } - delete(m.hostifs, resp.GetPortId()) sendErr := c.Send(&pktiopb.HostPortControlRequest{Msg: &pktiopb.HostPortControlRequest_Status{ Status: &status.Status{ @@ -219,6 +218,36 @@ func (m *PacketIOMgr) ManagePorts(c pktiopb.PacketIO_HostPortControlClient) erro if err := m.writePorts(); err != nil { log.Warningf("failed to write file: %v", err) } + } else if resp.Op == pktiopb.PortOperation_PORT_OPERATION_SET_UP || resp.Op == pktiopb.PortOperation_PORT_OPERATION_SET_DOWN { + p, ok := m.hostifs[resp.GetPortId()] + if !ok { + sendErr := c.Send(&pktiopb.HostPortControlRequest{Msg: &pktiopb.HostPortControlRequest_Status{ + Status: &status.Status{ + Code: int32(codes.FailedPrecondition), + Message: fmt.Sprintf("port %v doesn't exist", resp.GetPortId()), + }, + }}) + if sendErr != nil { + return sendErr + } + continue + } + st := &status.Status{ + Code: int32(codes.OK), + } + state := resp.Op == pktiopb.PortOperation_PORT_OPERATION_SET_UP + if p.SetAdminState(state); err != nil { + st = &status.Status{ + Code: int32(codes.Internal), + Message: err.Error(), + } + } + sendErr := c.Send(&pktiopb.HostPortControlRequest{Msg: &pktiopb.HostPortControlRequest_Status{ + Status: st, + }}) + if sendErr != nil { + return sendErr + } } } } diff --git a/dataplane/standalone/pkthandler/pktiohandler/pktiohandler_test.go b/dataplane/standalone/pkthandler/pktiohandler/pktiohandler_test.go index 3470fa7d..0ff8371b 100644 --- a/dataplane/standalone/pkthandler/pktiohandler/pktiohandler_test.go +++ b/dataplane/standalone/pkthandler/pktiohandler/pktiohandler_test.go @@ -124,6 +124,37 @@ func TestManagePorts(t *testing.T) { PortId: 1, DataplanePort: 2, Create: true, + Op: pktiopb.PortOperation_PORT_OPERATION_CREATE, + }}, + want: codes.OK, + }, { + desc: "delete not existing", + msgs: []*pktiopb.HostPortControlMessage{{ + PortId: 1, + Create: false, + Op: pktiopb.PortOperation_PORT_OPERATION_DELETE, + }}, + want: codes.FailedPrecondition, + }, { + desc: "delete", + msgs: []*pktiopb.HostPortControlMessage{{ + PortId: 2, + Create: false, + Op: pktiopb.PortOperation_PORT_OPERATION_DELETE, + }}, + want: codes.OK, + }, { + desc: "set state not existing", + msgs: []*pktiopb.HostPortControlMessage{{ + PortId: 1, + Op: pktiopb.PortOperation_PORT_OPERATION_SET_DOWN, + }}, + want: codes.FailedPrecondition, + }, { + desc: "set state", + msgs: []*pktiopb.HostPortControlMessage{{ + PortId: 2, + Op: pktiopb.PortOperation_PORT_OPERATION_SET_DOWN, }}, want: codes.OK, }} @@ -133,6 +164,10 @@ func TestManagePorts(t *testing.T) { if err != nil { t.Fatalf("unexpected error on New(): %v", err) } + mgr.hostifs[2] = &port{ + PortIO: &fakePort{}, + cancelFn: func() {}, + } builder[pktiopb.PortType_PORT_TYPE_NETDEV] = func(hpcm *pktiopb.HostPortControlMessage) (PortIO, error) { return &fakePort{}, nil } @@ -162,6 +197,14 @@ type fakePort struct { writtenData []*portWriteData } +func (p *fakePort) Delete() error { + return nil +} + +func (p *fakePort) SetAdminState(bool) error { + return nil +} + func (p *fakePort) Read([]byte) (int, error) { return 0, nil }