diff options
-rw-r--r-- | adapter/socketclient/socketclient.go | 430 | ||||
-rw-r--r-- | core/channel.go | 5 | ||||
-rw-r--r-- | core/request_handler.go | 8 | ||||
-rw-r--r-- | examples/bin_api/memclnt.api.json | 598 | ||||
-rw-r--r-- | examples/bin_api/memclnt/memclnt.ba.go | 470 | ||||
-rw-r--r-- | examples/perf-bench/perf-bench.go | 20 |
6 files changed, 1523 insertions, 8 deletions
diff --git a/adapter/socketclient/socketclient.go b/adapter/socketclient/socketclient.go new file mode 100644 index 0000000..eec4fd0 --- /dev/null +++ b/adapter/socketclient/socketclient.go @@ -0,0 +1,430 @@ +package socketclient + +import ( + "bufio" + "bytes" + "fmt" + "io" + "net" + "os" + "strings" + "sync" + "time" + + "github.com/lunixbochs/struc" + logger "github.com/sirupsen/logrus" + + "git.fd.io/govpp.git/adapter" + "git.fd.io/govpp.git/codec" + "git.fd.io/govpp.git/examples/bin_api/memclnt" +) + +const ( + // DefaultSocketName is default VPP API socket file name + DefaultSocketName = "/run/vpp-api.sock" + + sockCreateMsgId = 15 // hard-coded id for sockclnt_create message + govppClientName = "govppsock" // client name used for socket registration +) + +var ( + ConnectTimeout = time.Second * 3 + DisconnectTimeout = time.Second + + Debug = os.Getenv("DEBUG_GOVPP_SOCK") != "" + DebugMsgIds = os.Getenv("DEBUG_GOVPP_SOCKMSG") != "" + + Log = logger.New() // global logger +) + +// init initializes global logger, which logs debug level messages to stdout. +func init() { + Log.Out = os.Stdout + if Debug { + Log.Level = logger.DebugLevel + } +} + +type vppClient struct { + sockAddr string + conn *net.UnixConn + reader *bufio.Reader + cb adapter.MsgCallback + clientIndex uint32 + msgTable map[string]uint16 + sockDelMsgId uint16 + writeMu sync.Mutex + quit chan struct{} + wg sync.WaitGroup +} + +func NewVppClient(sockAddr string) *vppClient { + if sockAddr == "" { + sockAddr = DefaultSocketName + } + return &vppClient{ + sockAddr: sockAddr, + cb: nilCallback, + } +} + +func nilCallback(msgID uint16, data []byte) { + Log.Warnf("no callback set, dropping message: ID=%v len=%d", msgID, len(data)) +} + +func (*vppClient) WaitReady() error { + // TODO: add watcher for socket file? + return nil +} + +func (c *vppClient) SetMsgCallback(cb adapter.MsgCallback) { + Log.Debug("SetMsgCallback") + c.cb = cb +} + +func (c *vppClient) Connect() error { + Log.Debugf("Connecting to: %v", c.sockAddr) + + if err := c.connect(c.sockAddr); err != nil { + return err + } + + if err := c.open(); err != nil { + return err + } + + c.quit = make(chan struct{}) + c.wg.Add(1) + go c.readerLoop() + + return nil +} + +func (c *vppClient) connect(sockAddr string) error { + addr, err := net.ResolveUnixAddr("unixpacket", sockAddr) + if err != nil { + Log.Debugln("ResolveUnixAddr error:", err) + return err + } + + conn, err := net.DialUnix("unixpacket", nil, addr) + if err != nil { + Log.Debugln("Dial error:", err) + return err + } + + c.conn = conn + c.reader = bufio.NewReader(c.conn) + + Log.Debugf("Connected to socket: %v", addr) + + return nil +} + +func (c *vppClient) open() error { + msgCodec := new(codec.MsgCodec) + + req := &memclnt.SockclntCreate{ + Name: []byte(govppClientName), + } + msg, err := msgCodec.EncodeMsg(req, sockCreateMsgId) + if err != nil { + Log.Debugln("Encode error:", err) + return err + } + // set non-0 context + msg[5] = 123 + + if err := c.write(msg); err != nil { + Log.Debugln("Write error: ", err) + return err + } + + readDeadline := time.Now().Add(ConnectTimeout) + if err := c.conn.SetReadDeadline(readDeadline); err != nil { + return err + } + msgReply, err := c.read() + if err != nil { + Log.Println("Read error:", err) + return err + } + // reset read deadline + if err := c.conn.SetReadDeadline(time.Time{}); err != nil { + return err + } + + //log.Printf("Client got (%d): % 0X", len(msgReply), msgReply) + + reply := new(memclnt.SockclntCreateReply) + if err := msgCodec.DecodeMsg(msgReply, reply); err != nil { + Log.Println("Decode error:", err) + return err + } + + Log.Debugf("SockclntCreateReply: Response=%v Index=%v Count=%v", + reply.Response, reply.Index, reply.Count) + + c.clientIndex = reply.Index + c.msgTable = make(map[string]uint16, reply.Count) + for _, x := range reply.MessageTable { + name := string(bytes.TrimSuffix(bytes.Split(x.Name, []byte{0x00})[0], []byte{0x13})) + c.msgTable[name] = x.Index + if strings.HasPrefix(name, "sockclnt_delete_") { + c.sockDelMsgId = x.Index + } + if DebugMsgIds { + Log.Debugf(" - %4d: %q", x.Index, name) + } + } + + return nil +} + +func (c *vppClient) Disconnect() error { + if c.conn == nil { + return nil + } + Log.Debugf("Disconnecting..") + + close(c.quit) + + // force readerLoop to timeout + if err := c.conn.SetReadDeadline(time.Now()); err != nil { + return err + } + + // wait for readerLoop to return + c.wg.Wait() + + if err := c.close(); err != nil { + return err + } + + if err := c.conn.Close(); err != nil { + Log.Debugln("Close socket conn failed:", err) + return err + } + + return nil +} + +func (c *vppClient) close() error { + msgCodec := new(codec.MsgCodec) + + req := &memclnt.SockclntDelete{ + Index: c.clientIndex, + } + msg, err := msgCodec.EncodeMsg(req, c.sockDelMsgId) + if err != nil { + Log.Debugln("Encode error:", err) + return err + } + // set non-0 context + msg[5] = 124 + + Log.Debugf("sending socklntDel (%d byes): % 0X\n", len(msg), msg) + if err := c.write(msg); err != nil { + Log.Debugln("Write error: ", err) + return err + } + + readDeadline := time.Now().Add(DisconnectTimeout) + if err := c.conn.SetReadDeadline(readDeadline); err != nil { + return err + } + msgReply, err := c.read() + if err != nil { + Log.Debugln("Read error:", err) + if nerr, ok := err.(net.Error); ok && nerr.Timeout() { + // we accept timeout for reply + return nil + } + return err + } + // reset read deadline + if err := c.conn.SetReadDeadline(time.Time{}); err != nil { + return err + } + + reply := new(memclnt.SockclntDeleteReply) + if err := msgCodec.DecodeMsg(msgReply, reply); err != nil { + Log.Debugln("Decode error:", err) + return err + } + + Log.Debugf("SockclntDeleteReply: Response=%v", reply.Response) + + return nil +} + +func (c *vppClient) GetMsgID(msgName string, msgCrc string) (uint16, error) { + msg := msgName + "_" + msgCrc + msgID, ok := c.msgTable[msg] + if !ok { + return 0, fmt.Errorf("unknown message: %q", msg) + } + return msgID, nil +} + +type reqHeader struct { + //MsgID uint16 + ClientIndex uint32 + Context uint32 +} + +func (c *vppClient) SendMsg(context uint32, data []byte) error { + h := &reqHeader{ + ClientIndex: c.clientIndex, + Context: context, + } + buf := new(bytes.Buffer) + if err := struc.Pack(buf, h); err != nil { + return err + } + copy(data[2:], buf.Bytes()) + + Log.Debugf("SendMsg (%d) context=%v client=%d: data: % 02X", len(data), context, c.clientIndex, data) + + if err := c.write(data); err != nil { + Log.Debugln("write error: ", err) + return err + } + + return nil +} + +func (c *vppClient) write(msg []byte) error { + h := &msgheader{ + Data_len: uint32(len(msg)), + } + buf := new(bytes.Buffer) + if err := struc.Pack(buf, h); err != nil { + return err + } + header := buf.Bytes() + + // we lock to prevent mixing multiple message sends + c.writeMu.Lock() + defer c.writeMu.Unlock() + + var w io.Writer = c.conn + + if n, err := w.Write(header); err != nil { + return err + } else { + Log.Debugf(" - header sent (%d/%d): % 0X", n, len(header), header) + } + if n, err := w.Write(msg); err != nil { + return err + } else { + Log.Debugf(" - msg sent (%d/%d): % 0X", n, len(msg), msg) + } + + return nil +} + +type msgHeader struct { + MsgID uint16 + Context uint32 +} + +func (c *vppClient) readerLoop() { + defer c.wg.Done() + for { + select { + case <-c.quit: + Log.Debugf("reader quit") + return + default: + } + + msg, err := c.read() + if err != nil { + if isClosedError(err) { + return + } + Log.Debugf("READ FAILED: %v", err) + continue + } + h := new(msgHeader) + if err := struc.Unpack(bytes.NewReader(msg), h); err != nil { + Log.Debugf("unpacking header failed: %v", err) + continue + } + + Log.Debugf("recvMsg (%d) msgID=%d context=%v", len(msg), h.MsgID, h.Context) + c.cb(h.MsgID, msg) + } +} + +type msgheader struct { + Q int `struc:"uint64"` + Data_len uint32 `struc:"uint32"` + Gc_mark_timestamp uint32 `struc:"uint32"` + //data [0]uint8 +} + +func (c *vppClient) read() ([]byte, error) { + Log.Debug("reading next msg..") + + header := make([]byte, 16) + + n, err := io.ReadAtLeast(c.reader, header, 16) + if err != nil { + return nil, err + } else if n == 0 { + Log.Debugln("zero bytes header") + return nil, nil + } + if n != 16 { + Log.Debug("invalid header data (%d): % 0X", n, header[:n]) + return nil, fmt.Errorf("invalid header (expected 16 bytes, got %d)", n) + } + Log.Debugf(" - read header %d bytes: % 0X", n, header) + + h := &msgheader{} + if err := struc.Unpack(bytes.NewReader(header[:]), h); err != nil { + return nil, err + } + Log.Debugf(" - decoded header: %+v", h) + + msgLen := int(h.Data_len) + msg := make([]byte, msgLen) + + n, err = c.reader.Read(msg) + if err != nil { + return nil, err + } + Log.Debugf(" - read msg %d bytes (%d buffered)", n, c.reader.Buffered()) + + if msgLen > n { + remain := msgLen - n + Log.Debugf("continue read for another %d bytes", remain) + view := msg[n:] + + for remain > 0 { + + nbytes, err := c.reader.Read(view) + if err != nil { + return nil, err + } else if nbytes == 0 { + return nil, fmt.Errorf("zero nbytes") + } + + remain -= nbytes + Log.Debugf("another data received: %d bytes (remain: %d)", nbytes, remain) + + view = view[nbytes:] + } + } + + return msg, nil +} + +func isClosedError(err error) bool { + if err == io.EOF { + return true + } + return strings.HasSuffix(err.Error(), "use of closed network connection") +} diff --git a/core/channel.go b/core/channel.go index bf27b73..6cb02f7 100644 --- a/core/channel.go +++ b/core/channel.go @@ -258,6 +258,7 @@ func (ch *Channel) receiveReplyInternal(msg api.Message, expSeqNum uint16) (last case vppReply := <-ch.replyChan: ignore, lastReplyReceived, err = ch.processReply(vppReply, expSeqNum, msg) if ignore { + logrus.Warnf("ignoring reply: %+v", vppReply) continue } return lastReplyReceived, err @@ -275,8 +276,8 @@ func (ch *Channel) processReply(reply *vppReply, expSeqNum uint16, msg api.Messa cmpSeqNums := compareSeqNumbers(reply.seqNum, expSeqNum) if cmpSeqNums == -1 { // reply received too late, ignore the message - logrus.WithField("seqNum", reply.seqNum).Warn( - "Received reply to an already closed binary API request") + logrus.WithField("seqNum", reply.seqNum). + Warn("Received reply to an already closed binary API request") ignore = true return } diff --git a/core/request_handler.go b/core/request_handler.go index 55a825a..fd8aa59 100644 --- a/core/request_handler.go +++ b/core/request_handler.go @@ -23,6 +23,8 @@ import ( logger "github.com/sirupsen/logrus" ) +var ReplyChannelTimeout = time.Millisecond * 100 + var ( ErrNotConnected = errors.New("not connected to VPP, ignoring the request") ErrProbeTimeout = errors.New("probe reply not received within timeout period") @@ -91,7 +93,7 @@ func (c *Connection) processRequest(ch *Channel, req *vppRequest) error { "msg_size": len(data), "seq_num": req.seqNum, "msg_crc": req.msg.GetCrcString(), - }).Debugf(" --> sending msg: %s", req.msg.GetMessageName()) + }).Debugf("--> govpp send: %s: %+v", req.msg.GetMessageName(), req.msg) } // send the request to VPP @@ -163,7 +165,7 @@ func (c *Connection) msgCallback(msgID uint16, data []byte) { "is_multi": isMulti, "seq_num": seqNum, "msg_crc": msg.GetCrcString(), - }).Debugf(" <- received msg: %s", msg.GetMessageName()) + }).Debugf("<-- govpp recv: %s", msg.GetMessageName()) } if context == 0 || c.isNotificationMessage(msgID) { @@ -209,7 +211,7 @@ func sendReply(ch *Channel, reply *vppReply) { select { case ch.replyChan <- reply: // reply sent successfully - case <-time.After(time.Millisecond * 100): + case <-time.After(ReplyChannelTimeout): // receiver still not ready log.WithFields(logger.Fields{ "channel": ch, diff --git a/examples/bin_api/memclnt.api.json b/examples/bin_api/memclnt.api.json new file mode 100644 index 0000000..8014a26 --- /dev/null +++ b/examples/bin_api/memclnt.api.json @@ -0,0 +1,598 @@ +{ + "messages": [ + [ + "memclnt_create", + [ + "u16", + "_vl_msg_id" + ], + [ + "u32", + "context" + ], + [ + "i32", + "ctx_quota" + ], + [ + "u64", + "input_queue" + ], + [ + "u8", + "name", + 64 + ], + [ + "u32", + "api_versions", + 8 + ], + { + "crc": "0x6d33c5ea" + } + ], + [ + "memclnt_create_reply", + [ + "u16", + "_vl_msg_id" + ], + [ + "u32", + "context" + ], + [ + "i32", + "response" + ], + [ + "u64", + "handle" + ], + [ + "u32", + "index" + ], + [ + "u64", + "message_table" + ], + { + "crc": "0x42ec4560" + } + ], + [ + "memclnt_delete", + [ + "u16", + "_vl_msg_id" + ], + [ + "u32", + "index" + ], + [ + "u64", + "handle" + ], + [ + "u8", + "do_cleanup" + ], + { + "crc": "0x4dd351e9" + } + ], + [ + "memclnt_delete_reply", + [ + "u16", + "_vl_msg_id" + ], + [ + "i32", + "response" + ], + [ + "u64", + "handle" + ], + { + "crc": "0x3d3b6312" + } + ], + [ + "rx_thread_exit", + [ + "u16", + "_vl_msg_id" + ], + [ + "u8", + "dummy" + ], + { + "crc": "0xc3a3a452" + } + ], + [ + "memclnt_rx_thread_suspend", + [ + "u16", + "_vl_msg_id" + ], + [ + "u8", + "dummy" + ], + { + "crc": "0xc3a3a452" + } + ], + [ + "memclnt_read_timeout", + [ + "u16", + "_vl_msg_id" + ], + [ + "u8", + "dummy" + ], + { + "crc": "0xc3a3a452" + } + ], + [ + "rpc_call", + [ + "u16", + "_vl_msg_id" + ], + [ + "u32", + "client_index" + ], + [ + "u32", + "context" + ], + [ + "u64", + "function" + ], + [ + "u8", + "multicast" + ], + [ + "u8", + "need_barrier_sync" + ], + [ + "u8", + "send_reply" + ], + [ + "u32", + "data_len" + ], + [ + "u8", + "data", + 0, + "data_len" + ], + { + "crc": "0x7e8a2c95" + } + ], + [ + "rpc_call_reply", + [ + "u16", + "_vl_msg_id" + ], + [ + "u32", + "context" + ], + [ + "i32", + "retval" + ], + { + "crc": "0xe8d4e804" + } + ], + [ + "get_first_msg_id", + [ + "u16", + "_vl_msg_id" + ], + [ + "u32", + "client_index" + ], + [ + "u32", + "context" + ], + [ + "u8", + "name", + 64 + ], + { + "crc": "0x0cb71b0e" + } + ], + [ + "get_first_msg_id_reply", + [ + "u16", + "_vl_msg_id" + ], + [ + "u32", + "context" + ], + [ + "i32", + "retval" + ], + [ + "u16", + "first_msg_id" + ], + { + "crc": "0x7d337472" + } + ], + [ + "api_versions", + [ + "u16", + "_vl_msg_id" + ], + [ + "u32", + "client_index" + ], + [ + "u32", + "context" + ], + { + "crc": "0x51077d14" + } + ], + [ + "api_versions_reply", + [ + "u16", + "_vl_msg_id" + ], + [ + "u32", + "context" + ], + [ + "i32", + "retval" + ], + [ + "u32", + "count" + ], + [ + "vl_api_module_version_t", + "api_versions", + 0, + "count" + ], + { + "crc": "0x90a39195" + } + ], + [ + "trace_plugin_msg_ids", + [ + "u16", + "_vl_msg_id" + ], + [ + "u32", + "client_index" + ], + [ + "u32", + "context" + ], + [ + "u8", + "plugin_name", + 128 + ], + [ + "u16", + "first_msg_id" + ], + [ + "u16", + "last_msg_id" + ], + { + "crc": "0x64af79f9" + } + ], + [ + "sockclnt_create", + [ + "u16", + "_vl_msg_id" + ], + [ + "u32", + "context" + ], + [ + "u8", + "name", + 64 + ], + { + "crc": "0xdf2cf94d" + } + ], + [ + "sockclnt_create_reply", + [ + "u16", + "_vl_msg_id" + ], + [ + "u32", + "client_index" + ], + [ + "u32", + "context" + ], + [ + "i32", + "response" + ], + [ + "u32", + "index" + ], + [ + "u16", + "count" + ], + [ + "vl_api_message_table_entry_t", + "message_table", + 0, + "count" + ], + { + "crc": "0xa134a8a8" + } + ], + [ + "sockclnt_delete", + [ + "u16", + "_vl_msg_id" + ], + [ + "u32", + "client_index" + ], + [ + "u32", + "context" + ], + [ + "u32", + "index" + ], + { + "crc": "0x8ac76db6" + } + ], + [ + "sockclnt_delete_reply", + [ + "u16", + "_vl_msg_id" + ], + [ + "u32", + "context" + ], + [ + "i32", + "response" + ], + { + "crc": "0x8f38b1ee" + } + ], + [ + "sock_init_shm", + [ + "u16", + "_vl_msg_id" + ], + [ + "u32", + "client_index" + ], + [ + "u32", + "context" + ], + [ + "u32", + "requested_size" + ], + [ + "u8", + "nitems" + ], + [ + "u64", + "configs", + 0, + "nitems" + ], + { + "crc": "0x51646d92" + } + ], + [ + "sock_init_shm_reply", + [ + "u16", + "_vl_msg_id" + ], + [ + "u32", + "context" + ], + [ + "i32", + "retval" + ], + { + "crc": "0xe8d4e804" + } + ], + [ + "memclnt_keepalive", + [ + "u16", + "_vl_msg_id" + ], + [ + "u32", + "client_index" + ], + [ + "u32", + "context" + ], + { + "crc": "0x51077d14" + } + ], + [ + "memclnt_keepalive_reply", + [ + "u16", + "_vl_msg_id" + ], + [ + "u32", + "context" + ], + [ + "i32", + "retval" + ], + { + "crc": "0xe8d4e804" + } + ] + ], + "vl_api_version": "0xb619530", + "unions": [], + "services": { + "api_versions": { + "reply": "api_versions_reply" + }, + "memclnt_keepalive": { + "reply": "memclnt_keepalive_reply" + }, + "memclnt_rx_thread_suspend": { + "reply": "null" + }, + "sockclnt_delete": { + "reply": "sockclnt_delete_reply" + }, + "memclnt_create": { + "reply": "memclnt_create_reply" + }, + "get_first_msg_id": { + "reply": "get_first_msg_id_reply" + }, + "memclnt_read_timeout": { + "reply": "null" + }, + "rpc_call": { + "reply": "rpc_call_reply" + }, + "rx_thread_exit": { + "reply": "null" + }, + "sock_init_shm": { + "reply": "sock_init_shm_reply" + }, + "memclnt_delete": { + "reply": "memclnt_delete_reply" + }, + "sockclnt_create": { + "reply": "sockclnt_create_reply" + }, + "trace_plugin_msg_ids": { + "reply": "null" + } + }, + "enums": [], + "types": [ + [ + "module_version", + [ + "u32", + "major" + ], + [ + "u32", + "minor" + ], + [ + "u32", + "patch" + ], + [ + "u8", + "name", + 64 + ], + { + "crc": "0x4b6da11a" + } + ], + [ + "message_table_entry", + [ + "u16", + "index" + ], + [ + "u8", + "name", + 64 + ], + { + "crc": "0x913bf1c6" + } + ] + ], + "aliases": {} +} diff --git a/examples/bin_api/memclnt/memclnt.ba.go b/examples/bin_api/memclnt/memclnt.ba.go new file mode 100644 index 0000000..68ff320 --- /dev/null +++ b/examples/bin_api/memclnt/memclnt.ba.go @@ -0,0 +1,470 @@ +// Code generated by GoVPP binapi-generator. DO NOT EDIT. +// source: memclnt.api.json + +/* + Package memclnt is a generated from VPP binary API module 'memclnt'. + + It contains following objects: + 13 services + 2 types + 22 messages +*/ +package memclnt + +import api "git.fd.io/govpp.git/api" +import struc "github.com/lunixbochs/struc" +import bytes "bytes" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = api.RegisterMessage +var _ = struc.Pack +var _ = bytes.NewBuffer + +// Services represents VPP binary API services: +type Services interface { + APIVersions(*APIVersions) (*APIVersionsReply, error) + GetFirstMsgID(*GetFirstMsgID) (*GetFirstMsgIDReply, error) + MemclntCreate(*MemclntCreate) (*MemclntCreateReply, error) + MemclntDelete(*MemclntDelete) (*MemclntDeleteReply, error) + MemclntKeepalive(*MemclntKeepalive) (*MemclntKeepaliveReply, error) + MemclntReadTimeout(*MemclntReadTimeout) error + MemclntRxThreadSuspend(*MemclntRxThreadSuspend) error + RPCCall(*RPCCall) (*RPCCallReply, error) + RxThreadExit(*RxThreadExit) error + SockInitShm(*SockInitShm) (*SockInitShmReply, error) + SockclntCreate(*SockclntCreate) (*SockclntCreateReply, error) + SockclntDelete(*SockclntDelete) (*SockclntDeleteReply, error) + TracePluginMsgIds(*TracePluginMsgIds) error +} + +/* Types */ + +// MessageTableEntry represents VPP binary API type 'message_table_entry': +type MessageTableEntry struct { + Index uint16 + Name []byte `struc:"[64]byte"` +} + +func (*MessageTableEntry) GetTypeName() string { + return "message_table_entry" +} +func (*MessageTableEntry) GetCrcString() string { + return "913bf1c6" +} + +// ModuleVersion represents VPP binary API type 'module_version': +type ModuleVersion struct { + Major uint32 + Minor uint32 + Patch uint32 + Name []byte `struc:"[64]byte"` +} + +func (*ModuleVersion) GetTypeName() string { + return "module_version" +} +func (*ModuleVersion) GetCrcString() string { + return "4b6da11a" +} + +/* Messages */ + +// APIVersions represents VPP binary API message 'api_versions': +type APIVersions struct{} + +func (*APIVersions) GetMessageName() string { + return "api_versions" +} +func (*APIVersions) GetCrcString() string { + return "51077d14" +} +func (*APIVersions) GetMessageType() api.MessageType { + return api.RequestMessage +} + +// APIVersionsReply represents VPP binary API message 'api_versions_reply': +type APIVersionsReply struct { + Retval int32 + Count uint32 `struc:"sizeof=APIVersions"` + APIVersions []ModuleVersion +} + +func (*APIVersionsReply) GetMessageName() string { + return "api_versions_reply" +} +func (*APIVersionsReply) GetCrcString() string { + return "90a39195" +} +func (*APIVersionsReply) GetMessageType() api.MessageType { + return api.ReplyMessage +} + +// GetFirstMsgID represents VPP binary API message 'get_first_msg_id': +type GetFirstMsgID struct { + Name []byte `struc:"[64]byte"` +} + +func (*GetFirstMsgID) GetMessageName() string { + return "get_first_msg_id" +} +func (*GetFirstMsgID) GetCrcString() string { + return "0cb71b0e" +} +func (*GetFirstMsgID) GetMessageType() api.MessageType { + return api.RequestMessage +} + +// GetFirstMsgIDReply represents VPP binary API message 'get_first_msg_id_reply': +type GetFirstMsgIDReply struct { + Retval int32 + FirstMsgID uint16 +} + +func (*GetFirstMsgIDReply) GetMessageName() string { + return "get_first_msg_id_reply" +} +func (*GetFirstMsgIDReply) GetCrcString() string { + return "7d337472" +} +func (*GetFirstMsgIDReply) GetMessageType() api.MessageType { + return api.ReplyMessage +} + +// MemclntCreate represents VPP binary API message 'memclnt_create': +type MemclntCreate struct { + CtxQuota int32 + InputQueue uint64 + Name []byte `struc:"[64]byte"` + APIVersions []uint32 `struc:"[8]uint32"` +} + +func (*MemclntCreate) GetMessageName() string { + return "memclnt_create" +} +func (*MemclntCreate) GetCrcString() string { + return "6d33c5ea" +} +func (*MemclntCreate) GetMessageType() api.MessageType { + return api.ReplyMessage +} + +// MemclntCreateReply represents VPP binary API message 'memclnt_create_reply': +type MemclntCreateReply struct { + Response int32 + Handle uint64 + Index uint32 + MessageTable uint64 +} + +func (*MemclntCreateReply) GetMessageName() string { + return "memclnt_create_reply" +} +func (*MemclntCreateReply) GetCrcString() string { + return "42ec4560" +} +func (*MemclntCreateReply) GetMessageType() api.MessageType { + return api.ReplyMessage +} + +// MemclntDelete represents VPP binary API message 'memclnt_delete': +type MemclntDelete struct { + Index uint32 + Handle uint64 + DoCleanup uint8 +} + +func (*MemclntDelete) GetMessageName() string { + return "memclnt_delete" +} +func (*MemclntDelete) GetCrcString() string { + return "4dd351e9" +} +func (*MemclntDelete) GetMessageType() api.MessageType { + return api.OtherMessage +} + +// MemclntDeleteReply represents VPP binary API message 'memclnt_delete_reply': +type MemclntDeleteReply struct { + Response int32 + Handle uint64 +} + +func (*MemclntDeleteReply) GetMessageName() string { + return "memclnt_delete_reply" +} +func (*MemclntDeleteReply) GetCrcString() string { + return "3d3b6312" +} +func (*MemclntDeleteReply) GetMessageType() api.MessageType { + return api.OtherMessage +} + +// MemclntKeepalive represents VPP binary API message 'memclnt_keepalive': +type MemclntKeepalive struct{} + +func (*MemclntKeepalive) GetMessageName() string { + return "memclnt_keepalive" +} +func (*MemclntKeepalive) GetCrcString() string { + return "51077d14" +} +func (*MemclntKeepalive) GetMessageType() api.MessageType { + return api.RequestMessage +} + +// MemclntKeepaliveReply represents VPP binary API message 'memclnt_keepalive_reply': +type MemclntKeepaliveReply struct { + Retval int32 +} + +func (*MemclntKeepaliveReply) GetMessageName() string { + return "memclnt_keepalive_reply" +} +func (*MemclntKeepaliveReply) GetCrcString() string { + return "e8d4e804" +} +func (*MemclntKeepaliveReply) GetMessageType() api.MessageType { + return api.ReplyMessage +} + +// MemclntReadTimeout represents VPP binary API message 'memclnt_read_timeout': +type MemclntReadTimeout struct { + Dummy uint8 +} + +func (*MemclntReadTimeout) GetMessageName() string { + return "memclnt_read_timeout" +} +func (*MemclntReadTimeout) GetCrcString() string { + return "c3a3a452" +} +func (*MemclntReadTimeout) GetMessageType() api.MessageType { + return api.OtherMessage +} + +// MemclntRxThreadSuspend represents VPP binary API message 'memclnt_rx_thread_suspend': +type MemclntRxThreadSuspend struct { + Dummy uint8 +} + +func (*MemclntRxThreadSuspend) GetMessageName() string { + return "memclnt_rx_thread_suspend" +} +func (*MemclntRxThreadSuspend) GetCrcString() string { + return "c3a3a452" +} +func (*MemclntRxThreadSuspend) GetMessageType() api.MessageType { + return api.OtherMessage +} + +// RPCCall represents VPP binary API message 'rpc_call': +type RPCCall struct { + Function uint64 + Multicast uint8 + NeedBarrierSync uint8 + SendReply uint8 + DataLen uint32 `struc:"sizeof=Data"` + Data []byte +} + +func (*RPCCall) GetMessageName() string { + return "rpc_call" +} +func (*RPCCall) GetCrcString() string { + return "7e8a2c95" +} +func (*RPCCall) GetMessageType() api.MessageType { + return api.RequestMessage +} + +// RPCCallReply represents VPP binary API message 'rpc_call_reply': +type RPCCallReply struct { + Retval int32 +} + +func (*RPCCallReply) GetMessageName() string { + return "rpc_call_reply" +} +func (*RPCCallReply) GetCrcString() string { + return "e8d4e804" +} +func (*RPCCallReply) GetMessageType() api.MessageType { + return api.ReplyMessage +} + +// RxThreadExit represents VPP binary API message 'rx_thread_exit': +type RxThreadExit struct { + Dummy uint8 +} + +func (*RxThreadExit) GetMessageName() string { + return "rx_thread_exit" +} +func (*RxThreadExit) GetCrcString() string { + return "c3a3a452" +} +func (*RxThreadExit) GetMessageType() api.MessageType { + return api.OtherMessage +} + +// SockInitShm represents VPP binary API message 'sock_init_shm': +type SockInitShm struct { + RequestedSize uint32 + Nitems uint8 `struc:"sizeof=Configs"` + Configs []uint64 +} + +func (*SockInitShm) GetMessageName() string { + return "sock_init_shm" +} +func (*SockInitShm) GetCrcString() string { + return "51646d92" +} +func (*SockInitShm) GetMessageType() api.MessageType { + return api.RequestMessage +} + +// SockInitShmReply represents VPP binary API message 'sock_init_shm_reply': +type SockInitShmReply struct { + Retval int32 +} + +func (*SockInitShmReply) GetMessageName() string { + return "sock_init_shm_reply" +} +func (*SockInitShmReply) GetCrcString() string { + return "e8d4e804" +} +func (*SockInitShmReply) GetMessageType() api.MessageType { + return api.ReplyMessage +} + +// SockclntCreate represents VPP binary API message 'sockclnt_create': +type SockclntCreate struct { + Name []byte `struc:"[64]byte"` +} + +func (*SockclntCreate) GetMessageName() string { + return "sockclnt_create" +} +func (*SockclntCreate) GetCrcString() string { + return "df2cf94d" +} +func (*SockclntCreate) GetMessageType() api.MessageType { + return api.ReplyMessage +} + +// SockclntCreateReply represents VPP binary API message 'sockclnt_create_reply': +type SockclntCreateReply struct { + Response int32 + Index uint32 + Count uint16 `struc:"sizeof=MessageTable"` + MessageTable []MessageTableEntry +} + +func (*SockclntCreateReply) GetMessageName() string { + return "sockclnt_create_reply" +} +func (*SockclntCreateReply) GetCrcString() string { + return "a134a8a8" +} +func (*SockclntCreateReply) GetMessageType() api.MessageType { + return api.RequestMessage +} + +// SockclntDelete represents VPP binary API message 'sockclnt_delete': +type SockclntDelete struct { + Index uint32 +} + +func (*SockclntDelete) GetMessageName() string { + return "sockclnt_delete" +} +func (*SockclntDelete) GetCrcString() string { + return "8ac76db6" +} +func (*SockclntDelete) GetMessageType() api.MessageType { + return api.RequestMessage +} + +// SockclntDeleteReply represents VPP binary API message 'sockclnt_delete_reply': +type SockclntDeleteReply struct { + Response int32 +} + +func (*SockclntDeleteReply) GetMessageName() string { + return "sockclnt_delete_reply" +} +func (*SockclntDeleteReply) GetCrcString() string { + return "8f38b1ee" +} +func (*SockclntDeleteReply) GetMessageType() api.MessageType { + return api.ReplyMessage +} + +// TracePluginMsgIds represents VPP binary API message 'trace_plugin_msg_ids': +type TracePluginMsgIds struct { + PluginName []byte `struc:"[128]byte"` + FirstMsgID uint16 + LastMsgID uint16 +} + +func (*TracePluginMsgIds) GetMessageName() string { + return "trace_plugin_msg_ids" +} +func (*TracePluginMsgIds) GetCrcString() string { + return "64af79f9" +} +func (*TracePluginMsgIds) GetMessageType() api.MessageType { + return api.RequestMessage +} + +func init() { + api.RegisterMessage((*APIVersions)(nil), "memclnt.APIVersions") + api.RegisterMessage((*APIVersionsReply)(nil), "memclnt.APIVersionsReply") + api.RegisterMessage((*GetFirstMsgID)(nil), "memclnt.GetFirstMsgID") + api.RegisterMessage((*GetFirstMsgIDReply)(nil), "memclnt.GetFirstMsgIDReply") + api.RegisterMessage((*MemclntCreate)(nil), "memclnt.MemclntCreate") + api.RegisterMessage((*MemclntCreateReply)(nil), "memclnt.MemclntCreateReply") + api.RegisterMessage((*MemclntDelete)(nil), "memclnt.MemclntDelete") + api.RegisterMessage((*MemclntDeleteReply)(nil), "memclnt.MemclntDeleteReply") + api.RegisterMessage((*MemclntKeepalive)(nil), "memclnt.MemclntKeepalive") + api.RegisterMessage((*MemclntKeepaliveReply)(nil), "memclnt.MemclntKeepaliveReply") + api.RegisterMessage((*MemclntReadTimeout)(nil), "memclnt.MemclntReadTimeout") + api.RegisterMessage((*MemclntRxThreadSuspend)(nil), "memclnt.MemclntRxThreadSuspend") + api.RegisterMessage((*RPCCall)(nil), "memclnt.RPCCall") + api.RegisterMessage((*RPCCallReply)(nil), "memclnt.RPCCallReply") + api.RegisterMessage((*RxThreadExit)(nil), "memclnt.RxThreadExit") + api.RegisterMessage((*SockInitShm)(nil), "memclnt.SockInitShm") + api.RegisterMessage((*SockInitShmReply)(nil), "memclnt.SockInitShmReply") + api.RegisterMessage((*SockclntCreate)(nil), "memclnt.SockclntCreate") + api.RegisterMessage((*SockclntCreateReply)(nil), "memclnt.SockclntCreateReply") + api.RegisterMessage((*SockclntDelete)(nil), "memclnt.SockclntDelete") + api.RegisterMessage((*SockclntDeleteReply)(nil), "memclnt.SockclntDeleteReply") + api.RegisterMessage((*TracePluginMsgIds)(nil), "memclnt.TracePluginMsgIds") +} + +var Messages = []api.Message{ + (*APIVersions)(nil), + (*APIVersionsReply)(nil), + (*GetFirstMsgID)(nil), + (*GetFirstMsgIDReply)(nil), + (*MemclntCreate)(nil), + (*MemclntCreateReply)(nil), + (*MemclntDelete)(nil), + (*MemclntDeleteReply)(nil), + (*MemclntKeepalive)(nil), + (*MemclntKeepaliveReply)(nil), + (*MemclntReadTimeout)(nil), + (*MemclntRxThreadSuspend)(nil), + (*RPCCall)(nil), + (*RPCCallReply)(nil), + (*RxThreadExit)(nil), + (*SockInitShm)(nil), + (*SockInitShmReply)(nil), + (*SockclntCreate)(nil), + (*SockclntCreateReply)(nil), + (*SockclntDelete)(nil), + (*SockclntDeleteReply)(nil), + (*TracePluginMsgIds)(nil), +} diff --git a/examples/perf-bench/perf-bench.go b/examples/perf-bench/perf-bench.go index 24d3ebb..e5b0926 100644 --- a/examples/perf-bench/perf-bench.go +++ b/examples/perf-bench/perf-bench.go @@ -25,7 +25,9 @@ import ( "github.com/pkg/profile" "github.com/sirupsen/logrus" - "git.fd.io/govpp.git" + "git.fd.io/govpp.git/adapter" + "git.fd.io/govpp.git/adapter/socketclient" + "git.fd.io/govpp.git/adapter/vppapiclient" "git.fd.io/govpp.git/api" "git.fd.io/govpp.git/core" "git.fd.io/govpp.git/examples/bin_api/vpe" @@ -38,9 +40,10 @@ const ( func main() { // parse optional flags - var sync, prof bool + var sync, prof, sock bool var cnt int flag.BoolVar(&sync, "sync", false, "run synchronous perf test") + flag.BoolVar(&sock, "sock", false, "use socket client for VPP API") flag.IntVar(&cnt, "count", 0, "count of requests to be sent to VPP") flag.BoolVar(&prof, "prof", false, "generate profile data") flag.Parse() @@ -58,8 +61,15 @@ func main() { defer profile.Start().Stop() } + var a adapter.VppAPI + if sock { + a = socketclient.NewVppClient("/run/vpp-api.sock") + } else { + a = vppapiclient.NewVppClient("") + } + // connect to VPP - conn, err := govpp.Connect("") + conn, err := core.Connect(a) if err != nil { log.Fatalln("Error:", err) } @@ -72,6 +82,8 @@ func main() { } defer ch.Close() + ch.SetReplyTimeout(time.Second * 2) + // log only errors core.SetLogger(&logrus.Logger{Level: logrus.ErrorLevel}) @@ -89,6 +101,8 @@ func main() { elapsed := time.Since(start) fmt.Println("Test took:", elapsed) fmt.Printf("Requests per second: %.0f\n", float64(cnt)/elapsed.Seconds()) + + time.Sleep(time.Second) } func syncTest(ch api.Channel, cnt int) { |