vppapigen: add parser support for enumflags

Type: improvement

Change-Id: I0f15862cc8399a4f7c8a81fe44ba8b27d8772278
Signed-off-by: Paul Vinciguerra <pvinci@vinciconsulting.com>
Signed-off-by: Ole Troan <ot@cisco.com>
(cherry picked from commit e15523297b)
This commit is contained in:
Paul Vinciguerra
2020-11-24 23:26:06 -05:00
committed by Ole Tr�an
parent 86ffb6b232
commit a51f9b3747
4 changed files with 221 additions and 57 deletions

View File

@ -1,9 +1,11 @@
#!/usr/bin/env python3
import unittest
from vppapigen import VPPAPI, Option, ParseError, Union, foldup_crcs, global_types
from vppapigen import VPPAPI, Option, ParseError, Union, foldup_crcs, \
global_types
import vppapigen
# TODO
# - test parsing of options, typedefs, enums, defines
# - test JSON, C output
@ -19,6 +21,7 @@ class TestVersion(unittest.TestCase):
r = self.parser.parse_string(version_string)
self.assertTrue(isinstance(r[0], Option))
class TestUnion(unittest.TestCase):
@classmethod
def setUpClass(cls):
@ -49,7 +52,6 @@ class TestUnion(unittest.TestCase):
self.assertTrue(r[0].vla)
s = self.parser.process(r)
test_string2 = '''
union foo_union_vla2 {
u32 a;
@ -74,6 +76,7 @@ class TestUnion(unittest.TestCase):
'''
self.assertRaises(ValueError, self.parser.parse_string, test_string3)
class TestTypedef(unittest.TestCase):
@classmethod
def setUpClass(cls):
@ -169,7 +172,7 @@ class TestCRC(unittest.TestCase):
'''
crc = get_crc(test_string, 'foo')
# modify underlaying type
# modify underlying type
test_string = '''
typedef list { u8 foo2; };
autoreply define foo { u8 foo; vl_api_list_t l;};
@ -255,5 +258,97 @@ autoreply define sr_policy_add
self.assertNotEqual(crc, crc2)
class TestEnum(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.parser = VPPAPI()
def test_enum_as_enum(self):
test_string = """\
enum tunnel_mode : u8
{
/** point-to-point */
TUNNEL_API_MODE_P2P = 0,
/** multi-point */
TUNNEL_API_MODE_MP,
};
"""
r = self.parser.parse_string(test_string)
self.assertIsNotNone(r)
s = self.parser.process(r)
for o in s['types']:
if o.type == 'Enum':
self.assertEqual(o.name, "tunnel_mode")
break
else:
self.fail()
def test_enumflag_as_enum(self):
test_string = """\
enum virtio_flags {
VIRTIO_API_FLAG_GSO = 1, /* enable gso on the interface */
VIRTIO_API_FLAG_CSUM_OFFLOAD = 2, /* enable checksum offload without gso on the interface */
VIRTIO_API_FLAG_GRO_COALESCE = 4, /* enable packet coalescing on tx side, provided gso enabled */
VIRTIO_API_FLAG_PACKED = 8, /* enable packed ring support, provided it is available from backend */
VIRTIO_API_FLAG_IN_ORDER = 16, /* enable in order support, provided it is available from backend */
VIRTIO_API_FLAG_BUFFERING = 32 [backwards_compatible], /* enable buffering to handle backend jitter/delays */
};"""
r = self.parser.parse_string(test_string)
self.assertIsNotNone(r)
s = self.parser.process(r)
for o in s['types']:
if o.type == 'Enum':
self.assertEqual(o.name, "virtio_flags")
break
else:
self.fail()
class TestEnumFlag(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.parser = VPPAPI()
def test_enum_as_enumflag(self):
test_string = """\
enumflag tunnel_mode_ef : u8
{
/** point-to-point */
TUNNEL_API_MODE_P2P = 0,
/** multi-point */
TUNNEL_API_MODE_MP,
TUNNEL_API_MODE_FOO,
TUNNEL_API_MODE_BAR,
};"""
with self.assertRaises(TypeError) as ctx:
r = self.parser.parse_string(test_string)
self.assertTrue(str(ctx.exception).startswith(
'tunnel_mode_ef is not a flag enum.'))
def test_enumflag_as_enumflag(self):
test_string = """\
enumflag virtio_flags_ef {
VIRTIO_API_FLAG_GSO = 1, /* enable gso on the interface */
VIRTIO_API_FLAG_CSUM_OFFLOAD = 2, /* enable checksum offload without gso on the interface */
VIRTIO_API_FLAG_GRO_COALESCE = 4, /* enable packet coalescing on tx side, provided gso enabled */
VIRTIO_API_FLAG_PACKED = 8, /* enable packed ring support, provided it is available from backend */
VIRTIO_API_FLAG_IN_ORDER = 16, /* enable in order support, provided it is available from backend */
VIRTIO_API_FLAG_BUFFERING = 32 [backwards_compatible], /* enable buffering to handle backend jitter/delays */
};"""
r = self.parser.parse_string(test_string)
self.assertIsNotNone(r)
s = self.parser.process(r)
for o in s['types']:
if o.type == 'EnumFlag':
self.assertEqual(o.name, "virtio_flags_ef")
break
else:
self.fail()
if __name__ == '__main__':
unittest.main(verbosity=2)

File diff suppressed because it is too large Load Diff

View File

@ -32,6 +32,7 @@ import shutil
process_imports = False
###############################################################################
class ToJSON():
'''Class to generate functions converting from VPP binary API to JSON.'''
@ -89,7 +90,7 @@ class ToJSON():
return 'cJSON_AddBoolToObject', '', False
# Lookup type name check if it's enum
if vt.type == 'Enum':
if vt.type == 'Enum' or vt.type == 'EnumFlag':
return '{t}_tojson'.format(t=t), '', True
return '{t}_tojson'.format(t=t), '&', True
@ -186,6 +187,7 @@ class ToJSON():
write('}\n')
_dispatch['Enum'] = print_enum
_dispatch['EnumFlag'] = print_enum
def print_typedef(self, o):
'''Create cJSON (dictionary) object from VPP API typedef'''
@ -454,6 +456,7 @@ class FromJSON():
write('}\n')
_dispatch['Enum'] = print_enum
_dispatch['EnumFlag'] = print_enum
def print_typedef(self, o):
'''Convert from JSON object to VPP API binary representation'''
@ -845,6 +848,7 @@ class Printfun():
write(' }\n')
_dispatch['Enum'] = print_enum
_dispatch['EnumFlag'] = print_enum
def print_obj(self, o, stream):
'''Entry point'''
@ -935,7 +939,7 @@ static inline u8 *format_vl_api_{name}_t (u8 *s, va_list * args)
'''
for t in objs:
if t.__class__.__name__ == 'Enum':
if t.__class__.__name__ == 'Enum' or t.__class__.__name__ == 'EnumFlag':
write(signature.format(name=t.name))
pp.print_enum(t.block, stream)
write(' return s;\n')
@ -1071,7 +1075,7 @@ static inline void vl_api_{name}_t_endian (vl_api_{name}_t *a)
'''
for t in objs:
if t.__class__.__name__ == 'Enum':
if t.__class__.__name__ == 'Enum' or t.__class__.__name__ == 'EnumFlag' :
output += signature.format(name=t.name)
if t.enumtype in ENDIAN_STRINGS:
output += (' *a = {}(*a);\n'
@ -1191,7 +1195,7 @@ def generate_include_types(s, module, stream):
(o.alias['type'], o.name, o.alias['length']))
else:
write('typedef %s vl_api_%s_t;\n' % (o.alias['type'], o.name))
elif tname == 'Enum':
elif tname == 'Enum' or tname == 'EnumFlag':
if o.enumtype == 'u32':
write("typedef enum {\n")
else:

View File

@ -96,6 +96,8 @@ def run(args, filename, s):
if o.__class__.__name__ == 'Union']))
j['enums'] = (walk_enums([o for o in s['types']
if o.__class__.__name__ == 'Enum']))
j['enumflags'] = (walk_enums([o for o in s['types']
if o.__class__.__name__ == 'EnumFlag']))
j['services'] = walk_services(s['Service'])
j['options'] = s['Option']
j['aliases'] = {o.name:o.alias for o in s['types'] if o.__class__.__name__ == 'Using'}