
Change-Id: I86e7382395a8b6471a0deaf57163718d41b71b83 Signed-off-by: Steven <sluong@cisco.com>
292 lines
8.5 KiB
Python
Executable File
292 lines
8.5 KiB
Python
Executable File
#!/usr/bin/env python
|
|
#
|
|
# Copyright (c) 2016 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.
|
|
#
|
|
|
|
from __future__ import print_function
|
|
import argparse, sys, os, importlib, pprint
|
|
|
|
parser = argparse.ArgumentParser(description='VPP Python API generator')
|
|
parser.add_argument('-i', '--input', action="store", dest="inputfile", type=argparse.FileType('r'))
|
|
parser.add_argument('-c', '--cfile', action="store")
|
|
args = parser.parse_args()
|
|
|
|
#
|
|
# Read API definitions file into vppapidefs
|
|
#
|
|
exec(args.inputfile.read())
|
|
|
|
# https://docs.python.org/3/library/struct.html
|
|
format_struct = {'u8': 'B',
|
|
'u16' : 'H',
|
|
'u32' : 'I',
|
|
'i32' : 'i',
|
|
'u64' : 'Q',
|
|
'f64' : 'd',
|
|
'vl_api_fib_path_t' : 'IIBBBBBBBBBBBBBBBBBBBBB',
|
|
'vl_api_ip4_fib_counter_t' : 'IBQQ',
|
|
'vl_api_ip6_fib_counter_t' : 'QQBQQ',
|
|
'vl_api_lisp_adjacency_t' : 'B' * 35
|
|
};
|
|
#
|
|
# NB: If new types are introduced in vpe.api, these must be updated.
|
|
#
|
|
type_size = {'u8': 1,
|
|
'u16' : 2,
|
|
'u32' : 4,
|
|
'i32' : 4,
|
|
'u64' : 8,
|
|
'f64' : 8,
|
|
'vl_api_fib_path_t' : 29,
|
|
'vl_api_ip4_fib_counter_t' : 21,
|
|
'vl_api_ip6_fib_counter_t' : 33,
|
|
'vl_api_lisp_adjacency_t' : 35
|
|
};
|
|
|
|
def eprint(*args, **kwargs):
|
|
print(*args, file=sys.stderr, **kwargs)
|
|
|
|
def get_args(t):
|
|
argslist = []
|
|
for i in t:
|
|
if i[1][0] == '_':
|
|
argslist.append(i[1][1:])
|
|
else:
|
|
argslist.append(i[1])
|
|
|
|
return argslist
|
|
|
|
def get_pack(f):
|
|
zeroarray = False
|
|
bytecount = 0
|
|
pack = ''
|
|
elements = 1
|
|
if len(f) is 3 or len(f) is 4:
|
|
size = type_size[f[0]]
|
|
bytecount += size * int(f[2])
|
|
# Check if we have a zero length array
|
|
if f[2] == '0':
|
|
# If len 3 zero array
|
|
elements = 0;
|
|
pack += format_struct[f[0]]
|
|
bytecount = size
|
|
elif size == 1:
|
|
n = f[2] * size
|
|
pack += str(n) + 's'
|
|
else:
|
|
pack += format_struct[f[0]] * int(f[2])
|
|
elements = int(f[2])
|
|
else:
|
|
bytecount += type_size[f[0]]
|
|
pack += format_struct[f[0]]
|
|
return (pack, elements, bytecount)
|
|
|
|
|
|
'''
|
|
def get_reply_func(f):
|
|
if f['name']+'_reply' in func_name:
|
|
return func_name[f['name']+'_reply']
|
|
if f['name'].find('_dump') > 0:
|
|
r = f['name'].replace('_dump','_details')
|
|
if r in func_name:
|
|
return func_name[r]
|
|
return None
|
|
'''
|
|
|
|
def footer_print():
|
|
print('''
|
|
def msg_id_base_set(b):
|
|
global base
|
|
base = b
|
|
|
|
import os
|
|
name = os.path.splitext(os.path.basename(__file__))[0]
|
|
''')
|
|
print(u"plugin_register(name, api_func_table, api_name_to_id,", vl_api_version, ", msg_id_base_set)")
|
|
|
|
def api_table_print(name, i):
|
|
msg_id_in = 'VL_API_' + name.upper()
|
|
fstr = name + '_decode'
|
|
print('api_func_table.append(' + fstr + ')')
|
|
print('api_name_to_id["' + msg_id_in + '"] =', i)
|
|
print('')
|
|
|
|
|
|
def encode_print(name, id, t):
|
|
args = get_args(t)
|
|
|
|
if name.find('_dump') > 0:
|
|
multipart = True
|
|
else:
|
|
multipart = False
|
|
|
|
if len(args) < 4:
|
|
print(u"def", name + "(async = False):")
|
|
else:
|
|
print(u"def", name + "(" + ', '.join(args[3:]) + ", async = False):")
|
|
print(u" global base")
|
|
print(u" context = get_context(base + " + id + ")")
|
|
|
|
print('''
|
|
results_prepare(context)
|
|
waiting_for_reply_set()
|
|
''')
|
|
if multipart == True:
|
|
print(u" results_more_set(context)")
|
|
|
|
t = list(t)
|
|
|
|
# only the last field can be a variable-length-array
|
|
# it can either be 0, or a string
|
|
# first, deal with all the other fields
|
|
pack = '>' + ''.join([get_pack(f)[0] for f in t[:-1]])
|
|
|
|
# named variable-length-array
|
|
if len(t[-1]) == 4 and t[-1][2] == '0' and t[-1][3] == t[-2][1]:
|
|
print(u" vpp_api.write(pack('" + pack + "', base + "
|
|
+ id + ", 0, context, " + ', '.join(args[3:-2] + ["len(" + args[-1] + ")"])
|
|
+ ") + " + args[-1] + ")")
|
|
|
|
# unnamed variable-length-array
|
|
elif len(t[-1]) >= 3 and t[-1][2] == '0':
|
|
print(u" vpp_api.write(pack('" + pack + "', base + " +
|
|
id + ", 0, context, " + ', '.join(args[3:-1]) + ") + "
|
|
+ args[-1] + ")")
|
|
|
|
|
|
# not a variable-length-array
|
|
else:
|
|
pack += get_pack(t[-1])[0]
|
|
print(u" vpp_api.write(pack('" + pack + "', base + " + id +
|
|
", 0, context, " + ', '.join(args[3:]) + "))")
|
|
|
|
if multipart == True:
|
|
print(
|
|
u" vpp_api.write(pack('>HII', VL_API_CONTROL_PING, 0, context))")
|
|
|
|
print('''
|
|
if not async:
|
|
results_event_wait(context, 5)
|
|
return results_get(context)
|
|
return context
|
|
''')
|
|
|
|
def get_normal_pack(t, i, pack, offset):
|
|
while t:
|
|
f = t.pop(0)
|
|
i += 1
|
|
if len(f) >= 3:
|
|
return t, i, pack, offset, f
|
|
p, elements, size = get_pack(f)
|
|
pack += p
|
|
offset += size
|
|
return t, i, pack, offset, None
|
|
|
|
def decode_print(name, t):
|
|
#
|
|
# Generate code for each element
|
|
#
|
|
print(u'def ' + name + u'_decode(msg):')
|
|
total = 0
|
|
args = get_args(t)
|
|
print(u" n = namedtuple('" + name + "', '" + ', '.join(args) + "')")
|
|
print(u" res = []")
|
|
|
|
pack = '>'
|
|
start = 0
|
|
end = 0
|
|
offset = 0
|
|
t = list(t)
|
|
i = 0
|
|
while t:
|
|
t, i, pack, offset, array = get_normal_pack(t, i, pack, offset)
|
|
if array:
|
|
p, elements, size = get_pack(array)
|
|
|
|
# Byte string
|
|
if elements > 0 and type_size[array[0]] == 1:
|
|
pack += p
|
|
offset += size * elements
|
|
continue
|
|
|
|
# Dump current pack string
|
|
if pack != '>':
|
|
print(u" tr = unpack_from('" + pack + "', msg[" + str(start) + ":])")
|
|
print(u" res.extend(list(tr))")
|
|
start += offset
|
|
pack = '>'
|
|
|
|
if elements == 0:
|
|
# This has to be the last element
|
|
if len(array) == 3:
|
|
print(u" res.append(msg[" + str(offset) + ":])")
|
|
if len(t) > 0:
|
|
eprint('WARNING: Variable length array must be last element in message', name, array)
|
|
|
|
continue
|
|
if size == 1 or len(p) == 1:
|
|
# Do it as a bytestring.
|
|
if p == 'B':
|
|
p = 's'
|
|
# XXX: Assume that length parameter is the previous field. Add validation.
|
|
print(u" c = res[" + str(i - 2) + "]")
|
|
print(u" tr = unpack_from('>' + str(c) + '" + p + "', msg[" + str(start) + ":])")
|
|
print(u" res.append(tr)")
|
|
continue
|
|
print(u" tr2 = []")
|
|
print(u" offset = " + str(total))
|
|
print(u" for j in range(res[" + str(i - 2) + "]):")
|
|
print(u" tr2.append(unpack_from('>" + p + "', msg[" + str(start) + ":], offset))")
|
|
print(u" offset += " + str(size))
|
|
print(u" res.append(tr2)")
|
|
continue
|
|
|
|
# Missing something!!
|
|
print(u" tr = unpack_from('>" + p + "', msg[" + str(start) + ":])")
|
|
start += size
|
|
|
|
print(u" res.append(tr)")
|
|
|
|
if pack != '>':
|
|
print(u" tr = unpack_from('" + pack + "', msg[" + str(start) + ":])")
|
|
print(u" res.extend(list(tr))")
|
|
print(u" return n._make(res)")
|
|
print('')
|
|
|
|
#
|
|
# Generate the main Python file
|
|
#
|
|
def main():
|
|
print('''
|
|
#
|
|
# AUTO-GENERATED FILE. PLEASE DO NOT EDIT.
|
|
#
|
|
from vpp_api_base import *
|
|
from struct import *
|
|
from collections import namedtuple
|
|
import vpp_api
|
|
api_func_table = []
|
|
api_name_to_id = {}
|
|
''')
|
|
|
|
for i, a in enumerate(messages):
|
|
name = a[0]
|
|
encode_print(name, str(i), a[1:])
|
|
decode_print(name, a[1:])
|
|
api_table_print(name, i)
|
|
footer_print()
|
|
|
|
if __name__ == "__main__":
|
|
main()
|