vppapigen: Fold up CRC from dependent types. 42/19142/5
authorOle Troan <ot@cisco.com>
Wed, 24 Apr 2019 12:31:18 +0000 (14:31 +0200)
committerPaul Vinciguerra <pvinci@vinciconsulting.com>
Fri, 7 Jun 2019 10:13:59 +0000 (10:13 +0000)
Change-Id: Id51f26f225cd567ca19efc2301e94fa88840ae8f
Signed-off-by: Ole Troan <ot@cisco.com>
Type: fix
Signed-off-by: Ole Troan <ot@cisco.com>
src/tools/vppapigen/vppapigen.py
src/tools/vppapigen/vppapigen_c.py
src/tools/vppapigen/vppapigen_json.py
src/vpp-api/vapi/vapi_json_parser.py

index ae2b0b1..c60e43e 100755 (executable)
@@ -18,15 +18,14 @@ sys.dont_write_bytecode = True
 
 # Global dictionary of new types (including enums)
 global_types = {}
-global_crc = 0
 
 
-def global_type_add(name):
+def global_type_add(name, obj):
     '''Add new type to the dictionary of types '''
     type_name = 'vl_api_' + name + '_t'
     if type_name in global_types:
         raise KeyError('Type is already defined: {}'.format(name))
-    global_types[type_name] = True
+    global_types[type_name] = obj
 
 
 # All your trace are belong to us!
@@ -122,15 +121,9 @@ class VPPAPILexer(object):
     t_ignore = ' \t'
 
 
-#
-# Side-effect: Sets global_crc
-#
-def crc_block(block):
-    global global_crc
+def crc_block_combine(block, crc):
     s = str(block).encode()
-    global_crc = binascii.crc32(s, global_crc)
-    return binascii.crc32(s) & 0xffffffff
-
+    return binascii.crc32(s, crc) & 0xffffffff
 
 class Service():
     def __init__(self, caller, reply, events=None, stream=False):
@@ -145,7 +138,7 @@ class Typedef():
         self.name = name
         self.flags = flags
         self.block = block
-        self.crc = crc_block(block)
+        self.crc = str(block).encode()
         self.manual_print = False
         self.manual_endian = False
         for f in flags:
@@ -153,7 +146,7 @@ class Typedef():
                 self.manual_print = True
             elif f == 'manual_endian':
                 self.manual_endian = True
-        global_type_add(name)
+        global_type_add(name, self)
 
     def __repr__(self):
         return self.name + str(self.flags) + str(self.block)
@@ -161,7 +154,6 @@ class Typedef():
 
 class Using():
     def __init__(self, name, alias):
-        global global_crc
         self.name = name
 
         if isinstance(alias, Array):
@@ -170,9 +162,8 @@ class Using():
         else:
             a = { 'type': alias.fieldtype }  # noqa: E201,E202
         self.alias = a
-        self.crc = binascii.crc32(str(alias).encode()) & 0xffffffff
-        global_crc = binascii.crc32(str(alias).encode(), global_crc)
-        global_type_add(name)
+        self.crc = str(alias).encode()
+        global_type_add(name, self)
 
     def __repr__(self):
         return self.name + str(self.alias)
@@ -183,11 +174,10 @@ class Union():
         self.type = 'Union'
         self.manual_print = False
         self.manual_endian = False
-        global global_crc
         self.name = name
         self.block = block
-        self.crc = crc_block(block)
-        global_type_add(name)
+        self.crc = str(block).encode()
+        global_type_add(name, self)
 
     def __repr__(self):
         return str(self.block)
@@ -198,7 +188,7 @@ class Define():
         self.name = name
         self.flags = flags
         self.block = block
-        self.crc = crc_block(block)
+        self.crc = str(block).encode()
         self.dont_trace = False
         self.manual_print = False
         self.manual_endian = False
@@ -238,8 +228,8 @@ class Enum():
                 block[i] = [b, count]
 
         self.block = block
-        self.crc = crc_block(block)
-        global_type_add(name)
+        self.crc = str(block).encode()
+        global_type_add(name, self)
 
     def __repr__(self):
         return self.name + str(self.block)
@@ -271,7 +261,7 @@ class Import():
 class Option():
     def __init__(self, option):
         self.option = option
-        self.crc = crc_block(option)
+        self.crc = str(option).encode()
 
     def __repr__(self):
         return str(self.option)
