summaryrefslogtreecommitdiffstats
path: root/src/vpp-api
diff options
context:
space:
mode:
authorOle Troan <ot@cisco.com>2018-12-11 13:04:01 +0100
committerDamjan Marion <dmarion@me.com>2018-12-12 00:34:43 +0000
commit0bcad32b3870f9998fa1393418081cdda685272f (patch)
tree0fcb518ffa5553bbec94c219cbc33fef48dbede3 /src/vpp-api
parent41b25cf6380d1420b24e191cd7e95cbce1e7cfdc (diff)
PAPI: Allow ipaddress object as argument and return values from API calls
The API calls that use any of vl_api_address_t, vl_api_ip4_address, vl_api_ip6_address_t, vl_api_prefix_t, vl_api_ip4_prefix_t, vl_api_ip6_prefix_t now accepts either the old style dictionary, a text string (2001:db8::/32) or an ipaddress ojbect. Unless it is called with '_no_type_conversion':True, it will also return an appropriate ipaddress object. Change-Id: I84e4a1577bd57f6b5ae725f316a523988b6a955b Signed-off-by: Ole Troan <ot@cisco.com>
Diffstat (limited to 'src/vpp-api')
-rwxr-xr-xsrc/vpp-api/python/vpp_papi/tests/test_vpp_serializer.py92
-rw-r--r--src/vpp-api/python/vpp_papi/vpp_format.py234
-rw-r--r--src/vpp-api/python/vpp_papi/vpp_papi.py22
-rw-r--r--src/vpp-api/python/vpp_papi/vpp_serializer.py138
4 files changed, 266 insertions, 220 deletions
diff --git a/src/vpp-api/python/vpp_papi/tests/test_vpp_serializer.py b/src/vpp-api/python/vpp_papi/tests/test_vpp_serializer.py
index ba3190cadf9..ca3afc4dcef 100755
--- a/src/vpp-api/python/vpp_papi/tests/test_vpp_serializer.py
+++ b/src/vpp-api/python/vpp_papi/tests/test_vpp_serializer.py
@@ -4,10 +4,10 @@ import unittest
from vpp_papi.vpp_serializer import VPPType, VPPEnumType
from vpp_papi.vpp_serializer import VPPUnionType, VPPMessage
from vpp_papi.vpp_serializer import VPPTypeAlias
-from vpp_papi.vpp_format import VPPFormat
from socket import inet_pton, AF_INET, AF_INET6
import logging
import sys
+from ipaddress import *
class TestAddType(unittest.TestCase):
@@ -27,8 +27,10 @@ class TestAddType(unittest.TestCase):
af = VPPEnumType('vl_api_address_family_t', [["ADDRESS_IP4", 0],
["ADDRESS_IP6", 1],
{"enumtype": "u32"}])
- ip4 = VPPType('vl_api_ip4_address_t', [['u8', 'address', 4]])
- ip6 = VPPType('vl_api_ip6_address_t', [['u8', 'address', 16]])
+ ip4 = VPPTypeAlias('vl_api_ip4_address_t', {'type': 'u8',
+ 'length': 4})
+ ip6 = VPPTypeAlias('vl_api_ip6_address_t', {'type': 'u8',
+ 'length': 16})
VPPUnionType('vl_api_address_union_t',
[["vl_api_ip4_address_t", "ip4"],
["vl_api_ip6_address_t", "ip6"]])
@@ -47,41 +49,34 @@ class TestAddType(unittest.TestCase):
'vla_address'],
['u8', 'is_cool']])
- b = ip4.pack({'address': inet_pton(AF_INET, '1.1.1.1')})
+ b = ip4.pack(inet_pton(AF_INET, '1.1.1.1'))
self.assertEqual(len(b), 4)
nt, size = ip4.unpack(b)
- self.assertEqual(nt.address, inet_pton(AF_INET, '1.1.1.1'))
+ self.assertEqual(str(nt), '1.1.1.1')
- b = ip6.pack({'address': inet_pton(AF_INET6, '1::1')})
+ b = ip6.pack(inet_pton(AF_INET6, '1::1'))
self.assertEqual(len(b), 16)
b = address.pack({'af': af.ADDRESS_IP4,
'un':
- {'ip4':
- {'address': inet_pton(AF_INET, '2.2.2.2')}}})
+ {'ip4': inet_pton(AF_INET, '2.2.2.2')}})
self.assertEqual(len(b), 20)
nt, size = address.unpack(b)
- self.assertEqual(nt.af, af.ADDRESS_IP4)
- self.assertEqual(nt.un.ip4.address,
- inet_pton(AF_INET, '2.2.2.2'))
- self.assertEqual(nt.un.ip6.address,
- inet_pton(AF_INET6, '0202:0202::'))
+ self.assertEqual(str(nt), '2.2.2.2')
# List of addresses
address_list = []
for i in range(4):
address_list.append({'af': af.ADDRESS_IP4,
'un':
- {'ip4':
- {'address': inet_pton(AF_INET, '2.2.2.2')}}})
+ {'ip4': inet_pton(AF_INET, '2.2.2.2')}})
b = va_address_list.pack({'count': len(address_list),
'addresses': address_list})
self.assertEqual(len(b), 81)
nt, size = va_address_list.unpack(b)
- self.assertEqual(nt.addresses[0].un.ip4.address,
- inet_pton(AF_INET, '2.2.2.2'))
+ self.assertEqual(str(nt.addresses[0]), '2.2.2.2')
b = message_with_va_address_list.pack({'vla_address':
{'count': len(address_list),
@@ -97,6 +92,12 @@ class TestAddType(unittest.TestCase):
{"enumtype": "u32"}])
ip4 = VPPTypeAlias('vl_api_ip4_address_t', {'type': 'u8',
'length': 4})
+ b = ip4.pack('1.1.1.1')
+ self.assertEqual(len(b), 4)
+ nt, size = ip4.unpack(b)
+
+ self.assertEqual(str(nt), '1.1.1.1')
+
ip6 = VPPTypeAlias('vl_api_ip6_address_t', {'type': 'u8',
'length': 16})
VPPUnionType('vl_api_address_union_t',
@@ -108,44 +109,65 @@ class TestAddType(unittest.TestCase):
['vl_api_address_union_t', 'un']])
prefix = VPPType('vl_api_prefix_t',
- [['vl_api_address_t', 'address'],
- ['u8', 'address_length']])
+ [['vl_api_address_t', 'address'],
+ ['u8', 'address_length']])
message = VPPMessage('svs',
- [['vl_api_prefix_t', 'prefix']])
+ [['vl_api_prefix_t', 'prefix']])
message_addr = VPPMessage('svs_address',
[['vl_api_address_t', 'address']])
b = message_addr.pack({'address': "1::1"})
self.assertEqual(len(b), 20)
nt, size = message_addr.unpack(b)
- self.assertEqual("1::1", VPPFormat.unformat(nt.address))
+ self.assertEqual("1::1", str(nt.address))
b = message_addr.pack({'address': "1.1.1.1"})
self.assertEqual(len(b), 20)
nt, size = message_addr.unpack(b)
- self.assertEqual("1.1.1.1", VPPFormat.unformat(nt.address))
+ self.assertEqual("1.1.1.1", str(nt.address))
- b = message.pack({'prefix': "1.1.1.1/24"})
+ b = message.pack({'prefix': "1.1.1.0/24"})
self.assertEqual(len(b), 21)
nt, size = message.unpack(b)
- self.assertEqual("1.1.1.1/24", VPPFormat.unformat(nt.prefix))
+ self.assertEqual("1.1.1.0/24", str(nt.prefix))
message_array = VPPMessage('address_array',
- [['vl_api_ip4_address_t',
+ [['vl_api_ip6_address_t',
'addresses', 2]])
- b = message_array.pack({'addresses': ["1::1", "2::2"]})
- self.assertEqual(len(b), 8)
-
+ b = message_array.pack({'addresses': [IPv6Address(u"1::1"), "2::2"]})
+ self.assertEqual(len(b), 32)
message_array_vla = VPPMessage('address_array_vla',
[['u32', 'num'],
- ['vl_api_ip4_address_t',
+ ['vl_api_ip6_address_t',
'addresses', 0, 'num']])
b = message_array_vla.pack({'addresses': ["1::1", "2::2"], 'num': 2})
- self.assertEqual(len(b), 12)
+ self.assertEqual(len(b), 36)
+
+ message_array4 = VPPMessage('address_array4',
+ [['vl_api_ip4_address_t',
+ 'addresses', 2]])
+ b = message_array4.pack({'addresses': ["1.1.1.1", "2.2.2.2"]})
+ self.assertEqual(len(b), 8)
+ b = message_array4.pack({'addresses': [IPv4Address(u"1.1.1.1"),
+ "2.2.2.2"]})
+ self.assertEqual(len(b), 8)
+
+ message = VPPMessage('address', [['vl_api_address_t', 'address']])
+ b = message.pack({'address': '1::1'})
+ self.assertEqual(len(b), 20)
+ b = message.pack({'address': '1.1.1.1'})
+ self.assertEqual(len(b), 20)
+ message = VPPMessage('prefix', [['vl_api_prefix_t', 'prefix']])
+ b = message.pack({'prefix': '1::1/130'})
+ self.assertEqual(len(b), 21)
+ b = message.pack({'prefix': IPv6Network(u'1::/119')})
+ self.assertEqual(len(b), 21)
+ b = message.pack({'prefix': IPv4Network(u'1.1.0.0/16')})
+ self.assertEqual(len(b), 21)
def test_zero_vla(self):
'''Default zero'ed out for VLAs'''
list = VPPType('vl_api_list_t',
- [['u8', 'count', 10]])
+ [['u8', 'count', 10]])
# Define an embedded VLA type
valist = VPPType('vl_api_valist_t',
@@ -153,12 +175,12 @@ class TestAddType(unittest.TestCase):
['u8', 'string', 0, 'count']])
# Define a message
vamessage = VPPMessage('vamsg',
- [['vl_api_valist_t', 'valist'],
- ['u8', 'is_something']])
+ [['vl_api_valist_t', 'valist'],
+ ['u8', 'is_something']])
message = VPPMessage('msg',
- [['vl_api_list_t', 'list'],
- ['u8', 'is_something']])
+ [['vl_api_list_t', 'list'],
+ ['u8', 'is_something']])
# Pack message without VLA specified
b = message.pack({'is_something': 1})
diff --git a/src/vpp-api/python/vpp_papi/vpp_format.py b/src/vpp-api/python/vpp_papi/vpp_format.py
index 908606a92cc..1b880ecd248 100644
--- a/src/vpp-api/python/vpp_papi/vpp_format.py
+++ b/src/vpp-api/python/vpp_papi/vpp_format.py
@@ -15,137 +15,107 @@
from socket import inet_pton, inet_ntop, AF_INET6, AF_INET
import socket
+import ipaddress
+# Copies from vl_api_address_t definition
+ADDRESS_IP4 = 0
+ADDRESS_IP6 = 1
-class VPPFormatError(Exception):
- pass
-
-
-class VPPFormat(object):
- VPPFormatError = VPPFormatError
-
- @staticmethod
- def format_vl_api_ip6_prefix_t(args):
- prefix, len = args.split('/')
- return {'prefix': {'address': inet_pton(AF_INET6, prefix)},
- 'len': int(len)}
-
- @staticmethod
- def unformat_vl_api_ip6_prefix_t(args):
- return "{}/{}".format(inet_ntop(AF_INET6, args.prefix),
- args.len)
-
- @staticmethod
- def format_vl_api_ip4_prefix_t(args):
- prefix, len = args.split('/')
- return {'prefix': {'address': inet_pton(AF_INET, prefix)},
- 'len': int(len)}
-
- @staticmethod
- def unformat_vl_api_ip4_prefix_t(args):
- return "{}/{}".format(inet_ntop(AF_INET, args.prefix),
- args.len)
-
- @staticmethod
- def format_vl_api_ip6_address_t(args):
- return {'address': inet_pton(AF_INET6, args)}
-
- @staticmethod
- def format_vl_api_ip4_address_t(args):
- return {'address': inet_pton(AF_INET, args)}
-
- @staticmethod
- def format_vl_api_address_t(args):
- try:
- return {'un': {'ip6': inet_pton(AF_INET6, args)},
- 'af': int(1)}
- except socket.error as e:
- return {'un': {'ip4': inet_pton(AF_INET, args)},
- 'af': int(0)}
-
- @staticmethod
- def unformat_vl_api_address_t(arg):
- if arg.af == 1:
- return inet_ntop(AF_INET6, arg.un.ip6)
- if arg.af == 0:
- return inet_ntop(AF_INET, arg.un.ip4)
- raise VPPFormatError
-
- @staticmethod
- def format_vl_api_prefix_t(args):
- prefix, len = args.split('/')
- return {'address': VPPFormat.format_vl_api_address_t(prefix),
- 'address_length': int(len)}
-
- @staticmethod
- def unformat_vl_api_prefix_t(arg):
- if arg.address.af == 1:
- return "{}/{}".format(inet_ntop(AF_INET6,
- arg.address.un.ip6),
- arg.address_length)
- if arg.address.af == 0:
- return "{}/{}".format(inet_ntop(AF_INET,
- arg.address.un.ip4),
- arg.address_length)
- raise VPPFormatError
-
- @staticmethod
- def format_u8(args):
- try:
- return int(args)
- except Exception as e:
- return args.encode()
-
- @staticmethod
- def format(typename, args):
- try:
- return getattr(VPPFormat, 'format_' + typename)(args)
- except AttributeError:
- # Default
- return (int(args))
-
- @staticmethod
- def unformat_bytes(args):
- try:
- return args.decode('utf-8')
- except ValueError as e:
- return args
-
- @staticmethod
- def unformat_list(args):
- s = '['
- for f in args:
- t = type(f).__name__
- if type(f) is int:
- s2 = str(f)
- else:
- s2 = VPPFormat.unformat_t(t, f)
- s += '{} '.format(s2)
- return s[:-1] + ']'
-
- @staticmethod
- def unformat(args):
- s = ''
- return VPPFormat.unformat_t(type(args).__name__, args)
- '''
- for i, f in enumerate(args):
- print('F', f)
- t = type(f).__name__
- if type(f) is int:
- s2 = str(f)
- else:
- s2 = VPPFormat.unformat_t(t, f)
- s += '{} {} '.format(args._fields[i], s2)
- return s[:-1]
- '''
-
- @staticmethod
- def unformat_t(typename, args):
- try:
- return getattr(VPPFormat, 'unformat_' + typename)(args)
- except AttributeError:
- # Type without explicit override
- return VPPFormat.unformat(args)
-
- # Default handling
- return args
+#
+# Type conversion for input arguments and return values
+#
+
+
+def format_vl_api_address_t(args):
+ try:
+ return {'un': {'ip6': inet_pton(AF_INET6, args)},
+ 'af': ADDRESS_IP6}
+ except socket.error as e:
+ return {'un': {'ip4': inet_pton(AF_INET, args)},
+ 'af': ADDRESS_IP4}
+
+
+def format_vl_api_prefix_t(args):
+ p, length = args.split('/')
+ return {'address': format_vl_api_address_t(p),
+ 'address_length': int(length)}
+
+
+def format_vl_api_ip6_prefix_t(args):
+ p, length = args.split('/')
+ return {'prefix': inet_pton(AF_INET6, p),
+ 'len': int(length)}
+
+
+def format_vl_api_ip4_prefix_t(args):
+ p, length = args.split('/')
+ return {'prefix': inet_pton(AF_INET, p),
+ 'len': int(length)}
+
+
+conversion_table = {
+ 'vl_api_ip6_address_t':
+ {
+ 'IPv6Address': lambda o: o.packed,
+ 'str': lambda s: inet_pton(AF_INET6, s)
+ },
+ 'vl_api_ip4_address_t':
+ {
+ 'IPv4Address': lambda o: o.packed,
+ 'str': lambda s: inet_pton(AF_INET, s)
+ },
+ 'vl_api_ip6_prefix_t':
+ {
+ 'IPv6Network': lambda o: {'prefix': o.network_address.packed,
+ 'len': o.prefixlen},
+ 'str': lambda s: format_vl_api_ip6_prefix_t(s)
+ },
+ 'vl_api_ip4_prefix_t':
+ {
+ 'IPv4Network': lambda o: {'prefix': o.network_address.packed,
+ 'len': o.prefixlen},
+ 'str': lambda s: format_vl_api_ip4_prefix_t(s)
+ },
+ 'vl_api_address_t':
+ {
+ 'IPv4Address': lambda o: {'af': ADDRESS_IP4, 'un': {'ip4': o.packed}},
+ 'IPv6Address': lambda o: {'af': ADDRESS_IP6, 'un': {'ip6': o.packed}},
+ 'str': lambda s: format_vl_api_address_t(s)
+ },
+ 'vl_api_prefix_t':
+ {
+ 'IPv4Network': lambda o: {'prefix':
+ {'af': ADDRESS_IP4, 'un':
+ {'ip4': o.network_address.packed}},
+ 'len': o.prefixlen},
+ 'IPv6Network': lambda o: {'prefix':
+ {'af': ADDRESS_IP6, 'un':
+ {'ip6': o.network_address.packed}},
+ 'len': o.prefixlen},
+ 'str': lambda s: format_vl_api_prefix_t(s)
+ },
+}
+
+
+def unformat_api_address_t(o):
+ if o.af == 1:
+ return ipaddress.IPv6Address(o.un.ip6)
+ if o.af == 0:
+ return ipaddress.IPv4Address(o.un.ip4)
+
+
+def unformat_api_prefix_t(o):
+ if isinstance(o.address, ipaddress.IPv4Address):
+ return ipaddress.IPv4Network((o.address, o.address_length), False)
+ if isinstance(o.address, ipaddress.IPv6Address):
+ return ipaddress.IPv6Network((o.address, o.address_length), False)
+
+
+conversion_unpacker_table = {
+ 'vl_api_ip6_address_t': lambda o: ipaddress.IPv6Address(o),
+ 'vl_api_ip6_prefix_t': lambda o: ipaddress.IPv6Network((o.prefix, o.len)),
+ 'vl_api_ip4_address_t': lambda o: ipaddress.IPv4Address(o),
+ 'vl_api_ip4_prefix_t': lambda o: ipaddress.IPv4Network((o.prefix, o.len)),
+ 'vl_api_address_t': lambda o: unformat_api_address_t(o),
+ 'vl_api_prefix_t': lambda o: unformat_api_prefix_t(o),
+}
diff --git a/src/vpp-api/python/vpp_papi/vpp_papi.py b/src/vpp-api/python/vpp_papi/vpp_papi.py
index c37334cd4e5..32abe14da94 100644
--- a/src/vpp-api/python/vpp_papi/vpp_papi.py
+++ b/src/vpp-api/python/vpp_papi/vpp_papi.py
@@ -28,7 +28,6 @@ import weakref
import atexit
from . vpp_serializer import VPPType, VPPEnumType, VPPUnionType, BaseTypes
from . vpp_serializer import VPPMessage, vpp_get_type, VPPTypeAlias
-from . vpp_format import VPPFormat
if sys.version[0] == '2':
import Queue as queue
@@ -56,11 +55,11 @@ def vpp_atexit(vpp_weakref):
vpp_instance.logger.debug('Cleaning up VPP on exit')
vpp_instance.disconnect()
-
-def vpp_iterator(d):
- if sys.version[0] == '2':
+if sys.version[0] == '2':
+ def vpp_iterator(d):
return d.iteritems()
- else:
+else:
+ def vpp_iterator(d):
return d.items()
@@ -409,7 +408,8 @@ class VPP(object):
# Create function for client side messages.
if name in self.services:
- if 'stream' in self.services[name] and self.services[name]['stream']:
+ if 'stream' in self.services[name] and \
+ self.services[name]['stream']:
multipart = True
else:
multipart = False
@@ -493,7 +493,7 @@ class VPP(object):
else:
raise VPPIOError(2, 'RPC reply message received in event handler')
- def decode_incoming_msg(self, msg):
+ def decode_incoming_msg(self, msg, no_type_conversion=False):
if not msg:
self.logger.warning('vpp_api.read failed')
return
@@ -508,7 +508,7 @@ class VPP(object):
if not msgobj:
raise VPPIOError(2, 'Reply message undefined')
- r, size = msgobj.unpack(msg)
+ r, size = msgobj.unpack(msg, ntc=no_type_conversion)
return r
def msg_handler_async(self, msg):
@@ -535,7 +535,7 @@ class VPP(object):
d = set(kwargs.keys()) - set(msg.field_by_name.keys())
if d:
raise VPPValueError('Invalid argument {} to {}'
- .format(list(d), msg.name))
+ .format(list(d), msg.name))
def _call_vpp(self, i, msg, multipart, **kwargs):
"""Given a message, send the message and await a reply.
@@ -560,6 +560,8 @@ class VPP(object):
context = kwargs['context']
kwargs['_vl_msg_id'] = i
+ no_type_conversion = kwargs.pop('_no_type_conversion', False)
+
try:
if self.transport.socket_index:
kwargs['client_index'] = self.transport.socket_index
@@ -582,7 +584,7 @@ class VPP(object):
msg = self.transport.read()
if not msg:
raise VPPIOError(2, 'VPP API client: read failed')
- r = self.decode_incoming_msg(msg)
+ r = self.decode_incoming_msg(msg, no_type_conversion)
msgname = type(r).__name__
if context not in r or r.context == 0 or context != r.context:
# Message being queued
diff --git a/src/vpp-api/python/vpp_papi/vpp_serializer.py b/src/vpp-api/python/vpp_papi/vpp_serializer.py
index 13721ff88d4..5dce03b6188 100644
--- a/src/vpp-api/python/vpp_papi/vpp_serializer.py
+++ b/src/vpp-api/python/vpp_papi/vpp_serializer.py
@@ -17,7 +17,10 @@ import struct
import collections
from enum import IntEnum
import logging
-from .vpp_format import VPPFormat
+from . import vpp_format
+import ipaddress
+import sys
+import socket
#
# Set log-level in application by doing e.g.:
@@ -26,6 +29,32 @@ from .vpp_format import VPPFormat
#
logger = logging.getLogger(__name__)
+if sys.version[0] == '2':
+ check = lambda d: type(d) is dict
+else:
+ check = lambda d: type(d) is dict or type(d) is bytes
+
+def conversion_required(data, field_type):
+ if check(data):
+ return False
+ try:
+ if type(data).__name__ in vpp_format.conversion_table[field_type]:
+ return True
+ except KeyError:
+ return False
+
+
+def conversion_packer(data, field_type):
+ t = type(data).__name__
+ return types[field_type].pack(vpp_format.
+ conversion_table[field_type][t](data))
+
+
+def conversion_unpacker(data, field_type):
+ if field_type not in vpp_format.conversion_unpacker_table:
+ return data
+ return vpp_format.conversion_unpacker_table[field_type](data)
+
class BaseTypes(object):
def __init__(self, type, elements=0):
@@ -51,7 +80,7 @@ class BaseTypes(object):
data = 0
return self.packer.pack(data)
- def unpack(self, data, offset, result=None):
+ def unpack(self, data, offset, result=None, ntc=False):
return self.packer.unpack_from(data, offset)[0], self.packer.size
@@ -79,19 +108,21 @@ class FixedList_u8(object):
self.packer = BaseTypes(field_type, num)
self.size = self.packer.size
- def pack(self, list, kwargs=None):
+ def pack(self, data, kwargs=None):
"""Packs a fixed length bytestring. Left-pads with zeros
if input data is too short."""
- if not list:
+ if not data:
return b'\x00' * self.size
- if len(list) > self.num:
+
+ if len(data) > self.num:
raise VPPSerializerValueError(
'Fixed list length error for "{}", got: {}'
' expected: {}'
- .format(self.name, len(list), self.num))
- return self.packer.pack(list)
+ .format(self.name, len(data), self.num))
+
+ return self.packer.pack(data)
- def unpack(self, data, offset=0, result=None):
+ def unpack(self, data, offset=0, result=None, ntc=False):
if len(data[offset:]) < self.num:
raise VPPSerializerValueError(
'Invalid array length for "{}" got {}'
@@ -105,6 +136,8 @@ class FixedList(object):
self.num = num
self.packer = types[field_type]
self.size = self.packer.size * num
+ self.name = name
+ self.field_type = field_type
def pack(self, list, kwargs):
if len(list) != self.num:
@@ -116,12 +149,12 @@ class FixedList(object):
b += self.packer.pack(e)
return b
- def unpack(self, data, offset=0, result=None):
+ def unpack(self, data, offset=0, result=None, ntc=False):
# Return a list of arguments
result = []
total = 0
for e in range(self.num):
- x, size = self.packer.unpack(data, offset)
+ x, size = self.packer.unpack(data, offset, ntc=ntc)
result.append(x)
offset += size
total += size
@@ -153,7 +186,7 @@ class VLAList(object):
b += self.packer.pack(e)
return b
- def unpack(self, data, offset=0, result=None):
+ def unpack(self, data, offset=0, result=None, ntc=False):
# Return a list of arguments
total = 0
@@ -162,11 +195,11 @@ class VLAList(object):
if result[self.index] == 0:
return b'', 0
p = BaseTypes('u8', result[self.index])
- return p.unpack(data, offset)
+ return p.unpack(data, offset, ntc=ntc)
r = []
for e in range(result[self.index]):
- x, size = self.packer.unpack(data, offset)
+ x, size = self.packer.unpack(data, offset, ntc=ntc)
r.append(x)
offset += size
total += size
@@ -187,7 +220,7 @@ class VLAList_legacy():
b += self.packer.pack(e)
return b
- def unpack(self, data, offset=0, result=None):
+ def unpack(self, data, offset=0, result=None, ntc=False):
total = 0
# Return a list of arguments
if (len(data) - offset) % self.packer.size:
@@ -196,7 +229,7 @@ class VLAList_legacy():
elements = int((len(data) - offset) / self.packer.size)
r = []
for e in range(elements):
- x, size = self.packer.unpack(data, offset)
+ x, size = self.packer.unpack(data, offset, ntc=ntc)
r.append(x)
offset += self.packer.size
total += size
@@ -227,7 +260,7 @@ class VPPEnumType(object):
def pack(self, data, kwargs=None):
return types['u32'].pack(data)
- def unpack(self, data, offset=0, result=None):
+ def unpack(self, data, offset=0, result=None, ntc=False):
x, size = types['u32'].unpack(data, offset)
return self.enum(x), size
@@ -272,31 +305,53 @@ class VPPUnionType(object):
r[:len(b)] = b
return r
- def unpack(self, data, offset=0, result=None):
+ def unpack(self, data, offset=0, result=None, ntc=False):
r = []
maxsize = 0
for k, p in self.packers.items():
- x, size = p.unpack(data, offset)
+ x, size = p.unpack(data, offset, ntc=ntc)
if size > maxsize:
maxsize = size
r.append(x)
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:
+class VPPTypeAlias(object):
+ def __init__(self, name, msgdef):
+ self.name = name
+ t = vpp_get_type(msgdef['type'])
+ if not t:
raise ValueError()
- if msgdef['type'] == 'u8':
- types[name] = FixedList_u8(name, msgdef['type'],
- msgdef['length'])
+ if 'length' in msgdef:
+ if msgdef['length'] == 0:
+ raise ValueError()
+ if msgdef['type'] == 'u8':
+ self.packer = FixedList_u8(name, msgdef['type'],
+ msgdef['length'])
+ self.size = self.packer.size
+ else:
+ self.packer = FixedList(name, msgdef['type'], msgdef['length'])
else:
- types[name] = FixedList(name, msgdef['type'], msgdef['length'])
- else:
- types[name] = t
+ self.packer = t
+ self.size = t.size
+
+ types[name] = self
+
+ def pack(self, data, kwargs=None):
+ if data and conversion_required(data, self.name):
+ try:
+ return conversion_packer(data, self.name)
+ # Python 2 and 3 raises different exceptions from inet_pton
+ except(OSError, socket.error, TypeError):
+ pass
+
+ return self.packer.pack(data, kwargs)
+
+ def unpack(self, data, offset=0, result=None, ntc=False):
+ t, size = self.packer.unpack(data, offset, result, ntc=ntc)
+ if not ntc:
+ return conversion_unpacker(t, self.name), size
+ return t, size
class VPPType(object):
@@ -352,9 +407,12 @@ class VPPType(object):
if not kwargs:
kwargs = data
b = bytes()
- for i, a in enumerate(self.fields):
- # Try one of the format functions
+ # Try one of the format functions
+ if data and conversion_required(data, self.name):
+ return conversion_packer(data, self.name)
+
+ for i, a in enumerate(self.fields):
if data and type(data) is not dict and a not in data:
raise VPPSerializerValueError(
"Invalid argument: {} expected {}.{}".
@@ -367,33 +425,27 @@ class VPPType(object):
else:
arg = data[a]
kwarg = kwargs[a] if a in kwargs else None
-
if isinstance(self.packers[i], VPPType):
- try:
- b += self.packers[i].pack(arg, kwarg)
- except ValueError:
- # Invalid argument, can we convert it?
- arg = VPPFormat.format(self.packers[i].name, data[a])
- data[a] = arg
- kwarg = arg
- b += self.packers[i].pack(arg, kwarg)
+ b += self.packers[i].pack(arg, kwarg)
else:
b += self.packers[i].pack(arg, kwargs)
return b
- def unpack(self, data, offset=0, result=None):
+ def unpack(self, data, offset=0, result=None, ntc=False):
# Return a list of arguments
result = []
total = 0
for p in self.packers:
- x, size = p.unpack(data, offset, result)
+ x, size = p.unpack(data, offset, result, ntc)
if type(x) is tuple and len(x) == 1:
x = x[0]
result.append(x)
offset += size
total += size
t = self.tuple._make(result)
+ if not ntc:
+ t = conversion_unpacker(t, self.name)
return t, total