3 # Copyright (c) 2016 Cisco and/or its affiliates.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
17 from __future__ import print_function
18 import argparse, sys, os, importlib, pprint
20 parser = argparse.ArgumentParser(description='VPP Python API generator')
21 parser.add_argument('-i', '--input', action="store", dest="inputfile", type=argparse.FileType('r'))
22 parser.add_argument('-c', '--cfile', action="store")
23 args = parser.parse_args()
26 # Read API definitions file into vppapidefs
28 exec(args.inputfile.read())
30 # https://docs.python.org/3/library/struct.html
31 format_struct = {'u8': 'B',
37 'vl_api_fib_path_t' : 'IIBBBBBBBBBBBBBBBBBBBBB',
38 'vl_api_ip4_fib_counter_t' : 'IBQQ',
39 'vl_api_ip6_fib_counter_t' : 'QQBQQ',
40 'vl_api_lisp_adjacency_t' : 'B' * 35
43 # NB: If new types are introduced in vpe.api, these must be updated.
51 'vl_api_fib_path_t' : 29,
52 'vl_api_ip4_fib_counter_t' : 21,
53 'vl_api_ip6_fib_counter_t' : 33,
54 'vl_api_lisp_adjacency_t' : 35
57 def eprint(*args, **kwargs):
58 print(*args, file=sys.stderr, **kwargs)
64 argslist.append(i[1][1:])
75 if len(f) is 3 or len(f) is 4:
76 size = type_size[f[0]]
77 bytecount += size * int(f[2])
78 # Check if we have a zero length array
82 pack += format_struct[f[0]]
88 pack += format_struct[f[0]] * int(f[2])
91 bytecount += type_size[f[0]]
92 pack += format_struct[f[0]]
93 return (pack, elements, bytecount)
97 def get_reply_func(f):
98 if f['name']+'_reply' in func_name:
99 return func_name[f['name']+'_reply']
100 if f['name'].find('_dump') > 0:
101 r = f['name'].replace('_dump','_details')
109 def msg_id_base_set(b):
114 name = os.path.splitext(os.path.basename(__file__))[0]
116 print(u"plugin_register(name, api_func_table, api_name_to_id,", vl_api_version, ", msg_id_base_set)")
118 def api_table_print(name, i):
119 msg_id_in = 'VL_API_' + name.upper()
120 fstr = name + '_decode'
121 print('api_func_table.append(' + fstr + ')')
122 print('api_name_to_id["' + msg_id_in + '"] =', i)
126 def encode_print(name, id, t):
129 if name.find('_dump') > 0:
135 print(u"def", name + "(async = False):")
137 print(u"def", name + "(" + ', '.join(args[3:]) + ", async = False):")
138 print(u" global base")
139 print(u" context = get_context(base + " + id + ")")
142 results_prepare(context)
143 waiting_for_reply_set()
145 if multipart == True:
146 print(u" results_more_set(context)")
150 # only the last field can be a variable-length-array
151 # it can either be 0, or a string
152 # first, deal with all the other fields
153 pack = '>' + ''.join([get_pack(f)[0] for f in t[:-1]])
155 # named variable-length-array
156 if len(t[-1]) == 4 and t[-1][2] == '0' and t[-1][3] == t[-2][1]:
157 print(u" vpp_api.write(pack('" + pack + "', base + "
158 + id + ", 0, context, " + ', '.join(args[3:-2] + ["len(" + args[-1] + ")"])
159 + ") + " + args[-1] + ")")
161 # unnamed variable-length-array
162 elif len(t[-1]) >= 3 and t[-1][2] == '0':
163 print(u" vpp_api.write(pack('" + pack + "', base + " +
164 id + ", 0, context, " + ', '.join(args[3:-1]) + ") + "
168 # not a variable-length-array
170 pack += get_pack(t[-1])[0]
171 print(u" vpp_api.write(pack('" + pack + "', base + " + id +
172 ", 0, context, " + ', '.join(args[3:]) + "))")
174 if multipart == True:
176 u" vpp_api.write(pack('>HII', VL_API_CONTROL_PING, 0, context))")
180 results_event_wait(context, 5)
181 return results_get(context)
185 def get_normal_pack(t, i, pack, offset):
190 return t, i, pack, offset, f
191 p, elements, size = get_pack(f)
194 return t, i, pack, offset, None
196 def decode_print(name, t):
198 # Generate code for each element
200 print(u'def ' + name + u'_decode(msg):')
203 print(u" n = namedtuple('" + name + "', '" + ', '.join(args) + "')")
213 t, i, pack, offset, array = get_normal_pack(t, i, pack, offset)
215 p, elements, size = get_pack(array)
218 if elements > 0 and type_size[array[0]] == 1:
220 offset += size * elements
223 # Dump current pack string
225 print(u" tr = unpack_from('" + pack + "', msg[" + str(start) + ":])")
226 print(u" res.extend(list(tr))")
231 # This has to be the last element
233 print(u" res.append(msg[" + str(offset) + ":])")
235 eprint('WARNING: Variable length array must be last element in message', name, array)
238 if size == 1 or len(p) == 1:
239 # Do it as a bytestring.
242 # XXX: Assume that length parameter is the previous field. Add validation.
243 print(u" c = res[" + str(i - 2) + "]")
244 print(u" tr = unpack_from('>' + str(c) + '" + p + "', msg[" + str(start) + ":])")
245 print(u" res.append(tr)")
248 print(u" offset = " + str(total))
249 print(u" for j in range(res[" + str(i - 2) + "]):")
250 print(u" tr2.append(unpack_from('>" + p + "', msg[" + str(start) + ":], offset))")
251 print(u" offset += " + str(size))
252 print(u" res.append(tr2)")
255 # Missing something!!
256 print(u" tr = unpack_from('>" + p + "', msg[" + str(start) + ":])")
259 print(u" res.append(tr)")
262 print(u" tr = unpack_from('" + pack + "', msg[" + str(start) + ":])")
263 print(u" res.extend(list(tr))")
264 print(u" return n._make(res)")
268 # Generate the main Python file
273 # AUTO-GENERATED FILE. PLEASE DO NOT EDIT.
275 from vpp_api_base import *
277 from collections import namedtuple
283 for i, a in enumerate(messages):
285 encode_print(name, str(i), a[1:])
286 decode_print(name, a[1:])
287 api_table_print(name, i)
290 if __name__ == "__main__":