From df67791c6ffc96331f75aec7d3addfe2efca7739 Mon Sep 17 00:00:00 2001 From: Ondrej Fabry Date: Thu, 25 Jun 2020 11:55:58 +0200 Subject: Introduce Stream - experimental API for low-level access to VPP API Change-Id: I2698e11b76ff55d9730b47d4fee990be93349516 Signed-off-by: Ondrej Fabry --- api/api.go | 125 +++++++++++++++++++ api/binapi.go | 79 ------------ api/errors.go | 301 ++++++++++++++++++++++++++++++++++++++++++++++ api/errors_test.go | 23 ++++ api/vppapi_errors.go | 290 -------------------------------------------- api/vppapi_errors_test.go | 23 ---- 6 files changed, 449 insertions(+), 392 deletions(-) create mode 100644 api/api.go create mode 100644 api/errors.go create mode 100644 api/errors_test.go delete mode 100644 api/vppapi_errors.go delete mode 100644 api/vppapi_errors_test.go (limited to 'api') diff --git a/api/api.go b/api/api.go new file mode 100644 index 0000000..977b02e --- /dev/null +++ b/api/api.go @@ -0,0 +1,125 @@ +// Copyright (c) 2020 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 api + +import ( + "context" + "time" +) + +// Connection represents the client connection to VPP API. +// +// NOTE: This API is EXPERIMENTAL. +type Connection interface { + // NewStream creates a new stream for sending and receiving messages. + // Context can be used to close the stream using cancel or timeout. + NewStream(ctx context.Context) (Stream, error) + + // Invoke can be used for a simple request-reply RPC. + // It creates stream and calls SendMsg with req and RecvMsg with reply. + Invoke(ctx context.Context, req Message, reply Message) error +} + +// Stream provides low-level access for sending and receiving messages. +// Users should handle correct type and ordering of messages. +// +// NOTE: This API is EXPERIMENTAL. +type Stream interface { + // SendMsg sends a message to the client. + // It blocks until message is sent to the transport. + // + // It is safe to have a goroutine calling SendMsg and another goroutine + // calling RecvMsg on the same stream at the same time, but it is not safe + // to call SendMsg on the same stream in different goroutines. + SendMsg(Message) error + + // RecvMsg blocks until a message is received or error occurs. + // + // It is safe to have a goroutine calling SendMsg and another goroutine + // calling RecvMsg on the same stream at the same time, but it is not safe + // to call SendMsg on the same stream in different goroutines. + RecvMsg() (Message, error) + + // Close closes the stream. Calling SendMsg and RecvMsg will return error + // after closing stream. + Close() error +} + +// ChannelProvider provides the communication channel with govpp core. +type ChannelProvider interface { + // NewAPIChannel returns a new channel for communication with VPP via govpp core. + // It uses default buffer sizes for the request and reply Go channels. + NewAPIChannel() (Channel, error) + + // NewAPIChannelBuffered returns a new channel for communication with VPP via govpp core. + // It allows to specify custom buffer sizes for the request and reply Go channels. + NewAPIChannelBuffered(reqChanBufSize, replyChanBufSize int) (Channel, error) +} + +// Channel provides methods for direct communication with VPP channel. +type Channel interface { + // SendRequest asynchronously sends a request to VPP. Returns a request context, that can be used to call ReceiveReply. + // In case of any errors by sending, the error will be delivered to ReplyChan (and returned by ReceiveReply). + SendRequest(msg Message) RequestCtx + + // SendMultiRequest asynchronously sends a multipart request (request to which multiple responses are expected) to VPP. + // Returns a multipart request context, that can be used to call ReceiveReply. + // In case of any errors by sending, the error will be delivered to ReplyChan (and returned by ReceiveReply). + SendMultiRequest(msg Message) MultiRequestCtx + + // SubscribeNotification subscribes for receiving of the specified notification messages via provided Go channel. + // Note that the caller is responsible for creating the Go channel with preferred buffer size. If the channel's + // buffer is full, the notifications will not be delivered into it. + SubscribeNotification(notifChan chan Message, event Message) (SubscriptionCtx, error) + + // SetReplyTimeout sets the timeout for replies from VPP. It represents the maximum time the API waits for a reply + // from VPP before returning an error. + SetReplyTimeout(timeout time.Duration) + + // CheckCompatibility checks the compatiblity for the given messages. + // It will return an error if any of the given messages are not compatible. + CheckCompatiblity(msgs ...Message) error + + // Close closes the API channel and releases all API channel-related resources + // in the ChannelProvider. + Close() +} + +// RequestCtx is helper interface which allows to receive reply on request. +type RequestCtx interface { + // ReceiveReply receives a reply from VPP (blocks until a reply is delivered + // from VPP, or until an error occurs). The reply will be decoded into the msg + // argument. Error will be returned if the response cannot be received or decoded. + ReceiveReply(msg Message) error +} + +// MultiRequestCtx is helper interface which allows to receive reply on multi-request. +type MultiRequestCtx interface { + // ReceiveReply receives a reply from VPP (blocks until a reply is delivered + // from VPP, or until an error occurs).The reply will be decoded into the msg + // argument. If the last reply has been already consumed, lastReplyReceived is + // set to true. Do not use the message itself if lastReplyReceived is + // true - it won't be filled with actual data.Error will be returned if the + // response cannot be received or decoded. + ReceiveReply(msg Message) (lastReplyReceived bool, err error) +} + +// SubscriptionCtx is helper interface which allows to control subscription for +// notification events. +type SubscriptionCtx interface { + // Unsubscribe unsubscribes from receiving the notifications tied to the + // subscription context. + Unsubscribe() error +} diff --git a/api/binapi.go b/api/binapi.go index 20ddd28..04fdc9e 100644 --- a/api/binapi.go +++ b/api/binapi.go @@ -17,7 +17,6 @@ package api import ( "fmt" "reflect" - "time" ) // MessageType represents the type of a VPP message. @@ -56,84 +55,6 @@ type DataType interface { GetTypeName() string } -// ChannelProvider provides the communication channel with govpp core. -type ChannelProvider interface { - // NewAPIChannel returns a new channel for communication with VPP via govpp core. - // It uses default buffer sizes for the request and reply Go channels. - NewAPIChannel() (Channel, error) - - // NewAPIChannelBuffered returns a new channel for communication with VPP via govpp core. - // It allows to specify custom buffer sizes for the request and reply Go channels. - NewAPIChannelBuffered(reqChanBufSize, replyChanBufSize int) (Channel, error) -} - -// Channel provides methods for direct communication with VPP channel. -type Channel interface { - // SendRequest asynchronously sends a request to VPP. Returns a request context, that can be used to call ReceiveReply. - // In case of any errors by sending, the error will be delivered to ReplyChan (and returned by ReceiveReply). - SendRequest(msg Message) RequestCtx - - // SendMultiRequest asynchronously sends a multipart request (request to which multiple responses are expected) to VPP. - // Returns a multipart request context, that can be used to call ReceiveReply. - // In case of any errors by sending, the error will be delivered to ReplyChan (and returned by ReceiveReply). - SendMultiRequest(msg Message) MultiRequestCtx - - // SubscribeNotification subscribes for receiving of the specified notification messages via provided Go channel. - // Note that the caller is responsible for creating the Go channel with preferred buffer size. If the channel's - // buffer is full, the notifications will not be delivered into it. - SubscribeNotification(notifChan chan Message, event Message) (SubscriptionCtx, error) - - // SetReplyTimeout sets the timeout for replies from VPP. It represents the maximum time the API waits for a reply - // from VPP before returning an error. - SetReplyTimeout(timeout time.Duration) - - // CheckCompatibility checks the compatiblity for the given messages. - // It will return an error if any of the given messages are not compatible. - CheckCompatiblity(msgs ...Message) error - - // Close closes the API channel and releases all API channel-related resources - // in the ChannelProvider. - Close() -} - -// RequestCtx is helper interface which allows to receive reply on request. -type RequestCtx interface { - // ReceiveReply receives a reply from VPP (blocks until a reply is delivered - // from VPP, or until an error occurs). The reply will be decoded into the msg - // argument. Error will be returned if the response cannot be received or decoded. - ReceiveReply(msg Message) error -} - -// MultiRequestCtx is helper interface which allows to receive reply on multi-request. -type MultiRequestCtx interface { - // ReceiveReply receives a reply from VPP (blocks until a reply is delivered - // from VPP, or until an error occurs).The reply will be decoded into the msg - // argument. If the last reply has been already consumed, lastReplyReceived is - // set to true. Do not use the message itself if lastReplyReceived is - // true - it won't be filled with actual data.Error will be returned if the - // response cannot be received or decoded. - ReceiveReply(msg Message) (lastReplyReceived bool, err error) -} - -// SubscriptionCtx is helper interface which allows to control subscription for -// notification events. -type SubscriptionCtx interface { - // Unsubscribe unsubscribes from receiving the notifications tied to the - // subscription context. - Unsubscribe() error -} - -// CompatibilityError is the error type usually returned by CheckCompatibility -// method of Channel. It contains list of all the compatible/incompatible messages. -type CompatibilityError struct { - CompatibleMessages []string - IncompatibleMessages []string -} - -func (c *CompatibilityError) Error() string { - return fmt.Sprintf("%d/%d messages incompatible", len(c.IncompatibleMessages), len(c.CompatibleMessages)+len(c.IncompatibleMessages)) -} - var ( registeredMessageTypes = make(map[reflect.Type]string) registeredMessages = make(map[string]Message) diff --git a/api/errors.go b/api/errors.go new file mode 100644 index 0000000..32cc677 --- /dev/null +++ b/api/errors.go @@ -0,0 +1,301 @@ +package api + +import ( + "fmt" + "strconv" +) + +// CompatibilityError is the error type usually returned by CheckCompatibility +// method of Channel. It contains list of all the compatible/incompatible messages. +type CompatibilityError struct { + CompatibleMessages []string + IncompatibleMessages []string +} + +func (c *CompatibilityError) Error() string { + return fmt.Sprintf("%d/%d messages incompatible", len(c.IncompatibleMessages), len(c.CompatibleMessages)+len(c.IncompatibleMessages)) +} + +// RetvalToVPPApiError returns error for retval value. +// Retval 0 returns nil error. +func RetvalToVPPApiError(retval int32) error { + if retval == 0 { + return nil + } + return VPPApiError(retval) +} + +// VPPApiError represents VPP's vnet API error that is usually +// returned as Retval field in replies from VPP binary API. +type VPPApiError int32 + +func (e VPPApiError) Error() string { + errid := int64(e) + var errstr string + if s, ok := vppApiErrors[e]; ok { + errstr = fmt.Sprintf("%s (%d)", s, errid) + } else { + errstr = strconv.FormatInt(errid, 10) + } + return fmt.Sprintf("VPPApiError: %s", errstr) +} + +// definitions from: vpp/src/vnet/api_errno.h +const ( + _ VPPApiError = 0 + UNSPECIFIED = -1 + INVALID_SW_IF_INDEX = -2 + NO_SUCH_FIB = -3 + NO_SUCH_INNER_FIB = -4 + NO_SUCH_LABEL = -5 + NO_SUCH_ENTRY = -6 + INVALID_VALUE = -7 + INVALID_VALUE_2 = -8 + UNIMPLEMENTED = -9 + INVALID_SW_IF_INDEX_2 = -10 + SYSCALL_ERROR_1 = -11 + SYSCALL_ERROR_2 = -12 + SYSCALL_ERROR_3 = -13 + SYSCALL_ERROR_4 = -14 + SYSCALL_ERROR_5 = -15 + SYSCALL_ERROR_6 = -16 + SYSCALL_ERROR_7 = -17 + SYSCALL_ERROR_8 = -18 + SYSCALL_ERROR_9 = -19 + SYSCALL_ERROR_10 = -20 + FEATURE_DISABLED = -30 + INVALID_REGISTRATION = -31 + NEXT_HOP_NOT_IN_FIB = -50 + UNKNOWN_DESTINATION = -51 + PREFIX_MATCHES_NEXT_HOP = -52 + NEXT_HOP_NOT_FOUND_MP = -53 + NO_MATCHING_INTERFACE = -54 + INVALID_VLAN = -55 + VLAN_ALREADY_EXISTS = -56 + INVALID_SRC_ADDRESS = -57 + INVALID_DST_ADDRESS = -58 + ADDRESS_LENGTH_MISMATCH = -59 + ADDRESS_NOT_FOUND_FOR_INTERFACE = -60 + ADDRESS_NOT_DELETABLE = -61 + IP6_NOT_ENABLED = -62 + IN_PROGRESS = 10 + NO_SUCH_NODE = -63 + NO_SUCH_NODE2 = -64 + NO_SUCH_TABLE = -65 + NO_SUCH_TABLE2 = -66 + NO_SUCH_TABLE3 = -67 + SUBIF_ALREADY_EXISTS = -68 + SUBIF_CREATE_FAILED = -69 + INVALID_MEMORY_SIZE = -70 + INVALID_INTERFACE = -71 + INVALID_VLAN_TAG_COUNT = -72 + INVALID_ARGUMENT = -73 + UNEXPECTED_INTF_STATE = -74 + TUNNEL_EXIST = -75 + INVALID_DECAP_NEXT = -76 + RESPONSE_NOT_READY = -77 + NOT_CONNECTED = -78 + IF_ALREADY_EXISTS = -79 + BOND_SLAVE_NOT_ALLOWED = -80 + VALUE_EXIST = -81 + SAME_SRC_DST = -82 + IP6_MULTICAST_ADDRESS_NOT_PRESENT = -83 + SR_POLICY_NAME_NOT_PRESENT = -84 + NOT_RUNNING_AS_ROOT = -85 + ALREADY_CONNECTED = -86 + UNSUPPORTED_JNI_VERSION = -87 + FAILED_TO_ATTACH_TO_JAVA_THREAD = -88 + INVALID_WORKER = -89 + LISP_DISABLED = -90 + CLASSIFY_TABLE_NOT_FOUND = -91 + INVALID_EID_TYPE = -92 + CANNOT_CREATE_PCAP_FILE = -93 + INCORRECT_ADJACENCY_TYPE = -94 + EXCEEDED_NUMBER_OF_RANGES_CAPACITY = -95 + EXCEEDED_NUMBER_OF_PORTS_CAPACITY = -96 + INVALID_ADDRESS_FAMILY = -97 + INVALID_SUB_SW_IF_INDEX = -98 + TABLE_TOO_BIG = -99 + CANNOT_ENABLE_DISABLE_FEATURE = -100 + BFD_EEXIST = -101 + BFD_ENOENT = -102 + BFD_EINUSE = -103 + BFD_NOTSUPP = -104 + ADDRESS_IN_USE = -105 + ADDRESS_NOT_IN_USE = -106 + QUEUE_FULL = -107 + APP_UNSUPPORTED_CFG = -108 + URI_FIFO_CREATE_FAILED = -109 + LISP_RLOC_LOCAL = -110 + BFD_EAGAIN = -111 + INVALID_GPE_MODE = -112 + LISP_GPE_ENTRIES_PRESENT = -113 + ADDRESS_FOUND_FOR_INTERFACE = -114 + SESSION_CONNECT = -115 + ENTRY_ALREADY_EXISTS = -116 + SVM_SEGMENT_CREATE_FAIL = -117 + APPLICATION_NOT_ATTACHED = -118 + BD_ALREADY_EXISTS = -119 + BD_IN_USE = -120 + BD_NOT_MODIFIABLE = -121 + BD_ID_EXCEED_MAX = -122 + SUBIF_DOESNT_EXIST = -123 + L2_MACS_EVENT_CLINET_PRESENT = -124 + INVALID_QUEUE = -125 + UNSUPPORTED = -126 + DUPLICATE_IF_ADDRESS = -127 + APP_INVALID_NS = -128 + APP_WRONG_NS_SECRET = -129 + APP_CONNECT_SCOPE = -130 + APP_ALREADY_ATTACHED = -131 + SESSION_REDIRECT = -132 + ILLEGAL_NAME = -133 + NO_NAME_SERVERS = -134 + NAME_SERVER_NOT_FOUND = -135 + NAME_RESOLUTION_NOT_ENABLED = -136 + NAME_SERVER_FORMAT_ERROR = -137 + NAME_SERVER_NO_SUCH_NAME = -138 + NAME_SERVER_NO_ADDRESSES = -139 + NAME_SERVER_NEXT_SERVER = -140 + APP_CONNECT_FILTERED = -141 + ACL_IN_USE_INBOUND = -142 + ACL_IN_USE_OUTBOUND = -143 + INIT_FAILED = -144 + NETLINK_ERROR = -145 + BIER_BSL_UNSUP = -146 + INSTANCE_IN_USE = -147 + INVALID_SESSION_ID = -148 + ACL_IN_USE_BY_LOOKUP_CONTEXT = -149 + INVALID_VALUE_3 = -150 + NON_ETHERNET = -151 + BD_ALREADY_HAS_BVI = -152 +) + +var vppApiErrors = map[VPPApiError]string{ + UNSPECIFIED: "Unspecified Error", + INVALID_SW_IF_INDEX: "Invalid sw_if_index", + NO_SUCH_FIB: "No such FIB / VRF", + NO_SUCH_INNER_FIB: "No such inner FIB / VRF", + NO_SUCH_LABEL: "No such label", + NO_SUCH_ENTRY: "No such entry", + INVALID_VALUE: "Invalid value", + INVALID_VALUE_2: "Invalid value #2", + UNIMPLEMENTED: "Unimplemented", + INVALID_SW_IF_INDEX_2: "Invalid sw_if_index #2", + SYSCALL_ERROR_1: "System call error #1", + SYSCALL_ERROR_2: "System call error #2", + SYSCALL_ERROR_3: "System call error #3", + SYSCALL_ERROR_4: "System call error #4", + SYSCALL_ERROR_5: "System call error #5", + SYSCALL_ERROR_6: "System call error #6", + SYSCALL_ERROR_7: "System call error #7", + SYSCALL_ERROR_8: "System call error #8", + SYSCALL_ERROR_9: "System call error #9", + SYSCALL_ERROR_10: "System call error #10", + FEATURE_DISABLED: "Feature disabled by configuration", + INVALID_REGISTRATION: "Invalid registration", + NEXT_HOP_NOT_IN_FIB: "Next hop not in FIB", + UNKNOWN_DESTINATION: "Unknown destination", + PREFIX_MATCHES_NEXT_HOP: "Prefix matches next hop", + NEXT_HOP_NOT_FOUND_MP: "Next hop not found (multipath)", + NO_MATCHING_INTERFACE: "No matching interface for probe", + INVALID_VLAN: "Invalid VLAN", + VLAN_ALREADY_EXISTS: "VLAN subif already exists", + INVALID_SRC_ADDRESS: "Invalid src address", + INVALID_DST_ADDRESS: "Invalid dst address", + ADDRESS_LENGTH_MISMATCH: "Address length mismatch", + ADDRESS_NOT_FOUND_FOR_INTERFACE: "Address not found for interface", + ADDRESS_NOT_DELETABLE: "Address not deletable", + IP6_NOT_ENABLED: "ip6 not enabled", + IN_PROGRESS: "Operation in progress", + NO_SUCH_NODE: "No such graph node", + NO_SUCH_NODE2: "No such graph node #2", + NO_SUCH_TABLE: "No such table", + NO_SUCH_TABLE2: "No such table #2", + NO_SUCH_TABLE3: "No such table #3", + SUBIF_ALREADY_EXISTS: "Subinterface already exists", + SUBIF_CREATE_FAILED: "Subinterface creation failed", + INVALID_MEMORY_SIZE: "Invalid memory size requested", + INVALID_INTERFACE: "Invalid interface", + INVALID_VLAN_TAG_COUNT: "Invalid number of tags for requested operation", + INVALID_ARGUMENT: "Invalid argument", + UNEXPECTED_INTF_STATE: "Unexpected interface state", + TUNNEL_EXIST: "Tunnel already exists", + INVALID_DECAP_NEXT: "Invalid decap-next", + RESPONSE_NOT_READY: "Response not ready", + NOT_CONNECTED: "Not connected to the data plane", + IF_ALREADY_EXISTS: "Interface already exists", + BOND_SLAVE_NOT_ALLOWED: "Operation not allowed on slave of BondEthernet", + VALUE_EXIST: "Value already exists", + SAME_SRC_DST: "Source and destination are the same", + IP6_MULTICAST_ADDRESS_NOT_PRESENT: "IP6 multicast address required", + SR_POLICY_NAME_NOT_PRESENT: "Segement routing policy name required", + NOT_RUNNING_AS_ROOT: "Not running as root", + ALREADY_CONNECTED: "Connection to the data plane already exists", + UNSUPPORTED_JNI_VERSION: "Unsupported JNI version", + FAILED_TO_ATTACH_TO_JAVA_THREAD: "Failed to attach to Java thread", + INVALID_WORKER: "Invalid worker thread", + LISP_DISABLED: "LISP is disabled", + CLASSIFY_TABLE_NOT_FOUND: "Classify table not found", + INVALID_EID_TYPE: "Unsupported LSIP EID type", + CANNOT_CREATE_PCAP_FILE: "Cannot create pcap file", + INCORRECT_ADJACENCY_TYPE: "Invalid adjacency type for this operation", + EXCEEDED_NUMBER_OF_RANGES_CAPACITY: "Operation would exceed configured capacity of ranges", + EXCEEDED_NUMBER_OF_PORTS_CAPACITY: "Operation would exceed capacity of number of ports", + INVALID_ADDRESS_FAMILY: "Invalid address family", + INVALID_SUB_SW_IF_INDEX: "Invalid sub-interface sw_if_index", + TABLE_TOO_BIG: "Table too big", + CANNOT_ENABLE_DISABLE_FEATURE: "Cannot enable/disable feature", + BFD_EEXIST: "Duplicate BFD object", + BFD_ENOENT: "No such BFD object", + BFD_EINUSE: "BFD object in use", + BFD_NOTSUPP: "BFD feature not supported", + ADDRESS_IN_USE: "Address in use", + ADDRESS_NOT_IN_USE: "Address not in use", + QUEUE_FULL: "Queue full", + APP_UNSUPPORTED_CFG: "Unsupported application config", + URI_FIFO_CREATE_FAILED: "URI FIFO segment create failed", + LISP_RLOC_LOCAL: "RLOC address is local", + BFD_EAGAIN: "BFD object cannot be manipulated at this time", + INVALID_GPE_MODE: "Invalid GPE mode", + LISP_GPE_ENTRIES_PRESENT: "LISP GPE entries are present", + ADDRESS_FOUND_FOR_INTERFACE: "Address found for interface", + SESSION_CONNECT: "Session failed to connect", + ENTRY_ALREADY_EXISTS: "Entry already exists", + SVM_SEGMENT_CREATE_FAIL: "svm segment create fail", + APPLICATION_NOT_ATTACHED: "application not attached", + BD_ALREADY_EXISTS: "Bridge domain already exists", + BD_IN_USE: "Bridge domain has member interfaces", + BD_NOT_MODIFIABLE: "Bridge domain 0 can't be deleted/modified", + BD_ID_EXCEED_MAX: "Bridge domain ID exceed 16M limit", + SUBIF_DOESNT_EXIST: "Subinterface doesn't exist", + L2_MACS_EVENT_CLINET_PRESENT: "Client already exist for L2 MACs events", + INVALID_QUEUE: "Invalid queue", + UNSUPPORTED: "Unsupported", + DUPLICATE_IF_ADDRESS: "Address already present on another interface", + APP_INVALID_NS: "Invalid application namespace", + APP_WRONG_NS_SECRET: "Wrong app namespace secret", + APP_CONNECT_SCOPE: "Connect scope", + APP_ALREADY_ATTACHED: "App already attached", + SESSION_REDIRECT: "Redirect failed", + ILLEGAL_NAME: "Illegal name", + NO_NAME_SERVERS: "No name servers configured", + NAME_SERVER_NOT_FOUND: "Name server not found", + NAME_RESOLUTION_NOT_ENABLED: "Name resolution not enabled", + NAME_SERVER_FORMAT_ERROR: "Server format error (bug!)", + NAME_SERVER_NO_SUCH_NAME: "No such name", + NAME_SERVER_NO_ADDRESSES: "No addresses available", + NAME_SERVER_NEXT_SERVER: "Retry with new server", + APP_CONNECT_FILTERED: "Connect was filtered", + ACL_IN_USE_INBOUND: "Inbound ACL in use", + ACL_IN_USE_OUTBOUND: "Outbound ACL in use", + INIT_FAILED: "Initialization Failed", + NETLINK_ERROR: "netlink error", + BIER_BSL_UNSUP: "BIER bit-string-length unsupported", + INSTANCE_IN_USE: "Instance in use", + INVALID_SESSION_ID: "session ID out of range", + ACL_IN_USE_BY_LOOKUP_CONTEXT: "ACL in use by a lookup context", + INVALID_VALUE_3: "Invalid value #3", + NON_ETHERNET: "Interface is not an Ethernet interface", + BD_ALREADY_HAS_BVI: "Bridge domain already has a BVI interface", +} diff --git a/api/errors_test.go b/api/errors_test.go new file mode 100644 index 0000000..78e1fbf --- /dev/null +++ b/api/errors_test.go @@ -0,0 +1,23 @@ +package api + +import ( + "testing" + + . "github.com/onsi/gomega" +) + +func TestUnspecified(t *testing.T) { + RegisterTestingT(t) + + var err error = VPPApiError(-1) + errstr := err.Error() + Expect(errstr).Should(BeEquivalentTo("VPPApiError: Unspecified Error (-1)")) +} + +func TestUnknown(t *testing.T) { + RegisterTestingT(t) + + var err error = VPPApiError(-999) + errstr := err.Error() + Expect(errstr).Should(BeEquivalentTo("VPPApiError: -999")) +} diff --git a/api/vppapi_errors.go b/api/vppapi_errors.go deleted file mode 100644 index c9ce3a3..0000000 --- a/api/vppapi_errors.go +++ /dev/null @@ -1,290 +0,0 @@ -package api - -import ( - "fmt" - "strconv" -) - -// RetvalToVPPApiError returns error for retval value. -// Retval 0 returns nil error. -func RetvalToVPPApiError(retval int32) error { - if retval == 0 { - return nil - } - return VPPApiError(retval) -} - -// VPPApiError represents VPP's vnet API error that is usually -// returned as Retval field in replies from VPP binary API. -type VPPApiError int32 - -func (e VPPApiError) Error() string { - errid := int64(e) - var errstr string - if s, ok := vppApiErrors[e]; ok { - errstr = fmt.Sprintf("%s (%d)", s, errid) - } else { - errstr = strconv.FormatInt(errid, 10) - } - return fmt.Sprintf("VPPApiError: %s", errstr) -} - -// definitions from: vpp/src/vnet/api_errno.h -const ( - _ VPPApiError = 0 - UNSPECIFIED = -1 - INVALID_SW_IF_INDEX = -2 - NO_SUCH_FIB = -3 - NO_SUCH_INNER_FIB = -4 - NO_SUCH_LABEL = -5 - NO_SUCH_ENTRY = -6 - INVALID_VALUE = -7 - INVALID_VALUE_2 = -8 - UNIMPLEMENTED = -9 - INVALID_SW_IF_INDEX_2 = -10 - SYSCALL_ERROR_1 = -11 - SYSCALL_ERROR_2 = -12 - SYSCALL_ERROR_3 = -13 - SYSCALL_ERROR_4 = -14 - SYSCALL_ERROR_5 = -15 - SYSCALL_ERROR_6 = -16 - SYSCALL_ERROR_7 = -17 - SYSCALL_ERROR_8 = -18 - SYSCALL_ERROR_9 = -19 - SYSCALL_ERROR_10 = -20 - FEATURE_DISABLED = -30 - INVALID_REGISTRATION = -31 - NEXT_HOP_NOT_IN_FIB = -50 - UNKNOWN_DESTINATION = -51 - PREFIX_MATCHES_NEXT_HOP = -52 - NEXT_HOP_NOT_FOUND_MP = -53 - NO_MATCHING_INTERFACE = -54 - INVALID_VLAN = -55 - VLAN_ALREADY_EXISTS = -56 - INVALID_SRC_ADDRESS = -57 - INVALID_DST_ADDRESS = -58 - ADDRESS_LENGTH_MISMATCH = -59 - ADDRESS_NOT_FOUND_FOR_INTERFACE = -60 - ADDRESS_NOT_DELETABLE = -61 - IP6_NOT_ENABLED = -62 - IN_PROGRESS = 10 - NO_SUCH_NODE = -63 - NO_SUCH_NODE2 = -64 - NO_SUCH_TABLE = -65 - NO_SUCH_TABLE2 = -66 - NO_SUCH_TABLE3 = -67 - SUBIF_ALREADY_EXISTS = -68 - SUBIF_CREATE_FAILED = -69 - INVALID_MEMORY_SIZE = -70 - INVALID_INTERFACE = -71 - INVALID_VLAN_TAG_COUNT = -72 - INVALID_ARGUMENT = -73 - UNEXPECTED_INTF_STATE = -74 - TUNNEL_EXIST = -75 - INVALID_DECAP_NEXT = -76 - RESPONSE_NOT_READY = -77 - NOT_CONNECTED = -78 - IF_ALREADY_EXISTS = -79 - BOND_SLAVE_NOT_ALLOWED = -80 - VALUE_EXIST = -81 - SAME_SRC_DST = -82 - IP6_MULTICAST_ADDRESS_NOT_PRESENT = -83 - SR_POLICY_NAME_NOT_PRESENT = -84 - NOT_RUNNING_AS_ROOT = -85 - ALREADY_CONNECTED = -86 - UNSUPPORTED_JNI_VERSION = -87 - FAILED_TO_ATTACH_TO_JAVA_THREAD = -88 - INVALID_WORKER = -89 - LISP_DISABLED = -90 - CLASSIFY_TABLE_NOT_FOUND = -91 - INVALID_EID_TYPE = -92 - CANNOT_CREATE_PCAP_FILE = -93 - INCORRECT_ADJACENCY_TYPE = -94 - EXCEEDED_NUMBER_OF_RANGES_CAPACITY = -95 - EXCEEDED_NUMBER_OF_PORTS_CAPACITY = -96 - INVALID_ADDRESS_FAMILY = -97 - INVALID_SUB_SW_IF_INDEX = -98 - TABLE_TOO_BIG = -99 - CANNOT_ENABLE_DISABLE_FEATURE = -100 - BFD_EEXIST = -101 - BFD_ENOENT = -102 - BFD_EINUSE = -103 - BFD_NOTSUPP = -104 - ADDRESS_IN_USE = -105 - ADDRESS_NOT_IN_USE = -106 - QUEUE_FULL = -107 - APP_UNSUPPORTED_CFG = -108 - URI_FIFO_CREATE_FAILED = -109 - LISP_RLOC_LOCAL = -110 - BFD_EAGAIN = -111 - INVALID_GPE_MODE = -112 - LISP_GPE_ENTRIES_PRESENT = -113 - ADDRESS_FOUND_FOR_INTERFACE = -114 - SESSION_CONNECT = -115 - ENTRY_ALREADY_EXISTS = -116 - SVM_SEGMENT_CREATE_FAIL = -117 - APPLICATION_NOT_ATTACHED = -118 - BD_ALREADY_EXISTS = -119 - BD_IN_USE = -120 - BD_NOT_MODIFIABLE = -121 - BD_ID_EXCEED_MAX = -122 - SUBIF_DOESNT_EXIST = -123 - L2_MACS_EVENT_CLINET_PRESENT = -124 - INVALID_QUEUE = -125 - UNSUPPORTED = -126 - DUPLICATE_IF_ADDRESS = -127 - APP_INVALID_NS = -128 - APP_WRONG_NS_SECRET = -129 - APP_CONNECT_SCOPE = -130 - APP_ALREADY_ATTACHED = -131 - SESSION_REDIRECT = -132 - ILLEGAL_NAME = -133 - NO_NAME_SERVERS = -134 - NAME_SERVER_NOT_FOUND = -135 - NAME_RESOLUTION_NOT_ENABLED = -136 - NAME_SERVER_FORMAT_ERROR = -137 - NAME_SERVER_NO_SUCH_NAME = -138 - NAME_SERVER_NO_ADDRESSES = -139 - NAME_SERVER_NEXT_SERVER = -140 - APP_CONNECT_FILTERED = -141 - ACL_IN_USE_INBOUND = -142 - ACL_IN_USE_OUTBOUND = -143 - INIT_FAILED = -144 - NETLINK_ERROR = -145 - BIER_BSL_UNSUP = -146 - INSTANCE_IN_USE = -147 - INVALID_SESSION_ID = -148 - ACL_IN_USE_BY_LOOKUP_CONTEXT = -149 - INVALID_VALUE_3 = -150 - NON_ETHERNET = -151 - BD_ALREADY_HAS_BVI = -152 -) - -var vppApiErrors = map[VPPApiError]string{ - UNSPECIFIED: "Unspecified Error", - INVALID_SW_IF_INDEX: "Invalid sw_if_index", - NO_SUCH_FIB: "No such FIB / VRF", - NO_SUCH_INNER_FIB: "No such inner FIB / VRF", - NO_SUCH_LABEL: "No such label", - NO_SUCH_ENTRY: "No such entry", - INVALID_VALUE: "Invalid value", - INVALID_VALUE_2: "Invalid value #2", - UNIMPLEMENTED: "Unimplemented", - INVALID_SW_IF_INDEX_2: "Invalid sw_if_index #2", - SYSCALL_ERROR_1: "System call error #1", - SYSCALL_ERROR_2: "System call error #2", - SYSCALL_ERROR_3: "System call error #3", - SYSCALL_ERROR_4: "System call error #4", - SYSCALL_ERROR_5: "System call error #5", - SYSCALL_ERROR_6: "System call error #6", - SYSCALL_ERROR_7: "System call error #7", - SYSCALL_ERROR_8: "System call error #8", - SYSCALL_ERROR_9: "System call error #9", - SYSCALL_ERROR_10: "System call error #10", - FEATURE_DISABLED: "Feature disabled by configuration", - INVALID_REGISTRATION: "Invalid registration", - NEXT_HOP_NOT_IN_FIB: "Next hop not in FIB", - UNKNOWN_DESTINATION: "Unknown destination", - PREFIX_MATCHES_NEXT_HOP: "Prefix matches next hop", - NEXT_HOP_NOT_FOUND_MP: "Next hop not found (multipath)", - NO_MATCHING_INTERFACE: "No matching interface for probe", - INVALID_VLAN: "Invalid VLAN", - VLAN_ALREADY_EXISTS: "VLAN subif already exists", - INVALID_SRC_ADDRESS: "Invalid src address", - INVALID_DST_ADDRESS: "Invalid dst address", - ADDRESS_LENGTH_MISMATCH: "Address length mismatch", - ADDRESS_NOT_FOUND_FOR_INTERFACE: "Address not found for interface", - ADDRESS_NOT_DELETABLE: "Address not deletable", - IP6_NOT_ENABLED: "ip6 not enabled", - IN_PROGRESS: "Operation in progress", - NO_SUCH_NODE: "No such graph node", - NO_SUCH_NODE2: "No such graph node #2", - NO_SUCH_TABLE: "No such table", - NO_SUCH_TABLE2: "No such table #2", - NO_SUCH_TABLE3: "No such table #3", - SUBIF_ALREADY_EXISTS: "Subinterface already exists", - SUBIF_CREATE_FAILED: "Subinterface creation failed", - INVALID_MEMORY_SIZE: "Invalid memory size requested", - INVALID_INTERFACE: "Invalid interface", - INVALID_VLAN_TAG_COUNT: "Invalid number of tags for requested operation", - INVALID_ARGUMENT: "Invalid argument", - UNEXPECTED_INTF_STATE: "Unexpected interface state", - TUNNEL_EXIST: "Tunnel already exists", - INVALID_DECAP_NEXT: "Invalid decap-next", - RESPONSE_NOT_READY: "Response not ready", - NOT_CONNECTED: "Not connected to the data plane", - IF_ALREADY_EXISTS: "Interface already exists", - BOND_SLAVE_NOT_ALLOWED: "Operation not allowed on slave of BondEthernet", - VALUE_EXIST: "Value already exists", - SAME_SRC_DST: "Source and destination are the same", - IP6_MULTICAST_ADDRESS_NOT_PRESENT: "IP6 multicast address required", - SR_POLICY_NAME_NOT_PRESENT: "Segement routing policy name required", - NOT_RUNNING_AS_ROOT: "Not running as root", - ALREADY_CONNECTED: "Connection to the data plane already exists", - UNSUPPORTED_JNI_VERSION: "Unsupported JNI version", - FAILED_TO_ATTACH_TO_JAVA_THREAD: "Failed to attach to Java thread", - INVALID_WORKER: "Invalid worker thread", - LISP_DISABLED: "LISP is disabled", - CLASSIFY_TABLE_NOT_FOUND: "Classify table not found", - INVALID_EID_TYPE: "Unsupported LSIP EID type", - CANNOT_CREATE_PCAP_FILE: "Cannot create pcap file", - INCORRECT_ADJACENCY_TYPE: "Invalid adjacency type for this operation", - EXCEEDED_NUMBER_OF_RANGES_CAPACITY: "Operation would exceed configured capacity of ranges", - EXCEEDED_NUMBER_OF_PORTS_CAPACITY: "Operation would exceed capacity of number of ports", - INVALID_ADDRESS_FAMILY: "Invalid address family", - INVALID_SUB_SW_IF_INDEX: "Invalid sub-interface sw_if_index", - TABLE_TOO_BIG: "Table too big", - CANNOT_ENABLE_DISABLE_FEATURE: "Cannot enable/disable feature", - BFD_EEXIST: "Duplicate BFD object", - BFD_ENOENT: "No such BFD object", - BFD_EINUSE: "BFD object in use", - BFD_NOTSUPP: "BFD feature not supported", - ADDRESS_IN_USE: "Address in use", - ADDRESS_NOT_IN_USE: "Address not in use", - QUEUE_FULL: "Queue full", - APP_UNSUPPORTED_CFG: "Unsupported application config", - URI_FIFO_CREATE_FAILED: "URI FIFO segment create failed", - LISP_RLOC_LOCAL: "RLOC address is local", - BFD_EAGAIN: "BFD object cannot be manipulated at this time", - INVALID_GPE_MODE: "Invalid GPE mode", - LISP_GPE_ENTRIES_PRESENT: "LISP GPE entries are present", - ADDRESS_FOUND_FOR_INTERFACE: "Address found for interface", - SESSION_CONNECT: "Session failed to connect", - ENTRY_ALREADY_EXISTS: "Entry already exists", - SVM_SEGMENT_CREATE_FAIL: "svm segment create fail", - APPLICATION_NOT_ATTACHED: "application not attached", - BD_ALREADY_EXISTS: "Bridge domain already exists", - BD_IN_USE: "Bridge domain has member interfaces", - BD_NOT_MODIFIABLE: "Bridge domain 0 can't be deleted/modified", - BD_ID_EXCEED_MAX: "Bridge domain ID exceed 16M limit", - SUBIF_DOESNT_EXIST: "Subinterface doesn't exist", - L2_MACS_EVENT_CLINET_PRESENT: "Client already exist for L2 MACs events", - INVALID_QUEUE: "Invalid queue", - UNSUPPORTED: "Unsupported", - DUPLICATE_IF_ADDRESS: "Address already present on another interface", - APP_INVALID_NS: "Invalid application namespace", - APP_WRONG_NS_SECRET: "Wrong app namespace secret", - APP_CONNECT_SCOPE: "Connect scope", - APP_ALREADY_ATTACHED: "App already attached", - SESSION_REDIRECT: "Redirect failed", - ILLEGAL_NAME: "Illegal name", - NO_NAME_SERVERS: "No name servers configured", - NAME_SERVER_NOT_FOUND: "Name server not found", - NAME_RESOLUTION_NOT_ENABLED: "Name resolution not enabled", - NAME_SERVER_FORMAT_ERROR: "Server format error (bug!)", - NAME_SERVER_NO_SUCH_NAME: "No such name", - NAME_SERVER_NO_ADDRESSES: "No addresses available", - NAME_SERVER_NEXT_SERVER: "Retry with new server", - APP_CONNECT_FILTERED: "Connect was filtered", - ACL_IN_USE_INBOUND: "Inbound ACL in use", - ACL_IN_USE_OUTBOUND: "Outbound ACL in use", - INIT_FAILED: "Initialization Failed", - NETLINK_ERROR: "netlink error", - BIER_BSL_UNSUP: "BIER bit-string-length unsupported", - INSTANCE_IN_USE: "Instance in use", - INVALID_SESSION_ID: "session ID out of range", - ACL_IN_USE_BY_LOOKUP_CONTEXT: "ACL in use by a lookup context", - INVALID_VALUE_3: "Invalid value #3", - NON_ETHERNET: "Interface is not an Ethernet interface", - BD_ALREADY_HAS_BVI: "Bridge domain already has a BVI interface", -} diff --git a/api/vppapi_errors_test.go b/api/vppapi_errors_test.go deleted file mode 100644 index 78e1fbf..0000000 --- a/api/vppapi_errors_test.go +++ /dev/null @@ -1,23 +0,0 @@ -package api - -import ( - "testing" - - . "github.com/onsi/gomega" -) - -func TestUnspecified(t *testing.T) { - RegisterTestingT(t) - - var err error = VPPApiError(-1) - errstr := err.Error() - Expect(errstr).Should(BeEquivalentTo("VPPApiError: Unspecified Error (-1)")) -} - -func TestUnknown(t *testing.T) { - RegisterTestingT(t) - - var err error = VPPApiError(-999) - errstr := err.Error() - Expect(errstr).Should(BeEquivalentTo("VPPApiError: -999")) -} -- cgit 1.2.3-korg