@@ -629,8 +619,13 @@ class VPPAPI(object):
         s['types'] = []
         s['Import'] = []
         s['Alias'] = {}
+        crc = 0
         for o in objs:
             tname = o.__class__.__name__
+            try:
+                crc = binascii.crc32(o.crc, crc)
+            except AttributeError:
+                pass
             if isinstance(o, Define):
                 s[tname].append(o)
                 if o.autoreply:
@@ -658,6 +653,8 @@ class VPPAPI(object):
         replies = {s.reply: s for s in s['Service']}
         seen_services = {}
 
+        s['file_crc'] = crc
+
         for service in svcs:
             if service not in msgs:
                 raise ValueError(
@@ -754,6 +751,23 @@ def dirlist_add(dirs):
 def dirlist_get():
     return dirlist
 
+def foldup_blocks(block, crc):
+    for b in block:
+        # Look up CRC in user defined types
+        if b.fieldtype.startswith('vl_api_'):
+            # Recursively
+            t = global_types[b.fieldtype]
+            try:
+                crc = crc_block_combine(t.block, crc)
+                return foldup_blocks(t.block, crc)
+            except:
+                pass
+    return crc
+
+def foldup_crcs(s):
+    for f in s:
+        f.crc = foldup_blocks(f.block,
+                              binascii.crc32(f.crc))
 
 #
 # Main
@@ -811,7 +825,8 @@ def main():
     # Add msg_id field
     s['Define'] = add_msg_id(s['Define'])
 
-    file_crc = global_crc & 0xffffffff
+    # Fold up CRCs
+    foldup_crcs(s['Define'])
 
     #
     # Debug
@@ -855,7 +870,7 @@ def main():
         raise Exception('Error importing output plugin: {}, {}'
                         .format(module_path, err))
 
-    result = plugin.run(filename, s, file_crc)
+    result = plugin.run(filename, s)
     if result:
         print(result, file=args.output)
     else:
index b34d063..93d14f3 100644 (file)
@@ -295,7 +295,7 @@ def version_tuple(s, module):
 #
 # Plugin entry point
 #
-def run(input_filename, s, file_crc):
+def run(input_filename, s):
     basename = os.path.basename(input_filename)
     filename, file_extension = os.path.splitext(basename)
     output = top_boilerplate.format(datestring=datestring,
@@ -308,6 +308,6 @@ def run(input_filename, s, file_crc):
     output += endianfun(s['types'] + s['Define'])
     output += version_tuple(s, basename)
     output += bottom_boilerplate.format(input_filename=basename,
-                                        file_crc=file_crc)
+                                        file_crc=s['file_crc'])
 
     return output
index 94a9e19..124c0d3 100644 (file)
@@ -26,7 +26,7 @@ def walk_services(s):
     return r
 
 
-def walk_defs(s):
+def walk_defs(s, is_message = False):
     r = []
     for t in s:
         d = []
@@ -47,7 +47,7 @@ def walk_defs(s):
             else:
                 raise ValueError("Error in processing array type %s" % b)
 
-        if t.crc:
+        if is_message and t.crc:
             c = {}
             c['crc'] = "{0:#0{1}x}".format(t.crc, 10)
             d.append(c)
@@ -59,15 +59,15 @@ def walk_defs(s):
 #
 # Plugin entry point
 #
-def run(filename, s, file_crc):
+def run(filename, s):
     j = {}
 
     j['types'] = walk_defs([o for o in s['types'] if o.__class__.__name__ == 'Typedef'])
-    j['messages'] = walk_defs(s['Define'])
+    j['messages'] = walk_defs(s['Define'], True)
     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['options'] = s['Option']
     j['aliases'] = s['Alias']
-    j['vl_api_version'] = hex(file_crc)
+    j['vl_api_version'] = hex(s['file_crc'])
     return json.dumps(j, indent=4, separators=(',', ': '))
index fbeb188..a9d2c81 100644 (file)
@@ -365,9 +365,8 @@ class JsonParser(object):
                         continue
                     try:
                         type_pairs = [[self.lookup_type_like_id(t), n]
-                                      for t, n in u[1:-1]]
-                        crc = u[-1]["crc"]
-                        union = self.union_class(name, type_pairs, crc)
+                                      for t, n in u[1:]]
+                        union = self.union_class(name, type_pairs, 0)
                         progress = progress + 1
                     except ParseError as e:
                         exceptions.append(e)