From a3bb834db727a3ac9a1ffcfeae9265e5dead851f Mon Sep 17 00:00:00 2001 From: Ondrej Fabry Date: Wed, 15 Aug 2018 12:59:25 +0200 Subject: Refactor GoVPP Squashed commit of the following: commit 348930db31575e9f59b3834d9fec07411f011e05 Author: Ondrej Fabry Date: Wed Aug 15 11:30:13 2018 +0200 Use debug level for log about different context commit 9fc963c559cea67a41b85c6cdadc322fb3b1fc7c Author: Ondrej Fabry Date: Wed Aug 15 11:22:03 2018 +0200 Remove annoying logs and add env vars for debugging commit fdc9fd624d13feadb602e0d03d58f8a44b7a565f Author: Ondrej Fabry Date: Wed Aug 15 11:18:47 2018 +0200 Fix printing unknown VPPApiError commit 8f968be36a91de4d4a8ea17593ba314f82aa9583 Author: Ondrej Fabry Date: Tue Aug 14 17:25:10 2018 +0200 Refactor entire GoVPP - fix some cases with inconsistent VPP messages, causing messages to be incorrectly identified as event or request - simplify API, remove direct access to internal Go channels - add module name with message to registration of messages - start watching filesystem only when vpe-api file does not exist - simplify code in message codec and remove unneeded parts - retrieve IDs of all registered messages after connect to VPP - define fallback for control ping in core to avoid duplicate registration - add SetLogLevel function to set logger level more easily - remove lot of unused code commit 34dd1b7e10ef0324aa8c4e4cc42375bd6021c6cb Author: Ondrej Fabry Date: Mon Aug 13 11:29:54 2018 +0200 Rename VnetError to VPPApiError commit c6549d6f77847a1367a12ff47fb716e2955e973a Author: Ondrej Fabry Date: Mon Aug 13 10:23:43 2018 +0200 Fix examples and regenerate binapi commit 4612e36b416779771f5efab4fc654c2766d2cb1c Author: Ondrej Fabry Date: Mon Aug 13 09:51:22 2018 +0200 Add parsing and generation for services commit ac9c5280c5aa27e325f327609e2364cc66f3723f Author: Ondrej Fabry Date: Fri Aug 10 14:30:15 2018 +0200 Fix exit status on error and add continue-onerror flag commit 9b3f4ef9fc7c8c62037fa107085eae18a8725314 Author: Ondrej Fabry Date: Thu Aug 9 15:20:56 2018 +0200 Return VnetError when Retval != 0 commit 8fd21a907b5e628ec4d2026215b83d15da96c297 Author: Ondrej Fabry Date: Thu Aug 9 14:59:05 2018 +0200 Add all missing errors from api_errno.h commit 08450f288d3046ebaecf40203174ae342a07f1eb Author: Ondrej Fabry Date: Thu Aug 9 14:29:27 2018 +0200 Update README commit d8dced0728dd62243539be741868fb7d9b8de4cc Author: Ondrej Fabry Date: Thu Aug 9 13:59:59 2018 +0200 Regenerate vpe in core commit 254da7592cdbf634cf7aa46ae36ce7bb6d4ee555 Author: Ondrej Fabry Date: Thu Aug 9 13:37:00 2018 +0200 Add VnetError type for Retvals commit 4475c1087fb53ab4c788e530bc7fef7cfc89d2cd Author: Ondrej Fabry Date: Thu Aug 9 13:36:07 2018 +0200 Add registration API commit 892a3ea5a2c703e2f7c29331663f6a6fa706bff5 Author: Ondrej Fabry Date: Thu Aug 9 13:30:43 2018 +0200 Generate registration for messages and check all IDs on connect commit 389ed03b6e7082260281866c3449d72d72347c99 Author: Ondrej Fabry Date: Thu Aug 9 11:32:41 2018 +0200 Show error for empty adapter (on Darwin/Windows) commit ef1ea040d656ade64242432dc5f06810ed8dcde6 Author: Ondrej Fabry Date: Thu Aug 9 11:31:37 2018 +0200 Improve logged info commit d4adae3b14ed54c8d693060dd857fa9ba5ec8e06 Author: Ondrej Fabry Date: Thu Aug 9 11:27:48 2018 +0200 Update examples commit 63921e1346014701a22639a2611129563bb1eb78 Author: Ondrej Fabry Date: Thu Aug 9 11:02:56 2018 +0200 Generate unions and fix some issues - add comments between sections - define structs on single line if it has no fields - generate unions with setters/getters for each field - fix detection of message type commit 6ab3e3fa590b245898306a6ffaf32c7721eab60c Author: Ondrej Fabry Date: Wed Aug 8 15:37:10 2018 +0200 Refactor binapi-generator - split JSON parsing from code generation - parse and generate enums - parse unions (no generation yet) - change output file suffix to '.ba.go' - cleanup and simplify code - split code into files - add flag for debug mode Change-Id: I58f685e0d4c7a38e9a7b6ea0a1f47792d95d7399 Signed-off-by: Ondrej Fabry --- adapter/adapter.go | 12 ++++- adapter/mock/mock_adapter.go | 30 ++++++------ adapter/vppapiclient/empty_adapter.go | 4 +- adapter/vppapiclient/vppapiclient_adapter.go | 71 +++++++++++++++------------- 4 files changed, 64 insertions(+), 53 deletions(-) (limited to 'adapter') diff --git a/adapter/adapter.go b/adapter/adapter.go index bc3a573..7d3d1e4 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -14,6 +14,16 @@ package adapter +import ( + "errors" +) + +// ErrNotImplemented is an error returned when missing implementation. +var ErrNotImplemented = errors.New("not implemented for this OS") + +// MsgCallback defines func signature for message callback. +type MsgCallback func(msgID uint16, context uint32, data []byte) + // VppAdapter provides connection to VPP. It is responsible for sending and receiving of binary-encoded messages to/from VPP. type VppAdapter interface { // Connect connects the process to VPP. @@ -29,7 +39,7 @@ type VppAdapter interface { SendMsg(context uint32, data []byte) error // SetMsgCallback sets a callback function that will be called by the adapter whenever a message comes from VPP. - SetMsgCallback(func(context uint32, msgId uint16, data []byte)) + SetMsgCallback(cb MsgCallback) // WaitReady waits until adapter is ready. WaitReady() error diff --git a/adapter/mock/mock_adapter.go b/adapter/mock/mock_adapter.go index a5cb62d..3f5686f 100644 --- a/adapter/mock/mock_adapter.go +++ b/adapter/mock/mock_adapter.go @@ -25,7 +25,6 @@ import ( "git.fd.io/govpp.git/adapter" "git.fd.io/govpp.git/adapter/mock/binapi" "git.fd.io/govpp.git/api" - "git.fd.io/govpp.git/codec" "github.com/lunixbochs/struc" ) @@ -33,24 +32,24 @@ import ( type replyMode int const ( - _ replyMode = 0 - useRepliesQueue = 1 // use replies in the queue - useReplyHandlers = 2 // use reply handler + _ replyMode = iota + useRepliesQueue // use replies in the queue + useReplyHandlers // use reply handler ) // VppAdapter represents a mock VPP adapter that can be used for unit/integration testing instead of the vppapiclient adapter. type VppAdapter struct { - callback func(context uint32, msgId uint16, data []byte) + callback adapter.MsgCallback + msgIDSeq uint16 + access sync.RWMutex msgNameToIds map[string]uint16 msgIDsToName map[uint16]string - msgIDSeq uint16 binAPITypes map[string]reflect.Type - access sync.RWMutex + repliesLock sync.Mutex // mutex for the queue replies []reply // FIFO queue of messages replyHandlers []ReplyHandler // callbacks that are able to calculate mock responses - repliesLock sync.Mutex // mutex for the queue mode replyMode // mode in which the mock operates } @@ -211,8 +210,6 @@ func (a *VppAdapter) GetMsgID(msgName string, msgCrc string) (uint16, error) { a.msgNameToIds[msgName] = msgID a.msgIDsToName[msgID] = msgName - log.Println("VPP GetMessageId ", msgID, " name:", msgName, " crc:", msgCrc) - return msgID, nil } @@ -252,11 +249,12 @@ func (a *VppAdapter) SendMsg(clientID uint32, data []byte) error { Data: data, }) if finished { - a.callback(clientID, msgID, reply) + a.callback(msgID, clientID, reply) return nil } } fallthrough + case useRepliesQueue: a.repliesLock.Lock() defer a.repliesLock.Unlock() @@ -274,15 +272,15 @@ func (a *VppAdapter) SendMsg(clientID uint32, data []byte) error { } if msg.Msg.GetMessageType() == api.ReplyMessage { struc.Pack(buf, &codec.VppReplyHeader{VlMsgID: msgID, Context: context}) - } else if msg.Msg.GetMessageType() == api.EventMessage { - struc.Pack(buf, &codec.VppEventHeader{VlMsgID: msgID, Context: context}) } else if msg.Msg.GetMessageType() == api.RequestMessage { struc.Pack(buf, &codec.VppRequestHeader{VlMsgID: msgID, Context: context}) + } else if msg.Msg.GetMessageType() == api.EventMessage { + struc.Pack(buf, &codec.VppEventHeader{VlMsgID: msgID}) } else { struc.Pack(buf, &codec.VppOtherHeader{VlMsgID: msgID}) } struc.Pack(buf, msg.Msg) - a.callback(context, msgID, buf.Bytes()) + a.callback(msgID, context, buf.Bytes()) } a.replies = a.replies[1:] @@ -301,13 +299,13 @@ func (a *VppAdapter) SendMsg(clientID uint32, data []byte) error { msgID := uint16(defaultReplyMsgID) struc.Pack(buf, &codec.VppReplyHeader{VlMsgID: msgID, Context: clientID}) struc.Pack(buf, &defaultReply{}) - a.callback(clientID, msgID, buf.Bytes()) + a.callback(msgID, clientID, buf.Bytes()) } return nil } // SetMsgCallback sets a callback function that will be called by the adapter whenever a message comes from the mock. -func (a *VppAdapter) SetMsgCallback(cb func(context uint32, msgID uint16, data []byte)) { +func (a *VppAdapter) SetMsgCallback(cb adapter.MsgCallback) { a.callback = cb } diff --git a/adapter/vppapiclient/empty_adapter.go b/adapter/vppapiclient/empty_adapter.go index c3010a0..7514048 100644 --- a/adapter/vppapiclient/empty_adapter.go +++ b/adapter/vppapiclient/empty_adapter.go @@ -32,7 +32,7 @@ func NewVppAdapter(string) adapter.VppAdapter { } func (a *vppAPIClientAdapter) Connect() error { - return nil + return adapter.ErrNotImplemented } func (a *vppAPIClientAdapter) Disconnect() { @@ -47,7 +47,7 @@ func (a *vppAPIClientAdapter) SendMsg(clientID uint32, data []byte) error { return nil } -func (a *vppAPIClientAdapter) SetMsgCallback(cb func(context uint32, msgID uint16, data []byte)) { +func (a *vppAPIClientAdapter) SetMsgCallback(cb adapter.MsgCallback) { // no op } diff --git a/adapter/vppapiclient/vppapiclient_adapter.go b/adapter/vppapiclient/vppapiclient_adapter.go index c77d7f1..7aafa55 100644 --- a/adapter/vppapiclient/vppapiclient_adapter.go +++ b/adapter/vppapiclient/vppapiclient_adapter.go @@ -28,7 +28,7 @@ package vppapiclient #include #include -extern void go_msg_callback(uint16_t, uint32_t, void*, size_t); +extern void go_msg_callback(uint16_t msg_id, uint32_t context, void* data, size_t size); typedef struct __attribute__((__packed__)) _req_header { uint16_t msg_id; @@ -38,7 +38,7 @@ typedef struct __attribute__((__packed__)) _req_header { typedef struct __attribute__((__packed__)) _reply_header { uint16_t msg_id; - uint32_t context; + uint32_t context; // currently not all reply messages contain context field } reply_header_t; static void @@ -49,23 +49,23 @@ govpp_msg_callback (unsigned char *data, int size) } static int -govpp_connect (char *shm) +govpp_send(uint32_t context, void *data, size_t size) { - return vac_connect("govpp", shm, govpp_msg_callback, 32); + req_header_t *header = ((req_header_t *)data); + header->context = htonl(context); + return vac_write(data, size); } static int -govvp_disconnect() +govpp_connect (char *shm) { - return vac_disconnect(); + return vac_connect("govpp", shm, govpp_msg_callback, 32); } static int -govpp_send(uint32_t context, void *data, size_t size) +govvp_disconnect() { - req_header_t *header = ((req_header_t *)data); - header->context = htonl(context); - return vac_write(data, size); + return vac_disconnect(); } static uint32_t @@ -79,6 +79,7 @@ import "C" import ( "fmt" "os" + "path/filepath" "reflect" "unsafe" @@ -98,7 +99,7 @@ const ( // vppAPIClientAdapter is the opaque context of the adapter. type vppAPIClientAdapter struct { shmPrefix string - callback func(context uint32, msgId uint16, data []byte) + callback adapter.MsgCallback } var vppClient *vppAPIClientAdapter // global vpp API client adapter context @@ -138,6 +139,7 @@ func (a *vppAPIClientAdapter) GetMsgID(msgName string, msgCrc string) (uint16, e msgID := uint16(C.govpp_get_msg_index(nameAndCrc)) if msgID == ^uint16(0) { + // VPP does not know this message return msgID, fmt.Errorf("unknown message: %v (crc: %v)", msgName, msgCrc) } @@ -154,40 +156,41 @@ func (a *vppAPIClientAdapter) SendMsg(context uint32, data []byte) error { } // SetMsgCallback sets a callback function that will be called by the adapter whenever a message comes from VPP. -func (a *vppAPIClientAdapter) SetMsgCallback(cb func(context uint32, msgID uint16, data []byte)) { +func (a *vppAPIClientAdapter) SetMsgCallback(cb adapter.MsgCallback) { a.callback = cb } // WaitReady blocks until shared memory for sending // binary api calls is present on the file system. func (a *vppAPIClientAdapter) WaitReady() error { - watcher, err := fsnotify.NewWatcher() - if err != nil { - return err - } - defer watcher.Close() - - err = watcher.Add(watchedFolder) - if err != nil { - return err - } - // Path to the shared memory segment with prefix, if set + // Path to the shared memory segment var path string if a.shmPrefix == "" { - path = watchedFolder + watchedFile + path = filepath.Join(watchedFolder, watchedFile) } else { - path = watchedFolder + a.shmPrefix + "-" + watchedFile - } - if fileExists(path) { - return nil + path = filepath.Join(watchedFolder, a.shmPrefix+"-"+watchedFile) } - for { - ev := <-watcher.Events - if ev.Name == path && (ev.Op&fsnotify.Create) == fsnotify.Create { - break + // Watch folder if file does not exist yet + if !fileExists(path) { + watcher, err := fsnotify.NewWatcher() + if err != nil { + return err + } + defer watcher.Close() + + if err := watcher.Add(watchedFolder); err != nil { + return err + } + + for { + ev := <-watcher.Events + if ev.Name == path && (ev.Op&fsnotify.Create) == fsnotify.Create { + break + } } } + return nil } @@ -206,5 +209,5 @@ func go_msg_callback(msgID C.uint16_t, context C.uint32_t, data unsafe.Pointer, slice := &reflect.SliceHeader{Data: uintptr(data), Len: int(size), Cap: int(size)} byteArr := *(*[]byte)(unsafe.Pointer(slice)) - vppClient.callback(uint32(context), uint16(msgID), byteArr) -} \ No newline at end of file + vppClient.callback(uint16(msgID), uint32(context), byteArr) +} -- cgit 1.2.3-korg