aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorOle Troan <ot@cisco.com>2018-11-13 12:36:56 +0100
committerFlorin Coras <florin.coras@gmail.com>2018-11-29 07:39:22 +0000
commit53fffa1db7cb04982db8977acd61b808ef60d5a8 (patch)
tree7f8c8b25b51d722cc6353c028ddad4e0ad6fcd31 /src
parent4f10db317382832068d67b5d19be4a696d80c19a (diff)
API: Add support for type aliases
Previously all types are compound. This adds support for aliases, so one can do things like: typedef u32 interface_index; or typedef u8 ip4_address[4]; Change-Id: I0455cad0123fc88acb491d2a3ea2725426bdb246 Signed-off-by: Ole Troan <ot@cisco.com> Signed-off-by: Klement Sekera <ksekera@cisco.com>
Diffstat (limited to 'src')
-rwxr-xr-xsrc/tools/vppapigen/vppapigen.py29
-rw-r--r--src/tools/vppapigen/vppapigen_c.py13
-rw-r--r--src/tools/vppapigen/vppapigen_json.py1
-rw-r--r--src/vnet/interface.api18
-rw-r--r--src/vnet/interface_types.api18
-rw-r--r--src/vnet/ipip/ipip.api13
-rw-r--r--src/vpp-api/python/vpp_papi/vpp_papi.py11
-rw-r--r--src/vpp-api/python/vpp_papi/vpp_serializer.py14
-rwxr-xr-xsrc/vpp-api/vapi/vapi_c_gen.py43
-rwxr-xr-xsrc/vpp-api/vapi/vapi_cpp_gen.py9
-rw-r--r--src/vpp-api/vapi/vapi_json_parser.py33
11 files changed, 170 insertions, 32 deletions
diff --git a/src/tools/vppapigen/vppapigen.py b/src/tools/vppapigen/vppapigen.py
index 9d04ec24cfc..3f882c455e6 100755
--- a/src/tools/vppapigen/vppapigen.py
+++ b/src/tools/vppapigen/vppapigen.py
@@ -151,6 +151,25 @@ class Typedef():
return self.name + str(self.flags) + str(self.block)
+class Using():
+ def __init__(self, name, alias):
+ global global_crc
+ self.name = name
+
+ if isinstance(alias, Array):
+ a = { 'type': alias.fieldtype,
+ 'length': alias.length }
+ else:
+ a = { 'type': alias.fieldtype }
+ self.alias = a
+ self.crc = binascii.crc32(str(alias)) & 0xffffffff
+ global_crc = binascii.crc32(str(alias), global_crc)
+ global_type_add(name)
+
+ def __repr__(self):
+ return self.name + str(self.alias)
+
+
class Union():
def __init__(self, name, block):
self.type = 'Union'
@@ -457,6 +476,10 @@ class VPPAPIParser(object):
'''typedef : TYPEDEF ID '{' block_statements_opt '}' ';' '''
p[0] = Typedef(p[2], [], p[4])
+ def p_typedef_alias(self, p):
+ '''typedef : TYPEDEF declaration '''
+ p[0] = Using(p[2].fieldname, p[2])
+
def p_block_statements_opt(self, p):
'''block_statements_opt : block_statements '''
p[0] = p[1]
@@ -594,6 +617,7 @@ class VPPAPI(object):
s['Service'] = []
s['types'] = []
s['Import'] = []
+ s['Alias'] = {}
for o in objs:
tname = o.__class__.__name__
if isinstance(o, Define):
@@ -608,6 +632,8 @@ class VPPAPI(object):
s['Service'].append(o2)
elif isinstance(o, Enum) or isinstance(o, Typedef) or isinstance(o, Union):
s['types'].append(o)
+ elif isinstance(o, Using):
+ s['Alias'][o.name] = o.alias
else:
if tname not in s:
raise ValueError('Unknown class type: {} {}'.format(tname, o))
@@ -686,7 +712,8 @@ class VPPAPI(object):
if in_import and not (isinstance(o, Enum) or
isinstance(o, Union) or
isinstance(o, Typedef) or
- isinstance(o, Import)):
+ isinstance(o, Import) or
+ isinstance(o, Using)):
continue
if isinstance(o, Import):
self.process_imports(o.result, True, result)
diff --git a/src/tools/vppapigen/vppapigen_c.py b/src/tools/vppapigen/vppapigen_c.py
index b56e0722122..2a66ff3159e 100644
--- a/src/tools/vppapigen/vppapigen_c.py
+++ b/src/tools/vppapigen/vppapigen_c.py
@@ -94,7 +94,7 @@ def duplicate_wrapper_tail():
return '#endif\n\n'
-def typedefs(objs, filename):
+def typedefs(objs, aliases, filename):
name = filename.replace('.', '_')
output = '''\
@@ -106,6 +106,15 @@ def typedefs(objs, filename):
#define included_{module}
'''
output = output.format(module=name)
+
+ for k, v in aliases.items():
+ output += duplicate_wrapper_head(k)
+ if 'length' in v:
+ output += 'typedef %s vl_api_%s_t[%s];\n' % (v['type'], k, v['length'])
+ else:
+ output += 'typedef %s vl_api_%s_t;\n' % (v['type'], k)
+ output += duplicate_wrapper_tail()
+
for o in objs:
tname = o.__class__.__name__
output += duplicate_wrapper_head(o.name)
@@ -276,7 +285,7 @@ def run(input_filename, s, file_crc):
output += msg_ids(s)
output += msg_names(s)
output += msg_name_crc_list(s, filename)
- output += typedefs(s['types'] + s['Define'], filename + file_extension)
+ output += typedefs(s['types'] + s['Define'], s['Alias'], filename + file_extension)
output += printfun(s['types'] + s['Define'])
output += endianfun(s['types'] + s['Define'])
output += version_tuple(s, basename)
diff --git a/src/tools/vppapigen/vppapigen_json.py b/src/tools/vppapigen/vppapigen_json.py
index 2991bec57ac..b57e16c990d 100644
--- a/src/tools/vppapigen/vppapigen_json.py
+++ b/src/tools/vppapigen/vppapigen_json.py
@@ -65,5 +65,6 @@ def run(filename, s, file_crc):
j['unions'] = walk_defs([o for o in s['types'] if o.__class__.__name__ == 'Union'])
j['enums'] = walk_enums([o for o in s['types'] if o.__class__.__name__ == 'Enum'])
j['services'] = walk_services(s['Service'])
+ j['aliases'] = s['Alias']
j['vl_api_version'] = hex(file_crc)
return json.dumps(j, indent=4, separators=(',', ': '))
diff --git a/src/vnet/interface.api b/src/vnet/interface.api
index 2010d8b5f54..84e0483df67 100644
--- a/src/vnet/interface.api
+++ b/src/vnet/interface.api
@@ -1,5 +1,23 @@
+/* Hey Emacs use -*- mode: C -*- */
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
option version = "2.2.0";
+import "vnet/interface_types.api";
+
service {
rpc want_interface_events returns want_interface_events_reply
events sw_interface_event;
diff --git a/src/vnet/interface_types.api b/src/vnet/interface_types.api
new file mode 100644
index 00000000000..f6fb4219ef8
--- /dev/null
+++ b/src/vnet/interface_types.api
@@ -0,0 +1,18 @@
+/* Hey Emacs use -*- mode: C -*- */
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+typedef u32 interface_index;
+
diff --git a/src/vnet/ipip/ipip.api b/src/vnet/ipip/ipip.api
index 5cad28f2814..3dc087c954f 100644
--- a/src/vnet/ipip/ipip.api
+++ b/src/vnet/ipip/ipip.api
@@ -49,6 +49,7 @@
*/
option version = "1.1.0";
+import "vnet/interface_types.api";
/**
* Create an IP{v4,v6} over IP{v4,v6} tunnel.
@@ -70,7 +71,7 @@ define ipip_add_tunnel_reply
{
u32 context;
i32 retval;
- u32 sw_if_index;
+ vl_api_interface_index_t sw_if_index;
};
/**
@@ -80,7 +81,7 @@ autoreply define ipip_del_tunnel
{
u32 client_index;
u32 context;
- u32 sw_if_index;
+ vl_api_interface_index_t sw_if_index;
};
/**
@@ -106,7 +107,7 @@ define ipip_6rd_add_tunnel_reply
{
u32 context;
i32 retval;
- u32 sw_if_index;
+ vl_api_interface_index_t sw_if_index;
};
/**
@@ -116,7 +117,7 @@ autoreply define ipip_6rd_del_tunnel
{
u32 client_index;
u32 context;
- u32 sw_if_index;
+ vl_api_interface_index_t sw_if_index;
};
/**
@@ -126,13 +127,13 @@ define ipip_tunnel_dump
{
u32 client_index;
u32 context;
- u32 sw_if_index;
+ vl_api_interface_index_t sw_if_index;
};
define ipip_tunnel_details
{
u32 context;
- u32 sw_if_index;
+ vl_api_interface_index_t sw_if_index;
u32 instance;
u8 is_ipv6;
u8 src_address[16];
diff --git a/src/vpp-api/python/vpp_papi/vpp_papi.py b/src/vpp-api/python/vpp_papi/vpp_papi.py
index ca4b955fd07..bd2682f5b8f 100644
--- a/src/vpp-api/python/vpp_papi/vpp_papi.py
+++ b/src/vpp-api/python/vpp_papi/vpp_papi.py
@@ -27,7 +27,7 @@ import fnmatch
import weakref
import atexit
from . vpp_serializer import VPPType, VPPEnumType, VPPUnionType, BaseTypes
-from . vpp_serializer import VPPMessage, vpp_get_type
+from . vpp_serializer import VPPMessage, vpp_get_type, VPPTypeAlias
from . vpp_format import VPPFormat
if sys.version[0] == '2':
@@ -102,13 +102,15 @@ class VPP(object):
for t in api['types']:
t[0] = 'vl_api_' + t[0] + '_t'
types[t[0]] = {'type': 'type', 'data': t}
+ for t, v in api['aliases'].items():
+ types['vl_api_' + t + '_t'] = {'type': 'alias', 'data': v}
i = 0
while True:
unresolved = {}
for k, v in types.items():
t = v['data']
- if not vpp_get_type(t[0]):
+ if not vpp_get_type(k):
if v['type'] == 'enum':
try:
VPPEnumType(t[0], t[1:])
@@ -124,6 +126,11 @@ class VPP(object):
VPPType(t[0], t[1:])
except ValueError:
unresolved[k] = v
+ elif v['type'] == 'alias':
+ try:
+ VPPTypeAlias(k, t)
+ except ValueError:
+ unresolved[k] = v
if len(unresolved) == 0:
break
if i > 3:
diff --git a/src/vpp-api/python/vpp_papi/vpp_serializer.py b/src/vpp-api/python/vpp_papi/vpp_serializer.py
index bd0f73803da..a001cca565a 100644
--- a/src/vpp-api/python/vpp_papi/vpp_serializer.py
+++ b/src/vpp-api/python/vpp_papi/vpp_serializer.py
@@ -79,7 +79,7 @@ class FixedList_u8(object):
self.packer = BaseTypes(field_type, num)
self.size = self.packer.size
- def pack(self, list, kwargs):
+ def pack(self, list, kwargs = None):
"""Packs a fixed length bytestring. Left-pads with zeros
if input data is too short."""
if not list:
@@ -277,6 +277,18 @@ class VPPUnionType(object):
return self.tuple._make(r), maxsize
+def VPPTypeAlias(name, msgdef):
+ t = vpp_get_type(msgdef['type'])
+ if not t:
+ raise ValueError()
+ if 'length' in msgdef:
+ if msgdef['length'] == 0:
+ raise ValueError()
+ types[name] = FixedList(name, msgdef['type'], msgdef['length'])
+ else:
+ types[name] = t
+
+
class VPPType(object):
# Set everything up to be able to pack / unpack
def __init__(self, name, msgdef):
diff --git a/src/vpp-api/vapi/vapi_c_gen.py b/src/vpp-api/vapi/vapi_c_gen.py
index eb1006d3a7e..9939bc0556c 100755
--- a/src/vpp-api/vapi/vapi_c_gen.py
+++ b/src/vpp-api/vapi/vapi_c_gen.py
@@ -5,15 +5,18 @@ import os
import sys
import logging
from vapi_json_parser import Field, Struct, Enum, Union, Message, JsonParser,\
- SimpleType, StructType
+ SimpleType, StructType, Alias
class CField(Field):
+ def get_c_name(self):
+ return self.name
+
def get_c_def(self):
if self.len is not None:
- return "%s %s[%d]" % (self.type.get_c_name(), self.name, self.len)
+ return "%s %s[%d];" % (self.type.get_c_name(), self.name, self.len)
else:
- return "%s %s" % (self.type.get_c_name(), self.name)
+ return "%s %s;" % (self.type.get_c_name(), self.name)
def get_swap_to_be_code(self, struct, var):
if self.len is not None:
@@ -95,12 +98,26 @@ class CField(Field):
return result
+class CAlias(CField):
+ def get_c_name(self):
+ return self.name
+
+ def get_c_def(self):
+ return "typedef %s" % super(CAlias, self).get_c_def()
+ # if self.len is not None:
+ # return "typedef %s %s[%d];" % (self.type.get_c_name(), self.name, self.len)
+ # else:
+ # return "typedef %s %s;" % (self.type.get_c_name(), self.name)
+
+ # def needs_byte_swap
+
+
class CStruct(Struct):
def get_c_def(self):
return "\n".join([
- "typedef struct __attribute__((__packed__)) {\n%s;" % (
- ";\n".join([" %s" % x.get_c_def()
- for x in self.fields])),
+ "typedef struct __attribute__((__packed__)) {\n%s" % (
+ "\n".join([" %s" % x.get_c_def()
+ for x in self.fields])),
"} %s;" % self.get_c_name()])
def get_vla_assign_code(self, prefix, path):
@@ -156,7 +173,7 @@ class CSimpleType (SimpleType):
try:
self.get_swap_to_host_func_name()
return True
- except:
+ except KeyError:
pass
return False
@@ -335,8 +352,8 @@ class CMessage (Message):
if self.has_payload():
return "\n".join([
"typedef struct __attribute__ ((__packed__)) {",
- "%s; " %
- ";\n".join(self.payload_members),
+ "%s " %
+ "\n".join(self.payload_members),
"} %s;" % self.get_payload_struct_name(),
"",
"typedef struct __attribute__ ((__packed__)) {",
@@ -609,7 +626,8 @@ def emit_definition(parser, json_file, emitted, o):
if (o not in parser.enums_by_json[json_file] and
o not in parser.types_by_json[json_file] and
o not in parser.unions_by_json[json_file] and
- o.name not in parser.messages_by_json[json_file]):
+ o.name not in parser.messages_by_json[json_file] and
+ o not in parser.aliases_by_json[json_file]):
return
guard = "defined_%s" % o.get_c_name()
print("#ifndef %s" % guard)
@@ -690,6 +708,8 @@ def gen_json_unified_header(parser, logger, j, io, name):
emitted = []
for e in parser.enums_by_json[j]:
emit_definition(parser, j, emitted, e)
+ for a in parser.aliases_by_json[j]:
+ emit_definition(parser, j, emitted, a)
for u in parser.unions_by_json[j]:
emit_definition(parser, j, emitted, u)
for t in parser.types_by_json[j]:
@@ -765,7 +785,8 @@ if __name__ == '__main__':
union_class=CUnion,
struct_type_class=CStructType,
field_class=CField,
- message_class=CMessage)
+ message_class=CMessage,
+ alias_class=CAlias)
# not using the model of having separate generated header and code files
# with generated symbols present in shared library (per discussion with
diff --git a/src/vpp-api/vapi/vapi_cpp_gen.py b/src/vpp-api/vapi/vapi_cpp_gen.py
index 6b62bc4da22..c08993dc918 100755
--- a/src/vpp-api/vapi/vapi_cpp_gen.py
+++ b/src/vpp-api/vapi/vapi_cpp_gen.py
@@ -5,7 +5,7 @@ import os
import sys
import logging
from vapi_c_gen import CField, CEnum, CStruct, CSimpleType, CStructType,\
- CMessage, json_to_c_header_name
+ CMessage, json_to_c_header_name, CAlias
from vapi_json_parser import JsonParser
@@ -21,6 +21,10 @@ class CppEnum(CEnum):
pass
+class CppAlias(CAlias):
+ pass
+
+
class CppSimpleType (CSimpleType):
pass
@@ -251,7 +255,8 @@ if __name__ == '__main__':
struct_type_class=CppStructType,
field_class=CppField,
enum_class=CppEnum,
- message_class=CppMessage)
+ message_class=CppMessage,
+ alias_class=CppAlias)
gen_cpp_headers(jsonparser, logger, args.prefix, args.gen_h_prefix,
args.remove_path)
diff --git a/src/vpp-api/vapi/vapi_json_parser.py b/src/vpp-api/vapi/vapi_json_parser.py
index 39acca0b538..3eb5d3616e1 100644
--- a/src/vpp-api/vapi/vapi_json_parser.py
+++ b/src/vpp-api/vapi/vapi_json_parser.py
@@ -45,6 +45,10 @@ class Field(object):
return self.is_vla() or self.type.has_vla()
+class Alias(Field):
+ pass
+
+
class Type(object):
def __init__(self, name):
self.name = name
@@ -55,12 +59,6 @@ class Type(object):
class SimpleType (Type):
- def __init__(self, name):
- super(SimpleType, self).__init__(name)
-
- def __str__(self):
- return self.name
-
def has_vla(self):
return False
@@ -290,11 +288,12 @@ class JsonParser(object):
def __init__(self, logger, files, simple_type_class=SimpleType,
enum_class=Enum, union_class=Union,
struct_type_class=StructType, field_class=Field,
- message_class=Message):
+ message_class=Message, alias_class=Alias):
self.services = {}
self.messages = {}
self.enums = {}
self.unions = {}
+ self.aliases = {}
self.types = {
x: simple_type_class(x) for x in [
'i8', 'i16', 'i32', 'i64',
@@ -310,6 +309,7 @@ class JsonParser(object):
self.union_class = union_class
self.struct_type_class = struct_type_class
self.field_class = field_class
+ self.alias_class = alias_class
self.message_class = message_class
self.exceptions = []
@@ -317,6 +317,7 @@ class JsonParser(object):
self.types_by_json = {}
self.enums_by_json = {}
self.unions_by_json = {}
+ self.aliases_by_json = {}
self.messages_by_json = {}
self.logger = logger
for f in files:
@@ -329,6 +330,7 @@ class JsonParser(object):
self.types_by_json[path] = []
self.enums_by_json[path] = []
self.unions_by_json[path] = []
+ self.aliases_by_json[path] = []
self.messages_by_json[path] = {}
with open(path) as f:
j = json.load(f)
@@ -369,6 +371,19 @@ class JsonParser(object):
self.unions[union.name] = union
self.logger.debug("Parsed union: %s" % union)
self.unions_by_json[path].append(union)
+ for name, body in j['aliases'].iteritems():
+ if name in self.aliases:
+ progress = progress + 1
+ continue
+ if 'length' in body:
+ array_len = body['length']
+ else:
+ array_len = None
+ t = self.types[body['type']]
+ alias = self.alias_class(name, t, array_len)
+ self.aliases[name] = alias
+ self.logger.debug("Parsed alias: %s" % alias)
+ self.aliases_by_json[path].append(alias)
for t in j['types']:
if t[0] in self.types:
progress = progress + 1
@@ -429,12 +444,16 @@ class JsonParser(object):
return self.enums[name]
elif name in self.unions:
return self.unions[name]
+ elif name in self.aliases:
+ return self.aliases[name]
elif mundane_name in self.types:
return self.types[mundane_name]
elif mundane_name in self.enums:
return self.enums[mundane_name]
elif mundane_name in self.unions:
return self.unions[mundane_name]
+ elif mundane_name in self.aliases:
+ return self.aliases[mundane_name]
raise ParseError(
"Could not find type, enum or union by magic name `%s' nor by "
"mundane name `%s'" % (name, mundane_name))