Change-Id: I9e822ce7e9b9f44f7d074b0294d6eda37c2a0f12
Signed-off-by: Rastislav Szabo <raszabo@cisco.com>
binapi_generator/binapi_generator
examples/examples
binapi_generator/binapi_generator
examples/examples
msgIdsToName *map[uint16]string
msgIdSeq uint16
binApiTypes map[string]reflect.Type
msgIdsToName *map[uint16]string
msgIdSeq uint16
binApiTypes map[string]reflect.Type
}
// replyHeader represents a common header of each VPP request message.
}
// replyHeader represents a common header of each VPP request message.
}
func (a *VppAdapter) GetMsgNameByID(msgId uint16) (string, bool) {
}
func (a *VppAdapter) GetMsgNameByID(msgId uint16) (string, bool) {
switch msgId {
case 100:
return "control_ping", true
switch msgId {
case 100:
return "control_ping", true
return "sw_interface_details", true
}
return "sw_interface_details", true
}
+ a.access.Lock()
+ defer a.access.Unlock()
+ a.initMaps()
msgName, found := (*a.msgIdsToName)[msgId]
return msgName, found
}
func (a *VppAdapter) RegisterBinApiTypes(binApiTypes map[string]reflect.Type) {
msgName, found := (*a.msgIdsToName)[msgId]
return msgName, found
}
func (a *VppAdapter) RegisterBinApiTypes(binApiTypes map[string]reflect.Type) {
+ a.access.Lock()
+ defer a.access.Unlock()
a.initMaps()
for _, v := range binApiTypes {
if msg, ok := reflect.New(v).Interface().(api.Message); ok {
a.initMaps()
for _, v := range binApiTypes {
if msg, ok := reflect.New(v).Interface().(api.Message); ok {
+ a.access.Lock()
+ defer a.access.Unlock()
a.initMaps()
if msgId, found := (*a.msgNameToIds)[msgName]; found {
a.initMaps()
if msgId, found := (*a.msgNameToIds)[msgName]; found {
func (a *VppAdapter) SendMsg(clientID uint32, data []byte) error {
switch mode {
case useReplyHandlers:
func (a *VppAdapter) SendMsg(clientID uint32, data []byte) error {
switch mode {
case useReplyHandlers:
for i := len(replyHandlers) - 1; i >= 0; i-- {
replyHandler := replyHandlers[i]
for i := len(replyHandlers) - 1; i >= 0; i-- {
replyHandler := replyHandlers[i]
reqHeader := requestHeader{}
struc.Unpack(buf, &reqHeader)
reqHeader := requestHeader{}
struc.Unpack(buf, &reqHeader)
reqMsgName, _ := (*a.msgIdsToName)[reqHeader.VlMsgID]
reqMsgName, _ := (*a.msgIdsToName)[reqHeader.VlMsgID]
reply, msgID, finished := replyHandler(MessageDTO{reqHeader.VlMsgID, reqMsgName,
clientID, data})
reply, msgID, finished := replyHandler(MessageDTO{reqHeader.VlMsgID, reqMsgName,
clientID, data})
// Channel is the main communication interface with govpp core. It contains two Go channels, one for sending the requests
// to VPP and one for receiving the replies from it. The user can access the Go channels directly, or use the helper
// Channel is the main communication interface with govpp core. It contains two Go channels, one for sending the requests
// to VPP and one for receiving the replies from it. The user can access the Go channels directly, or use the helper
-// methods provided inside of this package.
+// methods provided inside of this package. Do not use the same channel from multiple goroutines concurrently,
+// otherwise the responses could mix! Use multiple channels instead.
type Channel struct {
ReqChan chan *VppRequest // channel for sending the requests to VPP, closing this channel releases all resources in the ChannelProvider
ReplyChan chan *VppReply // channel where VPP replies are delivered to
type Channel struct {
ReqChan chan *VppRequest // channel for sending the requests to VPP, closing this channel releases all resources in the ChannelProvider
ReplyChan chan *VppReply // channel where VPP replies are delivered to
return false, err
}
if vppReply.MessageID != expMsgID {
return false, err
}
if vppReply.MessageID != expMsgID {
- err = fmt.Errorf("invalid message ID %d, expected %d", vppReply.MessageID, expMsgID)
+ err = fmt.Errorf("invalid message ID %d, expected %d "+
+ "(also check if multiple goroutines are not sharing one GoVPP channel)", vppReply.MessageID, expMsgID)
return false, err
}
// decode the message
return false, err
}
// decode the message
"os/exec"
"path/filepath"
"strings"
"os/exec"
"path/filepath"
"strings"
"unicode"
"github.com/bennyscetbun/jsongo"
"unicode"
"github.com/bennyscetbun/jsongo"
const (
apiImportPath = "git.fd.io/govpp.git/api" // import path of the govpp API
const (
apiImportPath = "git.fd.io/govpp.git/api" // import path of the govpp API
- inputFileExt = ".json" // filename extension of files that should be processed as the input
+ inputFileExt = ".json" // filename extension of files that should be processed as the input
)
// context is a structure storing details of a particular code generation task
)
// context is a structure storing details of a particular code generation task
// generatePackageHeader generates package header into provider writer
func generatePackageHeader(ctx *context, w io.Writer, rootNode *jsongo.JSONNode) {
fmt.Fprintln(w, "// Package "+ctx.packageName+" represents the VPP binary API of the '"+ctx.packageName+"' VPP module.")
// generatePackageHeader generates package header into provider writer
func generatePackageHeader(ctx *context, w io.Writer, rootNode *jsongo.JSONNode) {
fmt.Fprintln(w, "// Package "+ctx.packageName+" represents the VPP binary API of the '"+ctx.packageName+"' VPP module.")
- fmt.Fprintln(w, "// DO NOT EDIT. Generated from '"+ctx.inputFile+"' on "+time.Now().Format(time.RFC1123)+".")
+ fmt.Fprintln(w, "// DO NOT EDIT. Generated from '"+ctx.inputFile+"'")
fmt.Fprintln(w, "package "+ctx.packageName)
fmt.Fprintln(w, "package "+ctx.packageName)
"msg_size": len(data),
}).Debug("Sending a message to VPP.")
"msg_size": len(data),
}).Debug("Sending a message to VPP.")
- c.vpp.SendMsg(chMeta.id, data)
-
+ // expect multipart response
atomic.StoreUint32(&chMeta.multipart, 1)
atomic.StoreUint32(&chMeta.multipart, 1)
+ // send the request to VPP
+ c.vpp.SendMsg(chMeta.id, data)
+
+ if req.Multipart {
+ // send a control ping to determine end of the multipart response
ping := &vpe.ControlPing{}
pingData, _ := c.codec.EncodeMsg(ping, c.pingReqID)
ping := &vpe.ControlPing{}
pingData, _ := c.codec.EncodeMsg(ping, c.pingReqID)