blob: 75d6a1416fa3ddad098a9da6eb114a0db71868d5 [file] [log] [blame]
Ole Troan5f9dcff2016-08-01 04:59:13 +02001#!/usr/bin/env python
2#
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:
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
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.
15#
16
17from __future__ import print_function
18import argparse, sys, os, importlib, pprint
19
20parser = argparse.ArgumentParser(description='VPP Python API generator')
21parser.add_argument('-i', '--input', action="store", dest="inputfile", type=argparse.FileType('r'))
22parser.add_argument('-c', '--cfile', action="store")
23args = parser.parse_args()
24
25#
26# Read API definitions file into vppapidefs
27#
28exec(args.inputfile.read())
29
30# https://docs.python.org/3/library/struct.html
31format_struct = {'u8': 'B',
32 'u16' : 'H',
33 'u32' : 'I',
34 'i32' : 'i',
35 'u64' : 'Q',
36 'f64' : 'd',
37 'vl_api_ip4_fib_counter_t' : 'IBQQ',
38 'vl_api_ip6_fib_counter_t' : 'QQBQQ',
Filip Tehlar69a9b762016-09-23 10:00:52 +020039 'vl_api_lisp_adjacency_t' : 'B' * 35
Ole Troan5f9dcff2016-08-01 04:59:13 +020040 };
41#
42# NB: If new types are introduced in vpe.api, these must be updated.
43#
44type_size = {'u8': 1,
45 'u16' : 2,
46 'u32' : 4,
47 'i32' : 4,
48 'u64' : 8,
49 'f64' : 8,
50 'vl_api_ip4_fib_counter_t' : 21,
51 'vl_api_ip6_fib_counter_t' : 33,
Filip Tehlar69a9b762016-09-23 10:00:52 +020052 'vl_api_lisp_adjacency_t' : 35
Ole Troan5f9dcff2016-08-01 04:59:13 +020053};
54
55def eprint(*args, **kwargs):
56 print(*args, file=sys.stderr, **kwargs)
57
58def get_args(t):
59 argslist = []
60 for i in t:
61 if i[1][0] == '_':
62 argslist.append(i[1][1:])
63 else:
64 argslist.append(i[1])
65
66 return argslist
67
68def get_pack(f):
69 zeroarray = False
70 bytecount = 0
71 pack = ''
72 elements = 1
Ole Troan1732fc12016-08-30 21:03:51 +020073 if len(f) is 3 or len(f) is 4:
Ole Troan5f9dcff2016-08-01 04:59:13 +020074 size = type_size[f[0]]
75 bytecount += size * int(f[2])
76 # Check if we have a zero length array
77 if f[2] == '0':
78 # If len 3 zero array
79 elements = 0;
80 pack += format_struct[f[0]]
81 bytecount = size
82 elif size == 1:
83 n = f[2] * size
84 pack += str(n) + 's'
85 else:
86 pack += format_struct[f[0]] * int(f[2])
87 elements = int(f[2])
88 else:
89 bytecount += type_size[f[0]]
90 pack += format_struct[f[0]]
91 return (pack, elements, bytecount)
92
93
94'''
95def get_reply_func(f):
96 if f['name']+'_reply' in func_name:
97 return func_name[f['name']+'_reply']
98 if f['name'].find('_dump') > 0:
99 r = f['name'].replace('_dump','_details')
100 if r in func_name:
101 return func_name[r]
102 return None
103'''
104
105def footer_print():
106 print('''
107def msg_id_base_set(b):
108 global base
109 base = b
110
111import os
112name = os.path.splitext(os.path.basename(__file__))[0]
113 ''')
114 print(u"plugin_register(name, api_func_table, api_name_to_id,", vl_api_version, ", msg_id_base_set)")
115
116def api_table_print(name, i):
117 msg_id_in = 'VL_API_' + name.upper()
118 fstr = name + '_decode'
119 print('api_func_table.append(' + fstr + ')')
120 print('api_name_to_id["' + msg_id_in + '"] =', i)
121 print('')
122
Gabriel Gannece64b8e2016-09-19 14:05:15 +0200123
Ole Troan5f9dcff2016-08-01 04:59:13 +0200124def encode_print(name, id, t):
Ole Troan5f9dcff2016-08-01 04:59:13 +0200125 args = get_args(t)
Ole Troan5f9dcff2016-08-01 04:59:13 +0200126
127 if name.find('_dump') > 0:
128 multipart = True
129 else:
130 multipart = False
131
132 if len(args) < 4:
133 print(u"def", name + "(async = False):")
134 else:
135 print(u"def", name + "(" + ', '.join(args[3:]) + ", async = False):")
136 print(u" global base")
137 print(u" context = get_context(base + " + id + ")")
138
139 print('''
140 results_prepare(context)
141 waiting_for_reply_set()
142 ''')
143 if multipart == True:
144 print(u" results_more_set(context)")
145
Ole Troan1732fc12016-08-30 21:03:51 +0200146 t = list(t)
Ole Troan1732fc12016-08-30 21:03:51 +0200147
Gabriel Gannece64b8e2016-09-19 14:05:15 +0200148 # only the last field can be a variable-length-array
149 # it can either be 0, or a string
150 # first, deal with all the other fields
151 pack = '>' + ''.join([get_pack(f)[0] for f in t[:-1]])
152
153 # now see if the last field is a vla
154 if len(t[-1]) >= 3 and t[-1][2] == '0':
155 print(u" vpp_api.write(pack('" + pack + "', base + " +
156 id + ", 0, context, " + ', '.join(args[3:-1]) + ") + "
157 + args[-1] + ")")
158 else:
159 pack += get_pack(t[-1])[0]
160 print(u" vpp_api.write(pack('" + pack + "', base + " + id +
161 ", 0, context, " + ', '.join(args[3:]) + "))")
Ole Troan5f9dcff2016-08-01 04:59:13 +0200162
163 if multipart == True:
Ole Troan1732fc12016-08-30 21:03:51 +0200164 print(
165 u" vpp_api.write(pack('>HII', VL_API_CONTROL_PING, 0, context))")
Ole Troan5f9dcff2016-08-01 04:59:13 +0200166
167 print('''
168 if not async:
169 results_event_wait(context, 5)
170 return results_get(context)
171 return context
172 ''')
173
174def get_normal_pack(t, i, pack, offset):
175 while t:
176 f = t.pop(0)
177 i += 1
178 if len(f) >= 3:
179 return t, i, pack, offset, f
180 p, elements, size = get_pack(f)
181 pack += p
182 offset += size
183 return t, i, pack, offset, None
184
185def decode_print(name, t):
186 #
187 # Generate code for each element
188 #
189 print(u'def ' + name + u'_decode(msg):')
190 total = 0
191 args = get_args(t)
192 print(u" n = namedtuple('" + name + "', '" + ', '.join(args) + "')")
193 print(u" res = []")
194
195 pack = '>'
196 start = 0
197 end = 0
198 offset = 0
199 t = list(t)
200 i = 0
201 while t:
202 t, i, pack, offset, array = get_normal_pack(t, i, pack, offset)
203 if array:
204 p, elements, size = get_pack(array)
205
206 # Byte string
207 if elements > 0 and type_size[array[0]] == 1:
208 pack += p
209 offset += size * elements
210 continue
211
212 # Dump current pack string
213 if pack != '>':
214 print(u" tr = unpack_from('" + pack + "', msg[" + str(start) + ":])")
215 print(u" res.extend(list(tr))")
216 start += offset
217 pack = '>'
218
219 if elements == 0:
220 # This has to be the last element
221 if len(array) == 3:
222 print(u" res.append(msg[" + str(offset) + ":])")
223 if len(t) > 0:
224 eprint('WARNING: Variable length array must be last element in message', name, array)
225
226 continue
227 if size == 1 or len(p) == 1:
228 # Do it as a bytestring.
229 if p == 'B':
230 p = 's'
231 # XXX: Assume that length parameter is the previous field. Add validation.
232 print(u" c = res[" + str(i - 2) + "]")
233 print(u" tr = unpack_from('>' + str(c) + '" + p + "', msg[" + str(start) + ":])")
234 print(u" res.append(tr)")
235 continue
236 print(u" tr2 = []")
237 print(u" offset = " + str(total))
238 print(u" for j in range(res[" + str(i - 2) + "]):")
239 print(u" tr2.append(unpack_from('>" + p + "', msg[" + str(start) + ":], offset))")
240 print(u" offset += " + str(size))
241 print(u" res.append(tr2)")
242 continue
243
244 # Missing something!!
245 print(u" tr = unpack_from('>" + p + "', msg[" + str(start) + ":])")
246 start += size
247
248 print(u" res.append(tr)")
249
250 if pack != '>':
251 print(u" tr = unpack_from('" + pack + "', msg[" + str(start) + ":])")
252 print(u" res.extend(list(tr))")
253 print(u" return n._make(res)")
254 print('')
255
256#
257# Generate the main Python file
258#
259def main():
260 print('''
261#
262# AUTO-GENERATED FILE. PLEASE DO NOT EDIT.
263#
264from vpp_api_base import *
265from struct import *
266from collections import namedtuple
267import vpp_api
268api_func_table = []
269api_name_to_id = {}
270 ''')
271
Marek Gradzki101759c2016-09-29 13:20:52 +0200272 for i, a in enumerate(messages):
Ole Troan5f9dcff2016-08-01 04:59:13 +0200273 name = a[0]
274 encode_print(name, str(i), a[1:])
275 decode_print(name, a[1:])
276 api_table_print(name, i)
277 footer_print()
278
279if __name__ == "__main__":
280 main()