diff options
Diffstat (limited to 'binapigen')
-rw-r--r-- | binapigen/binapigen.go | 42 | ||||
-rw-r--r-- | binapigen/binapigen_test.go | 6 | ||||
-rw-r--r-- | binapigen/gen_encoding.go | 12 | ||||
-rw-r--r-- | binapigen/gen_helpers.go | 81 | ||||
-rw-r--r-- | binapigen/gen_helpers_test.go | 31 | ||||
-rw-r--r-- | binapigen/gen_http.go (renamed from binapigen/gen_rest.go) | 14 | ||||
-rw-r--r-- | binapigen/gen_rpc.go | 16 | ||||
-rw-r--r-- | binapigen/generate.go | 84 | ||||
-rw-r--r-- | binapigen/generate_test.go | 21 | ||||
-rw-r--r-- | binapigen/generator.go | 65 | ||||
-rw-r--r-- | binapigen/generator_test.go | 94 | ||||
-rw-r--r-- | binapigen/run.go | 16 | ||||
-rw-r--r-- | binapigen/types.go | 64 | ||||
-rw-r--r-- | binapigen/vppapi.go | 28 | ||||
-rw-r--r-- | binapigen/vppapi/api_schema.go | 16 | ||||
-rw-r--r-- | binapigen/vppapi/integration_test.go | 2 | ||||
-rw-r--r-- | binapigen/vppapi/parse_json.go | 48 | ||||
-rw-r--r-- | binapigen/vppapi/testdata/ip.api.json | 3096 | ||||
-rw-r--r-- | binapigen/vppapi/testdata/union.api.json | 231 | ||||
-rw-r--r-- | binapigen/vppapi/util.go | 23 | ||||
-rw-r--r-- | binapigen/vppapi/vppapi.go | 25 | ||||
-rw-r--r-- | binapigen/vppapi/vppapi_test.go | 2 |
22 files changed, 2982 insertions, 1035 deletions
diff --git a/binapigen/binapigen.go b/binapigen/binapigen.go index 2dbd661..5c9553f 100644 --- a/binapigen/binapigen.go +++ b/binapigen/binapigen.go @@ -20,7 +20,7 @@ import ( "strconv" "strings" - "git.fd.io/govpp.git/binapigen/vppapi" + "go.fd.io/govpp/binapigen/vppapi" ) // generatedCodeVersion indicates a version of the generated code. @@ -71,7 +71,10 @@ func newFile(gen *Generator, apifile *vppapi.File, packageName GoPackageName, im } for _, enumType := range apifile.EnumTypes { - file.Enums = append(file.Enums, newEnum(gen, file, enumType)) + file.Enums = append(file.Enums, newEnum(gen, file, enumType, false)) + } + for _, enumflagType := range apifile.EnumflagTypes { + file.Enums = append(file.Enums, newEnum(gen, file, enumflagType, true)) } for _, aliasType := range apifile.AliasTypes { file.Aliases = append(file.Aliases, newAlias(gen, file, aliasType)) @@ -167,15 +170,18 @@ type Enum struct { vppapi.EnumType GoIdent + + IsFlag bool } -func newEnum(gen *Generator, file *File, apitype vppapi.EnumType) *Enum { +func newEnum(gen *Generator, file *File, apitype vppapi.EnumType, isFlag bool) *Enum { typ := &Enum{ EnumType: apitype, GoIdent: GoIdent{ GoName: camelCaseName(apitype.Name), GoImportPath: file.GoImportPath, }, + IsFlag: isFlag, } gen.enumsByName[typ.Name] = typ return typ @@ -243,8 +249,8 @@ func newStruct(gen *Generator, file *File, apitype vppapi.StructType) *Struct { }, } gen.structsByName[typ.Name] = typ - for _, fieldType := range apitype.Fields { - field := newField(gen, file, typ, fieldType) + for i, fieldType := range apitype.Fields { + field := newField(gen, file, typ, fieldType, i) typ.Fields = append(typ.Fields, field) } return typ @@ -271,13 +277,13 @@ func newUnion(gen *Generator, file *File, apitype vppapi.UnionType) *Union { typ := &Union{ UnionType: apitype, GoIdent: GoIdent{ - GoName: camelCaseName(apitype.Name), + GoName: withSuffix(camelCaseName(apitype.Name), "Union"), GoImportPath: file.GoImportPath, }, } gen.unionsByName[typ.Name] = typ - for _, fieldType := range apitype.Fields { - field := newField(gen, file, typ, fieldType) + for i, fieldType := range apitype.Fields { + field := newField(gen, file, typ, fieldType, i) typ.Fields = append(typ.Fields, field) } return typ @@ -302,11 +308,12 @@ const ( msgTypeEvent // msg_id, client_index ) -// message fields +// common message fields const ( fieldMsgID = "_vl_msg_id" fieldClientIndex = "client_index" fieldContext = "context" + fieldRetval = "retval" ) // field options @@ -343,7 +350,7 @@ func newMessage(gen *Generator, file *File, apitype vppapi.Message) *Message { } } n++ - field := newField(gen, file, msg, fieldType) + field := newField(gen, file, msg, fieldType, n) msg.Fields = append(msg.Fields, field) } return msg @@ -394,12 +401,24 @@ func getMsgType(m vppapi.Message) (msgType, error) { return typ, nil } +func getRetvalField(m *Message) *Field { + for _, field := range m.Fields { + if field.Name == fieldRetval { + return field + } + } + return nil +} + // Field represents a field for message or struct/union types. type Field struct { vppapi.Field GoName string + // Index defines field index in parent. + Index int + // DefaultValue is a default value of field or // nil if default value is not defined for field. DefaultValue interface{} @@ -423,10 +442,11 @@ type Field struct { FieldSizeFrom *Field } -func newField(gen *Generator, file *File, parent interface{}, apitype vppapi.Field) *Field { +func newField(gen *Generator, file *File, parent interface{}, apitype vppapi.Field, index int) *Field { typ := &Field{ Field: apitype, GoName: camelCaseName(apitype.Name), + Index: index, } switch p := parent.(type) { case *Message: diff --git a/binapigen/binapigen_test.go b/binapigen/binapigen_test.go index 9a25420..c9bfba7 100644 --- a/binapigen/binapigen_test.go +++ b/binapigen/binapigen_test.go @@ -19,7 +19,7 @@ import ( . "github.com/onsi/gomega" - "git.fd.io/govpp.git/binapigen/vppapi" + "go.fd.io/govpp/binapigen/vppapi" ) func TestGenerator(t *testing.T) { @@ -40,11 +40,11 @@ func TestGenerator(t *testing.T) { t.Run(test.name, func(t *testing.T) { RegisterTestingT(t) - apifiles := []*vppapi.File{test.file} + apiFiles := []*vppapi.File{test.file} gen, err := New(Options{ ImportPrefix: "test", - }, apifiles, nil) + }, apiFiles, nil) Expect(err).ToNot(HaveOccurred(), "unexpected generator error: %v", err) Expect(gen.Files).To(HaveLen(1)) diff --git a/binapigen/gen_encoding.go b/binapigen/gen_encoding.go index d946771..ca1e848 100644 --- a/binapigen/gen_encoding.go +++ b/binapigen/gen_encoding.go @@ -21,10 +21,6 @@ import ( "github.com/sirupsen/logrus" ) -func init() { - //RegisterPlugin("encoding", GenerateEncoding) -} - func genMessageSize(g *GenFile, name string, fields []*Field) { g.P("func (m *", name, ") Size() (size int) {") g.P("if m == nil { return 0 }") @@ -230,7 +226,7 @@ func encodeBaseType(g *GenFile, typ, orig, name string, length int, sizefrom str g.P("buf.EncodeBytes(", name, "[:], ", length, ")") } return - case I8, I16, U16, I32, U32, I64, U64, F64: + case I8, I16, U16, I32, U32, I64, U64, F64, BOOL: gotype := BaseTypesGo[typ] if length != 0 { g.P("for i := 0; i < ", length, "; i++ {") @@ -268,7 +264,7 @@ func encodeBaseType(g *GenFile, typ, orig, name string, length int, sizefrom str } if isArray { switch typ { - case I8, U8, I16, U16, I32, U32, I64, U64, F64: + case I8, U8, I16, U16, I32, U32, I64, U64, F64, BOOL: g.P("}") } } @@ -369,7 +365,7 @@ func decodeBaseType(g *GenFile, typ, orig, name string, length int, sizefrom str g.P("copy(", name, "[:], buf.DecodeBytes(", size, "))") } return - case I8, I16, U16, I32, U32, I64, U64, F64: + case I8, I16, U16, I32, U32, I64, U64, F64, BOOL: if alloc { g.P(name, " = make([]", orig, ", ", size, ")") } @@ -401,7 +397,7 @@ func decodeBaseType(g *GenFile, typ, orig, name string, length int, sizefrom str } if isArray { switch typ { - case I8, U8, I16, U16, I32, U32, I64, U64, F64: + case I8, U8, I16, U16, I32, U32, I64, U64, F64, BOOL: g.P("}") } } diff --git a/binapigen/gen_helpers.go b/binapigen/gen_helpers.go index 5eafc76..0fc303d 100644 --- a/binapigen/gen_helpers.go +++ b/binapigen/gen_helpers.go @@ -22,6 +22,7 @@ func init() { const ( fmtPkg = GoImportPath("fmt") netPkg = GoImportPath("net") + timePkg = GoImportPath("time") stringsPkg = GoImportPath("strings") ) @@ -54,16 +55,19 @@ func genIPConversion(g *GenFile, structName string, ipv int) { g.P(" return ", netPkg.Ident("IP"), "(x[:]).To16()") } g.P("}") + g.P() // String method g.P("func (x ", structName, ") String() string {") g.P(" return x.ToIP().String()") g.P("}") + g.P() // MarshalText method g.P("func (x *", structName, ") MarshalText() ([]byte, error) {") g.P(" return []byte(x.String()), nil") g.P("}") + g.P() // UnmarshalText method g.P("func (x *", structName, ") UnmarshalText(text []byte) error {") @@ -84,6 +88,12 @@ func genAddressConversion(g *GenFile, structName string) { g.P(" if ip == nil {") g.P(" return ", structName, "{}, ", fmtPkg.Ident("Errorf"), "(\"invalid address: %s\", s)") g.P(" }") + g.P(" return ", structName, "FromIP(ip), nil") + g.P("}") + g.P() + + // AddressFromIP method + g.P("func ", structName, "FromIP(ip ", netPkg.Ident("IP"), ") ", structName, " {") g.P(" var addr ", structName) g.P(" if ip.To4() == nil {") g.P(" addr.Af = ADDRESS_IP6") @@ -96,8 +106,9 @@ func genAddressConversion(g *GenFile, structName string) { g.P(" copy(ip4[:], ip.To4())") g.P(" addr.Un.SetIP4(ip4)") g.P(" }") - g.P(" return addr, nil") + g.P(" return addr") g.P("}") + g.P() // ToIP method g.P("func (x ", structName, ") ToIP() ", netPkg.Ident("IP"), " {") @@ -109,16 +120,19 @@ func genAddressConversion(g *GenFile, structName string) { g.P(" return ", netPkg.Ident("IP"), "(ip4[:]).To4()") g.P(" }") g.P("}") + g.P() // String method g.P("func (x ", structName, ") String() string {") g.P(" return x.ToIP().String()") g.P("}") + g.P() // MarshalText method g.P("func (x *", structName, ") MarshalText() ([]byte, error) {") g.P(" return []byte(x.String()), nil") g.P("}") + g.P() // UnmarshalText method g.P("func (x *", structName, ") UnmarshalText(text []byte) error {") @@ -169,6 +183,7 @@ func genIPPrefixConversion(g *GenFile, structName string, ipv int) { g.P(" }") g.P(" return prefix, nil") g.P("}") + g.P() // ToIPNet method g.P("func (x ", structName, ") ToIPNet() *", netPkg.Ident("IPNet"), " {") @@ -180,24 +195,20 @@ func genIPPrefixConversion(g *GenFile, structName string, ipv int) { g.P(" ipnet := &", netPkg.Ident("IPNet"), "{IP: x.Address.ToIP(), Mask: mask}") g.P(" return ipnet") g.P("}") + g.P() // String method g.P("func (x ", structName, ") String() string {") g.P(" ip := x.Address.String()") g.P(" return ip + \"/\" + ", strconvPkg.Ident("Itoa"), "(int(x.Len))") - /*if ipv == 4 { - g.P(" mask := ", netPkg.Ident("CIDRMask"), "(int(x.Len), 32)") - } else { - g.P(" mask := ", netPkg.Ident("CIDRMask"), "(int(x.Len), 128)") - } - g.P(" ipnet := &", netPkg.Ident("IPNet"), "{IP: x.Address.ToIP(), Mask: mask}") - g.P(" return ipnet.String()")*/ g.P("}") + g.P() // MarshalText method g.P("func (x *", structName, ") MarshalText() ([]byte, error) {") g.P(" return []byte(x.String()), nil") g.P("}") + g.P() // UnmarshalText method g.P("func (x *", structName, ") UnmarshalText(text []byte) error {") @@ -240,6 +251,7 @@ func genPrefixConversion(g *GenFile, structName string) { g.P(" }") g.P(" return prefix, nil") g.P("}") + g.P() // ToIPNet method g.P("func (x ", structName, ") ToIPNet() *", netPkg.Ident("IPNet"), " {") @@ -252,17 +264,20 @@ func genPrefixConversion(g *GenFile, structName string) { g.P(" ipnet := &", netPkg.Ident("IPNet"), "{IP: x.Address.ToIP(), Mask: mask}") g.P(" return ipnet") g.P("}") + g.P() // String method g.P("func (x ", structName, ") String() string {") g.P(" ip := x.Address.String()") g.P(" return ip + \"/\" + ", strconvPkg.Ident("Itoa"), "(int(x.Len))") g.P("}") + g.P() // MarshalText method g.P("func (x *", structName, ") MarshalText() ([]byte, error) {") g.P(" return []byte(x.String()), nil") g.P("}") + g.P() // UnmarshalText method g.P("func (x *", structName, ") UnmarshalText(text []byte) error {") @@ -285,16 +300,19 @@ func genAddressWithPrefixConversion(g *GenFile, structName string) { g.P(" }") g.P(" return ", structName, "(prefix), nil") g.P("}") + g.P() // String method g.P("func (x ", structName, ") String() string {") g.P(" return Prefix(x).String()") g.P("}") + g.P() // MarshalText method g.P("func (x *", structName, ") MarshalText() ([]byte, error) {") g.P(" return []byte(x.String()), nil") g.P("}") + g.P() // UnmarshalText method g.P("func (x *", structName, ") UnmarshalText(text []byte) error {") @@ -319,21 +337,25 @@ func genMacAddressConversion(g *GenFile, structName string) { g.P(" copy(macaddr[:], mac[:])") g.P(" return macaddr, nil") g.P("}") + g.P() // ToMAC method g.P("func (x ", structName, ") ToMAC() ", netPkg.Ident("HardwareAddr"), " {") g.P(" return ", netPkg.Ident("HardwareAddr"), "(x[:])") g.P("}") + g.P() // String method g.P("func (x ", structName, ") String() string {") g.P(" return x.ToMAC().String()") g.P("}") + g.P() // MarshalText method g.P("func (x *", structName, ") MarshalText() ([]byte, error) {") g.P(" return []byte(x.String()), nil") g.P("}") + g.P() // UnmarshalText method g.P("func (x *", structName, ") UnmarshalText(text []byte) error {") @@ -346,3 +368,46 @@ func genMacAddressConversion(g *GenFile, structName string) { g.P("}") g.P() } + +func genTimestampConversion(g *GenFile, structName string) { + // NewTimestamp method + g.P("func New", structName, "(t ", timePkg.Ident("Time"), ") ", structName, " {") + g.P(" sec := int64(t.Unix())") + g.P(" nsec := int32(t.Nanosecond())") + g.P(" ns := float64(sec) + float64(nsec / 1e9)") + g.P(" return ", structName, "(ns)") + g.P("}") + g.P() + + // ToTime method + g.P("func (x ", structName, ") ToTime() ", timePkg.Ident("Time"), " {") + g.P(" ns := int64(x * 1e9)") + g.P(" sec := ns / 1e9") + g.P(" nsec := ns % 1e9") + g.P(" return ", timePkg.Ident("Unix"), "(sec, nsec)") + g.P("}") + g.P() + + // String method + g.P("func (x ", structName, ") String() string {") + g.P(" return x.ToTime().String()") + g.P("}") + g.P() + + // MarshalText method + g.P("func (x *", structName, ") MarshalText() ([]byte, error) {") + g.P(" return []byte(x.ToTime().Format(", timePkg.Ident("RFC3339Nano"), ")), nil") + g.P("}") + g.P() + + // UnmarshalText method + g.P("func (x *", structName, ") UnmarshalText(text []byte) error {") + g.P(" t, err := ", timePkg.Ident("Parse"), "(", timePkg.Ident("RFC3339Nano"), ", string(text))") + g.P(" if err != nil {") + g.P(" return err") + g.P(" }") + g.P(" *x = New", structName, "(t)") + g.P(" return nil") + g.P("}") + g.P() +} diff --git a/binapigen/gen_helpers_test.go b/binapigen/gen_helpers_test.go index 371fd6c..a8d159f 100644 --- a/binapigen/gen_helpers_test.go +++ b/binapigen/gen_helpers_test.go @@ -17,11 +17,13 @@ package binapigen import ( "strings" "testing" + "time" . "github.com/onsi/gomega" - "git.fd.io/govpp.git/binapi/ethernet_types" - "git.fd.io/govpp.git/binapi/ip_types" + "go.fd.io/govpp/binapi/ethernet_types" + "go.fd.io/govpp/binapi/ip_types" + "go.fd.io/govpp/binapi/vpe_types" ) func TestGeneratedParseAddress(t *testing.T) { @@ -154,3 +156,28 @@ func TestGeneratedParseMACError(t *testing.T) { _, err := ethernet_types.ParseMacAddress("malformed_mac") Expect(err).Should(HaveOccurred()) } + +func TestGeneratedParseTimestamp(t *testing.T) { + RegisterTestingT(t) + + var data = []struct { + input time.Time + result vpe_types.Timestamp + }{ + {time.Unix(0, 0), vpe_types.Timestamp(0)}, + {time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), + vpe_types.Timestamp(9.466848e+08)}, + } + + for _, entry := range data { + t.Run(entry.input.String(), func(t *testing.T) { + ts := vpe_types.NewTimestamp(entry.input) + Expect(ts).To(Equal(entry.result)) + + Expect(entry.input.Equal(ts.ToTime())).To(BeTrue()) + + originTime := ts.String() + Expect(originTime).To(Equal(entry.input.Local().String())) + }) + } +} diff --git a/binapigen/gen_rest.go b/binapigen/gen_http.go index 6ddb57a..4c9697e 100644 --- a/binapigen/gen_rest.go +++ b/binapigen/gen_http.go @@ -20,7 +20,7 @@ import ( ) func init() { - RegisterPlugin("rest", GenerateREST) + RegisterPlugin("http", GenerateHTTP) } // library dependencies @@ -30,16 +30,16 @@ const ( jsonPkg = GoImportPath("encoding/json") ) -func GenerateREST(gen *Generator, file *File) *GenFile { +func GenerateHTTP(gen *Generator, file *File) *GenFile { if file.Service == nil { return nil } logf("----------------------------") - logf(" Generate REST - %s", file.Desc.Name) + logf(" Generate HTTP - %s", file.Desc.Name) logf("----------------------------") - filename := path.Join(file.FilenamePrefix, file.Desc.Name+"_rest.ba.go") + filename := path.Join(file.FilenamePrefix, file.Desc.Name+"_http.ba.go") g := gen.NewGenFile(filename, file.GoImportPath) g.file = file @@ -51,15 +51,15 @@ func GenerateREST(gen *Generator, file *File) *GenFile { // generate RPC service if len(file.Service.RPCs) > 0 { - genRESTHandler(g, file.Service) + genHTTPHandler(g, file.Service) } return g } -func genRESTHandler(g *GenFile, svc *Service) { +func genHTTPHandler(g *GenFile, svc *Service) { // generate handler constructor - g.P("func RESTHandler(rpc ", serviceApiName, ") ", httpPkg.Ident("Handler"), " {") + g.P("func HTTPHandler(rpc ", serviceApiName, ") ", httpPkg.Ident("Handler"), " {") g.P(" mux := ", httpPkg.Ident("NewServeMux"), "()") // generate http handlers for rpc diff --git a/binapigen/gen_rpc.go b/binapigen/gen_rpc.go index ba23f4a..fa123f0 100644 --- a/binapigen/gen_rpc.go +++ b/binapigen/gen_rpc.go @@ -71,7 +71,7 @@ func GenerateRPC(gen *Generator, file *File) *GenFile { func genService(g *GenFile, svc *Service) { // generate comment - g.P("// ", serviceApiName, " defines RPC service ", g.file.Desc.Name, ".") + g.P("// ", serviceApiName, " defines RPC service ", g.file.Desc.Name, ".") // generate service interface g.P("type ", serviceApiName, " interface {") @@ -152,6 +152,8 @@ func genService(g *GenFile, svc *Service) { g.P(" case *", msgDetails.GoIdent, ":") g.P(" return m, nil") g.P(" case *", msgReply.GoIdent, ":") + g.P(" err = c.Stream.Close()") + g.P(" if err != nil { return nil, err }") g.P(" return nil, ", ioPkg.Ident("EOF")) g.P(" default:") g.P(" return nil, ", fmtPkg.Ident("Errorf"), "(\"unexpected message: %T %v\", m, m)") @@ -160,12 +162,22 @@ func genService(g *GenFile, svc *Service) { g.P("out := new(", rpc.MsgReply.GoIdent, ")") g.P("err := c.conn.Invoke(ctx, in, out)") g.P("if err != nil { return nil, err }") - g.P("return out, nil") + if retvalField := getRetvalField(rpc.MsgReply); retvalField != nil { + if fieldType := getFieldType(g, retvalField); fieldType == "int32" { + g.P("return out, ", govppApiPkg.Ident("RetvalToVPPApiError"), "(out.", retvalField.GoName, ")") + } else { + g.P("return out, ", govppApiPkg.Ident("RetvalToVPPApiError"), "(int32(out.", retvalField.GoName, "))") + } + } else { + g.P("return out, nil") + } } else { g.P("stream, err := c.conn.NewStream(ctx)") g.P("if err != nil { return err }") g.P("err = stream.SendMsg(in)") g.P("if err != nil { return err }") + g.P("err = stream.Close()") + g.P("if err != nil { return err }") g.P("return nil") } g.P("}") diff --git a/binapigen/generate.go b/binapigen/generate.go index 679dd54..2be33d1 100644 --- a/binapigen/generate.go +++ b/binapigen/generate.go @@ -21,15 +21,15 @@ import ( "strconv" "strings" - "git.fd.io/govpp.git/internal/version" + "go.fd.io/govpp/version" ) // library dependencies const ( strconvPkg = GoImportPath("strconv") - govppApiPkg = GoImportPath("git.fd.io/govpp.git/api") - govppCodecPkg = GoImportPath("git.fd.io/govpp.git/codec") + govppApiPkg = GoImportPath("go.fd.io/govpp/api") + govppCodecPkg = GoImportPath("go.fd.io/govpp/codec") ) // generated names @@ -41,6 +41,19 @@ const ( fieldUnionData = "XXX_UnionData" // name for the union data field ) +// option keys +const ( + msgStatus = "status" + msgDeprecated = "deprecated" + msgInProgress = "in_progress" +) + +// generated option messages +const ( + deprecatedMsg = "the message will be removed in the future versions" + inProgressMsg = "the message form may change in the future versions" +) + func GenerateAPI(gen *Generator, file *File) *GenFile { logf("----------------------------") logf(" Generate API - %s", file.Desc.Name) @@ -55,7 +68,9 @@ func GenerateAPI(gen *Generator, file *File) *GenFile { g.P("// versions:") g.P("// binapi-generator: ", version.Version()) g.P("// VPP: ", g.gen.vppVersion) - g.P("// source: ", g.file.Desc.Path) + if !gen.opts.NoSourcePathInfo { + g.P("// source: ", g.file.Desc.Path) + } } g.P() @@ -75,14 +90,12 @@ func GenerateAPI(gen *Generator, file *File) *GenFile { g.P("const _ = ", govppApiPkg.Ident("GoVppAPIPackageIsVersion"), generatedCodeVersion) g.P() - if !file.isTypesFile() { - g.P("const (") - g.P(apiName, " = ", strconv.Quote(g.file.Desc.Name)) - g.P(apiVersion, " = ", strconv.Quote(g.file.Version)) - g.P(apiCrc, " = ", g.file.Desc.CRC) - g.P(")") - g.P() - } + g.P("const (") + g.P(apiName, " = ", strconv.Quote(g.file.Desc.Name)) + g.P(apiVersion, " = ", strconv.Quote(g.file.Version)) + g.P(apiCrc, " = ", g.file.Desc.CRC) + g.P(")") + g.P() for _, enum := range g.file.Enums { genEnum(g, enum) @@ -143,6 +156,23 @@ func genTypeComment(g *GenFile, goName string, vppName string, objKind string) { g.P("// ", goName, " defines ", objKind, " '", vppName, "'.") } +func genTypeOptionComment(g *GenFile, options map[string]string) { + // all messages for API versions < 1.0.0 are in_progress by default + if msg, ok := options[msgInProgress]; ok || options[msgStatus] == msgInProgress || + len(g.file.Version) > 1 && g.file.Version[0:2] == "0." { + if msg == "" { + msg = inProgressMsg + } + g.P("// InProgress: ", msg) + } + if msg, ok := options[msgDeprecated]; ok || options[msgStatus] == msgDeprecated { + if msg == "" { + msg = deprecatedMsg + } + g.P("// Deprecated: ", msg) + } +} + func genEnum(g *GenFile, enum *Enum) { logf("gen ENUM %s (%s) - %d entries", enum.GoName, enum.Name, len(enum.Entries)) @@ -176,7 +206,7 @@ func genEnum(g *GenFile, enum *Enum) { g.P(")") g.P() - if isEnumFlag(enum) { + if enum.IsFlag || isEnumFlag(enum) { size := BaseTypeSizes[enum.Type] * 8 g.P("func (x ", enum.GoName, ") String() string {") g.P(" s, ok := ", enum.GoName, "_name[", gotype, "(x)]") @@ -244,6 +274,8 @@ func genAlias(g *GenFile, alias *Alias) { genAddressWithPrefixConversion(g, alias.GoName) case "mac_address": genMacAddressConversion(g, alias.GoName) + case "timestamp": + genTimestampConversion(g, alias.GoName) } } @@ -283,8 +315,10 @@ func genUnion(g *GenFile, union *Union) { g.P("type ", union.GoName, " struct {") + // generate field comments + g.P("// ", union.GoName, " can be one of:") for _, field := range union.Fields { - g.P("// ", field.GoName, " *", getFieldType(g, field)) + g.P("// - ", field.GoName, " *", getFieldType(g, field)) } // generate data field @@ -297,22 +331,23 @@ func genUnion(g *GenFile, union *Union) { // generate methods for fields for _, field := range union.Fields { - genUnionFieldMethods(g, union.GoName, field) + genUnionField(g, union, field) } g.P() } -func genUnionFieldMethods(g *GenFile, structName string, field *Field) { - getterStruct := fieldGoType(g, field) +func genUnionField(g *GenFile, union *Union, field *Field) { + fieldType := fieldGoType(g, field) + constructorName := union.GoName + field.GoName // Constructor - g.P("func ", structName, field.GoName, "(a ", getterStruct, ") (u ", structName, ") {") + g.P("func ", constructorName, "(a ", fieldType, ") (u ", union.GoName, ") {") g.P(" u.Set", field.GoName, "(a)") g.P(" return") g.P("}") // Setter - g.P("func (u *", structName, ") Set", field.GoName, "(a ", getterStruct, ") {") + g.P("func (u *", union.GoName, ") Set", field.GoName, "(a ", fieldType, ") {") g.P(" buf := ", govppCodecPkg.Ident("NewBuffer"), "(u.", fieldUnionData, "[:])") encodeField(g, field, "a", func(name string) string { return "a." + name @@ -320,16 +355,24 @@ func genUnionFieldMethods(g *GenFile, structName string, field *Field) { g.P("}") // Getter - g.P("func (u *", structName, ") Get", field.GoName, "() (a ", getterStruct, ") {") + g.P("func (u *", union.GoName, ") Get", field.GoName, "() (a ", fieldType, ") {") g.P(" buf := ", govppCodecPkg.Ident("NewBuffer"), "(u.", fieldUnionData, "[:])") decodeField(g, field, "a", func(name string) string { return "a." + name }, 0) g.P(" return") g.P("}") + g.P() } +func withSuffix(s string, suffix string) string { + if strings.HasSuffix(s, suffix) { + return s + } + return s + suffix +} + func genField(g *GenFile, fields []*Field, i int) { field := fields[i] @@ -438,6 +481,7 @@ func genMessage(g *GenFile, msg *Message) { logf("gen MESSAGE %s (%s) - %d fields", msg.GoName, msg.Name, len(msg.Fields)) genTypeComment(g, msg.GoIdent.GoName, msg.Name, "message") + genTypeOptionComment(g, msg.Options) // generate message definition if len(msg.Fields) == 0 { diff --git a/binapigen/generate_test.go b/binapigen/generate_test.go index 2fa5dc6..2a94636 100644 --- a/binapigen/generate_test.go +++ b/binapigen/generate_test.go @@ -20,8 +20,8 @@ import ( . "github.com/onsi/gomega" - "git.fd.io/govpp.git/binapi/ip_types" - "git.fd.io/govpp.git/binapigen/vppapi" + "go.fd.io/govpp/binapi/ip_types" + "go.fd.io/govpp/binapigen/vppapi" ) const testOutputDir = "test_output_dir" @@ -47,7 +47,7 @@ func GenerateFromFile(file string, opts Options) error { return nil } -func TestGenerateFromFile(t *testing.T) { +func TestGenerateFromFileACL(t *testing.T) { RegisterTestingT(t) // remove directory created during test @@ -62,6 +62,21 @@ func TestGenerateFromFile(t *testing.T) { Expect(fileInfo.Name()).To(BeEquivalentTo("acl.ba.go")) } +func TestGenerateFromFileIP(t *testing.T) { + RegisterTestingT(t) + + // remove directory created during test + defer os.RemoveAll(testOutputDir) + + opts := Options{OutputDir: testOutputDir} + err := GenerateFromFile("vppapi/testdata/ip.api.json", opts) + Expect(err).ShouldNot(HaveOccurred()) + fileInfo, err := os.Stat(testOutputDir + "/ip/ip.ba.go") + Expect(err).ShouldNot(HaveOccurred()) + Expect(fileInfo.IsDir()).To(BeFalse()) + Expect(fileInfo.Name()).To(BeEquivalentTo("ip.ba.go")) +} + func TestGenerateFromFileInputError(t *testing.T) { RegisterTestingT(t) diff --git a/binapigen/generator.go b/binapigen/generator.go index ce0954a..009c0ec 100644 --- a/binapigen/generator.go +++ b/binapigen/generator.go @@ -32,12 +32,13 @@ import ( "github.com/sirupsen/logrus" - "git.fd.io/govpp.git/binapigen/vppapi" + "go.fd.io/govpp/binapigen/vppapi" ) type Generator struct { Files []*File FilesByName map[string]*File + FilesByPath map[string]*File opts Options apifiles []*vppapi.File @@ -53,11 +54,12 @@ type Generator struct { messagesByName map[string]*Message } -func New(opts Options, apifiles []*vppapi.File, filesToGen []string) (*Generator, error) { +func New(opts Options, apiFiles []*vppapi.File, filesToGen []string) (*Generator, error) { gen := &Generator{ FilesByName: make(map[string]*File), + FilesByPath: make(map[string]*File), opts: opts, - apifiles: apifiles, + apifiles: apiFiles, filesToGen: filesToGen, enumsByName: map[string]*Enum{}, aliasesByName: map[string]*Alias{}, @@ -68,9 +70,9 @@ func New(opts Options, apifiles []*vppapi.File, filesToGen []string) (*Generator // Normalize API files SortFilesByImports(gen.apifiles) - for _, apifile := range apifiles { - RemoveImportedTypes(gen.apifiles, apifile) - SortFileObjectsByName(apifile) + for _, apiFile := range apiFiles { + RemoveImportedTypes(gen.apifiles, apiFile) + SortFileObjectsByName(apiFile) } // prepare package names and import paths @@ -96,6 +98,7 @@ func New(opts Options, apifiles []*vppapi.File, filesToGen []string) (*Generator } gen.Files = append(gen.Files, file) gen.FilesByName[apifile.Name] = file + gen.FilesByPath[apifile.Path] = file logrus.Debugf("added file %q (path: %v)", apifile.Name, apifile.Path) } @@ -103,16 +106,24 @@ func New(opts Options, apifiles []*vppapi.File, filesToGen []string) (*Generator // mark files for generation if len(gen.filesToGen) > 0 { logrus.Debugf("Checking %d files to generate: %v", len(gen.filesToGen), gen.filesToGen) - for _, genfile := range gen.filesToGen { - file, ok := gen.FilesByName[genfile] - if !ok { - return nil, fmt.Errorf("nol API file found for: %v", genfile) + for _, genFile := range gen.filesToGen { + markGen := func(file *File) { + file.Generate = true + // generate all imported files + for _, impFile := range file.importedFiles(gen) { + impFile.Generate = true + } } - file.Generate = true - // generate all imported files - for _, impFile := range file.importedFiles(gen) { - impFile.Generate = true + if file, ok := gen.FilesByName[genFile]; ok { + markGen(file) + continue + } + logrus.Debugf("File %s was not found by name", genFile) + if file, ok := gen.FilesByPath[genFile]; ok { + markGen(file) + continue } + return nil, fmt.Errorf("no API file found for: %v", genFile) } } else { logrus.Debugf("Files to generate not specified, marking all %d files for generate", len(gen.Files)) @@ -212,6 +223,13 @@ func (g *GenFile) Content() ([]byte, error) { return g.injectImports(g.buf.Bytes()) } +func getImportClass(importPath string) int { + if !strings.Contains(importPath, ".") { + return 0 /* std */ + } + return 1 /* External */ +} + // injectImports parses source, injects import block declaration with all imports and return formatted func (g *GenFile) injectImports(original []byte) ([]byte, error) { // Parse source code @@ -233,7 +251,7 @@ func (g *GenFile) injectImports(original []byte) ([]byte, error) { var importPaths []Import for importPath := range g.packageNames { importPaths = append(importPaths, Import{ - Name: string(g.packageNames[GoImportPath(importPath)]), + Name: string(g.packageNames[importPath]), Path: string(importPath), }) } @@ -248,7 +266,12 @@ func (g *GenFile) injectImports(original []byte) ([]byte, error) { } // Sort imports by import path sort.Slice(importPaths, func(i, j int) bool { - return importPaths[i].Path < importPaths[j].Path + ci := getImportClass(importPaths[i].Path) + cj := getImportClass(importPaths[j].Path) + if ci == cj { + return importPaths[i].Path < importPaths[j].Path + } + return ci < cj }) // Inject new import block into parsed AST if len(importPaths) > 0 { @@ -264,14 +287,20 @@ func (g *GenFile) injectImports(original []byte) ([]byte, error) { } // Prepare the import block impDecl := &ast.GenDecl{Tok: token.IMPORT, TokPos: pos, Lparen: pos, Rparen: pos} - for _, importPath := range importPaths { + for i, importPath := range importPaths { var name *ast.Ident if importPath.Name == "_" || strings.Contains(importPath.Path, ".") { name = &ast.Ident{Name: importPath.Name, NamePos: pos} } + value := strconv.Quote(importPath.Path) + if i < len(importPaths)-1 { + if getImportClass(importPath.Path) != getImportClass(importPaths[i+1].Path) { + value += "\n" + } + } impDecl.Specs = append(impDecl.Specs, &ast.ImportSpec{ Name: name, - Path: &ast.BasicLit{Kind: token.STRING, Value: strconv.Quote(importPath.Path), ValuePos: pos}, + Path: &ast.BasicLit{Kind: token.STRING, Value: value, ValuePos: pos}, EndPos: pos, }) } diff --git a/binapigen/generator_test.go b/binapigen/generator_test.go index 1dfaca4..8c2046d 100644 --- a/binapigen/generator_test.go +++ b/binapigen/generator_test.go @@ -15,11 +15,17 @@ package binapigen import ( + "bufio" + "fmt" + "go.fd.io/govpp/binapigen/vppapi" + . "github.com/onsi/gomega" + "os" + "strings" "testing" ) func TestGoModule(t *testing.T) { - const expected = "git.fd.io/govpp.git/binapi" + const expected = "go.fd.io/govpp/binapi" impPath, err := resolveImportPath("../binapi") if err != nil { @@ -45,10 +51,94 @@ func TestBinapiTypeSizes(t *testing.T) { } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - size := getSizeOfBinapiTypeLength(test.input, 1) + size := getSizeOfBinapiBaseType(test.input, 1) if size != test.expsize { t.Errorf("expected %d, got %d", test.expsize, size) } }) } } + +func TestBinapiUnionSizes(t *testing.T) { + RegisterTestingT(t) + + // order of the union sizes in file generated from union.api.json + var sizes = []int{16, 4, 32, 16, 64, 111} + + // remove directory created during test + defer func() { + err := os.RemoveAll(testOutputDir) + Expect(err).ToNot(HaveOccurred()) + }() + + err := GenerateFromFile("vppapi/testdata/union.api.json", Options{OutputDir: testOutputDir}) + Expect(err).ShouldNot(HaveOccurred()) + + file, err := os.Open(testOutputDir + "/union/union.ba.go") + Expect(err).ShouldNot(HaveOccurred()) + defer func() { + err := file.Close() + Expect(err).ToNot(HaveOccurred()) + }() + + // the generated line with union size is in format XXX_UnionData [<size>]byte + // the prefix identifies these lines (the starting tab is important) + prefix := fmt.Sprintf("\t%s", "XXX_UnionData [") + + index := 0 + scanner := bufio.NewScanner(file) + for scanner.Scan() { + if strings.HasPrefix(scanner.Text(), prefix) { + Expect(scanner.Text()).To(Equal(prefix + fmt.Sprintf("%d]byte", sizes[index]))) + index++ + } + } + // ensure all union sizes were found and tested + Expect(index).To(Equal(len(sizes))) +} + +// Typed data used for union size evaluation testing. +type typeTestData struct { + typ string + value string + fields []*typeTestData +} + +func (t typeTestData) getUnion(name string) *Union { + return &Union{ + UnionType: vppapi.UnionType{Name: name}, + Fields: t.getUnionFields(name), + } +} + +func (t typeTestData) getUnionFields(parentName string) (fields []*Field) { + for i, field := range t.fields { + var ( + dataType string + aliasType *Alias + enumType *Enum + structType *Struct + unionType *Union + ) + switch field.typ { + case "alias": + aliasType = &Alias{AliasType: vppapi.AliasType{Name: fmt.Sprintf("%s_alias_%d", parentName, i), Type: field.value}} + case "enum": + enumType = &Enum{EnumType: vppapi.EnumType{Name: fmt.Sprintf("%s_enum_%d", parentName, i), Type: field.value}} + case "struct": + structType = &Struct{Fields: field.getUnionFields(fmt.Sprintf("%s_struct_%d", parentName, i))} + case "union": + unionType = field.getUnion(parentName) + default: + dataType = field.value + } + fields = append(fields, &Field{ + Field: vppapi.Field{Name: fmt.Sprintf("%s_field_%d", parentName, i), Type: dataType}, + TypeAlias: aliasType, + TypeEnum: enumType, + TypeStruct: structType, + TypeUnion: unionType, + }) + } + return fields +} diff --git a/binapigen/run.go b/binapigen/run.go index d3a181a..5a1059a 100644 --- a/binapigen/run.go +++ b/binapigen/run.go @@ -25,13 +25,14 @@ import ( "github.com/sirupsen/logrus" - "git.fd.io/govpp.git/binapigen/vppapi" + "go.fd.io/govpp/binapigen/vppapi" ) type Options struct { - OutputDir string // output directory for generated files - ImportPrefix string // prefix for import paths - NoVersionInfo bool // disables generating version info + OutputDir string // output directory for generated files + ImportPrefix string // prefix for import paths + NoVersionInfo bool // disables generating version info + NoSourcePathInfo bool // disables the 'source: /path' comment } func Run(apiDir string, filesToGenerate []string, opts Options, f func(*Generator) error) { @@ -42,7 +43,7 @@ func Run(apiDir string, filesToGenerate []string, opts Options, f func(*Generato } func run(apiDir string, filesToGenerate []string, opts Options, fn func(*Generator) error) error { - apifiles, err := vppapi.ParseDir(apiDir) + apiFiles, err := vppapi.ParseDir(apiDir) if err != nil { return err } @@ -52,10 +53,10 @@ func run(apiDir string, filesToGenerate []string, opts Options, fn func(*Generat if err != nil { return fmt.Errorf("cannot resolve import path for output dir %s: %w", opts.OutputDir, err) } - logrus.Infof("resolved import path prefix: %s", opts.ImportPrefix) + logrus.Debugf("resolved import path prefix: %s", opts.ImportPrefix) } - gen, err := New(opts, apifiles, filesToGenerate) + gen, err := New(opts, apiFiles, filesToGenerate) if err != nil { return err } @@ -72,7 +73,6 @@ func run(apiDir string, filesToGenerate []string, opts Options, fn func(*Generat return err } } - if err = gen.Generate(); err != nil { return err } diff --git a/binapigen/types.go b/binapigen/types.go index 1d0dae5..addb122 100644 --- a/binapigen/types.go +++ b/binapigen/types.go @@ -128,45 +128,59 @@ func getFieldType(g *GenFile, field *Field) string { return gotype } -func getSizeOfBinapiTypeLength(typ string, length int) (size int) { - if n := BaseTypeSizes[typ]; n > 0 { - if length > 0 { - return n * length - } else { - return n +func getUnionSize(union *Union) (maxSize int) { + for _, field := range union.Fields { + if size, isBaseType := getSizeOfField(field); isBaseType { + logrus.Panicf("union %s field %s has unexpected type %q", union.Name, field.Name, field.Type) + } else if size > maxSize { + maxSize = size } } + //logf("getUnionSize: %s %+v max=%v", union.Name, union.Fields, maxSize) return } -func getSizeOfType(typ *Struct) (size int) { +func getSizeOfField(field *Field) (size int, isBaseType bool) { + if alias := field.TypeAlias; alias != nil { + size = getSizeOfBinapiBaseType(alias.Type, alias.Length) + return + } + if enum := field.TypeEnum; enum != nil { + size = getSizeOfBinapiBaseType(enum.Type, field.Length) + return + } + if structType := field.TypeStruct; structType != nil { + size = getSizeOfStruct(structType) + return + } + if union := field.TypeUnion; union != nil { + size = getUnionSize(union) + return + } + return size, true +} + +func getSizeOfStruct(typ *Struct) (size int) { for _, field := range typ.Fields { - if enum := field.TypeEnum; enum != nil { - size += getSizeOfBinapiTypeLength(enum.Type, field.Length) + fieldSize, isBaseType := getSizeOfField(field) + if isBaseType { + size += getSizeOfBinapiBaseType(field.Type, field.Length) continue } - size += getSizeOfBinapiTypeLength(field.Type, field.Length) + size += fieldSize } return size } -func getUnionSize(union *Union) (maxSize int) { - for _, field := range union.Fields { - if typ := field.TypeStruct; typ != nil { - if size := getSizeOfType(typ); size > maxSize { - maxSize = size - } - continue - } - if alias := field.TypeAlias; alias != nil { - if size := getSizeOfBinapiTypeLength(alias.Type, alias.Length); size > maxSize { - maxSize = size - } - continue +// Returns size of base type multiplied by length. Length equal to zero +// returns base type size. +func getSizeOfBinapiBaseType(typ string, length int) (size int) { + if n := BaseTypeSizes[typ]; n > 0 { + if length > 1 { + return n * length } else { - logrus.Panicf("no type or alias found for union %s field type %q", union.Name, field.Type) + return n } } - //logf("getUnionSize: %s %+v max=%v", union.Name, union.Fields, maxSize) return } diff --git a/binapigen/vppapi.go b/binapigen/vppapi.go index 7388ad5..5e2db28 100644 --- a/binapigen/vppapi.go +++ b/binapigen/vppapi.go @@ -18,7 +18,7 @@ import ( "log" "sort" - "git.fd.io/govpp.git/binapigen/vppapi" + "go.fd.io/govpp/binapigen/vppapi" ) func SortFileObjectsByName(file *vppapi.File) { @@ -28,6 +28,9 @@ func SortFileObjectsByName(file *vppapi.File) { sort.SliceStable(file.EnumTypes, func(i, j int) bool { return file.EnumTypes[i].Name < file.EnumTypes[j].Name }) + sort.SliceStable(file.EnumflagTypes, func(i, j int) bool { + return file.EnumflagTypes[i].Name < file.EnumflagTypes[j].Name + }) sort.Slice(file.AliasTypes, func(i, j int) bool { return file.AliasTypes[i].Name < file.AliasTypes[j].Name }) @@ -151,6 +154,22 @@ func ListImportedTypes(apifiles []*vppapi.File, file *vppapi.File) []string { } } } + for _, t := range file.EnumflagTypes { + var imported bool + for _, imp := range typeFiles { + for _, at := range imp.EnumflagTypes { + if at.Name != t.Name { + continue + } + importedTypes = append(importedTypes, t.Name) + imported = true + break + } + if imported { + break + } + } + } for _, t := range file.UnionTypes { var imported bool for _, imp := range typeFiles { @@ -186,6 +205,12 @@ func RemoveImportedTypes(apifiles []*vppapi.File, apifile *vppapi.File) { enums = append(enums, enumType) } } + var enumflags []vppapi.EnumType + for _, enumflagType := range apifile.EnumflagTypes { + if !isImportedType(enumflagType.Name) { + enumflags = append(enumflags, enumflagType) + } + } var aliases []vppapi.AliasType for _, aliasType := range apifile.AliasTypes { if !isImportedType(aliasType.Name) { @@ -205,6 +230,7 @@ func RemoveImportedTypes(apifiles []*vppapi.File, apifile *vppapi.File) { } } apifile.EnumTypes = enums + apifile.EnumflagTypes = enumflags apifile.AliasTypes = aliases apifile.StructTypes = structs apifile.UnionTypes = unions diff --git a/binapigen/vppapi/api_schema.go b/binapigen/vppapi/api_schema.go index 7eceab3..4dd0ac9 100644 --- a/binapigen/vppapi/api_schema.go +++ b/binapigen/vppapi/api_schema.go @@ -24,10 +24,11 @@ type ( Options map[string]string `json:",omitempty"` Imports []string `json:",omitempty"` - AliasTypes []AliasType `json:",omitempty"` - EnumTypes []EnumType `json:",omitempty"` - StructTypes []StructType `json:",omitempty"` - UnionTypes []UnionType `json:",omitempty"` + AliasTypes []AliasType `json:",omitempty"` + EnumTypes []EnumType `json:",omitempty"` + EnumflagTypes []EnumType `json:",omitempty"` + StructTypes []StructType `json:",omitempty"` + UnionTypes []UnionType `json:",omitempty"` Messages []Message `json:",omitempty"` Service *Service `json:",omitempty"` @@ -61,9 +62,10 @@ type ( } Message struct { - Name string - Fields []Field - CRC string + Name string + Fields []Field + CRC string + Options map[string]string } Field struct { diff --git a/binapigen/vppapi/integration_test.go b/binapigen/vppapi/integration_test.go index 9d619b8..c3df45c 100644 --- a/binapigen/vppapi/integration_test.go +++ b/binapigen/vppapi/integration_test.go @@ -20,7 +20,7 @@ import ( "encoding/json" "testing" - "git.fd.io/govpp.git/binapigen/vppapi" + "go.fd.io/govpp/binapigen/vppapi" ) func TestParse(t *testing.T) { diff --git a/binapigen/vppapi/parse_json.go b/binapigen/vppapi/parse_json.go index d14865c..ed7bcad 100644 --- a/binapigen/vppapi/parse_json.go +++ b/binapigen/vppapi/parse_json.go @@ -41,14 +41,16 @@ const ( fileMessages = "messages" fileUnions = "unions" fileEnums = "enums" + fileEnumflags = "enumflags" fileAliases = "aliases" fileServices = "services" fileImports = "imports" // type keys - messageCrc = "crc" - enumType = "enumtype" - aliasLength = "length" - aliasType = "type" + messageCrc = "crc" + messageOptions = "options" + enumType = "enumtype" + aliasLength = "length" + aliasType = "type" // service serviceReply = "reply" serviceStream = "stream" @@ -129,6 +131,20 @@ func parseJSON(data []byte) (module *File, err error) { module.EnumTypes = append(module.EnumTypes, *enum) } + // parse enumflags types + enumflagsNode := jsonRoot.Map(fileEnumflags) + module.EnumflagTypes = make([]EnumType, 0) + for i := 0; i < enumflagsNode.Len(); i++ { + enumflag, err := parseEnum(enumflagsNode.At(i)) + if err != nil { + return nil, err + } + if exists(enumflag.Name) { + continue + } + module.EnumflagTypes = append(module.EnumflagTypes, *enumflag) + } + // parse alias types aliasesNode := jsonRoot.Map(fileAliases) if aliasesNode.GetType() == jsongo.TypeMap { @@ -360,10 +376,30 @@ func parseMessage(msgNode *jsongo.Node) (*Message, error) { if !ok { return nil, fmt.Errorf("message crc invalid or missing") } + var msgOpts map[string]string + msgOptsNode := msgNode.At(msgNode.Len() - 1).Map(messageOptions) + if msgOptsNode.GetType() == jsongo.TypeMap { + msgOpts = make(map[string]string) + for _, opt := range msgOptsNode.GetKeys() { + if _, ok := opt.(string); !ok { + logf("invalid message option key, expected string") + continue + } + msgOpts[opt.(string)] = "" + if msgOptsNode.At(opt).Get() != nil { + if optMsgStr, ok := msgOptsNode.At(opt).Get().(string); ok { + msgOpts[opt.(string)] = optMsgStr + } else { + logf("invalid message option value, expected string") + } + } + } + } msg := Message{ - Name: msgName, - CRC: msgCRC, + Name: msgName, + CRC: msgCRC, + Options: msgOpts, } // loop through message fields, skip first (name) and last (crc) diff --git a/binapigen/vppapi/testdata/ip.api.json b/binapigen/vppapi/testdata/ip.api.json index 530b6d6..32be996 100644 --- a/binapigen/vppapi/testdata/ip.api.json +++ b/binapigen/vppapi/testdata/ip.api.json @@ -1,633 +1,594 @@ { - "services": [ - { - "ip_source_and_port_range_check_add_del": { - "reply": "ip_source_and_port_range_check_add_del_reply" - } - }, - { - "ip6_fib_dump": { - "reply": "ip6_fib_details", - "stream": true - } - }, - { - "want_ip6_nd_events": { - "reply": "want_ip6_nd_events_reply" - } - }, - { - "ip_punt_police": { - "reply": "ip_punt_police_reply" - } - }, - { - "set_arp_neighbor_limit": { - "reply": "set_arp_neighbor_limit_reply" - } - }, - { - "ip6nd_proxy_add_del": { - "reply": "ip6nd_proxy_add_del_reply" - } - }, - { - "ioam_disable": { - "reply": "ioam_disable_reply" - } - }, - { - "ip_table_add_del": { - "reply": "ip_table_add_del_reply" - } - }, - { - "ip_neighbor_dump": { - "reply": "ip_neighbor_details", - "stream": true - } - }, - { - "ip4_arp_event": { - "reply": null - } - }, - { - "ip_punt_redirect": { - "reply": "ip_punt_redirect_reply" - } - }, - { - "sw_interface_ip6nd_ra_prefix": { - "reply": "sw_interface_ip6nd_ra_prefix_reply" - } - }, - { - "reset_fib": { - "reply": "reset_fib_reply" - } - }, - { - "ip6_mfib_dump": { - "reply": "ip6_mfib_details", - "stream": true - } - }, - { - "sw_interface_ip6nd_ra_config": { - "reply": "sw_interface_ip6nd_ra_config_reply" - } - }, - { - "sw_interface_ip6_enable_disable": { - "reply": "sw_interface_ip6_enable_disable_reply" - } - }, - { - "sw_interface_ip6_set_link_local_address": { - "reply": "sw_interface_ip6_set_link_local_address_reply" - } - }, - { - "mfib_signal_dump": { - "reply": "mfib_signal_details", - "stream": true - } - }, - { - "ip_container_proxy_add_del": { - "reply": "ip_container_proxy_add_del_reply" - } - }, - { - "ip_mfib_dump": { - "reply": "ip_mfib_details", - "stream": true - } - }, - { - "ip_address_dump": { - "reply": "ip_address_details", - "stream": true - } - }, - { - "ip_dump": { - "reply": "ip_details", - "stream": true - } - }, - { - "ip_neighbor_add_del": { - "reply": "ip_neighbor_add_del_reply" - } - }, - { - "proxy_arp_intfc_enable_disable": { - "reply": "proxy_arp_intfc_enable_disable_reply" - } - }, - { - "proxy_arp_add_del": { - "reply": "proxy_arp_add_del_reply" - } - }, - { - "ip_add_del_route": { - "reply": "ip_add_del_route_reply" - } - }, - { - "ip6nd_proxy_dump": { - "reply": "ip6nd_proxy_details", - "stream": true - } - }, - { - "ip_fib_dump": { - "reply": "ip_fib_details", - "stream": true - } - }, - { - "want_ip4_arp_events": { - "reply": "want_ip4_arp_events_reply" - } - }, - { - "ioam_enable": { - "reply": "ioam_enable_reply" - } - }, - { - "ip6_nd_event": { - "reply": null - } - }, - { - "ip_mroute_add_del": { - "reply": "ip_mroute_add_del_reply" - } - }, - { - "ip_source_and_port_range_check_interface_add_del": { - "reply": "ip_source_and_port_range_check_interface_add_del_reply" - } - }, - { - "set_ip_flow_hash": { - "reply": "set_ip_flow_hash_reply" - } - } - ], - "vl_api_version": "0xb395c625", - "enums": [], - "messages": [ + "types": [ [ - "ip_table_add_del", + "address", [ - "u16", - "_vl_msg_id" + "vl_api_address_family_t", + "af" ], [ - "u32", - "client_index" - ], - [ - "u32", - "context" - ], + "vl_api_address_union_t", + "un" + ] + ], + [ + "prefix", [ - "u32", - "table_id" + "vl_api_address_t", + "address" ], [ "u8", - "is_ipv6" - ], + "len" + ] + ], + [ + "ip4_address_and_mask", [ - "u8", - "is_add" + "vl_api_ip4_address_t", + "addr" ], [ - "u8", - "name", - 64 - ], - { - "crc": "0x0240c89d" - } + "vl_api_ip4_address_t", + "mask" + ] ], [ - "ip_table_add_del_reply", + "ip6_address_and_mask", [ - "u16", - "_vl_msg_id" + "vl_api_ip6_address_t", + "addr" ], [ - "u32", - "context" - ], - [ - "i32", - "retval" - ], - { - "crc": "0xe8d4e804" - } + "vl_api_ip6_address_t", + "mask" + ] ], [ - "ip_fib_dump", + "mprefix", [ - "u16", - "_vl_msg_id" + "vl_api_address_family_t", + "af" ], [ - "u32", - "client_index" + "u16", + "grp_address_length" ], [ - "u32", - "context" + "vl_api_address_union_t", + "grp_address" ], - { - "crc": "0x51077d14" - } + [ + "vl_api_address_union_t", + "src_address" + ] ], [ - "ip_fib_details", + "ip6_prefix", [ - "u16", - "_vl_msg_id" + "vl_api_ip6_address_t", + "address" ], [ - "u32", - "context" - ], + "u8", + "len" + ] + ], + [ + "ip4_prefix", [ - "u32", - "table_id" + "vl_api_ip4_address_t", + "address" ], [ "u8", - "table_name", - 64 - ], + "len" + ] + ], + [ + "prefix_matcher", [ "u8", - "address_length" + "le" ], [ "u8", - "address", - 4 + "ge" + ] + ], + [ + "fib_mpls_label", + [ + "u8", + "is_uniform" ], [ "u32", - "count" + "label" ], [ - "vl_api_fib_path_t", - "path", - 0, - "count" + "u8", + "ttl" ], - { - "crc": "0x99dfd73b" - } + [ + "u8", + "exp" + ] ], [ - "ip6_fib_dump", + "fib_path_nh", [ - "u16", - "_vl_msg_id" + "vl_api_address_union_t", + "address" ], [ "u32", - "client_index" + "via_label" ], [ "u32", - "context" + "obj_id" ], - { - "crc": "0x51077d14" - } + [ + "u32", + "classify_table_index" + ] ], [ - "ip6_fib_details", + "fib_path", [ - "u16", - "_vl_msg_id" + "u32", + "sw_if_index" ], [ "u32", - "context" + "table_id" ], [ "u32", - "table_id" + "rpf_id" ], [ "u8", - "table_name", - 64 + "weight" ], [ "u8", - "address_length" + "preference" ], [ - "u8", - "address", - 16 + "vl_api_fib_path_type_t", + "type" ], [ - "u32", - "count" + "vl_api_fib_path_flags_t", + "flags" ], [ - "vl_api_fib_path_t", - "path", - 0, - "count" + "vl_api_fib_path_nh_proto_t", + "proto" ], - { - "crc": "0xabd0060e" - } - ], - [ - "ip_neighbor_dump", [ - "u16", - "_vl_msg_id" + "vl_api_fib_path_nh_t", + "nh" ], [ - "u32", - "client_index" + "u8", + "n_labels" ], [ - "u32", - "context" + "vl_api_fib_mpls_label_t", + "label_stack", + 16 + ] + ], + [ + "address", + [ + "vl_api_address_family_t", + "af" ], [ - "u32", - "sw_if_index" + "vl_api_address_union_t", + "un" + ] + ], + [ + "prefix", + [ + "vl_api_address_t", + "address" ], [ "u8", - "is_ipv6" + "len" + ] + ], + [ + "ip4_address_and_mask", + [ + "vl_api_ip4_address_t", + "addr" ], - { - "crc": "0x6b7bcd0a" - } + [ + "vl_api_ip4_address_t", + "mask" + ] ], [ - "ip_neighbor_details", + "ip6_address_and_mask", + [ + "vl_api_ip6_address_t", + "addr" + ], + [ + "vl_api_ip6_address_t", + "mask" + ] + ], + [ + "mprefix", + [ + "vl_api_address_family_t", + "af" + ], [ "u16", - "_vl_msg_id" + "grp_address_length" ], [ - "u32", - "context" + "vl_api_address_union_t", + "grp_address" ], [ - "u32", - "sw_if_index" + "vl_api_address_union_t", + "src_address" + ] + ], + [ + "ip6_prefix", + [ + "vl_api_ip6_address_t", + "address" ], [ "u8", - "is_static" + "len" + ] + ], + [ + "ip4_prefix", + [ + "vl_api_ip4_address_t", + "address" ], [ "u8", - "is_ipv6" + "len" + ] + ], + [ + "prefix_matcher", + [ + "u8", + "le" ], [ "u8", - "mac_address", - 6 + "ge" + ] + ], + [ + "fib_mpls_label", + [ + "u8", + "is_uniform" + ], + [ + "u32", + "label" ], [ "u8", - "ip_address", - 16 + "ttl" ], - { - "crc": "0x85e32a72" - } + [ + "u8", + "exp" + ] ], [ - "ip_neighbor_add_del", + "fib_path_nh", [ - "u16", - "_vl_msg_id" + "vl_api_address_union_t", + "address" ], [ "u32", - "client_index" + "via_label" ], [ "u32", - "context" + "obj_id" ], [ "u32", + "classify_table_index" + ] + ], + [ + "fib_path", + [ + "u32", "sw_if_index" ], [ - "u8", - "is_add" + "u32", + "table_id" ], [ - "u8", - "is_ipv6" + "u32", + "rpf_id" ], [ "u8", - "is_static" + "weight" ], [ "u8", - "is_no_adj_fib" + "preference" ], [ - "u8", - "mac_address", - 6 + "vl_api_fib_path_type_t", + "type" + ], + [ + "vl_api_fib_path_flags_t", + "flags" + ], + [ + "vl_api_fib_path_nh_proto_t", + "proto" + ], + [ + "vl_api_fib_path_nh_t", + "nh" ], [ "u8", - "dst_address", - 16 + "n_labels" ], - { - "crc": "0x4711eb25" - } + [ + "vl_api_fib_mpls_label_t", + "label_stack", + 16 + ] ], [ - "ip_neighbor_add_del_reply", + "address", [ - "u16", - "_vl_msg_id" + "vl_api_address_family_t", + "af" ], [ - "u32", - "context" - ], + "vl_api_address_union_t", + "un" + ] + ], + [ + "prefix", [ - "i32", - "retval" + "vl_api_address_t", + "address" ], - { - "crc": "0xe8d4e804" - } + [ + "u8", + "len" + ] ], [ - "set_ip_flow_hash", + "ip4_address_and_mask", [ - "u16", - "_vl_msg_id" + "vl_api_ip4_address_t", + "addr" ], [ - "u32", - "client_index" - ], + "vl_api_ip4_address_t", + "mask" + ] + ], + [ + "ip6_address_and_mask", [ - "u32", - "context" + "vl_api_ip6_address_t", + "addr" ], [ - "u32", - "vrf_id" + "vl_api_ip6_address_t", + "mask" + ] + ], + [ + "mprefix", + [ + "vl_api_address_family_t", + "af" ], [ - "u8", - "is_ipv6" + "u16", + "grp_address_length" ], [ - "u8", - "src" + "vl_api_address_union_t", + "grp_address" ], [ - "u8", - "dst" + "vl_api_address_union_t", + "src_address" + ] + ], + [ + "ip6_prefix", + [ + "vl_api_ip6_address_t", + "address" ], [ "u8", - "sport" + "len" + ] + ], + [ + "ip4_prefix", + [ + "vl_api_ip4_address_t", + "address" ], [ "u8", - "dport" - ], + "len" + ] + ], + [ + "prefix_matcher", [ "u8", - "proto" + "le" ], [ "u8", - "reverse" - ], - { - "crc": "0x32ebf737" - } + "ge" + ] ], [ - "set_ip_flow_hash_reply", + "mfib_path", [ - "u16", - "_vl_msg_id" + "vl_api_mfib_itf_flags_t", + "itf_flags" ], [ + "vl_api_fib_path_t", + "path" + ] + ], + [ + "ip_table", + [ "u32", - "context" + "table_id" ], [ - "i32", - "retval" + "bool", + "is_ip6" ], - { - "crc": "0xe8d4e804" - } + [ + "string", + "name", + 64 + ] ], [ - "sw_interface_ip6nd_ra_config", - [ - "u16", - "_vl_msg_id" - ], + "ip_route", [ "u32", - "client_index" + "table_id" ], [ "u32", - "context" + "stats_index" ], [ - "u32", - "sw_if_index" + "vl_api_prefix_t", + "prefix" ], [ "u8", - "suppress" + "n_paths" ], [ - "u8", - "managed" + "vl_api_fib_path_t", + "paths", + 0, + "n_paths" + ] + ], + [ + "ip_mroute", + [ + "u32", + "table_id" ], [ - "u8", - "other" + "vl_api_mfib_entry_flags_t", + "entry_flags" ], [ - "u8", - "ll_option" + "u32", + "rpf_id" ], [ - "u8", - "send_unicast" + "vl_api_mprefix_t", + "prefix" ], [ "u8", - "cease" + "n_paths" ], [ - "u8", - "is_no" + "vl_api_mfib_path_t", + "paths", + 0, + "n_paths" + ] + ], + [ + "punt_redirect", + [ + "vl_api_interface_index_t", + "rx_sw_if_index" ], [ - "u8", - "default_router" + "vl_api_interface_index_t", + "tx_sw_if_index" ], [ - "u32", - "max_interval" + "vl_api_address_t", + "nh" + ] + ] + ], + "messages": [ + [ + "ip_table_add_del", + [ + "u16", + "_vl_msg_id" ], [ "u32", - "min_interval" + "client_index" ], [ "u32", - "lifetime" + "context" ], [ - "u32", - "initial_count" + "bool", + "is_add", + { + "default": "true" + } ], [ - "u32", - "initial_interval" + "vl_api_ip_table_t", + "table" ], { - "crc": "0xc3f02daa" + "crc": "0x0ffdaec0" } ], [ - "sw_interface_ip6nd_ra_config_reply", + "ip_table_add_del_reply", [ "u16", "_vl_msg_id" @@ -645,7 +606,7 @@ } ], [ - "sw_interface_ip6nd_ra_prefix", + "ip_table_dump", [ "u16", "_vl_msg_id" @@ -658,57 +619,34 @@ "u32", "context" ], + { + "crc": "0x51077d14" + } + ], + [ + "ip_table_replace_begin", [ - "u32", - "sw_if_index" - ], - [ - "u8", - "address", - 16 - ], - [ - "u8", - "address_length" - ], - [ - "u8", - "use_default" - ], - [ - "u8", - "no_advertise" - ], - [ - "u8", - "off_link" - ], - [ - "u8", - "no_autoconfig" - ], - [ - "u8", - "no_onlink" + "u16", + "_vl_msg_id" ], [ - "u8", - "is_no" + "u32", + "client_index" ], [ "u32", - "val_lifetime" + "context" ], [ - "u32", - "pref_lifetime" + "vl_api_ip_table_t", + "table" ], { - "crc": "0xca763c9a" + "crc": "0xb9d2e09e" } ], [ - "sw_interface_ip6nd_ra_prefix_reply", + "ip_table_replace_begin_reply", [ "u16", "_vl_msg_id" @@ -726,7 +664,7 @@ } ], [ - "ip6nd_proxy_add_del", + "ip_table_replace_end", [ "u16", "_vl_msg_id" @@ -740,24 +678,15 @@ "context" ], [ - "u32", - "sw_if_index" - ], - [ - "u8", - "is_del" - ], - [ - "u8", - "address", - 16 + "vl_api_ip_table_t", + "table" ], { - "crc": "0xd95f0fa0" + "crc": "0xb9d2e09e" } ], [ - "ip6nd_proxy_add_del_reply", + "ip_table_replace_end_reply", [ "u16", "_vl_msg_id" @@ -775,7 +704,7 @@ } ], [ - "ip6nd_proxy_details", + "ip_table_flush", [ "u16", "_vl_msg_id" @@ -789,38 +718,51 @@ "context" ], [ + "vl_api_ip_table_t", + "table" + ], + { + "crc": "0xb9d2e09e" + } + ], + [ + "ip_table_flush_reply", + [ + "u16", + "_vl_msg_id" + ], + [ "u32", - "sw_if_index" + "context" ], [ - "u8", - "address", - 16 + "i32", + "retval" ], { - "crc": "0xd73bf1ab" + "crc": "0xe8d4e804" } ], [ - "ip6nd_proxy_dump", + "ip_table_details", [ "u16", "_vl_msg_id" ], [ "u32", - "client_index" + "context" ], [ - "u32", - "context" + "vl_api_ip_table_t", + "table" ], { - "crc": "0x51077d14" + "crc": "0xc79fca0f" } ], [ - "sw_interface_ip6_enable_disable", + "ip_route_add_del", [ "u16", "_vl_msg_id" @@ -834,19 +776,26 @@ "context" ], [ - "u32", - "sw_if_index" + "bool", + "is_add", + { + "default": "true" + } ], [ - "u8", - "enable" + "bool", + "is_multipath" + ], + [ + "vl_api_ip_route_t", + "route" ], { - "crc": "0xa36fadc0" + "crc": "0xc1ff832d" } ], [ - "sw_interface_ip6_enable_disable_reply", + "ip_route_add_del_reply", [ "u16", "_vl_msg_id" @@ -859,12 +808,16 @@ "i32", "retval" ], + [ + "u32", + "stats_index" + ], { - "crc": "0xe8d4e804" + "crc": "0x1992deab" } ], [ - "sw_interface_ip6_set_link_local_address", + "ip_route_dump", [ "u16", "_vl_msg_id" @@ -878,20 +831,15 @@ "context" ], [ - "u32", - "sw_if_index" - ], - [ - "u8", - "address", - 16 + "vl_api_ip_table_t", + "table" ], { - "crc": "0xd73bf1ab" + "crc": "0xb9d2e09e" } ], [ - "sw_interface_ip6_set_link_local_address_reply", + "ip_route_details", [ "u16", "_vl_msg_id" @@ -901,15 +849,15 @@ "context" ], [ - "i32", - "retval" + "vl_api_ip_route_t", + "route" ], { - "crc": "0xe8d4e804" + "crc": "0xd1ffaae1" } ], [ - "ip_add_del_route", + "ip_route_lookup", [ "u16", "_vl_msg_id" @@ -924,122 +872,146 @@ ], [ "u32", - "next_hop_sw_if_index" + "table_id" ], [ - "u32", - "table_id" + "u8", + "exact" ], [ - "u32", - "classify_table_index" + "vl_api_prefix_t", + "prefix" ], + { + "crc": "0xe2986185" + } + ], + [ + "ip_route_lookup_reply", [ - "u32", - "next_hop_table_id" + "u16", + "_vl_msg_id" ], [ "u32", - "next_hop_id" + "context" ], [ - "u8", - "is_add" + "i32", + "retval" ], [ - "u8", - "is_drop" + "vl_api_ip_route_t", + "route" ], + { + "crc": "0xae99de8e" + } + ], + [ + "set_ip_flow_hash", [ - "u8", - "is_unreach" + "u16", + "_vl_msg_id" ], [ - "u8", - "is_prohibit" + "u32", + "client_index" ], [ - "u8", - "is_ipv6" + "u32", + "context" ], [ - "u8", - "is_local" + "u32", + "vrf_id" ], [ - "u8", - "is_classify" + "bool", + "is_ipv6" ], [ - "u8", - "is_multipath" + "bool", + "src" ], [ - "u8", - "is_resolve_host" + "bool", + "dst" ], [ - "u8", - "is_resolve_attached" + "bool", + "sport" ], [ - "u8", - "is_dvr" + "bool", + "dport" ], [ - "u8", - "is_source_lookup" + "bool", + "proto" ], [ - "u8", - "is_udp_encap" + "bool", + "reverse" ], [ - "u8", - "next_hop_weight" + "bool", + "symmetric" ], + { + "crc": "0x084ee09e" + } + ], + [ + "set_ip_flow_hash_reply", [ - "u8", - "next_hop_preference" + "u16", + "_vl_msg_id" ], [ - "u8", - "next_hop_proto" + "u32", + "context" ], [ - "u8", - "dst_address_length" + "i32", + "retval" ], + { + "crc": "0xe8d4e804" + } + ], + [ + "set_ip_flow_hash_v2", [ - "u8", - "dst_address", - 16 + "u16", + "_vl_msg_id" ], [ - "u8", - "next_hop_address", - 16 + "u32", + "client_index" ], [ - "u8", - "next_hop_n_out_labels" + "u32", + "context" ], [ "u32", - "next_hop_via_label" + "table_id" ], [ - "u32", - "next_hop_out_label_stack", - 0, - "next_hop_n_out_labels" + "vl_api_address_family_t", + "af" + ], + [ + "vl_api_ip_flow_hash_config_t", + "flow_hash_config" ], { - "crc": "0xc85f8290" + "crc": "0x6d132100" } ], [ - "ip_add_del_route_reply", + "set_ip_flow_hash_v2_reply", [ "u16", "_vl_msg_id" @@ -1057,7 +1029,7 @@ } ], [ - "ip_mroute_add_del", + "set_ip_flow_hash_router_id", [ "u16", "_vl_msg_id" @@ -1072,64 +1044,58 @@ ], [ "u32", - "next_hop_sw_if_index" - ], - [ - "u32", - "table_id" - ], - [ - "u32", - "entry_flags" + "router_id" ], + { + "crc": "0x03e4f48e" + } + ], + [ + "set_ip_flow_hash_router_id_reply", [ - "u32", - "itf_flags" + "u16", + "_vl_msg_id" ], [ "u32", - "rpf_id" + "context" ], [ - "u32", - "bier_imp" + "i32", + "retval" ], + { + "crc": "0xe8d4e804" + } + ], + [ + "sw_interface_ip6_enable_disable", [ "u16", - "grp_address_length" - ], - [ - "u8", - "next_hop_afi" - ], - [ - "u8", - "is_add" + "_vl_msg_id" ], [ - "u8", - "is_ipv6" + "u32", + "client_index" ], [ - "u8", - "is_local" + "u32", + "context" ], [ - "u8", - "grp_address", - 16 + "vl_api_interface_index_t", + "sw_if_index" ], [ - "u8", - "src_address", - 16 + "bool", + "enable" ], { - "crc": "0xc37112f7" + "crc": "0xae6cfcfb" } ], [ - "ip_mroute_add_del_reply", + "sw_interface_ip6_enable_disable_reply", [ "u16", "_vl_msg_id" @@ -1147,7 +1113,7 @@ } ], [ - "ip_mfib_dump", + "ip_mtable_dump", [ "u16", "_vl_msg_id" @@ -1165,57 +1131,84 @@ } ], [ - "ip_mfib_details", + "ip_mtable_details", [ "u16", "_vl_msg_id" ], [ "u32", - "context" + "client_index" ], [ "u32", - "table_id" + "context" + ], + [ + "vl_api_ip_table_t", + "table" + ], + { + "crc": "0xb9d2e09e" + } + ], + [ + "ip_mroute_add_del", + [ + "u16", + "_vl_msg_id" ], [ "u32", - "entry_flags" + "client_index" ], [ "u32", - "rpf_id" + "context" ], [ - "u8", - "address_length" + "bool", + "is_add", + { + "default": "true" + } ], [ - "u8", - "grp_address", - 4 + "bool", + "is_multipath" ], [ - "u8", - "src_address", - 4 + "vl_api_ip_mroute_t", + "route" + ], + { + "crc": "0x0dd7e790" + } + ], + [ + "ip_mroute_add_del_reply", + [ + "u16", + "_vl_msg_id" ], [ "u32", - "count" + "context" ], [ - "vl_api_fib_path_t", - "path", - 0, - "count" + "i32", + "retval" + ], + [ + "u32", + "stats_index" ], { - "crc": "0x5e530d5e" + "crc": "0x1992deab" } ], [ - "ip6_mfib_dump", + "ip_mroute_dump", [ "u16", "_vl_msg_id" @@ -1228,12 +1221,16 @@ "u32", "context" ], + [ + "vl_api_ip_table_t", + "table" + ], { - "crc": "0x51077d14" + "crc": "0xb9d2e09e" } ], [ - "ip6_mfib_details", + "ip_mroute_details", [ "u16", "_vl_msg_id" @@ -1243,39 +1240,37 @@ "context" ], [ - "u32", - "table_id" - ], - [ - "u8", - "address_length" + "vl_api_ip_mroute_t", + "route" ], + { + "crc": "0xc5cb23fc" + } + ], + [ + "ip_address_details", [ - "u8", - "grp_address", - 16 + "u16", + "_vl_msg_id" ], [ - "u8", - "src_address", - 16 + "u32", + "context" ], [ - "u32", - "count" + "vl_api_interface_index_t", + "sw_if_index" ], [ - "vl_api_fib_path_t", - "path", - 0, - "count" + "vl_api_address_with_prefix_t", + "prefix" ], { - "crc": "0xe02dcb4b" + "crc": "0xb1199745" } ], [ - "ip_address_details", + "ip_address_dump", [ "u16", "_vl_msg_id" @@ -1289,28 +1284,41 @@ "context" ], [ - "u8", - "ip", - 16 + "vl_api_interface_index_t", + "sw_if_index" ], [ - "u8", - "prefix_length" + "bool", + "is_ipv6" + ], + { + "crc": "0x2d033de4" + } + ], + [ + "ip_unnumbered_details", + [ + "u16", + "_vl_msg_id" ], [ "u32", + "context" + ], + [ + "vl_api_interface_index_t", "sw_if_index" ], [ - "u8", - "is_ipv6" + "vl_api_interface_index_t", + "ip_sw_if_index" ], { - "crc": "0xbc7442f2" + "crc": "0xaa12a483" } ], [ - "ip_address_dump", + "ip_unnumbered_dump", [ "u16", "_vl_msg_id" @@ -1324,15 +1332,14 @@ "context" ], [ - "u32", - "sw_if_index" - ], - [ - "u8", - "is_ipv6" + "vl_api_interface_index_t", + "sw_if_index", + { + "default": 4294967295 + } ], { - "crc": "0x6b7bcd0a" + "crc": "0xf9e6675e" } ], [ @@ -1343,18 +1350,18 @@ ], [ "u32", - "sw_if_index" + "context" ], [ - "u32", - "context" + "vl_api_interface_index_t", + "sw_if_index" ], [ - "u8", + "bool", "is_ipv6" ], { - "crc": "0x452ffc5a" + "crc": "0xeb152d07" } ], [ @@ -1372,11 +1379,11 @@ "context" ], [ - "u8", + "bool", "is_ipv6" ], { - "crc": "0xde883da4" + "crc": "0x98d231ca" } ], [ @@ -1405,14 +1412,10 @@ ], [ "u32", - "client_index" - ], - [ - "u32", "context" ], [ - "u32", + "vl_api_interface_index_t", "sw_if_index" ], [ @@ -1420,18 +1423,8 @@ "table_id" ], [ - "u16", - "grp_address_len" - ], - [ - "u8", - "grp_address", - 16 - ], - [ - "u8", - "src_address", - 16 + "vl_api_mprefix_t", + "prefix" ], [ "u16", @@ -1443,7 +1436,7 @@ 256 ], { - "crc": "0x791bbeab" + "crc": "0x64398a9a" } ], [ @@ -1465,15 +1458,18 @@ "policer_index" ], [ - "u8", - "is_add" + "bool", + "is_add", + { + "default": "true" + } ], [ - "u8", + "bool", "is_ip6" ], { - "crc": "0x38691592" + "crc": "0xdb867cea" } ], [ @@ -1509,28 +1505,18 @@ "context" ], [ - "u32", - "rx_sw_if_index" + "vl_api_punt_redirect_t", + "punt" ], [ - "u32", - "tx_sw_if_index" - ], - [ - "u8", - "is_add" - ], - [ - "u8", - "is_ip6" - ], - [ - "u8", - "nh", - 16 + "bool", + "is_add", + { + "default": "true" + } ], { - "crc": "0x996b6603" + "crc": "0xa9a5592c" } ], [ @@ -1552,7 +1538,7 @@ } ], [ - "ip_container_proxy_add_del", + "ip_punt_redirect_dump", [ "u16", "_vl_msg_id" @@ -1566,28 +1552,66 @@ "context" ], [ - "u8", - "ip", - 16 + "vl_api_interface_index_t", + "sw_if_index" ], [ - "u8", - "is_ip4" + "bool", + "is_ipv6" ], + { + "crc": "0x2d033de4" + } + ], + [ + "ip_punt_redirect_details", [ - "u8", - "plen" + "u16", + "_vl_msg_id" + ], + [ + "u32", + "context" + ], + [ + "vl_api_punt_redirect_t", + "punt" + ], + { + "crc": "0x3924f5d3" + } + ], + [ + "ip_container_proxy_add_del", + [ + "u16", + "_vl_msg_id" ], [ "u32", + "client_index" + ], + [ + "u32", + "context" + ], + [ + "vl_api_prefix_t", + "pfx" + ], + [ + "vl_api_interface_index_t", "sw_if_index" ], [ - "u8", - "is_add" + "bool", + "is_add", + { + "default": "true" + } ], { - "crc": "0x0a355d39" + "crc": "0x91189f40" } ], [ @@ -1609,7 +1633,7 @@ } ], [ - "ip_source_and_port_range_check_add_del", + "ip_container_proxy_dump", [ "u16", "_vl_msg_id" @@ -1622,22 +1646,56 @@ "u32", "context" ], + { + "crc": "0x51077d14" + } + ], + [ + "ip_container_proxy_details", [ - "u8", - "is_ipv6" + "u16", + "_vl_msg_id" ], [ - "u8", - "is_add" + "u32", + "context" ], [ - "u8", - "mask_length" + "vl_api_interface_index_t", + "sw_if_index" ], [ - "u8", - "address", - 16 + "vl_api_prefix_t", + "prefix" + ], + { + "crc": "0x0ee460e8" + } + ], + [ + "ip_source_and_port_range_check_add_del", + [ + "u16", + "_vl_msg_id" + ], + [ + "u32", + "client_index" + ], + [ + "u32", + "context" + ], + [ + "bool", + "is_add", + { + "default": "true" + } + ], + [ + "vl_api_prefix_t", + "prefix" ], [ "u8", @@ -1658,7 +1716,7 @@ "vrf_id" ], { - "crc": "0x03d6b03a" + "crc": "0x8bfc76f2" } ], [ @@ -1694,11 +1752,14 @@ "context" ], [ - "u8", - "is_add" + "bool", + "is_add", + { + "default": "true" + } ], [ - "u32", + "vl_api_interface_index_t", "sw_if_index" ], [ @@ -1718,7 +1779,7 @@ "udp_out_vrf_id" ], { - "crc": "0x6966bc44" + "crc": "0xe1ba8987" } ], [ @@ -1740,7 +1801,7 @@ } ], [ - "want_ip4_arp_events", + "sw_interface_ip6_set_link_local_address", [ "u16", "_vl_msg_id" @@ -1754,23 +1815,19 @@ "context" ], [ - "u8", - "enable_disable" + "vl_api_interface_index_t", + "sw_if_index" ], [ - "u32", - "pid" - ], - [ - "u32", - "address" + "vl_api_ip6_address_t", + "ip" ], { - "crc": "0x77e06379" + "crc": "0x2931d9fa" } ], [ - "want_ip4_arp_events_reply", + "sw_interface_ip6_set_link_local_address_reply", [ "u16", "_vl_msg_id" @@ -1788,7 +1845,7 @@ } ], [ - "ip4_arp_event", + "sw_interface_ip6_get_link_local_address", [ "u16", "_vl_msg_id" @@ -1799,31 +1856,40 @@ ], [ "u32", - "address" + "context" ], [ - "u32", - "pid" + "vl_api_interface_index_t", + "sw_if_index" + ], + { + "crc": "0xf9e6675e" + } + ], + [ + "sw_interface_ip6_get_link_local_address_reply", + [ + "u16", + "_vl_msg_id" ], [ "u32", - "sw_if_index" + "context" ], [ - "u8", - "new_mac", - 6 + "i32", + "retval" ], [ - "u8", - "mac_ip" + "vl_api_ip6_address_t", + "ip" ], { - "crc": "0xef7235f7" + "crc": "0xd16b7130" } ], [ - "want_ip6_nd_events", + "ioam_enable", [ "u16", "_vl_msg_id" @@ -1837,24 +1903,35 @@ "context" ], [ - "u8", - "enable_disable" + "u16", + "id" ], [ - "u32", - "pid" + "bool", + "seqno" ], [ - "u8", - "address", - 16 + "bool", + "analyse" + ], + [ + "bool", + "pot_enable" + ], + [ + "bool", + "trace_enable" + ], + [ + "u32", + "node_id" ], { - "crc": "0x1cf65fbb" + "crc": "0x51ccd868" } ], [ - "want_ip6_nd_events_reply", + "ioam_enable_reply", [ "u16", "_vl_msg_id" @@ -1872,7 +1949,7 @@ } ], [ - "ip6_nd_event", + "ioam_disable", [ "u16", "_vl_msg_id" @@ -1883,32 +1960,36 @@ ], [ "u32", - "pid" + "context" ], [ - "u32", - "sw_if_index" + "u16", + "id" ], + { + "crc": "0x6b16a45e" + } + ], + [ + "ioam_disable_reply", [ - "u8", - "address", - 16 + "u16", + "_vl_msg_id" ], [ - "u8", - "new_mac", - 6 + "u32", + "context" ], [ - "u8", - "mac_ip" + "i32", + "retval" ], { - "crc": "0x96ab2fdd" + "crc": "0xe8d4e804" } ], [ - "proxy_arp_add_del", + "ip_reassembly_set", [ "u16", "_vl_msg_id" @@ -1923,28 +2004,34 @@ ], [ "u32", - "vrf_id" + "timeout_ms" ], [ - "u8", - "is_add" + "u32", + "max_reassemblies" ], [ - "u8", - "low_address", - 4 + "u32", + "max_reassembly_length" ], [ - "u8", - "hi_address", - 4 + "u32", + "expire_walk_interval_ms" + ], + [ + "bool", + "is_ip6" + ], + [ + "vl_api_ip_reass_type_t", + "type" ], { - "crc": "0xc2442918" + "crc": "0x16467d25" } ], [ - "proxy_arp_add_del_reply", + "ip_reassembly_set_reply", [ "u16", "_vl_msg_id" @@ -1962,7 +2049,7 @@ } ], [ - "proxy_arp_intfc_enable_disable", + "ip_reassembly_get", [ "u16", "_vl_msg_id" @@ -1976,19 +2063,19 @@ "context" ], [ - "u32", - "sw_if_index" + "bool", + "is_ip6" ], [ - "u8", - "enable_disable" + "vl_api_ip_reass_type_t", + "type" ], { - "crc": "0x69d24598" + "crc": "0xea13ff63" } ], [ - "proxy_arp_intfc_enable_disable_reply", + "ip_reassembly_get_reply", [ "u16", "_vl_msg_id" @@ -2001,12 +2088,32 @@ "i32", "retval" ], + [ + "u32", + "timeout_ms" + ], + [ + "u32", + "max_reassemblies" + ], + [ + "u32", + "max_reassembly_length" + ], + [ + "u32", + "expire_walk_interval_ms" + ], + [ + "bool", + "is_ip6" + ], { - "crc": "0xe8d4e804" + "crc": "0xd5eb8d34" } ], [ - "reset_fib", + "ip_reassembly_enable_disable", [ "u16", "_vl_msg_id" @@ -2020,19 +2127,27 @@ "context" ], [ - "u32", - "vrf_id" + "vl_api_interface_index_t", + "sw_if_index" ], [ - "u8", - "is_ipv6" + "bool", + "enable_ip4" + ], + [ + "bool", + "enable_ip6" + ], + [ + "vl_api_ip_reass_type_t", + "type" ], { - "crc": "0x8553ebd9" + "crc": "0x885c85a6" } ], [ - "reset_fib_reply", + "ip_reassembly_enable_disable_reply", [ "u16", "_vl_msg_id" @@ -2048,199 +2163,1416 @@ { "crc": "0xe8d4e804" } + ] + ], + "unions": [ + [ + "address_union", + [ + "vl_api_ip4_address_t", + "ip4" + ], + [ + "vl_api_ip6_address_t", + "ip6" + ] ], [ - "set_arp_neighbor_limit", + "address_union", [ - "u16", - "_vl_msg_id" + "vl_api_ip4_address_t", + "ip4" ], [ - "u32", - "client_index" + "vl_api_ip6_address_t", + "ip6" + ] + ], + [ + "address_union", + [ + "vl_api_ip4_address_t", + "ip4" ], [ - "u32", - "context" + "vl_api_ip6_address_t", + "ip6" + ] + ] + ], + "enums": [ + [ + "if_status_flags", + [ + "IF_STATUS_API_FLAG_ADMIN_UP", + 1 ], [ - "u8", - "is_ipv6" + "IF_STATUS_API_FLAG_LINK_UP", + 2 ], + { + "enumtype": "u32" + } + ], + [ + "mtu_proto", [ - "u32", - "arp_neighbor_limit" + "MTU_PROTO_API_L3", + 0 + ], + [ + "MTU_PROTO_API_IP4", + 1 + ], + [ + "MTU_PROTO_API_IP6", + 2 + ], + [ + "MTU_PROTO_API_MPLS", + 3 ], { - "crc": "0x97d01fd6" + "enumtype": "u32" } ], [ - "set_arp_neighbor_limit_reply", + "link_duplex", [ - "u16", - "_vl_msg_id" + "LINK_DUPLEX_API_UNKNOWN", + 0 ], [ - "u32", - "context" + "LINK_DUPLEX_API_HALF", + 1 ], [ - "i32", - "retval" + "LINK_DUPLEX_API_FULL", + 2 ], { - "crc": "0xe8d4e804" + "enumtype": "u32" } ], [ - "ioam_enable", + "sub_if_flags", [ - "u16", - "_vl_msg_id" + "SUB_IF_API_FLAG_NO_TAGS", + 1 ], [ - "u32", - "client_index" + "SUB_IF_API_FLAG_ONE_TAG", + 2 ], [ - "u32", - "context" + "SUB_IF_API_FLAG_TWO_TAGS", + 4 ], [ - "u16", - "id" + "SUB_IF_API_FLAG_DOT1AD", + 8 ], [ - "u8", - "seqno" + "SUB_IF_API_FLAG_EXACT_MATCH", + 16 ], [ - "u8", - "analyse" + "SUB_IF_API_FLAG_DEFAULT", + 32 ], [ - "u8", - "pot_enable" + "SUB_IF_API_FLAG_OUTER_VLAN_ID_ANY", + 64 ], [ - "u8", - "trace_enable" + "SUB_IF_API_FLAG_INNER_VLAN_ID_ANY", + 128 ], [ - "u32", - "node_id" + "SUB_IF_API_FLAG_MASK_VNET", + 254 + ], + [ + "SUB_IF_API_FLAG_DOT1AH", + 256 ], { - "crc": "0x9392e032" + "enumtype": "u32" } ], [ - "ioam_enable_reply", + "rx_mode", [ - "u16", - "_vl_msg_id" + "RX_MODE_API_UNKNOWN", + 0 ], [ - "u32", - "context" + "RX_MODE_API_POLLING", + 1 ], [ - "i32", - "retval" + "RX_MODE_API_INTERRUPT", + 2 + ], + [ + "RX_MODE_API_ADAPTIVE", + 3 + ], + [ + "RX_MODE_API_DEFAULT", + 4 ], { - "crc": "0xe8d4e804" + "enumtype": "u32" } ], [ - "ioam_disable", + "if_type", [ - "u16", - "_vl_msg_id" + "IF_API_TYPE_HARDWARE", + 0 ], [ - "u32", - "client_index" + "IF_API_TYPE_SUB", + 1 ], [ - "u32", - "context" + "IF_API_TYPE_P2P", + 2 ], [ - "u16", - "id" + "IF_API_TYPE_PIPE", + 3 ], { - "crc": "0x6b16a45e" + "enumtype": "u32" } ], [ - "ioam_disable_reply", + "address_family", [ - "u16", - "_vl_msg_id" + "ADDRESS_IP4", + 0 ], [ - "u32", - "context" + "ADDRESS_IP6", + 1 + ], + { + "enumtype": "u8" + } + ], + [ + "ip_feature_location", + [ + "IP_API_FEATURE_INPUT", + 0 ], [ - "i32", - "retval" + "IP_API_FEATURE_OUTPUT", + 1 + ], + [ + "IP_API_FEATURE_LOCAL", + 2 + ], + [ + "IP_API_FEATURE_PUNT", + 3 + ], + [ + "IP_API_FEATURE_DROP", + 4 ], { - "crc": "0xe8d4e804" + "enumtype": "u8" } - ] - ], - "types": [ + ], [ - "fib_path", + "ip_ecn", [ - "u32", - "sw_if_index" + "IP_API_ECN_NONE", + 0 ], [ - "u32", - "table_id" + "IP_API_ECN_ECT0", + 1 ], [ - "u8", - "weight" + "IP_API_ECN_ECT1", + 2 ], [ - "u8", - "preference" + "IP_API_ECN_CE", + 3 ], + { + "enumtype": "u8" + } + ], + [ + "ip_dscp", [ - "u8", - "is_local" + "IP_API_DSCP_CS0", + 0 ], [ - "u8", - "is_drop" + "IP_API_DSCP_CS1", + 8 ], [ - "u8", - "is_unreach" + "IP_API_DSCP_AF11", + 10 ], [ - "u8", - "is_prohibit" + "IP_API_DSCP_AF12", + 12 ], [ - "u8", - "afi" + "IP_API_DSCP_AF13", + 14 ], [ - "u8", - "next_hop", + "IP_API_DSCP_CS2", + 16 + ], + [ + "IP_API_DSCP_AF21", + 18 + ], + [ + "IP_API_DSCP_AF22", + 20 + ], + [ + "IP_API_DSCP_AF23", + 22 + ], + [ + "IP_API_DSCP_CS3", + 24 + ], + [ + "IP_API_DSCP_AF31", + 26 + ], + [ + "IP_API_DSCP_AF32", + 28 + ], + [ + "IP_API_DSCP_AF33", + 30 + ], + [ + "IP_API_DSCP_CS4", + 32 + ], + [ + "IP_API_DSCP_AF41", + 34 + ], + [ + "IP_API_DSCP_AF42", + 36 + ], + [ + "IP_API_DSCP_AF43", + 38 + ], + [ + "IP_API_DSCP_CS5", + 40 + ], + [ + "IP_API_DSCP_EF", + 46 + ], + [ + "IP_API_DSCP_CS6", + 48 + ], + [ + "IP_API_DSCP_CS7", + 50 + ], + { + "enumtype": "u8" + } + ], + [ + "ip_proto", + [ + "IP_API_PROTO_HOPOPT", + 0 + ], + [ + "IP_API_PROTO_ICMP", + 1 + ], + [ + "IP_API_PROTO_IGMP", + 2 + ], + [ + "IP_API_PROTO_TCP", + 6 + ], + [ + "IP_API_PROTO_UDP", + 17 + ], + [ + "IP_API_PROTO_GRE", + 47 + ], + [ + "IP_API_PROTO_ESP", + 50 + ], + [ + "IP_API_PROTO_AH", + 51 + ], + [ + "IP_API_PROTO_ICMP6", + 58 + ], + [ + "IP_API_PROTO_EIGRP", + 88 + ], + [ + "IP_API_PROTO_OSPF", + 89 + ], + [ + "IP_API_PROTO_SCTP", + 132 + ], + [ + "IP_API_PROTO_RESERVED", + 255 + ], + { + "enumtype": "u8" + } + ], + [ + "fib_path_nh_proto", + [ + "FIB_API_PATH_NH_PROTO_IP4", + 0 + ], + [ + "FIB_API_PATH_NH_PROTO_IP6", + 1 + ], + [ + "FIB_API_PATH_NH_PROTO_MPLS", + 2 + ], + [ + "FIB_API_PATH_NH_PROTO_ETHERNET", + 3 + ], + [ + "FIB_API_PATH_NH_PROTO_BIER", + 4 + ], + { + "enumtype": "u32" + } + ], + [ + "fib_path_flags", + [ + "FIB_API_PATH_FLAG_NONE", + 0 + ], + [ + "FIB_API_PATH_FLAG_RESOLVE_VIA_ATTACHED", + 1 + ], + [ + "FIB_API_PATH_FLAG_RESOLVE_VIA_HOST", + 2 + ], + [ + "FIB_API_PATH_FLAG_POP_PW_CW", + 4 + ], + { + "enumtype": "u32" + } + ], + [ + "fib_path_type", + [ + "FIB_API_PATH_TYPE_NORMAL", + 0 + ], + [ + "FIB_API_PATH_TYPE_LOCAL", + 1 + ], + [ + "FIB_API_PATH_TYPE_DROP", + 2 + ], + [ + "FIB_API_PATH_TYPE_UDP_ENCAP", + 3 + ], + [ + "FIB_API_PATH_TYPE_BIER_IMP", + 4 + ], + [ + "FIB_API_PATH_TYPE_ICMP_UNREACH", + 5 + ], + [ + "FIB_API_PATH_TYPE_ICMP_PROHIBIT", + 6 + ], + [ + "FIB_API_PATH_TYPE_SOURCE_LOOKUP", + 7 + ], + [ + "FIB_API_PATH_TYPE_DVR", + 8 + ], + [ + "FIB_API_PATH_TYPE_INTERFACE_RX", + 9 + ], + [ + "FIB_API_PATH_TYPE_CLASSIFY", + 10 + ], + { + "enumtype": "u32" + } + ], + [ + "address_family", + [ + "ADDRESS_IP4", + 0 + ], + [ + "ADDRESS_IP6", + 1 + ], + { + "enumtype": "u8" + } + ], + [ + "ip_feature_location", + [ + "IP_API_FEATURE_INPUT", + 0 + ], + [ + "IP_API_FEATURE_OUTPUT", + 1 + ], + [ + "IP_API_FEATURE_LOCAL", + 2 + ], + [ + "IP_API_FEATURE_PUNT", + 3 + ], + [ + "IP_API_FEATURE_DROP", + 4 + ], + { + "enumtype": "u8" + } + ], + [ + "ip_ecn", + [ + "IP_API_ECN_NONE", + 0 + ], + [ + "IP_API_ECN_ECT0", + 1 + ], + [ + "IP_API_ECN_ECT1", + 2 + ], + [ + "IP_API_ECN_CE", + 3 + ], + { + "enumtype": "u8" + } + ], + [ + "ip_dscp", + [ + "IP_API_DSCP_CS0", + 0 + ], + [ + "IP_API_DSCP_CS1", + 8 + ], + [ + "IP_API_DSCP_AF11", + 10 + ], + [ + "IP_API_DSCP_AF12", + 12 + ], + [ + "IP_API_DSCP_AF13", + 14 + ], + [ + "IP_API_DSCP_CS2", + 16 + ], + [ + "IP_API_DSCP_AF21", + 18 + ], + [ + "IP_API_DSCP_AF22", + 20 + ], + [ + "IP_API_DSCP_AF23", + 22 + ], + [ + "IP_API_DSCP_CS3", + 24 + ], + [ + "IP_API_DSCP_AF31", + 26 + ], + [ + "IP_API_DSCP_AF32", + 28 + ], + [ + "IP_API_DSCP_AF33", + 30 + ], + [ + "IP_API_DSCP_CS4", + 32 + ], + [ + "IP_API_DSCP_AF41", + 34 + ], + [ + "IP_API_DSCP_AF42", + 36 + ], + [ + "IP_API_DSCP_AF43", + 38 + ], + [ + "IP_API_DSCP_CS5", + 40 + ], + [ + "IP_API_DSCP_EF", + 46 + ], + [ + "IP_API_DSCP_CS6", + 48 + ], + [ + "IP_API_DSCP_CS7", + 50 + ], + { + "enumtype": "u8" + } + ], + [ + "ip_proto", + [ + "IP_API_PROTO_HOPOPT", + 0 + ], + [ + "IP_API_PROTO_ICMP", + 1 + ], + [ + "IP_API_PROTO_IGMP", + 2 + ], + [ + "IP_API_PROTO_TCP", + 6 + ], + [ + "IP_API_PROTO_UDP", + 17 + ], + [ + "IP_API_PROTO_GRE", + 47 + ], + [ + "IP_API_PROTO_ESP", + 50 + ], + [ + "IP_API_PROTO_AH", + 51 + ], + [ + "IP_API_PROTO_ICMP6", + 58 + ], + [ + "IP_API_PROTO_EIGRP", + 88 + ], + [ + "IP_API_PROTO_OSPF", + 89 + ], + [ + "IP_API_PROTO_SCTP", + 132 + ], + [ + "IP_API_PROTO_RESERVED", + 255 + ], + { + "enumtype": "u8" + } + ], + [ + "fib_path_nh_proto", + [ + "FIB_API_PATH_NH_PROTO_IP4", + 0 + ], + [ + "FIB_API_PATH_NH_PROTO_IP6", + 1 + ], + [ + "FIB_API_PATH_NH_PROTO_MPLS", + 2 + ], + [ + "FIB_API_PATH_NH_PROTO_ETHERNET", + 3 + ], + [ + "FIB_API_PATH_NH_PROTO_BIER", + 4 + ], + { + "enumtype": "u32" + } + ], + [ + "fib_path_flags", + [ + "FIB_API_PATH_FLAG_NONE", + 0 + ], + [ + "FIB_API_PATH_FLAG_RESOLVE_VIA_ATTACHED", + 1 + ], + [ + "FIB_API_PATH_FLAG_RESOLVE_VIA_HOST", + 2 + ], + [ + "FIB_API_PATH_FLAG_POP_PW_CW", + 4 + ], + { + "enumtype": "u32" + } + ], + [ + "fib_path_type", + [ + "FIB_API_PATH_TYPE_NORMAL", + 0 + ], + [ + "FIB_API_PATH_TYPE_LOCAL", + 1 + ], + [ + "FIB_API_PATH_TYPE_DROP", + 2 + ], + [ + "FIB_API_PATH_TYPE_UDP_ENCAP", + 3 + ], + [ + "FIB_API_PATH_TYPE_BIER_IMP", + 4 + ], + [ + "FIB_API_PATH_TYPE_ICMP_UNREACH", + 5 + ], + [ + "FIB_API_PATH_TYPE_ICMP_PROHIBIT", + 6 + ], + [ + "FIB_API_PATH_TYPE_SOURCE_LOOKUP", + 7 + ], + [ + "FIB_API_PATH_TYPE_DVR", + 8 + ], + [ + "FIB_API_PATH_TYPE_INTERFACE_RX", + 9 + ], + [ + "FIB_API_PATH_TYPE_CLASSIFY", + 10 + ], + { + "enumtype": "u32" + } + ], + [ + "address_family", + [ + "ADDRESS_IP4", + 0 + ], + [ + "ADDRESS_IP6", + 1 + ], + { + "enumtype": "u8" + } + ], + [ + "ip_feature_location", + [ + "IP_API_FEATURE_INPUT", + 0 + ], + [ + "IP_API_FEATURE_OUTPUT", + 1 + ], + [ + "IP_API_FEATURE_LOCAL", + 2 + ], + [ + "IP_API_FEATURE_PUNT", + 3 + ], + [ + "IP_API_FEATURE_DROP", + 4 + ], + { + "enumtype": "u8" + } + ], + [ + "ip_ecn", + [ + "IP_API_ECN_NONE", + 0 + ], + [ + "IP_API_ECN_ECT0", + 1 + ], + [ + "IP_API_ECN_ECT1", + 2 + ], + [ + "IP_API_ECN_CE", + 3 + ], + { + "enumtype": "u8" + } + ], + [ + "ip_dscp", + [ + "IP_API_DSCP_CS0", + 0 + ], + [ + "IP_API_DSCP_CS1", + 8 + ], + [ + "IP_API_DSCP_AF11", + 10 + ], + [ + "IP_API_DSCP_AF12", + 12 + ], + [ + "IP_API_DSCP_AF13", + 14 + ], + [ + "IP_API_DSCP_CS2", + 16 + ], + [ + "IP_API_DSCP_AF21", + 18 + ], + [ + "IP_API_DSCP_AF22", + 20 + ], + [ + "IP_API_DSCP_AF23", + 22 + ], + [ + "IP_API_DSCP_CS3", + 24 + ], + [ + "IP_API_DSCP_AF31", + 26 + ], + [ + "IP_API_DSCP_AF32", + 28 + ], + [ + "IP_API_DSCP_AF33", + 30 + ], + [ + "IP_API_DSCP_CS4", + 32 + ], + [ + "IP_API_DSCP_AF41", + 34 + ], + [ + "IP_API_DSCP_AF42", + 36 + ], + [ + "IP_API_DSCP_AF43", + 38 + ], + [ + "IP_API_DSCP_CS5", + 40 + ], + [ + "IP_API_DSCP_EF", + 46 + ], + [ + "IP_API_DSCP_CS6", + 48 + ], + [ + "IP_API_DSCP_CS7", + 50 + ], + { + "enumtype": "u8" + } + ], + [ + "ip_proto", + [ + "IP_API_PROTO_HOPOPT", + 0 + ], + [ + "IP_API_PROTO_ICMP", + 1 + ], + [ + "IP_API_PROTO_IGMP", + 2 + ], + [ + "IP_API_PROTO_TCP", + 6 + ], + [ + "IP_API_PROTO_UDP", + 17 + ], + [ + "IP_API_PROTO_GRE", + 47 + ], + [ + "IP_API_PROTO_ESP", + 50 + ], + [ + "IP_API_PROTO_AH", + 51 + ], + [ + "IP_API_PROTO_ICMP6", + 58 + ], + [ + "IP_API_PROTO_EIGRP", + 88 + ], + [ + "IP_API_PROTO_OSPF", + 89 + ], + [ + "IP_API_PROTO_SCTP", + 132 + ], + [ + "IP_API_PROTO_RESERVED", + 255 + ], + { + "enumtype": "u8" + } + ], + [ + "mfib_entry_flags", + [ + "MFIB_API_ENTRY_FLAG_NONE", + 0 + ], + [ + "MFIB_API_ENTRY_FLAG_SIGNAL", + 1 + ], + [ + "MFIB_API_ENTRY_FLAG_DROP", + 2 + ], + [ + "MFIB_API_ENTRY_FLAG_CONNECTED", + 4 + ], + [ + "MFIB_API_ENTRY_FLAG_ACCEPT_ALL_ITF", + 8 + ], + { + "enumtype": "u32" + } + ], + [ + "mfib_itf_flags", + [ + "MFIB_API_ITF_FLAG_NONE", + 0 + ], + [ + "MFIB_API_ITF_FLAG_NEGATE_SIGNAL", + 1 + ], + [ + "MFIB_API_ITF_FLAG_ACCEPT", + 2 + ], + [ + "MFIB_API_ITF_FLAG_FORWARD", + 4 + ], + [ + "MFIB_API_ITF_FLAG_SIGNAL_PRESENT", + 8 + ], + [ + "MFIB_API_ITF_FLAG_DONT_PRESERVE", + 16 + ], + { + "enumtype": "u32" + } + ], + [ + "if_status_flags", + [ + "IF_STATUS_API_FLAG_ADMIN_UP", + 1 + ], + [ + "IF_STATUS_API_FLAG_LINK_UP", + 2 + ], + { + "enumtype": "u32" + } + ], + [ + "mtu_proto", + [ + "MTU_PROTO_API_L3", + 0 + ], + [ + "MTU_PROTO_API_IP4", + 1 + ], + [ + "MTU_PROTO_API_IP6", + 2 + ], + [ + "MTU_PROTO_API_MPLS", + 3 + ], + { + "enumtype": "u32" + } + ], + [ + "link_duplex", + [ + "LINK_DUPLEX_API_UNKNOWN", + 0 + ], + [ + "LINK_DUPLEX_API_HALF", + 1 + ], + [ + "LINK_DUPLEX_API_FULL", + 2 + ], + { + "enumtype": "u32" + } + ], + [ + "sub_if_flags", + [ + "SUB_IF_API_FLAG_NO_TAGS", + 1 + ], + [ + "SUB_IF_API_FLAG_ONE_TAG", + 2 + ], + [ + "SUB_IF_API_FLAG_TWO_TAGS", + 4 + ], + [ + "SUB_IF_API_FLAG_DOT1AD", + 8 + ], + [ + "SUB_IF_API_FLAG_EXACT_MATCH", + 16 + ], + [ + "SUB_IF_API_FLAG_DEFAULT", + 32 + ], + [ + "SUB_IF_API_FLAG_OUTER_VLAN_ID_ANY", + 64 + ], + [ + "SUB_IF_API_FLAG_INNER_VLAN_ID_ANY", + 128 + ], + [ + "SUB_IF_API_FLAG_MASK_VNET", + 254 + ], + [ + "SUB_IF_API_FLAG_DOT1AH", + 256 + ], + { + "enumtype": "u32" + } + ], + [ + "rx_mode", + [ + "RX_MODE_API_UNKNOWN", + 0 + ], + [ + "RX_MODE_API_POLLING", + 1 + ], + [ + "RX_MODE_API_INTERRUPT", + 2 + ], + [ + "RX_MODE_API_ADAPTIVE", + 3 + ], + [ + "RX_MODE_API_DEFAULT", + 4 + ], + { + "enumtype": "u32" + } + ], + [ + "if_type", + [ + "IF_API_TYPE_HARDWARE", + 0 + ], + [ + "IF_API_TYPE_SUB", + 1 + ], + [ + "IF_API_TYPE_P2P", + 2 + ], + [ + "IF_API_TYPE_PIPE", + 3 + ], + { + "enumtype": "u32" + } + ], + [ + "ip_reass_type", + [ + "IP_REASS_TYPE_FULL", + 0 + ], + [ + "IP_REASS_TYPE_SHALLOW_VIRTUAL", + 1 + ], + { + "enumtype": "u32" + } + ] + ], + "enumflags": [ + [ + "ip_flow_hash_config", + [ + "IP_API_FLOW_HASH_SRC_IP", + 1 + ], + [ + "IP_API_FLOW_HASH_DST_IP", + 2 + ], + [ + "IP_API_FLOW_HASH_SRC_PORT", + 4 + ], + [ + "IP_API_FLOW_HASH_DST_PORT", + 8 + ], + [ + "IP_API_FLOW_HASH_PROTO", 16 ], + [ + "IP_API_FLOW_HASH_REVERSE", + 32 + ], + [ + "IP_API_FLOW_HASH_SYMETRIC", + 64 + ], + [ + "IP_API_FLOW_HASH_FLOW_LABEL", + 128 + ], { - "crc": "0xcd899e0a" + "enumtype": "u32" } ] - ] + ], + "services": { + "ip_table_add_del": { + "reply": "ip_table_add_del_reply" + }, + "ip_table_dump": { + "reply": "ip_table_details", + "stream": true + }, + "ip_table_replace_begin": { + "reply": "ip_table_replace_begin_reply" + }, + "ip_table_replace_end": { + "reply": "ip_table_replace_end_reply" + }, + "ip_table_flush": { + "reply": "ip_table_flush_reply" + }, + "ip_route_add_del": { + "reply": "ip_route_add_del_reply" + }, + "ip_route_dump": { + "reply": "ip_route_details", + "stream": true + }, + "ip_route_lookup": { + "reply": "ip_route_lookup_reply" + }, + "set_ip_flow_hash": { + "reply": "set_ip_flow_hash_reply" + }, + "set_ip_flow_hash_v2": { + "reply": "set_ip_flow_hash_v2_reply" + }, + "set_ip_flow_hash_router_id": { + "reply": "set_ip_flow_hash_router_id_reply" + }, + "sw_interface_ip6_enable_disable": { + "reply": "sw_interface_ip6_enable_disable_reply" + }, + "ip_mtable_dump": { + "reply": "ip_mtable_details", + "stream": true + }, + "ip_mroute_add_del": { + "reply": "ip_mroute_add_del_reply" + }, + "ip_mroute_dump": { + "reply": "ip_mroute_details", + "stream": true + }, + "ip_address_dump": { + "reply": "ip_address_details", + "stream": true + }, + "ip_unnumbered_dump": { + "reply": "ip_unnumbered_details", + "stream": true + }, + "ip_dump": { + "reply": "ip_details", + "stream": true + }, + "mfib_signal_dump": { + "reply": "mfib_signal_details", + "stream": true + }, + "ip_punt_police": { + "reply": "ip_punt_police_reply" + }, + "ip_punt_redirect": { + "reply": "ip_punt_redirect_reply" + }, + "ip_punt_redirect_dump": { + "reply": "ip_punt_redirect_details", + "stream": true + }, + "ip_container_proxy_add_del": { + "reply": "ip_container_proxy_add_del_reply" + }, + "ip_container_proxy_dump": { + "reply": "ip_container_proxy_details", + "stream": true + }, + "ip_source_and_port_range_check_add_del": { + "reply": "ip_source_and_port_range_check_add_del_reply" + }, + "ip_source_and_port_range_check_interface_add_del": { + "reply": "ip_source_and_port_range_check_interface_add_del_reply" + }, + "sw_interface_ip6_set_link_local_address": { + "reply": "sw_interface_ip6_set_link_local_address_reply" + }, + "sw_interface_ip6_get_link_local_address": { + "reply": "sw_interface_ip6_get_link_local_address_reply" + }, + "ioam_enable": { + "reply": "ioam_enable_reply" + }, + "ioam_disable": { + "reply": "ioam_disable_reply" + }, + "ip_reassembly_set": { + "reply": "ip_reassembly_set_reply" + }, + "ip_reassembly_get": { + "reply": "ip_reassembly_get_reply" + }, + "ip_reassembly_enable_disable": { + "reply": "ip_reassembly_enable_disable_reply" + } + }, + "options": { + "version": "3.0.3" + }, + "aliases": { + "interface_index": { + "type": "u32" + }, + "ip4_address": { + "type": "u8", + "length": 4 + }, + "ip6_address": { + "type": "u8", + "length": 16 + }, + "address_with_prefix": { + "type": "vl_api_prefix_t" + }, + "ip4_address_with_prefix": { + "type": "vl_api_ip4_prefix_t" + }, + "ip6_address_with_prefix": { + "type": "vl_api_ip6_prefix_t" + }, + "mac_address": { + "type": "u8", + "length": 6 + } + }, + "vl_api_version": "0xf2f5f4e" } diff --git a/binapigen/vppapi/testdata/union.api.json b/binapigen/vppapi/testdata/union.api.json new file mode 100644 index 0000000..0811f22 --- /dev/null +++ b/binapigen/vppapi/testdata/union.api.json @@ -0,0 +1,231 @@ +{ + "services": [], + "vl_api_version": "0x1db2ece9", + "enums": [ + [ + "enum1", + [ + "ENUM_1_VALUE_1", + 1 + ], + [ + "ENUM_1_VALUE_2", + 2 + ], + { + "enumtype": "u16" + } + ], + [ + "enum2", + [ + "ENUM_2_VALUE_1", + 10 + ], + [ + "ENUM_2_VALUE_2", + 20 + ], + { + "enumtype": "u32" + } + ] + ], + "messages": [], + "types": [ + [ + "type1", + [ + "u8", + "field1", + 16 + ], + [ + "u8", + "field2", + 16 + ] + ], + [ + "type2", + [ + "u16", + "field1" + ], + [ + "u32", + "field2" + ], + [ + "u32", + "field3" + ] + ], + [ + "type3", + [ + "u8", + "field1", + 64 + ] + ], + [ + "type4", + [ + "u8", + "field1" + ], + [ + "u8", + "field2", + 16 + ] + ], + [ + "type5", + [ + "u32", + "field1" + ], + [ + "union5", + "field2" + ] + ], + [ + "type6", + [ + "u16", + "field1" + ], + [ + "u32", + "field2" + ], + [ + "type4", + "field3" + ], + [ + "u16", + "field4" + ], + [ + "u32", + "field5" + ], + [ + "u32", + "field6" + ] + ], + [ + "complex_type", + [ + "u32", + "field1" + ], + [ + "u8", + "field2" + ], + [ + "u8", + "field3" + ], + [ + "u32", + "field4" + ], + [ + "type5", + "field5" + ], + [ + "type6", + "field6" + ] + ] + ], + "unions": [ + [ + "union1", + [ + "vl_api_alias1_t", + "alias1" + ], + [ + "vl_api_alias2_t", + "alias2" + ] + ], + [ + "union2", + [ + "vl_api_enum1_t", + "enum1" + ], + [ + "vl_api_enum2_t", + "enum2" + ] + ], + [ + "union3", + [ + "vl_api_type1_t", + "type1" + ], + [ + "vl_api_type2_t", + "type2" + ] + ], + [ + "union4", + [ + "vl_api_union1_t", + "union1" + ], + [ + "vl_api_union2_t", + "union2" + ] + ], + [ + "union5", + [ + "vl_api_type1_t", + "type1" + ], + [ + "vl_api_type3_t", + "type3" + ] + ], + [ + "union6", + [ + "vl_api_type1_t", + "type1" + ], + [ + "vl_api_complex_type_t", + "type3" + ] + ] + ], + "aliases": { + "alias1": { + "type": "u8", + "length": 4 + }, + "alias2": { + "type": "u8", + "length": 16 + }, + "alias3": { + "type": "u32" + } + } +} diff --git a/binapigen/vppapi/util.go b/binapigen/vppapi/util.go index 87f2e55..1374bb9 100644 --- a/binapigen/vppapi/util.go +++ b/binapigen/vppapi/util.go @@ -26,7 +26,9 @@ import ( ) const ( - VPPVersionEnvVar = "VPP_VERSION" + VPPVersionEnvVar = "VPP_VERSION" + VPPDirEnvVar = "VPP_DIR" + versionScriptPath = "./src/scripts/version" ) // ResolveVPPVersion resolves version of the VPP for target directory. @@ -35,17 +37,17 @@ const ( func ResolveVPPVersion(apidir string) string { // check env variable override if ver := os.Getenv(VPPVersionEnvVar); ver != "" { - logrus.Debugf("VPP version was manually set to %q via %s env var", ver, VPPVersionEnvVar) + logrus.Infof("VPP version was manually set to %q via %s env var", ver, VPPVersionEnvVar) return ver } // assuming VPP package is installed - if path.Clean(apidir) == DefaultDir { + if _, err := exec.LookPath("vpp"); err == nil { version, err := GetVPPVersionInstalled() if err != nil { logrus.Warnf("resolving VPP version from installed package failed: %v", err) } else { - logrus.Debugf("resolved VPP version from installed package: %v", version) + logrus.Infof("resolved VPP version from installed package: %v", version) return version } } @@ -60,7 +62,7 @@ func ResolveVPPVersion(apidir string) string { if err != nil { logrus.Warnf("resolving VPP version from version script failed: %v", err) } else { - logrus.Debugf("resolved VPP version from version script: %v", version) + logrus.Infof("resolved VPP version from version script: %v", version) return version } } @@ -85,14 +87,13 @@ func GetVPPVersionInstalled() (string, error) { return strings.TrimSpace(string(out)), nil } -const versionScriptPath = "./src/scripts/version" - // GetVPPVersionRepo retrieves VPP version using script in repo directory. func GetVPPVersionRepo(repoDir string) (string, error) { - if _, err := os.Stat(versionScriptPath); err != nil { + scriptPath := path.Join(repoDir, versionScriptPath) + if _, err := os.Stat(scriptPath); err != nil { return "", err } - cmd := exec.Command(versionScriptPath) + cmd := exec.Command(scriptPath) cmd.Dir = repoDir out, err := cmd.CombinedOutput() if err != nil { @@ -102,6 +103,10 @@ func GetVPPVersionRepo(repoDir string) (string, error) { } func findGitRepoRootDir(dir string) (string, error) { + if conf := os.Getenv(VPPDirEnvVar); conf != "" { + logrus.Infof("VPP directory was manually set to %q via %s env var", conf, VPPDirEnvVar) + return conf, nil + } cmd := exec.Command("git", "rev-parse", "--show-toplevel") cmd.Dir = dir out, err := cmd.CombinedOutput() diff --git a/binapigen/vppapi/vppapi.go b/binapigen/vppapi/vppapi.go index 665fa81..b54d287 100644 --- a/binapigen/vppapi/vppapi.go +++ b/binapigen/vppapi/vppapi.go @@ -24,6 +24,9 @@ import ( const ( // DefaultDir is default location of API files. DefaultDir = "/usr/share/vpp/api" + + // APIFileExtension is a VPP API file extension suffix + APIFileExtension = ".api.json" ) // FindFiles finds API files located in dir or in a nested directory that is not nested deeper than deep. @@ -40,7 +43,7 @@ func FindFiles(dir string, deep int) (files []string, err error) { } else { files = append(files, nested...) } - } else if !e.IsDir() && strings.HasSuffix(e.Name(), ".api.json") { + } else if !e.IsDir() && strings.HasSuffix(e.Name(), APIFileExtension) { files = append(files, filepath.Join(dir, e.Name())) } } @@ -54,13 +57,13 @@ func Parse() ([]*File, error) { // ParseDir finds and parses API files in given directory and returns parsed files. // Supports API files in JSON format (.api.json) only. -func ParseDir(apidir string) ([]*File, error) { - list, err := FindFiles(apidir, 1) +func ParseDir(apiDir string) ([]*File, error) { + list, err := FindFiles(apiDir, 1) if err != nil { return nil, err } - logf("found %d files in API dir %q", len(list), apidir) + logf("found %d files in API dir %q", len(list), apiDir) var files []*File for _, file := range list { @@ -74,17 +77,17 @@ func ParseDir(apidir string) ([]*File, error) { } // ParseFile parses API file and returns File. -func ParseFile(apifile string) (*File, error) { - if !strings.HasSuffix(apifile, ".api.json") { - return nil, fmt.Errorf("unsupported file format: %q", apifile) +func ParseFile(apiFile string) (*File, error) { + if !strings.HasSuffix(apiFile, APIFileExtension) { + return nil, fmt.Errorf("unsupported file format: %q", apiFile) } - data, err := ioutil.ReadFile(apifile) + data, err := ioutil.ReadFile(apiFile) if err != nil { - return nil, fmt.Errorf("reading file %s failed: %v", apifile, err) + return nil, fmt.Errorf("reading file %s failed: %v", apiFile, err) } - base := filepath.Base(apifile) + base := filepath.Base(apiFile) name := base[:strings.Index(base, ".")] logf("parsing file %q", base) @@ -94,7 +97,7 @@ func ParseFile(apifile string) (*File, error) { return nil, fmt.Errorf("parsing file %s failed: %v", base, err) } module.Name = name - module.Path = apifile + module.Path = apiFile return module, nil } diff --git a/binapigen/vppapi/vppapi_test.go b/binapigen/vppapi/vppapi_test.go index 027cc1f..a555d9f 100644 --- a/binapigen/vppapi/vppapi_test.go +++ b/binapigen/vppapi/vppapi_test.go @@ -27,7 +27,7 @@ func TestGetInputFiles(t *testing.T) { result, err := FindFiles("testdata", 1) Expect(err).ShouldNot(HaveOccurred()) - Expect(result).To(HaveLen(5)) + Expect(result).To(HaveLen(6)) for _, file := range result { Expect(file).To(BeAnExistingFile()) } |