summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOle Troan <ot@cisco.com>2019-04-30 10:04:36 +0200
committerPaul Vinciguerra <pvinci@vinciconsulting.com>2019-06-07 10:38:35 +0000
commit85465588b18fef9c4712f864f512e00741e2d4f2 (patch)
treed5914b37782edfa7d85a2366e080ca97bc7ece1f
parent8dbfb433619011b649b1b511ad88969a7f909861 (diff)
API: Add support for "defaults"
Add support in the API language for specifying a field default. Add default support in Python binding. define foo { u16 mtu [default = 1500]; }; This is client side only. I.e. if the mtu argument is not passed to the foo function, the client language binding will set it default to 1500. Change-Id: I5df43f3cd87cb300b40ca38e15dcab25b40e424a Signed-off-by: Ole Troan <ot@cisco.com>
-rwxr-xr-xsrc/tools/vppapigen/vppapigen.py21
-rwxr-xr-xsrc/vpp-api/python/vpp_papi/tests/test_vpp_serializer.py22
-rw-r--r--src/vpp-api/python/vpp_papi/vpp_serializer.py66
-rw-r--r--src/vpp-api/python/vpp_papi/vpp_stats.py10
-rw-r--r--src/vpp-api/python/vpp_papi/vpp_transport_socket.py12
5 files changed, 99 insertions, 32 deletions
diff --git a/src/tools/vppapigen/vppapigen.py b/src/tools/vppapigen/vppapigen.py
index c60e43e8ed3..fd87b18792b 100755
--- a/src/tools/vppapigen/vppapigen.py
+++ b/src/tools/vppapigen/vppapigen.py
@@ -509,18 +509,31 @@ class VPPAPIParser(object):
else:
p[0] = p[1]
+ def p_field_options(self, p):
+ '''field_options : field_option
+ | field_options field_option'''
+ if len(p) == 2:
+ p[0] = p[1]
+ else:
+ p[0] = { **p[1], **p[2] }
+
+ def p_field_option(self, p):
+ '''field_option : ID '=' assignee ','
+ | ID '=' assignee
+ '''
+ p[0] = { p[1]: p[3] }
+
def p_declaration(self, p):
'''declaration : type_specifier ID ';'
- | type_specifier ID '[' ID '=' assignee ']' ';' '''
- if len(p) == 9:
- p[0] = Field(p[1], p[2], {p[4]: p[6]})
+ | type_specifier ID '[' field_options ']' ';' '''
+ if len(p) == 7:
+ p[0] = Field(p[1], p[2], p[4])
elif len(p) == 4:
p[0] = Field(p[1], p[2])
else:
self._parse_error('ERROR')
self.fields.append(p[2])
-
def p_declaration_array(self, p):
'''declaration : type_specifier ID '[' NUM ']' ';'
| type_specifier ID '[' ID ']' ';' '''
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 ec7334712ab..74a0a62c021 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
@@ -9,6 +9,7 @@ import logging
import sys
from ipaddress import *
+
class TestLimits(unittest.TestCase):
def test_limit(self):
limited_type = VPPType('limited_type_t',
@@ -16,14 +17,27 @@ class TestLimits(unittest.TestCase):
unlimited_type = VPPType('limited_type_t',
[['string', 'name']])
-
- b = limited_type.pack({'name':'foobar'})
+ b = limited_type.pack({'name': 'foobar'})
self.assertEqual(len(b), 10)
- b = unlimited_type.pack({'name':'foobar'})
+ b = unlimited_type.pack({'name': 'foobar'})
self.assertEqual(len(b), 10)
with self.assertRaises(VPPSerializerValueError):
- b = limited_type.pack({'name':'foobar'*3})
+ b = limited_type.pack({'name': 'foobar'*3})
+
+
+class TestDefaults(unittest.TestCase):
+ def test_defaults(self):
+ default_type = VPPType('default_type_t',
+ [['u16', 'mtu', {'default': 1500, 'limit': 0}]])
+
+ b = default_type.pack({})
+ self.assertEqual(len(b), 2)
+
+ nt, size = default_type.unpack(b)
+ self.assertEqual(len(b), size)
+ self.assertEqual(nt.mtu, 1500)
+
class TestAddType(unittest.TestCase):
diff --git a/src/vpp-api/python/vpp_papi/vpp_serializer.py b/src/vpp-api/python/vpp_papi/vpp_serializer.py
index d1093318ed0..2d775d558b4 100644
--- a/src/vpp-api/python/vpp_papi/vpp_serializer.py
+++ b/src/vpp-api/python/vpp_papi/vpp_serializer.py
@@ -16,6 +16,10 @@
import struct
import collections
import sys
+import logging
+from . import vpp_format
+import ipaddress
+import socket
if sys.version_info <= (3, 4):
from aenum import IntEnum
@@ -27,11 +31,6 @@ if sys.version_info <= (3, 6):
else:
from enum import IntFlag
-import logging
-from . import vpp_format
-import ipaddress
-
-import socket
#
# Set log-level in application by doing e.g.:
@@ -69,7 +68,7 @@ def conversion_unpacker(data, field_type):
class BaseTypes(object):
- def __init__(self, type, elements=0):
+ def __init__(self, type, elements=0, options=None):
base_types = {'u8': '>B',
'string': '>s',
'u16': '>H',
@@ -85,10 +84,18 @@ class BaseTypes(object):
else:
self.packer = struct.Struct(base_types[type])
self.size = self.packer.size
+ self.options = options
+
+ def __call__(self, args):
+ self.options = args
+ return self
def pack(self, data, kwargs=None):
if not data: # Default to zero if not specified
- data = 0
+ if self.options and 'default' in self.options:
+ data = self.options['default']
+ else:
+ data = 0
return self.packer.pack(data)
def unpack(self, data, offset, result=None, ntc=False):
@@ -148,6 +155,10 @@ class FixedList_u8(object):
self.size = self.packer.size
self.field_type = field_type
+ def __call__(self, args):
+ self.options = args
+ return self
+
def pack(self, data, kwargs=None):
"""Packs a fixed length bytestring. Left-pads with zeros
if input data is too short."""
@@ -183,6 +194,10 @@ class FixedList(object):
self.name = name
self.field_type = field_type
+ def __call__(self, args):
+ self.options = args
+ return self
+
def pack(self, list, kwargs):
if len(list) != self.num:
raise VPPSerializerValueError(
@@ -214,6 +229,10 @@ class VLAList(object):
self.size = self.packer.size
self.length_field = len_field_name
+ def __call__(self, args):
+ self.options = args
+ return self
+
def pack(self, list, kwargs=None):
if not list:
return b""
@@ -257,6 +276,10 @@ class VLAList_legacy():
self.packer = types[field_type]
self.size = self.packer.size
+ def __call__(self, args):
+ self.options = args
+ return self
+
def pack(self, list, kwargs=None):
if self.packer.size == 1:
return bytes(list)
@@ -298,6 +321,10 @@ class VPPEnumType(object):
self.enum = IntFlag(name, e_hash)
types[name] = self
+ def __call__(self, args):
+ self.options = args
+ return self
+
def __getattr__(self, name):
return self.enum[name]
@@ -338,6 +365,10 @@ class VPPUnionType(object):
types[name] = self
self.tuple = collections.namedtuple(name, fields, rename=True)
+ def __call__(self, args):
+ self.options = args
+ return self
+
# Union of variable length?
def pack(self, data, kwargs=None):
if not data:
@@ -383,6 +414,10 @@ class VPPTypeAlias(object):
types[name] = self
+ def __call__(self, args):
+ self.options = args
+ return self
+
def pack(self, data, kwargs=None):
if data and conversion_required(data, self.name):
try:
@@ -423,14 +458,14 @@ class VPPType(object):
raise VPPSerializerValueError(
'Unknown message type {}'.format(f_type))
- l = len(f)
+ fieldlen = len(f)
options = [x for x in f if type(x) is dict]
if len(options):
self.options = options[0]
- l -= 1
+ fieldlen -= 1
else:
self.options = {}
- if l == 3: # list
+ if fieldlen == 3: # list
list_elements = f[2]
if list_elements == 0:
p = VLAList_legacy(f_name, f_type)
@@ -443,15 +478,12 @@ class VPPType(object):
p = FixedList(f_name, f_type, list_elements)
self.packers.append(p)
size += p.size
- elif l == 4: # Variable length list
+ elif fieldlen == 4: # Variable length list
length_index = self.fields.index(f[3])
p = VLAList(f_name, f_type, f[3], length_index)
self.packers.append(p)
else:
- if f_type == 'string':
- p = types[f_type](self.options)
- else:
- p = types[f_type]
+ p = types[f_type](self.options)
self.packers.append(p)
size += p.size
@@ -459,6 +491,10 @@ class VPPType(object):
self.tuple = collections.namedtuple(name, self.fields, rename=True)
types[name] = self
+ def __call__(self, args):
+ self.options = args
+ return self
+
def pack(self, data, kwargs=None):
if not kwargs:
kwargs = data
diff --git a/src/vpp-api/python/vpp_papi/vpp_stats.py b/src/vpp-api/python/vpp_papi/vpp_stats.py
index 76ccf1042f6..de72249ac6b 100644
--- a/src/vpp-api/python/vpp_papi/vpp_stats.py
+++ b/src/vpp-api/python/vpp_papi/vpp_stats.py
@@ -73,7 +73,8 @@ void stat_segment_disconnect (void);
uint32_t *stat_segment_ls_r (uint8_t ** patterns, stat_client_main_t * sm);
uint32_t *stat_segment_ls (uint8_t ** pattern);
-stat_segment_data_t *stat_segment_dump_r (uint32_t * stats, stat_client_main_t * sm);
+stat_segment_data_t *stat_segment_dump_r (uint32_t * stats,
+ stat_client_main_t * sm);
stat_segment_data_t *stat_segment_dump (uint32_t * counter_vec);
void stat_segment_data_free (stat_segment_data_t * res);
@@ -133,7 +134,9 @@ def error_vec_list(api, e):
return vec
def name_vec_list(api, e):
- return [ffi.string(e[i]).decode('utf-8') for i in range(api.stat_segment_vec_len(e)) if e[i] != ffi.NULL]
+ return [ffi.string(e[i]).decode('utf-8') for i in
+ range(api.stat_segment_vec_len(e)) if e[i] != ffi.NULL]
+
def stat_entry_to_python(api, e):
# Scalar index
@@ -222,7 +225,8 @@ class VPPStats(object):
if rv == ffi.NULL:
raise VPPStatsIOError()
- return [ffi.string(self.api.stat_segment_index_to_name_r(rv[i], self.client)).decode('utf-8')
+ return [ffi.string(self.api.stat_segment_index_to_name_r(
+ rv[i], self.client)).decode('utf-8')
for i in range(self.api.stat_segment_vec_len(rv))]
def dump(self, counters):
diff --git a/src/vpp-api/python/vpp_papi/vpp_transport_socket.py b/src/vpp-api/python/vpp_papi/vpp_transport_socket.py
index 6989e9ac9ba..6e228e46e11 100644
--- a/src/vpp-api/python/vpp_papi/vpp_transport_socket.py
+++ b/src/vpp-api/python/vpp_papi/vpp_transport_socket.py
@@ -193,23 +193,23 @@ class VppTransport(object):
hdr = self.socket.recv(16)
if not hdr:
return
- (_, l, _) = self.header.unpack(hdr) # If at head of message
+ (_, hdrlen, _) = self.header.unpack(hdr) # If at head of message
# Read rest of message
- msg = self.socket.recv(l)
- if l > len(msg):
+ msg = self.socket.recv(hdrlen)
+ if hdrlen > len(msg):
nbytes = len(msg)
- buf = bytearray(l)
+ buf = bytearray(hdrlen)
view = memoryview(buf)
view[:nbytes] = msg
view = view[nbytes:]
- left = l - nbytes
+ left = hdrlen - nbytes
while left:
nbytes = self.socket.recv_into(view, left)
view = view[nbytes:]
left -= nbytes
return buf
- if l == len(msg):
+ if hdrlen == len(msg):
return msg
raise VppTransportSocketIOError(1, 'Unknown socket read error')