msg := msgName + "_" + msgCrc
msgID, ok := c.msgTable[msg]
if !ok {
- return 0, fmt.Errorf("unknown message: %q", msg)
+ return 0, &adapter.UnknownMsgError{msgName, msgCrc}
}
return msgID, nil
}
import (
"errors"
+ "fmt"
)
const (
// WaitReady waits until adapter is ready.
WaitReady() error
}
+
+// UnknownMsgError is the error type usually returned by GetMsgID
+// method of VppAPI. It describes the name and CRC for the unknown message.
+type UnknownMsgError struct {
+ MsgName string
+ MsgCrc string
+}
+
+func (u *UnknownMsgError) Error() string {
+ return fmt.Sprintf("unknown message: %s_%s", u.MsgName, u.MsgCrc)
+}
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)
+ return msgID, &adapter.UnknownMsgError{msgName, msgCrc}
}
return msgID, nil
package api
import (
+ "fmt"
+ "reflect"
"time"
)
Unsubscribe() error
}
-var registeredMessages = make(map[string]Message)
+// CompatibilityError is the error type usually returned by CheckCompatibility
+// method of Channel. It describes all of the incompatible messages.
+type CompatibilityError struct {
+ // IncompatibleMessages is the list of all messages
+ // that failed compatibility check.
+ IncompatibleMessages []string
+}
+
+func (c *CompatibilityError) Error() string {
+ return fmt.Sprintf("%d incompatible messages: %v", len(c.IncompatibleMessages), c.IncompatibleMessages)
+}
+
+var (
+ registeredMessageTypes = make(map[reflect.Type]string)
+ registeredMessages = make(map[string]Message)
+)
// RegisterMessage is called from generated code to register message.
func RegisterMessage(x Message, name string) {
- name = x.GetMessageName() + "_" + x.GetCrcString()
- /*if _, ok := registeredMessages[name]; ok {
- panic(fmt.Errorf("govpp: duplicate message registered: %s (%s)", name, x.GetCrcString()))
- }*/
- registeredMessages[name] = x
+ typ := reflect.TypeOf(x)
+ namecrc := x.GetMessageName() + "_" + x.GetCrcString()
+ if _, ok := registeredMessageTypes[typ]; ok {
+ panic(fmt.Errorf("govpp: message type %v already registered as %s (%s)", typ, name, namecrc))
+ }
+ registeredMessages[namecrc] = x
+ registeredMessageTypes[typ] = name
}
// GetRegisteredMessages returns list of all registered messages.
return registeredMessages
}
+// GetRegisteredMessageTypes returns list of all registered message types.
+func GetRegisteredMessageTypes() map[reflect.Type]string {
+ return registeredMessageTypes
+}
+
// GoVppAPIPackageIsVersion1 is referenced from generated binapi files
// to assert that that code is compatible with this version of the GoVPP api package.
const GoVppAPIPackageIsVersion1 = true
"github.com/sirupsen/logrus"
+ "git.fd.io/govpp.git/adapter"
"git.fd.io/govpp.git/api"
)
}
func (ch *Channel) CheckCompatiblity(msgs ...api.Message) error {
+ var comperr api.CompatibilityError
for _, msg := range msgs {
- // TODO: collect all incompatible messages and return summarized error
_, err := ch.msgIdentifier.GetMessageID(msg)
if err != nil {
+ if uerr, ok := err.(*adapter.UnknownMsgError); ok {
+ m := fmt.Sprintf("%s_%s", uerr.MsgName, uerr.MsgCrc)
+ comperr.IncompatibleMessages = append(comperr.IncompatibleMessages, m)
+ continue
+ }
+ // other errors return immediatelly
return err
}
}
- return nil
+ if len(comperr.IncompatibleMessages) == 0 {
+ return nil
+ }
+ return &comperr
}
func (ch *Channel) SubscribeNotification(notifChan chan api.Message, event api.Message) (api.SubscriptionCtx, error) {
ctx.mockVpp.MockReply(
&interfaces.SwInterfaceDetails{
SwIfIndex: 1,
- InterfaceName: []byte("if-name-test"),
+ InterfaceName: "if-name-test",
},
&interfaces.SwInterfaceDetails{
SwIfIndex: 2,
- InterfaceName: []byte("if-name-test"),
+ InterfaceName: "if-name-test",
},
&interfaces.SwInterfaceDetails{
SwIfIndex: 3,
- InterfaceName: []byte("if-name-test"),
+ InterfaceName: "if-name-test",
},
)
ctx.mockVpp.MockReply(&ControlPingReply{})
msgs = append(msgs, mock.MsgWithContext{
Msg: &interfaces.SwInterfaceDetails{
SwIfIndex: uint32(i),
- InterfaceName: []byte("if-name-test"),
+ InterfaceName: "if-name-test",
},
Multipart: true,
SeqNum: 1,
mock.MsgWithContext{
Msg: &interfaces.SwInterfaceDetails{
SwIfIndex: uint32(i),
- InterfaceName: []byte("if-name-test"),
+ InterfaceName: "if-name-test",
},
Multipart: true,
SeqNum: 2,
msgs = append(msgs, mock.MsgWithContext{
Msg: &interfaces.SwInterfaceDetails{
SwIfIndex: uint32(i),
- InterfaceName: []byte("if-name-test"),
+ InterfaceName: "if-name-test",
},
Multipart: true,
SeqNum: 2,
package main
import (
- "bytes"
"context"
"flag"
"fmt"
"io"
"log"
+ "strings"
"git.fd.io/govpp.git"
"git.fd.io/govpp.git/adapter/socketclient"
if err != nil {
log.Fatalln("ERROR: DumpSwInterface failed:", err)
}
- fmt.Printf("- interface: %s\n", bytes.Trim(iface.InterfaceName, "\x00"))
+ fmt.Printf("- interface: %s\n", strings.Trim(iface.InterfaceName, "\x00"))
}
}
vppVersion(ch)
+ if err := ch.CheckCompatiblity(interfaces.AllMessages()...); err != nil {
+ log.Fatal(err)
+ }
+
createLoopback(ch)
createLoopback(ch)
interfaceDump(ch)