blob: f93e89843a3c9a7109952733a52ba981302a669d [file] [log] [blame]
Ole Troandf87f802020-11-18 19:17:48 +01001#
2# Copyright (c) 2020 Cisco and/or its affiliates.
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at:
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14#
15
16#
17# Provide two classes FromJSON and TOJSON that converts between JSON and VPP's
18# binary API format
19#
20
21'''
22This module creates C code for core VPP, VPP plugins and client side VAT and
23VAT2 tests.
24'''
25
Ole Troan9d420872017-10-12 13:06:35 +020026import datetime
Klement Sekera0eb83f42021-12-02 16:36:34 +000027import itertools
Ole Troan9d420872017-10-12 13:06:35 +020028import os
Nirmoy Dasc9f40222018-06-28 10:18:43 +020029import time
Ole Troan33a58172019-09-04 09:12:29 +020030import sys
31from io import StringIO
Ole Troan2a1ca782019-09-19 01:08:30 +020032import shutil
Ole Troan9d420872017-10-12 13:06:35 +020033
Paul Vinciguerra9046e442020-11-20 23:10:09 -050034process_imports = False
35
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -050036
Ole Troandf87f802020-11-18 19:17:48 +010037###############################################################################
38class ToJSON():
39 '''Class to generate functions converting from VPP binary API to JSON.'''
40 _dispatch = {}
41 noprint_fields = {'_vl_msg_id': None,
42 'client_index': None,
43 'context': None}
44 is_number = {'u8': None,
45 'i8': None,
46 'u16': None,
47 'i16': None,
48 'u32': None,
49 'i32': None,
50 'u64': None,
51 'i64': None,
52 'f64': None,
53 }
54
55 def __init__(self, module, types, defines, imported_types, stream):
56 self.stream = stream
57 self.module = module
58 self.defines = defines
59 self.types = types
60 self.types_hash = {'vl_api_'+d.name+'_t':
61 d for d in types + imported_types}
62 self.defines_hash = {d.name: d for d in defines}
63
64 def header(self):
65 '''Output the top boilerplate.'''
66 write = self.stream.write
67 write('#ifndef included_{}_api_tojson_h\n'.format(self.module))
68 write('#define included_{}_api_tojson_h\n'.format(self.module))
69 write('#include <vppinfra/cJSON.h>\n\n')
Filip Tehlar36217e32021-07-23 08:51:10 +000070 write('#include <vppinfra/jsonformat.h>\n\n')
71 if self.module == 'interface_types':
72 write('#define vl_printfun\n')
73 write('#include <vnet/interface_types.api.h>\n\n')
Ole Troandf87f802020-11-18 19:17:48 +010074
75 def footer(self):
76 '''Output the bottom boilerplate.'''
77 write = self.stream.write
78 write('#endif\n')
79
Ole Troan18327be2021-01-12 21:49:38 +010080 def get_base_type(self, t):
Ole Troandf87f802020-11-18 19:17:48 +010081 vt_type = None
82 try:
83 vt = self.types_hash[t]
84 if vt.type == 'Using' and 'length' not in vt.alias:
85 vt_type = vt.alias['type']
86 except KeyError:
87 vt = t
Ole Troan18327be2021-01-12 21:49:38 +010088 return vt, vt_type
89
90 def get_json_func(self, t):
91 '''Given the type, returns the function to use to create a
92 cJSON object'''
93 vt, vt_type = self.get_base_type(t)
Ole Troandf87f802020-11-18 19:17:48 +010094
95 if t in self.is_number or vt_type in self.is_number:
96 return 'cJSON_AddNumberToObject', '', False
97 if t == 'bool':
98 return 'cJSON_AddBoolToObject', '', False
99
100 # Lookup type name check if it's enum
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500101 if vt.type == 'Enum' or vt.type == 'EnumFlag':
Ole Troandf87f802020-11-18 19:17:48 +0100102 return '{t}_tojson'.format(t=t), '', True
103 return '{t}_tojson'.format(t=t), '&', True
104
105 def get_json_array_func(self, t):
106 '''Given a type returns the function to create a cJSON object
107 for arrays.'''
108 if t in self.is_number:
109 return 'cJSON_CreateNumber', ''
110 if t == 'bool':
111 return 'cJSON_CreateBool', ''
Ole Troan18327be2021-01-12 21:49:38 +0100112 vt, vt_type = self.get_base_type(t)
113 if vt.type == 'Enum' or vt.type == 'EnumFlag':
114 return '{t}_tojson'.format(t=t), ''
Ole Troandf87f802020-11-18 19:17:48 +0100115 return '{t}_tojson'.format(t=t), '&'
116
117 def print_string(self, o):
118 '''Create cJSON object from vl_api_string_t'''
119 write = self.stream.write
120 if o.modern_vla:
121 write(' vl_api_string_cJSON_AddToObject(o, "{n}", &a->{n});\n'
122 .format(n=o.fieldname))
123 else:
124
125 write(' cJSON_AddStringToObject(o, "{n}", (char *)a->{n});\n'
126 .format(n=o.fieldname))
127
128 def print_field(self, o):
129 '''Called for every field in a typedef or define.'''
130 write = self.stream.write
131 if o.fieldname in self.noprint_fields:
132 return
133
134 f, p, newobj = self.get_json_func(o.fieldtype)
135
136 if newobj:
137 write(' cJSON_AddItemToObject(o, "{n}", {f}({p}a->{n}));\n'
138 .format(f=f, p=p, n=o.fieldname))
139 else:
140 write(' {f}(o, "{n}", {p}a->{n});\n'
141 .format(f=f, p=p, n=o.fieldname))
142
143 _dispatch['Field'] = print_field
144
145 def print_array(self, o):
146 '''Converts a VPP API array to cJSON array.'''
147 write = self.stream.write
148
149 forloop = '''\
150 {{
151 int i;
152 cJSON *array = cJSON_AddArrayToObject(o, "{n}");
153 for (i = 0; i < {lfield}; i++) {{
154 cJSON_AddItemToArray(array, {f}({p}a->{n}[i]));
155 }}
156 }}
157'''
158
159 if o.fieldtype == 'string':
160 self.print_string(o)
161 return
162
163 lfield = 'a->' + o.lengthfield if o.lengthfield else o.length
164 if o.fieldtype == 'u8':
165 write(' {\n')
166 # What is length field doing here?
167 write(' u8 *s = format(0, "0x%U", format_hex_bytes, '
168 '&a->{n}, {lfield});\n'
169 .format(n=o.fieldname, lfield=lfield))
170 write(' cJSON_AddStringToObject(o, "{n}", (char *)s);\n'
171 .format(n=o.fieldname))
172 write(' vec_free(s);\n')
173 write(' }\n')
174 return
175
176 f, p = self.get_json_array_func(o.fieldtype)
177 write(forloop.format(lfield=lfield,
178 t=o.fieldtype,
179 n=o.fieldname,
180 f=f,
181 p=p))
182
183 _dispatch['Array'] = print_array
184
185 def print_enum(self, o):
186 '''Create cJSON object (string) for VPP API enum'''
187 write = self.stream.write
188 write('static inline cJSON *vl_api_{name}_t_tojson '
189 '(vl_api_{name}_t a) {{\n'.format(name=o.name))
190
191 write(" switch(a) {\n")
192 for b in o.block:
193 write(" case %s:\n" % b[1])
194 write(' return cJSON_CreateString("{}");\n'.format(b[0]))
195 write(' default: return cJSON_CreateString("Invalid ENUM");\n')
196 write(' }\n')
197 write(' return 0;\n')
198 write('}\n')
199
200 _dispatch['Enum'] = print_enum
Ole Troan793be462020-12-04 13:15:30 +0100201
202 def print_enum_flag(self, o):
203 '''Create cJSON object (string) for VPP API enum'''
204 write = self.stream.write
205 write('static inline cJSON *vl_api_{name}_t_tojson '
206 '(vl_api_{name}_t a) {{\n'.format(name=o.name))
207 write(' cJSON *array = cJSON_CreateArray();\n')
208
209 for b in o.block:
Ole Troan45517152021-11-23 10:49:36 +0100210 if b[1] == 0:
211 continue
Ole Troan793be462020-12-04 13:15:30 +0100212 write(' if (a & {})\n'.format(b[0]))
Klement Sekera9b7e8ac2021-11-22 21:26:20 +0100213 write(
214 ' cJSON_AddItemToArray(array, cJSON_CreateString("{}"));\n'.format(b[0]))
Ole Troan793be462020-12-04 13:15:30 +0100215 write(' return array;\n')
216 write('}\n')
217
218 _dispatch['EnumFlag'] = print_enum_flag
Ole Troandf87f802020-11-18 19:17:48 +0100219
220 def print_typedef(self, o):
221 '''Create cJSON (dictionary) object from VPP API typedef'''
222 write = self.stream.write
223 write('static inline cJSON *vl_api_{name}_t_tojson '
224 '(vl_api_{name}_t *a) {{\n'.format(name=o.name))
225 write(' cJSON *o = cJSON_CreateObject();\n')
226
227 for t in o.block:
228 self._dispatch[t.type](self, t)
229
230 write(' return o;\n')
231 write('}\n')
232
233 def print_define(self, o):
234 '''Create cJSON (dictionary) object from VPP API define'''
235 write = self.stream.write
236 write('static inline cJSON *vl_api_{name}_t_tojson '
237 '(vl_api_{name}_t *a) {{\n'.format(name=o.name))
238 write(' cJSON *o = cJSON_CreateObject();\n')
239 write(' cJSON_AddStringToObject(o, "_msgname", "{}");\n'
240 .format(o.name))
Filip Tehlar36217e32021-07-23 08:51:10 +0000241 write(' cJSON_AddStringToObject(o, "_crc", "{crc:08x}");\n'
242 .format(crc=o.crc))
Ole Troandf87f802020-11-18 19:17:48 +0100243
244 for t in o.block:
245 self._dispatch[t.type](self, t)
246
247 write(' return o;\n')
248 write('}\n')
249
250 def print_using(self, o):
251 '''Create cJSON (dictionary) object from VPP API aliased type'''
252 if o.manual_print:
253 return
254
255 write = self.stream.write
256 write('static inline cJSON *vl_api_{name}_t_tojson '
257 '(vl_api_{name}_t *a) {{\n'.format(name=o.name))
258
259 write(' u8 *s = format(0, "%U", format_vl_api_{}_t, a);\n'
260 .format(o.name))
261 write(' cJSON *o = cJSON_CreateString((char *)s);\n')
262 write(' vec_free(s);\n')
263 write(' return o;\n')
264 write('}\n')
265
266 _dispatch['Typedef'] = print_typedef
267 _dispatch['Define'] = print_define
268 _dispatch['Using'] = print_using
269 _dispatch['Union'] = print_typedef
270
271 def generate_function(self, t):
272 '''Main entry point'''
273 write = self.stream.write
274 if t.manual_print:
275 write('/* Manual print {} */\n'.format(t.name))
276 return
277 self._dispatch[t.type](self, t)
278
279 def generate_types(self):
280 '''Main entry point'''
281 for t in self.types:
282 self.generate_function(t)
283
284 def generate_defines(self):
285 '''Main entry point'''
286 for t in self.defines:
287 self.generate_function(t)
288
289
290class FromJSON():
291 '''
292 Parse JSON objects into VPP API binary message structures.
293 '''
294 _dispatch = {}
295 noprint_fields = {'_vl_msg_id': None,
296 'client_index': None,
297 'context': None}
298 is_number = {'u8': None,
299 'i8': None,
300 'u16': None,
301 'i16': None,
302 'u32': None,
303 'i32': None,
304 'u64': None,
305 'i64': None,
306 'f64': None,
307 }
308
309 def __init__(self, module, types, defines, imported_types, stream):
310 self.stream = stream
311 self.module = module
312 self.defines = defines
313 self.types = types
314 self.types_hash = {'vl_api_'+d.name+'_t':
315 d for d in types + imported_types}
316 self.defines_hash = {d.name: d for d in defines}
317
318 def header(self):
319 '''Output the top boilerplate.'''
320 write = self.stream.write
321 write('#ifndef included_{}_api_fromjson_h\n'.format(self.module))
322 write('#define included_{}_api_fromjson_h\n'.format(self.module))
323 write('#include <vppinfra/cJSON.h>\n\n')
Filip Tehlar36217e32021-07-23 08:51:10 +0000324 write('#include <vppinfra/jsonformat.h>\n\n')
Ole Troanfb0afab2021-02-11 11:13:46 +0100325 write('#pragma GCC diagnostic ignored "-Wunused-label"\n')
Ole Troandf87f802020-11-18 19:17:48 +0100326
327 def is_base_type(self, t):
328 '''Check if a type is one of the VPP API base types'''
329 if t in self.is_number:
330 return True
331 if t == 'bool':
332 return True
333 return False
334
335 def footer(self):
336 '''Output the bottom boilerplate.'''
337 write = self.stream.write
338 write('#endif\n')
339
340 def print_string(self, o, toplevel=False):
341 '''Convert JSON string to vl_api_string_t'''
342 write = self.stream.write
343
Ole Troanfb0afab2021-02-11 11:13:46 +0100344 msgvar = "a" if toplevel else "*mp"
Ole Troandf87f802020-11-18 19:17:48 +0100345 msgsize = "l" if toplevel else "*len"
346
347 if o.modern_vla:
348 write(' char *p = cJSON_GetStringValue(item);\n')
349 write(' size_t plen = strlen(p);\n')
Filip Tehlar36217e32021-07-23 08:51:10 +0000350 write(' {msgvar} = cJSON_realloc({msgvar}, {msgsize} + plen, {msgsize});\n'
Ole Troandf87f802020-11-18 19:17:48 +0100351 .format(msgvar=msgvar, msgsize=msgsize))
Ole Troanfb0afab2021-02-11 11:13:46 +0100352 write(' if ({msgvar} == 0) goto error;\n'.format(msgvar=msgvar))
Ole Troandf87f802020-11-18 19:17:48 +0100353 write(' vl_api_c_string_to_api_string(p, (void *){msgvar} + '
354 '{msgsize} - sizeof(vl_api_string_t));\n'
355 .format(msgvar=msgvar, msgsize=msgsize))
356 write(' {msgsize} += plen;\n'.format(msgsize=msgsize))
357 else:
358 write(' strncpy_s((char *)a->{n}, sizeof(a->{n}), '
359 'cJSON_GetStringValue(item), sizeof(a->{n}) - 1);\n'
360 .format(n=o.fieldname))
361
362 def print_field(self, o, toplevel=False):
363 '''Called for every field in a typedef or define.'''
364 write = self.stream.write
Ole Troandf87f802020-11-18 19:17:48 +0100365 if o.fieldname in self.noprint_fields:
366 return
367 is_bt = self.is_base_type(o.fieldtype)
368 t = 'vl_api_{}'.format(o.fieldtype) if is_bt else o.fieldtype
369
Ole Troanfb0afab2021-02-11 11:13:46 +0100370 msgvar = "(void **)&a" if toplevel else "mp"
Ole Troandf87f802020-11-18 19:17:48 +0100371 msgsize = "&l" if toplevel else "len"
372
373 if is_bt:
374 write(' vl_api_{t}_fromjson(item, &a->{n});\n'
375 .format(t=o.fieldtype, n=o.fieldname))
376 else:
Ole Troanfb0afab2021-02-11 11:13:46 +0100377 write(' if ({t}_fromjson({msgvar}, '
378 '{msgsize}, item, &a->{n}) < 0) goto error;\n'
Ole Troandf87f802020-11-18 19:17:48 +0100379 .format(t=t, n=o.fieldname, msgvar=msgvar, msgsize=msgsize))
Ole Troandf87f802020-11-18 19:17:48 +0100380
381 _dispatch['Field'] = print_field
382
383 def print_array(self, o, toplevel=False):
384 '''Convert JSON array to VPP API array'''
385 write = self.stream.write
386
387 forloop = '''\
388 {{
389 int i;
390 cJSON *array = cJSON_GetObjectItem(o, "{n}");
391 int size = cJSON_GetArraySize(array);
Ole Troan384c72f2021-02-17 13:46:54 +0100392 if (size != {lfield}) goto error;
Ole Troandf87f802020-11-18 19:17:48 +0100393 for (i = 0; i < size; i++) {{
394 cJSON *e = cJSON_GetArrayItem(array, i);
395 {call}
396 }}
397 }}
398'''
399 forloop_vla = '''\
400 {{
401 int i;
402 cJSON *array = cJSON_GetObjectItem(o, "{n}");
403 int size = cJSON_GetArraySize(array);
404 {lfield} = size;
Filip Tehlar36217e32021-07-23 08:51:10 +0000405 {realloc} = cJSON_realloc({realloc}, {msgsize} + sizeof({t}) * size, {msgsize});
Ole Troancf0102b2021-02-12 11:48:12 +0100406 {t} *d = (void *){realloc} + {msgsize};
Ole Troandf87f802020-11-18 19:17:48 +0100407 {msgsize} += sizeof({t}) * size;
408 for (i = 0; i < size; i++) {{
409 cJSON *e = cJSON_GetArrayItem(array, i);
410 {call}
411 }}
412 }}
413'''
414 t = o.fieldtype
415 if o.fieldtype == 'string':
416 self.print_string(o, toplevel)
417 return
418
419 lfield = 'a->' + o.lengthfield if o.lengthfield else o.length
Ole Troanfb0afab2021-02-11 11:13:46 +0100420 msgvar = "(void **)&a" if toplevel else "mp"
Ole Troancf0102b2021-02-12 11:48:12 +0100421 realloc = "a" if toplevel else "*mp"
Ole Troandf87f802020-11-18 19:17:48 +0100422 msgsize = "l" if toplevel else "*len"
423
424 if o.fieldtype == 'u8':
425 if o.lengthfield:
426 write(' s = u8string_fromjson(o, "{}");\n'
427 .format(o.fieldname))
Ole Troan93c4b1b2021-02-16 18:09:51 +0100428 write(' if (!s) goto error;\n')
Ole Troandf87f802020-11-18 19:17:48 +0100429 write(' {} = vec_len(s);\n'.format(lfield))
430
Filip Tehlar36217e32021-07-23 08:51:10 +0000431 write(' {realloc} = cJSON_realloc({realloc}, {msgsize} + '
432 'vec_len(s), {msgsize});\n'.format(msgvar=msgvar, msgsize=msgsize, realloc=realloc))
Ole Troancf0102b2021-02-12 11:48:12 +0100433 write(' memcpy((void *){realloc} + {msgsize}, s, '
434 'vec_len(s));\n'.format(realloc=realloc, msgsize=msgsize))
Ole Troandf87f802020-11-18 19:17:48 +0100435 write(' {msgsize} += vec_len(s);\n'.format(msgsize=msgsize))
436
437 write(' vec_free(s);\n')
438 else:
Ole Troan93c4b1b2021-02-16 18:09:51 +0100439 write(' if (u8string_fromjson2(o, "{n}", a->{n}) < 0) goto error;\n'
Ole Troandf87f802020-11-18 19:17:48 +0100440 .format(n=o.fieldname))
441 return
442
443 is_bt = self.is_base_type(o.fieldtype)
444
445 if o.lengthfield:
446 if is_bt:
447 call = ('vl_api_{t}_fromjson(e, &d[i]);'
448 .format(t=o.fieldtype))
449 else:
Ole Troan93c4b1b2021-02-16 18:09:51 +0100450 call = ('if ({t}_fromjson({msgvar}, len, e, &d[i]) < 0) goto error; '
Ole Troandf87f802020-11-18 19:17:48 +0100451 .format(t=o.fieldtype, msgvar=msgvar))
452 write(forloop_vla.format(lfield=lfield,
453 t=o.fieldtype,
454 n=o.fieldname,
455 call=call,
Ole Troancf0102b2021-02-12 11:48:12 +0100456 realloc=realloc,
Ole Troandf87f802020-11-18 19:17:48 +0100457 msgsize=msgsize))
458 else:
459 if is_bt:
460 call = ('vl_api_{t}_fromjson(e, &a->{n}[i]);'
461 .format(t=t, n=o.fieldname))
462 else:
Ole Troanfb0afab2021-02-11 11:13:46 +0100463 call = ('if ({}_fromjson({}, len, e, &a->{}[i]) < 0) goto error;'
Ole Troandf87f802020-11-18 19:17:48 +0100464 .format(t, msgvar, o.fieldname))
465 write(forloop.format(lfield=lfield,
466 t=t,
467 n=o.fieldname,
468 call=call,
469 msgvar=msgvar,
Ole Troancf0102b2021-02-12 11:48:12 +0100470 realloc=realloc,
Ole Troandf87f802020-11-18 19:17:48 +0100471 msgsize=msgsize))
472
473 _dispatch['Array'] = print_array
474
475 def print_enum(self, o):
476 '''Convert to JSON enum(string) to VPP API enum (int)'''
477 write = self.stream.write
Ole Troanfb0afab2021-02-11 11:13:46 +0100478 write('static inline int vl_api_{n}_t_fromjson'
479 '(void **mp, int *len, cJSON *o, vl_api_{n}_t *a) {{\n'
Ole Troandf87f802020-11-18 19:17:48 +0100480 .format(n=o.name))
481 write(' char *p = cJSON_GetStringValue(o);\n')
482 for b in o.block:
Ole Troanfb0afab2021-02-11 11:13:46 +0100483 write(' if (strcmp(p, "{}") == 0) {{*a = {}; return 0;}}\n'
Ole Troandf87f802020-11-18 19:17:48 +0100484 .format(b[0], b[1]))
Ole Troanfb0afab2021-02-11 11:13:46 +0100485 write(' *a = 0;\n')
486 write(' return -1;\n')
Ole Troandf87f802020-11-18 19:17:48 +0100487 write('}\n')
488
489 _dispatch['Enum'] = print_enum
Ole Troan793be462020-12-04 13:15:30 +0100490
491 def print_enum_flag(self, o):
492 '''Convert to JSON enum(string) to VPP API enum (int)'''
493 write = self.stream.write
Ole Troancf0102b2021-02-12 11:48:12 +0100494 write('static inline int vl_api_{n}_t_fromjson '
495 '(void **mp, int *len, cJSON *o, vl_api_{n}_t *a) {{\n'
Ole Troan793be462020-12-04 13:15:30 +0100496 .format(n=o.name))
497 write(' int i;\n')
498 write(' *a = 0;\n')
499 write(' for (i = 0; i < cJSON_GetArraySize(o); i++) {\n')
500 write(' cJSON *e = cJSON_GetArrayItem(o, i);\n')
501 write(' char *p = cJSON_GetStringValue(e);\n')
Ole Troancf0102b2021-02-12 11:48:12 +0100502 write(' if (!p) return -1;\n')
Ole Troan793be462020-12-04 13:15:30 +0100503 for b in o.block:
504 write(' if (strcmp(p, "{}") == 0) *a |= {};\n'
505 .format(b[0], b[1]))
506 write(' }\n')
Ole Troancf0102b2021-02-12 11:48:12 +0100507 write(' return 0;\n')
Ole Troan793be462020-12-04 13:15:30 +0100508 write('}\n')
509
510 _dispatch['EnumFlag'] = print_enum_flag
Ole Troandf87f802020-11-18 19:17:48 +0100511
512 def print_typedef(self, o):
513 '''Convert from JSON object to VPP API binary representation'''
514 write = self.stream.write
515
Ole Troanfb0afab2021-02-11 11:13:46 +0100516 write('static inline int vl_api_{name}_t_fromjson (void **mp, '
Ole Troandf87f802020-11-18 19:17:48 +0100517 'int *len, cJSON *o, vl_api_{name}_t *a) {{\n'
518 .format(name=o.name))
519 write(' cJSON *item __attribute__ ((unused));\n')
520 write(' u8 *s __attribute__ ((unused));\n')
521 for t in o.block:
522 if t.type == 'Field' and t.is_lengthfield:
523 continue
Ole Troanfb0afab2021-02-11 11:13:46 +0100524 write('\n item = cJSON_GetObjectItem(o, "{}");\n'
Ole Troandf87f802020-11-18 19:17:48 +0100525 .format(t.fieldname))
Ole Troanfb0afab2021-02-11 11:13:46 +0100526 write(' if (!item) goto error;\n')
Ole Troandf87f802020-11-18 19:17:48 +0100527 self._dispatch[t.type](self, t)
528
Ole Troanfb0afab2021-02-11 11:13:46 +0100529 write('\n return 0;\n')
530 write('\n error:\n')
531 write(' return -1;\n')
Ole Troandf87f802020-11-18 19:17:48 +0100532 write('}\n')
533
534 def print_union(self, o):
535 '''Convert JSON object to VPP API binary union'''
536 write = self.stream.write
537
Ole Troanfb0afab2021-02-11 11:13:46 +0100538 write('static inline int vl_api_{name}_t_fromjson (void **mp, '
Ole Troandf87f802020-11-18 19:17:48 +0100539 'int *len, cJSON *o, vl_api_{name}_t *a) {{\n'
540 .format(name=o.name))
541 write(' cJSON *item __attribute__ ((unused));\n')
542 write(' u8 *s __attribute__ ((unused));\n')
543 for t in o.block:
544 if t.type == 'Field' and t.is_lengthfield:
545 continue
546 write(' item = cJSON_GetObjectItem(o, "{}");\n'
547 .format(t.fieldname))
548 write(' if (item) {\n')
549 self._dispatch[t.type](self, t)
550 write(' };\n')
Ole Troanfb0afab2021-02-11 11:13:46 +0100551 write('\n return 0;\n')
552 write('\n error:\n')
553 write(' return -1;\n')
Ole Troandf87f802020-11-18 19:17:48 +0100554 write('}\n')
555
556 def print_define(self, o):
557 '''Convert JSON object to VPP API message'''
558 write = self.stream.write
Ole Troan93c4b1b2021-02-16 18:09:51 +0100559 error = 0
Ole Troandf87f802020-11-18 19:17:48 +0100560 write('static inline vl_api_{name}_t *vl_api_{name}_t_fromjson '
561 '(cJSON *o, int *len) {{\n'.format(name=o.name))
562 write(' cJSON *item __attribute__ ((unused));\n')
563 write(' u8 *s __attribute__ ((unused));\n')
564 write(' int l = sizeof(vl_api_{}_t);\n'.format(o.name))
Filip Tehlar36217e32021-07-23 08:51:10 +0000565 write(' vl_api_{}_t *a = cJSON_malloc(l);\n'.format(o.name))
Ole Troanfb0afab2021-02-11 11:13:46 +0100566 write('\n')
Ole Troandf87f802020-11-18 19:17:48 +0100567
568 for t in o.block:
569 if t.fieldname in self.noprint_fields:
570 continue
571 if t.type == 'Field' and t.is_lengthfield:
572 continue
Ole Troandf87f802020-11-18 19:17:48 +0100573 write(' item = cJSON_GetObjectItem(o, "{}");\n'
574 .format(t.fieldname))
Ole Troanfb0afab2021-02-11 11:13:46 +0100575 write(' if (!item) goto error;\n')
Ole Troan93c4b1b2021-02-16 18:09:51 +0100576 error += 1
Ole Troandf87f802020-11-18 19:17:48 +0100577 self._dispatch[t.type](self, t, toplevel=True)
578 write('\n')
579
Ole Troandf87f802020-11-18 19:17:48 +0100580 write(' *len = l;\n')
581 write(' return a;\n')
Ole Troan93c4b1b2021-02-16 18:09:51 +0100582
583 if error:
584 write('\n error:\n')
Filip Tehlar36217e32021-07-23 08:51:10 +0000585 write(' cJSON_free(a);\n')
Ole Troan93c4b1b2021-02-16 18:09:51 +0100586 write(' return 0;\n')
Ole Troandf87f802020-11-18 19:17:48 +0100587 write('}\n')
588
589 def print_using(self, o):
590 '''Convert JSON field to VPP type alias'''
591 write = self.stream.write
592
593 if o.manual_print:
594 return
595
596 t = o.using
Ole Troancf0102b2021-02-12 11:48:12 +0100597 write('static inline int vl_api_{name}_t_fromjson (void **mp, '
Ole Troandf87f802020-11-18 19:17:48 +0100598 'int *len, cJSON *o, vl_api_{name}_t *a) {{\n'
599 .format(name=o.name))
600 if 'length' in o.alias:
601 if t.fieldtype != 'u8':
602 raise ValueError("Error in processing type {} for {}"
603 .format(t.fieldtype, o.name))
604 write(' vl_api_u8_string_fromjson(o, (u8 *)a, {});\n'
605 .format(o.alias['length']))
606 else:
607 write(' vl_api_{t}_fromjson(o, ({t} *)a);\n'
608 .format(t=t.fieldtype))
609
Ole Troancf0102b2021-02-12 11:48:12 +0100610 write(' return 0;\n')
Ole Troandf87f802020-11-18 19:17:48 +0100611 write('}\n')
612
613 _dispatch['Typedef'] = print_typedef
614 _dispatch['Define'] = print_define
615 _dispatch['Using'] = print_using
616 _dispatch['Union'] = print_union
617
618 def generate_function(self, t):
619 '''Main entry point'''
620 write = self.stream.write
621 if t.manual_print:
622 write('/* Manual print {} */\n'.format(t.name))
623 return
624 self._dispatch[t.type](self, t)
625
626 def generate_types(self):
627 '''Main entry point'''
628 for t in self.types:
629 self.generate_function(t)
630
631 def generate_defines(self):
632 '''Main entry point'''
633 for t in self.defines:
634 self.generate_function(t)
635
636
637def generate_tojson(s, modulename, stream):
638 '''Generate all functions to convert from API to JSON'''
639 write = stream.write
640
641 write('/* Imported API files */\n')
642 for i in s['Import']:
643 f = i.filename.replace('plugins/', '')
644 write('#include <{}_tojson.h>\n'.format(f))
645
646 pp = ToJSON(modulename, s['types'], s['Define'], s['imported']['types'],
647 stream)
648 pp.header()
649 pp.generate_types()
650 pp.generate_defines()
651 pp.footer()
652 return ''
653
654
655def generate_fromjson(s, modulename, stream):
656 '''Generate all functions to convert from JSON to API'''
657 write = stream.write
658 write('/* Imported API files */\n')
659 for i in s['Import']:
660 f = i.filename.replace('plugins/', '')
661 write('#include <{}_fromjson.h>\n'.format(f))
662
663 pp = FromJSON(modulename, s['types'], s['Define'], s['imported']['types'],
664 stream)
665 pp.header()
666 pp.generate_types()
667 pp.generate_defines()
668 pp.footer()
669
670 return ''
671
672###############################################################################
673
674
675DATESTRING = datetime.datetime.utcfromtimestamp(
Ole Troan413f4a52018-11-28 11:36:05 +0100676 int(os.environ.get('SOURCE_DATE_EPOCH', time.time())))
Ole Troandf87f802020-11-18 19:17:48 +0100677TOP_BOILERPLATE = '''\
Ole Troan9d420872017-10-12 13:06:35 +0200678/*
679 * VLIB API definitions {datestring}
680 * Input file: {input_filename}
681 * Automatically generated: please edit the input file NOT this file!
682 */
683
Ole Troan288e0932019-05-29 12:30:05 +0200684#include <stdbool.h>
Ole Troan9d420872017-10-12 13:06:35 +0200685#if defined(vl_msg_id)||defined(vl_union_id) \\
686 || defined(vl_printfun) ||defined(vl_endianfun) \\
687 || defined(vl_api_version)||defined(vl_typedefs) \\
688 || defined(vl_msg_name)||defined(vl_msg_name_crc_list) \\
Klement Sekera9b7e8ac2021-11-22 21:26:20 +0100689 || defined(vl_api_version_tuple) || defined(vl_calcsizefun)
Ole Troan9d420872017-10-12 13:06:35 +0200690/* ok, something was selected */
691#else
692#warning no content included from {input_filename}
693#endif
694
695#define VL_API_PACKED(x) x __attribute__ ((packed))
696'''
697
Ole Troandf87f802020-11-18 19:17:48 +0100698BOTTOM_BOILERPLATE = '''\
Ole Troan9d420872017-10-12 13:06:35 +0200699/****** API CRC (whole file) *****/
700
701#ifdef vl_api_version
702vl_api_version({input_filename}, {file_crc:#08x})
703
704#endif
705'''
706
707
708def msg_ids(s):
Ole Troandf87f802020-11-18 19:17:48 +0100709 '''Generate macro to map API message id to handler'''
Ole Troan9d420872017-10-12 13:06:35 +0200710 output = '''\
711
712/****** Message ID / handler enum ******/
713
714#ifdef vl_msg_id
715'''
716
Ole Troan2c2feab2018-04-24 00:02:37 -0400717 for t in s['Define']:
Ole Troan9d420872017-10-12 13:06:35 +0200718 output += "vl_msg_id(VL_API_%s, vl_api_%s_t_handler)\n" % \
719 (t.name.upper(), t.name)
720 output += "#endif"
721
722 return output
723
724
725def msg_names(s):
Ole Troandf87f802020-11-18 19:17:48 +0100726 '''Generate calls to name mapping macro'''
Ole Troan9d420872017-10-12 13:06:35 +0200727 output = '''\
728
729/****** Message names ******/
730
731#ifdef vl_msg_name
732'''
733
Ole Troan2c2feab2018-04-24 00:02:37 -0400734 for t in s['Define']:
Ole Troan9d420872017-10-12 13:06:35 +0200735 dont_trace = 0 if t.dont_trace else 1
736 output += "vl_msg_name(vl_api_%s_t, %d)\n" % (t.name, dont_trace)
737 output += "#endif"
738
739 return output
740
741
742def msg_name_crc_list(s, suffix):
Ole Troandf87f802020-11-18 19:17:48 +0100743 '''Generate list of names to CRC mappings'''
Ole Troan9d420872017-10-12 13:06:35 +0200744 output = '''\
745
746/****** Message name, crc list ******/
747
748#ifdef vl_msg_name_crc_list
749'''
750 output += "#define foreach_vl_msg_name_crc_%s " % suffix
751
Ole Troan2c2feab2018-04-24 00:02:37 -0400752 for t in s['Define']:
Ole Troan9d420872017-10-12 13:06:35 +0200753 output += "\\\n_(VL_API_%s, %s, %08x) " % \
Klement Sekera9b7e8ac2021-11-22 21:26:20 +0100754 (t.name.upper(), t.name, t.crc)
Ole Troan9d420872017-10-12 13:06:35 +0200755 output += "\n#endif"
756
757 return output
758
759
Ole Troan413f4a52018-11-28 11:36:05 +0100760def api2c(fieldtype):
Ole Troandf87f802020-11-18 19:17:48 +0100761 '''Map between API type names and internal VPP type names'''
Ole Troan413f4a52018-11-28 11:36:05 +0100762 mappingtable = {'string': 'vl_api_string_t', }
763 if fieldtype in mappingtable:
764 return mappingtable[fieldtype]
765 return fieldtype
766
767
Ole Troan2a1ca782019-09-19 01:08:30 +0200768def typedefs(filename):
Ole Troandf87f802020-11-18 19:17:48 +0100769 '''Include in the main files to the types file'''
Ole Troan2a1ca782019-09-19 01:08:30 +0200770 output = '''\
Ole Troan9d420872017-10-12 13:06:35 +0200771
772/****** Typedefs ******/
773
774#ifdef vl_typedefs
Ole Troan2a1ca782019-09-19 01:08:30 +0200775#include "{include}.api_types.h"
776#endif
777'''.format(include=filename)
Ole Troan9d420872017-10-12 13:06:35 +0200778 return output
779
780
Ole Troandf87f802020-11-18 19:17:48 +0100781FORMAT_STRINGS = {'u8': '%u',
Ole Troan33a58172019-09-04 09:12:29 +0200782 'bool': '%u',
Ole Troan9d420872017-10-12 13:06:35 +0200783 'i8': '%d',
784 'u16': '%u',
785 'i16': '%d',
786 'u32': '%u',
787 'i32': '%ld',
788 'u64': '%llu',
Paul Vinciguerrab307c712019-11-23 10:13:39 -0500789 'i64': '%lld',
Ole Troan33a58172019-09-04 09:12:29 +0200790 'f64': '%.2f'}
791
Ole Troan9d420872017-10-12 13:06:35 +0200792
Ole Troan33a58172019-09-04 09:12:29 +0200793class Printfun():
Ole Troandf87f802020-11-18 19:17:48 +0100794 '''Functions for pretty printing VPP API messages'''
Ole Troan33a58172019-09-04 09:12:29 +0200795 _dispatch = {}
Ole Troandf87f802020-11-18 19:17:48 +0100796 noprint_fields = {'_vl_msg_id': None,
797 'client_index': None,
798 'context': None}
Ole Troan33a58172019-09-04 09:12:29 +0200799
800 def __init__(self, stream):
801 self.stream = stream
802
Ole Troandf87f802020-11-18 19:17:48 +0100803 @staticmethod
804 def print_string(o, stream):
805 '''Pretty print a vl_api_string_t'''
Ole Troan33a58172019-09-04 09:12:29 +0200806 write = stream.write
807 if o.modern_vla:
808 write(' if (vl_api_string_len(&a->{f}) > 0) {{\n'
809 .format(f=o.fieldname))
Jakub Grajciar2dbee932020-02-07 11:30:26 +0100810 write(' s = format(s, "\\n%U{f}: %U", '
Ole Troan33a58172019-09-04 09:12:29 +0200811 'format_white_space, indent, '
Jakub Grajciar2dbee932020-02-07 11:30:26 +0100812 'vl_api_format_string, (&a->{f}));\n'.format(f=o.fieldname))
Ole Troan33a58172019-09-04 09:12:29 +0200813 write(' } else {\n')
814 write(' s = format(s, "\\n%U{f}:", '
815 'format_white_space, indent);\n'.format(f=o.fieldname))
816 write(' }\n')
817 else:
818 write(' s = format(s, "\\n%U{f}: %s", '
819 'format_white_space, indent, a->{f});\n'
820 .format(f=o.fieldname))
821
822 def print_field(self, o, stream):
Ole Troandf87f802020-11-18 19:17:48 +0100823 '''Pretty print API field'''
Ole Troan33a58172019-09-04 09:12:29 +0200824 write = stream.write
Ole Troandf87f802020-11-18 19:17:48 +0100825 if o.fieldname in self.noprint_fields:
Ole Troan33a58172019-09-04 09:12:29 +0200826 return
Ole Troandf87f802020-11-18 19:17:48 +0100827 if o.fieldtype in FORMAT_STRINGS:
828 f = FORMAT_STRINGS[o.fieldtype]
Ole Troan33a58172019-09-04 09:12:29 +0200829 write(' s = format(s, "\\n%U{n}: {f}", '
830 'format_white_space, indent, a->{n});\n'
831 .format(n=o.fieldname, f=f))
832 else:
833 write(' s = format(s, "\\n%U{n}: %U", '
834 'format_white_space, indent, '
835 'format_{t}, &a->{n}, indent);\n'
836 .format(n=o.fieldname, t=o.fieldtype))
837
838 _dispatch['Field'] = print_field
839
840 def print_array(self, o, stream):
Ole Troandf87f802020-11-18 19:17:48 +0100841 '''Pretty print API array'''
Ole Troan33a58172019-09-04 09:12:29 +0200842 write = stream.write
843
844 forloop = '''\
845 for (i = 0; i < {lfield}; i++) {{
846 s = format(s, "\\n%U{n}: %U",
847 format_white_space, indent, format_{t}, &a->{n}[i], indent);
848 }}
849'''
850
851 forloop_format = '''\
852 for (i = 0; i < {lfield}; i++) {{
853 s = format(s, "\\n%U{n}: {t}",
854 format_white_space, indent, a->{n}[i]);
855 }}
856'''
857
858 if o.fieldtype == 'string':
Ole Troandf87f802020-11-18 19:17:48 +0100859 self.print_string(o, stream)
860 return
Ole Troan33a58172019-09-04 09:12:29 +0200861
862 if o.fieldtype == 'u8':
863 if o.lengthfield:
864 write(' s = format(s, "\\n%U{n}: %U", format_white_space, '
865 'indent, format_hex_bytes, a->{n}, a->{lfield});\n'
866 .format(n=o.fieldname, lfield=o.lengthfield))
867 else:
868 write(' s = format(s, "\\n%U{n}: %U", format_white_space, '
869 'indent, format_hex_bytes, a, {lfield});\n'
870 .format(n=o.fieldname, lfield=o.length))
871 return
872
873 lfield = 'a->' + o.lengthfield if o.lengthfield else o.length
Ole Troandf87f802020-11-18 19:17:48 +0100874 if o.fieldtype in FORMAT_STRINGS:
Ole Troan33a58172019-09-04 09:12:29 +0200875 write(forloop_format.format(lfield=lfield,
Ole Troandf87f802020-11-18 19:17:48 +0100876 t=FORMAT_STRINGS[o.fieldtype],
Ole Troan33a58172019-09-04 09:12:29 +0200877 n=o.fieldname))
878 else:
879 write(forloop.format(lfield=lfield, t=o.fieldtype, n=o.fieldname))
880
881 _dispatch['Array'] = print_array
882
Ole Troandf87f802020-11-18 19:17:48 +0100883 @staticmethod
884 def print_alias(k, v, stream):
885 '''Pretty print type alias'''
Ole Troan33a58172019-09-04 09:12:29 +0200886 write = stream.write
887 if ('length' in v.alias and v.alias['length'] and
888 v.alias['type'] == 'u8'):
889 write(' return format(s, "%U", format_hex_bytes, a, {});\n'
890 .format(v.alias['length']))
Ole Troandf87f802020-11-18 19:17:48 +0100891 elif v.alias['type'] in FORMAT_STRINGS:
Ole Troan33a58172019-09-04 09:12:29 +0200892 write(' return format(s, "{}", *a);\n'
Ole Troandf87f802020-11-18 19:17:48 +0100893 .format(FORMAT_STRINGS[v.alias['type']]))
Ole Troan33a58172019-09-04 09:12:29 +0200894 else:
Ole Troan75761b92019-09-11 17:49:08 +0200895 write(' return format(s, "{} (print not implemented)");\n'
Ole Troan33a58172019-09-04 09:12:29 +0200896 .format(k))
897
Ole Troandf87f802020-11-18 19:17:48 +0100898 @staticmethod
899 def print_enum(o, stream):
900 '''Pretty print API enum'''
Ole Troan33a58172019-09-04 09:12:29 +0200901 write = stream.write
902 write(" switch(*a) {\n")
903 for b in o:
904 write(" case %s:\n" % b[1])
905 write(' return format(s, "{}");\n'.format(b[0]))
906 write(' }\n')
907
908 _dispatch['Enum'] = print_enum
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500909 _dispatch['EnumFlag'] = print_enum
Ole Troan33a58172019-09-04 09:12:29 +0200910
911 def print_obj(self, o, stream):
Ole Troandf87f802020-11-18 19:17:48 +0100912 '''Entry point'''
Ole Troan33a58172019-09-04 09:12:29 +0200913 write = stream.write
914
915 if o.type in self._dispatch:
916 self._dispatch[o.type](self, o, stream)
917 else:
918 write(' s = format(s, "\\n{} {} {} (print not implemented");\n'
919 .format(o.type, o.fieldtype, o.fieldname))
920
921
922def printfun(objs, stream, modulename):
Ole Troandf87f802020-11-18 19:17:48 +0100923 '''Main entry point for pretty print function generation'''
Ole Troan33a58172019-09-04 09:12:29 +0200924 write = stream.write
925
926 h = '''\
Ole Troan9d420872017-10-12 13:06:35 +0200927/****** Print functions *****/
928#ifdef vl_printfun
Ole Troan33a58172019-09-04 09:12:29 +0200929#ifndef included_{module}_printfun
930#define included_{module}_printfun
Ole Troan9d420872017-10-12 13:06:35 +0200931
932#ifdef LP64
933#define _uword_fmt \"%lld\"
934#define _uword_cast (long long)
935#else
936#define _uword_fmt \"%ld\"
937#define _uword_cast long
938#endif
939
Filip Tehlar36217e32021-07-23 08:51:10 +0000940#include "{module}.api_tojson.h"
941#include "{module}.api_fromjson.h"
942
Ole Troan9d420872017-10-12 13:06:35 +0200943'''
Ole Troan33a58172019-09-04 09:12:29 +0200944
945 signature = '''\
Filip Tehlar36217e32021-07-23 08:51:10 +0000946static inline void *vl_api_{name}_t_print{suffix} (vl_api_{name}_t *a, void *handle)
Ole Troan33a58172019-09-04 09:12:29 +0200947{{
948 u8 *s = 0;
949 u32 indent __attribute__((unused)) = 2;
950 int i __attribute__((unused));
951'''
952
953 h = h.format(module=modulename)
954 write(h)
955
956 pp = Printfun(stream)
957 for t in objs:
958 if t.manual_print:
959 write("/***** manual: vl_api_%s_t_print *****/\n\n" % t.name)
960 continue
Filip Tehlar36217e32021-07-23 08:51:10 +0000961 write(signature.format(name=t.name, suffix=''))
Ole Troan33a58172019-09-04 09:12:29 +0200962 write(' /* Message definition: vl_api_{}_t: */\n'.format(t.name))
963 write(" s = format(s, \"vl_api_%s_t:\");\n" % t.name)
964 for o in t.block:
965 pp.print_obj(o, stream)
966 write(' vec_add1(s, 0);\n')
967 write(' vl_print (handle, (char *)s);\n')
968 write(' vec_free (s);\n')
969 write(' return handle;\n')
970 write('}\n\n')
971
Filip Tehlar36217e32021-07-23 08:51:10 +0000972 write(signature.format(name=t.name, suffix='_json'))
973 write(' cJSON * o = vl_api_{}_t_tojson(a);\n'.format(t.name))
Klement Sekera9b7e8ac2021-11-22 21:26:20 +0100974 write(' (void)s;\n')
Filip Tehlar36217e32021-07-23 08:51:10 +0000975 write(' char *out = cJSON_Print(o);\n')
Klement Sekera9b7e8ac2021-11-22 21:26:20 +0100976 write(' vl_print(handle, out);\n')
Filip Tehlar36217e32021-07-23 08:51:10 +0000977 write(' cJSON_Delete(o);\n')
Klement Sekera9b7e8ac2021-11-22 21:26:20 +0100978 write(' cJSON_free(out);\n')
Filip Tehlar36217e32021-07-23 08:51:10 +0000979 write(' return handle;\n')
Klement Sekera9b7e8ac2021-11-22 21:26:20 +0100980 write('}\n\n')
Filip Tehlar36217e32021-07-23 08:51:10 +0000981
Ole Troan33a58172019-09-04 09:12:29 +0200982 write("\n#endif")
983 write("\n#endif /* vl_printfun */\n")
984
985 return ''
986
987
Ole Troan75761b92019-09-11 17:49:08 +0200988def printfun_types(objs, stream, modulename):
Ole Troandf87f802020-11-18 19:17:48 +0100989 '''Pretty print API types'''
Ole Troan33a58172019-09-04 09:12:29 +0200990 write = stream.write
991 pp = Printfun(stream)
992
993 h = '''\
994/****** Print functions *****/
995#ifdef vl_printfun
996#ifndef included_{module}_printfun_types
997#define included_{module}_printfun_types
998
999'''
1000 h = h.format(module=modulename)
1001 write(h)
1002
1003 signature = '''\
1004static inline u8 *format_vl_api_{name}_t (u8 *s, va_list * args)
1005{{
1006 vl_api_{name}_t *a = va_arg (*args, vl_api_{name}_t *);
1007 u32 indent __attribute__((unused)) = va_arg (*args, u32);
1008 int i __attribute__((unused));
1009 indent += 2;
1010'''
1011
Ole Troan2c2feab2018-04-24 00:02:37 -04001012 for t in objs:
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -05001013 if t.__class__.__name__ == 'Enum' or t.__class__.__name__ == 'EnumFlag':
Ole Troan33a58172019-09-04 09:12:29 +02001014 write(signature.format(name=t.name))
1015 pp.print_enum(t.block, stream)
1016 write(' return s;\n')
1017 write('}\n\n')
Ole Troan2c2feab2018-04-24 00:02:37 -04001018 continue
Ole Troan33a58172019-09-04 09:12:29 +02001019
Ole Troan9d420872017-10-12 13:06:35 +02001020 if t.manual_print:
Ole Troan33a58172019-09-04 09:12:29 +02001021 write("/***** manual: vl_api_%s_t_print *****/\n\n" % t.name)
Ole Troan9d420872017-10-12 13:06:35 +02001022 continue
Ole Troan9d420872017-10-12 13:06:35 +02001023
Ole Troan75761b92019-09-11 17:49:08 +02001024 if t.__class__.__name__ == 'Using':
1025 write(signature.format(name=t.name))
1026 pp.print_alias(t.name, t, stream)
1027 write('}\n\n')
1028 continue
1029
Ole Troan33a58172019-09-04 09:12:29 +02001030 write(signature.format(name=t.name))
Ole Troan9d420872017-10-12 13:06:35 +02001031 for o in t.block:
Ole Troan33a58172019-09-04 09:12:29 +02001032 pp.print_obj(o, stream)
Ole Troan9d420872017-10-12 13:06:35 +02001033
Ole Troan33a58172019-09-04 09:12:29 +02001034 write(' return s;\n')
1035 write('}\n\n')
Ole Troan9d420872017-10-12 13:06:35 +02001036
Ole Troan33a58172019-09-04 09:12:29 +02001037 write("\n#endif")
1038 write("\n#endif /* vl_printfun_types */\n")
Ole Troan9d420872017-10-12 13:06:35 +02001039
Ole Troan33a58172019-09-04 09:12:29 +02001040
Ole Troandf87f802020-11-18 19:17:48 +01001041def generate_imports(imports):
1042 '''Add #include matching the API import statements'''
Ole Troan33a58172019-09-04 09:12:29 +02001043 output = '/* Imported API files */\n'
1044 output += '#ifndef vl_api_version\n'
1045
1046 for i in imports:
1047 s = i.filename.replace('plugins/', '')
1048 output += '#include <{}.h>\n'.format(s)
1049 output += '#endif\n'
Ole Troan9d420872017-10-12 13:06:35 +02001050 return output
1051
1052
Ole Troandf87f802020-11-18 19:17:48 +01001053ENDIAN_STRINGS = {
Ole Troan9d420872017-10-12 13:06:35 +02001054 'u16': 'clib_net_to_host_u16',
1055 'u32': 'clib_net_to_host_u32',
1056 'u64': 'clib_net_to_host_u64',
Paul Vinciguerra1c200dc2019-11-19 23:30:53 -05001057 'i16': 'clib_net_to_host_i16',
1058 'i32': 'clib_net_to_host_i32',
1059 'i64': 'clib_net_to_host_i64',
1060 'f64': 'clib_net_to_host_f64',
Ole Troan9d420872017-10-12 13:06:35 +02001061}
1062
1063
Ole Troan33a58172019-09-04 09:12:29 +02001064def endianfun_array(o):
Ole Troandf87f802020-11-18 19:17:48 +01001065 '''Generate endian functions for arrays'''
Ole Troan33a58172019-09-04 09:12:29 +02001066 forloop = '''\
1067 for (i = 0; i < {length}; i++) {{
1068 a->{name}[i] = {format}(a->{name}[i]);
1069 }}
1070'''
1071
1072 forloop_format = '''\
1073 for (i = 0; i < {length}; i++) {{
1074 {type}_endian(&a->{name}[i]);
1075 }}
1076'''
1077
1078 output = ''
Ole Troan18327be2021-01-12 21:49:38 +01001079 if o.fieldtype == 'u8' or o.fieldtype == 'string' or o.fieldtype == 'bool':
Ole Troan33a58172019-09-04 09:12:29 +02001080 output += ' /* a->{n} = a->{n} (no-op) */\n'.format(n=o.fieldname)
1081 else:
1082 lfield = 'a->' + o.lengthfield if o.lengthfield else o.length
Ole Troandf87f802020-11-18 19:17:48 +01001083 if o.fieldtype in ENDIAN_STRINGS:
Ole Troan33a58172019-09-04 09:12:29 +02001084 output += (forloop
1085 .format(length=lfield,
Ole Troandf87f802020-11-18 19:17:48 +01001086 format=ENDIAN_STRINGS[o.fieldtype],
Ole Troan33a58172019-09-04 09:12:29 +02001087 name=o.fieldname))
1088 else:
1089 output += (forloop_format
1090 .format(length=lfield, type=o.fieldtype,
1091 name=o.fieldname))
1092 return output
1093
Ole Troandf87f802020-11-18 19:17:48 +01001094
1095NO_ENDIAN_CONVERSION = {'client_index': None}
1096
Ole Troan33a58172019-09-04 09:12:29 +02001097
1098def endianfun_obj(o):
Ole Troandf87f802020-11-18 19:17:48 +01001099 '''Generate endian conversion function for type'''
Ole Troan33a58172019-09-04 09:12:29 +02001100 output = ''
1101 if o.type == 'Array':
1102 return endianfun_array(o)
Ole Troandf87f802020-11-18 19:17:48 +01001103 if o.type != 'Field':
Ole Troan33a58172019-09-04 09:12:29 +02001104 output += (' s = format(s, "\\n{} {} {} (print not implemented");\n'
1105 .format(o.type, o.fieldtype, o.fieldname))
1106 return output
Ole Troandf87f802020-11-18 19:17:48 +01001107 if o.fieldname in NO_ENDIAN_CONVERSION:
Ole Troane796a182020-05-18 11:14:05 +02001108 output += ' /* a->{n} = a->{n} (no-op) */\n'.format(n=o.fieldname)
1109 return output
Ole Troandf87f802020-11-18 19:17:48 +01001110 if o.fieldtype in ENDIAN_STRINGS:
Ole Troan33a58172019-09-04 09:12:29 +02001111 output += (' a->{name} = {format}(a->{name});\n'
1112 .format(name=o.fieldname,
Ole Troandf87f802020-11-18 19:17:48 +01001113 format=ENDIAN_STRINGS[o.fieldtype]))
Ole Troan33a58172019-09-04 09:12:29 +02001114 elif o.fieldtype.startswith('vl_api_'):
1115 output += (' {type}_endian(&a->{name});\n'
1116 .format(type=o.fieldtype, name=o.fieldname))
1117 else:
1118 output += ' /* a->{n} = a->{n} (no-op) */\n'.format(n=o.fieldname)
1119
1120 return output
1121
1122
Ole Troan75761b92019-09-11 17:49:08 +02001123def endianfun(objs, modulename):
Ole Troandf87f802020-11-18 19:17:48 +01001124 '''Main entry point for endian function generation'''
Ole Troan9d420872017-10-12 13:06:35 +02001125 output = '''\
1126
1127/****** Endian swap functions *****/\n\
1128#ifdef vl_endianfun
Ole Troan33a58172019-09-04 09:12:29 +02001129#ifndef included_{module}_endianfun
1130#define included_{module}_endianfun
Ole Troan9d420872017-10-12 13:06:35 +02001131
1132#undef clib_net_to_host_uword
1133#ifdef LP64
1134#define clib_net_to_host_uword clib_net_to_host_u64
1135#else
1136#define clib_net_to_host_uword clib_net_to_host_u32
1137#endif
1138
1139'''
Ole Troan33a58172019-09-04 09:12:29 +02001140 output = output.format(module=modulename)
1141
1142 signature = '''\
1143static inline void vl_api_{name}_t_endian (vl_api_{name}_t *a)
1144{{
1145 int i __attribute__((unused));
1146'''
1147
Ole Troan2c2feab2018-04-24 00:02:37 -04001148 for t in objs:
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001149 if t.__class__.__name__ == 'Enum' or t.__class__.__name__ == 'EnumFlag':
Ole Troan33a58172019-09-04 09:12:29 +02001150 output += signature.format(name=t.name)
Ole Troandf87f802020-11-18 19:17:48 +01001151 if t.enumtype in ENDIAN_STRINGS:
Ole Troan33a58172019-09-04 09:12:29 +02001152 output += (' *a = {}(*a);\n'
Ole Troandf87f802020-11-18 19:17:48 +01001153 .format(ENDIAN_STRINGS[t.enumtype]))
Ole Troan33a58172019-09-04 09:12:29 +02001154 else:
1155 output += (' /* a->{name} = a->{name} (no-op) */\n'
1156 .format(name=t.name))
1157
1158 output += '}\n\n'
Ole Troan2c2feab2018-04-24 00:02:37 -04001159 continue
Ole Troan33a58172019-09-04 09:12:29 +02001160
Ole Troan9d420872017-10-12 13:06:35 +02001161 if t.manual_endian:
1162 output += "/***** manual: vl_api_%s_t_endian *****/\n\n" % t.name
1163 continue
Ole Troan33a58172019-09-04 09:12:29 +02001164
Ole Troan75761b92019-09-11 17:49:08 +02001165 if t.__class__.__name__ == 'Using':
1166 output += signature.format(name=t.name)
1167 if ('length' in t.alias and t.alias['length'] and
1168 t.alias['type'] == 'u8'):
1169 output += (' /* a->{name} = a->{name} (no-op) */\n'
1170 .format(name=t.name))
Ole Troandf87f802020-11-18 19:17:48 +01001171 elif t.alias['type'] in FORMAT_STRINGS:
Ole Troan75761b92019-09-11 17:49:08 +02001172 output += (' *a = {}(*a);\n'
Ole Troandf87f802020-11-18 19:17:48 +01001173 .format(ENDIAN_STRINGS[t.alias['type']]))
Ole Troan75761b92019-09-11 17:49:08 +02001174 else:
1175 output += ' /* Not Implemented yet {} */'.format(t.name)
1176 output += '}\n\n'
1177 continue
1178
Ole Troan33a58172019-09-04 09:12:29 +02001179 output += signature.format(name=t.name)
Ole Troan9d420872017-10-12 13:06:35 +02001180
1181 for o in t.block:
Ole Troan33a58172019-09-04 09:12:29 +02001182 output += endianfun_obj(o)
Ole Troan9d420872017-10-12 13:06:35 +02001183 output += '}\n\n'
Ole Troan33a58172019-09-04 09:12:29 +02001184
1185 output += "\n#endif"
Ole Troan9d420872017-10-12 13:06:35 +02001186 output += "\n#endif /* vl_endianfun */\n\n"
1187
1188 return output
1189
1190
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001191def calc_size_fun(objs, modulename):
1192 '''Main entry point for calculate size function generation'''
1193 output = '''\
1194
1195/****** Calculate size functions *****/\n\
1196#ifdef vl_calcsizefun
1197#ifndef included_{module}_calcsizefun
1198#define included_{module}_calcsizefun
1199
1200'''
1201 output = output.format(module=modulename)
1202
1203 signature = '''\
1204/* calculate message size of message in network byte order */
1205static inline uword vl_api_{name}_t_calc_size (vl_api_{name}_t *a)
1206{{
1207'''
1208
1209 for o in objs:
1210 tname = o.__class__.__name__
1211
1212 output += signature.format(name=o.name)
1213 output += f" return sizeof(*a)"
1214 if tname == 'Using':
1215 if 'length' in o.alias:
1216 try:
1217 tmp = int(o.alias['length'])
1218 if tmp == 0:
1219 raise (f"Unexpected length '0' for alias {o}")
1220 except:
1221 # output += f" + vl_api_{o.alias.name}_t_calc_size({o.name})"
1222 print("culprit:")
1223 print(o)
1224 print(dir(o.alias))
1225 print(o.alias)
1226 raise
1227 elif tname == 'Enum' or tname == 'EnumFlag':
1228 pass
1229 else:
1230 for b in o.block:
1231 if b.type == 'Option':
1232 continue
1233 elif b.type == 'Field':
1234 if b.fieldtype.startswith('vl_api_'):
1235 output += f" - sizeof(a->{b.fieldname})"
1236 output += f" + {b.fieldtype}_calc_size(&a->{b.fieldname})"
1237 elif b.type == 'Array':
1238 if b.lengthfield:
1239 m = list(filter(lambda x: x.fieldname == b.lengthfield, o.block))
1240 if len(m) != 1:
1241 raise Exception(f"Expected 1 match for field '{b.lengthfield}', got '{m}'")
1242 lf = m[0]
1243 if lf.fieldtype in ENDIAN_STRINGS:
1244 output += f" + {ENDIAN_STRINGS[lf.fieldtype]}(a->{b.lengthfield}) * sizeof(a->{b.fieldname}[0])"
1245 elif lf.fieldtype == "u8":
1246 output += f" + a->{b.lengthfield} * sizeof(a->{b.fieldname}[0])"
1247 else:
1248 raise Exception(f"Don't know how to endian swap {lf.fieldtype}")
1249 else:
1250 # Fixed length strings decay to nul terminated u8
1251 if b.fieldtype == 'string':
1252 if b.modern_vla:
1253 output += f" + vl_api_string_len(&a->{b.fieldname})"
1254
1255 output += ";\n"
1256 output += '}\n\n'
1257 output += "\n#endif"
1258 output += "\n#endif /* vl_calcsizefun */\n\n"
1259
1260 return output
1261
1262
Ole Troan9d420872017-10-12 13:06:35 +02001263def version_tuple(s, module):
Ole Troandf87f802020-11-18 19:17:48 +01001264 '''Generate semantic version string'''
Ole Troan9d420872017-10-12 13:06:35 +02001265 output = '''\
1266/****** Version tuple *****/
1267
1268#ifdef vl_api_version_tuple
1269
1270'''
Ole Troan2c2feab2018-04-24 00:02:37 -04001271 if 'version' in s['Option']:
1272 v = s['Option']['version']
Ole Troan9d420872017-10-12 13:06:35 +02001273 (major, minor, patch) = v.split('.')
1274 output += "vl_api_version_tuple(%s, %s, %s, %s)\n" % \
1275 (module, major, minor, patch)
1276
1277 output += "\n#endif /* vl_api_version_tuple */\n\n"
1278
1279 return output
1280
1281
Ole Troan2a1ca782019-09-19 01:08:30 +02001282def generate_include_enum(s, module, stream):
Ole Troandf87f802020-11-18 19:17:48 +01001283 '''Generate <name>.api_enum.h'''
Ole Troan2a1ca782019-09-19 01:08:30 +02001284 write = stream.write
1285
Ole Troandf87f802020-11-18 19:17:48 +01001286 if 'Define' in s:
Ole Troan2a1ca782019-09-19 01:08:30 +02001287 write('typedef enum {\n')
1288 for t in s['Define']:
1289 write(' VL_API_{},\n'.format(t.name.upper()))
Ole Troan3d812672020-09-15 10:53:34 +02001290 write(' VL_MSG_{}_LAST\n'.format(module.upper()))
Ole Troan2a1ca782019-09-19 01:08:30 +02001291 write('}} vl_api_{}_enum_t;\n'.format(module))
1292
Paul Vinciguerra7c8803d2019-11-21 17:16:18 -05001293
Ole Troandf87f802020-11-18 19:17:48 +01001294def generate_include_counters(s, stream):
1295 '''Include file for the counter data model types.'''
Ole Troan148c7b72020-10-07 18:05:37 +02001296 write = stream.write
1297
1298 for counters in s:
1299 csetname = counters.name
1300 write('typedef enum {\n')
1301 for c in counters.block:
1302 write(' {}_ERROR_{},\n'
1303 .format(csetname.upper(), c['name'].upper()))
1304 write(' {}_N_ERROR\n'.format(csetname.upper()))
1305 write('}} vl_counter_{}_enum_t;\n'.format(csetname))
1306
Ole Troan2c4acdd2021-05-06 14:09:50 +02001307 write('extern vlib_error_desc_t {}_error_counters[];\n'.format(csetname))
Ole Troan148c7b72020-10-07 18:05:37 +02001308
Ole Troandf87f802020-11-18 19:17:48 +01001309
Ole Troan2a1ca782019-09-19 01:08:30 +02001310def generate_include_types(s, module, stream):
Ole Troandf87f802020-11-18 19:17:48 +01001311 '''Generate separate API _types file.'''
Ole Troan2a1ca782019-09-19 01:08:30 +02001312 write = stream.write
1313
1314 write('#ifndef included_{module}_api_types_h\n'.format(module=module))
1315 write('#define included_{module}_api_types_h\n'.format(module=module))
1316
Ole Troanf92bfb12020-02-28 13:45:42 +01001317 if 'version' in s['Option']:
1318 v = s['Option']['version']
1319 (major, minor, patch) = v.split('.')
Ole Troandf87f802020-11-18 19:17:48 +01001320 write('#define VL_API_{m}_API_VERSION_MAJOR {v}\n'
1321 .format(m=module.upper(), v=major))
1322 write('#define VL_API_{m}_API_VERSION_MINOR {v}\n'
1323 .format(m=module.upper(), v=minor))
1324 write('#define VL_API_{m}_API_VERSION_PATCH {v}\n'
1325 .format(m=module.upper(), v=patch))
Ole Troanf92bfb12020-02-28 13:45:42 +01001326
Ole Troandf87f802020-11-18 19:17:48 +01001327 if 'Import' in s:
Ole Troan2a1ca782019-09-19 01:08:30 +02001328 write('/* Imported API files */\n')
1329 for i in s['Import']:
1330 filename = i.filename.replace('plugins/', '')
1331 write('#include <{}_types.h>\n'.format(filename))
1332
Klement Sekera0eb83f42021-12-02 16:36:34 +00001333 for o in itertools.chain(s['types'], s['Define']):
Ole Troan2a1ca782019-09-19 01:08:30 +02001334 tname = o.__class__.__name__
1335 if tname == 'Using':
1336 if 'length' in o.alias:
Ole Troandf87f802020-11-18 19:17:48 +01001337 write('typedef %s vl_api_%s_t[%s];\n' %
1338 (o.alias['type'], o.name, o.alias['length']))
Ole Troan2a1ca782019-09-19 01:08:30 +02001339 else:
1340 write('typedef %s vl_api_%s_t;\n' % (o.alias['type'], o.name))
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -05001341 elif tname == 'Enum' or tname == 'EnumFlag':
Ole Troan2a1ca782019-09-19 01:08:30 +02001342 if o.enumtype == 'u32':
1343 write("typedef enum {\n")
1344 else:
1345 write("typedef enum __attribute__((packed)) {\n")
1346
1347 for b in o.block:
1348 write(" %s = %s,\n" % (b[0], b[1]))
1349 write('} vl_api_%s_t;\n' % o.name)
1350 if o.enumtype != 'u32':
1351 size1 = 'sizeof(vl_api_%s_t)' % o.name
1352 size2 = 'sizeof(%s)' % o.enumtype
1353 err_str = 'size of API enum %s is wrong' % o.name
1354 write('STATIC_ASSERT(%s == %s, "%s");\n'
1355 % (size1, size2, err_str))
1356 else:
1357 if tname == 'Union':
Ole Troandf87f802020-11-18 19:17:48 +01001358 write("typedef union __attribute__ ((packed)) _vl_api_%s {\n"
1359 % o.name)
Ole Troan2a1ca782019-09-19 01:08:30 +02001360 else:
1361 write(("typedef struct __attribute__ ((packed)) _vl_api_%s {\n")
Ole Troandf87f802020-11-18 19:17:48 +01001362 % o.name)
Ole Troan2a1ca782019-09-19 01:08:30 +02001363 for b in o.block:
1364 if b.type == 'Option':
1365 continue
1366 if b.type == 'Field':
Ole Troandf87f802020-11-18 19:17:48 +01001367 write(" %s %s;\n" % (api2c(b.fieldtype),
1368 b.fieldname))
Ole Troan2a1ca782019-09-19 01:08:30 +02001369 elif b.type == 'Array':
1370 if b.lengthfield:
Ole Troandf87f802020-11-18 19:17:48 +01001371 write(" %s %s[0];\n" % (api2c(b.fieldtype),
1372 b.fieldname))
Ole Troan2a1ca782019-09-19 01:08:30 +02001373 else:
1374 # Fixed length strings decay to nul terminated u8
1375 if b.fieldtype == 'string':
1376 if b.modern_vla:
1377 write(' {} {};\n'
1378 .format(api2c(b.fieldtype),
1379 b.fieldname))
1380 else:
1381 write(' u8 {}[{}];\n'
1382 .format(b.fieldname, b.length))
1383 else:
1384 write(" %s %s[%s];\n" %
1385 (api2c(b.fieldtype), b.fieldname,
1386 b.length))
1387 else:
1388 raise ValueError("Error in processing type {} for {}"
1389 .format(b, o.name))
1390
1391 write('} vl_api_%s_t;\n' % o.name)
Klement Sekera0eb83f42021-12-02 16:36:34 +00001392 write(f'#define VL_API_{o.name.upper()}_IS_CONSTANT_SIZE ({0 if o.vla else 1})\n\n')
Ole Troan2a1ca782019-09-19 01:08:30 +02001393
Ole Troan3f2d5712019-12-07 00:39:49 +01001394 for t in s['Define']:
1395 write('#define VL_API_{ID}_CRC "{n}_{crc:08x}"\n'
1396 .format(n=t.name, ID=t.name.upper(), crc=t.crc))
1397
Ole Troan2a1ca782019-09-19 01:08:30 +02001398 write("\n#endif\n")
1399
1400
Ole Troan148c7b72020-10-07 18:05:37 +02001401def generate_c_boilerplate(services, defines, counters, file_crc,
1402 module, stream):
Ole Troandf87f802020-11-18 19:17:48 +01001403 '''VPP side plugin.'''
Ole Troan2a1ca782019-09-19 01:08:30 +02001404 write = stream.write
Ole Troan148c7b72020-10-07 18:05:37 +02001405 define_hash = {d.name: d for d in defines}
Ole Troan2a1ca782019-09-19 01:08:30 +02001406
1407 hdr = '''\
1408#define vl_endianfun /* define message structures */
1409#include "{module}.api.h"
1410#undef vl_endianfun
1411
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001412#define vl_calcsizefun
1413#include "{module}.api.h"
1414#undef vl_calsizefun
1415
Ole Troan2a1ca782019-09-19 01:08:30 +02001416/* instantiate all the print functions we know about */
1417#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
1418#define vl_printfun
1419#include "{module}.api.h"
1420#undef vl_printfun
1421
1422'''
1423
1424 write(hdr.format(module=module))
1425 write('static u16\n')
1426 write('setup_message_id_table (void) {\n')
Dave Barach39d69112019-11-27 11:42:13 -05001427 write(' api_main_t *am = my_api_main;\n')
Ole Troane796a182020-05-18 11:14:05 +02001428 write(' vl_msg_api_msg_config_t c;\n')
Ole Troandf87f802020-11-18 19:17:48 +01001429 write(' u16 msg_id_base = vl_msg_api_get_msg_ids ("{}_{crc:08x}", '
1430 'VL_MSG_{m}_LAST);\n'
Ole Troan3d812672020-09-15 10:53:34 +02001431 .format(module, crc=file_crc, m=module.upper()))
Ole Troan2a1ca782019-09-19 01:08:30 +02001432
Ole Troan2a1ca782019-09-19 01:08:30 +02001433 for d in defines:
1434 write(' vl_msg_api_add_msg_name_crc (am, "{n}_{crc:08x}",\n'
1435 ' VL_API_{ID} + msg_id_base);\n'
1436 .format(n=d.name, ID=d.name.upper(), crc=d.crc))
1437 for s in services:
Ole Troane796a182020-05-18 11:14:05 +02001438 d = define_hash[s.caller]
Ole Troandf87f802020-11-18 19:17:48 +01001439 write(' c = (vl_msg_api_msg_config_t) '
1440 ' {{.id = VL_API_{ID} + msg_id_base,\n'
1441 ' .name = "{n}",\n'
1442 ' .handler = vl_api_{n}_t_handler,\n'
1443 ' .cleanup = vl_noop_handler,\n'
1444 ' .endian = vl_api_{n}_t_endian,\n'
1445 ' .print = vl_api_{n}_t_print,\n'
Ole Troan976a0ed2021-05-18 11:52:47 +02001446 ' .traced = 1,\n'
1447 ' .replay = 1,\n'
Filip Tehlar36217e32021-07-23 08:51:10 +00001448 ' .print_json = vl_api_{n}_t_print_json,\n'
1449 ' .tojson = vl_api_{n}_t_tojson,\n'
1450 ' .fromjson = vl_api_{n}_t_fromjson,\n'
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001451 ' .calc_size = vl_api_{n}_t_calc_size,\n'
Neale Ranns9302cfe2021-02-02 09:21:52 +00001452 ' .is_autoendian = {auto}}};\n'
1453 .format(n=s.caller, ID=s.caller.upper(),
1454 auto=d.autoendian))
Ole Troane796a182020-05-18 11:14:05 +02001455 write(' vl_msg_api_config (&c);\n')
Ole Troanbad67922020-08-24 12:22:01 +02001456 try:
1457 d = define_hash[s.reply]
Ole Troandf87f802020-11-18 19:17:48 +01001458 write(' c = (vl_msg_api_msg_config_t) '
1459 '{{.id = VL_API_{ID} + msg_id_base,\n'
1460 ' .name = "{n}",\n'
1461 ' .handler = 0,\n'
1462 ' .cleanup = vl_noop_handler,\n'
1463 ' .endian = vl_api_{n}_t_endian,\n'
1464 ' .print = vl_api_{n}_t_print,\n'
Filip Tehlar36217e32021-07-23 08:51:10 +00001465 ' .traced = 1,\n'
1466 ' .replay = 1,\n'
1467 ' .print_json = vl_api_{n}_t_print_json,\n'
1468 ' .tojson = vl_api_{n}_t_tojson,\n'
1469 ' .fromjson = vl_api_{n}_t_fromjson,\n'
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001470 ' .calc_size = vl_api_{n}_t_calc_size,\n'
Neale Ranns9302cfe2021-02-02 09:21:52 +00001471 ' .is_autoendian = {auto}}};\n'
1472 .format(n=s.reply, ID=s.reply.upper(),
1473 auto=d.autoendian))
Ole Troanbad67922020-08-24 12:22:01 +02001474 write(' vl_msg_api_config (&c);\n')
1475 except KeyError:
1476 pass
Ole Troan2a1ca782019-09-19 01:08:30 +02001477
1478 write(' return msg_id_base;\n')
1479 write('}\n')
1480
Ole Troan148c7b72020-10-07 18:05:37 +02001481 severity = {'error': 'VL_COUNTER_SEVERITY_ERROR',
1482 'info': 'VL_COUNTER_SEVERITY_INFO',
1483 'warn': 'VL_COUNTER_SEVERITY_WARN'}
1484
1485 for cnt in counters:
1486 csetname = cnt.name
Ole Troan2c4acdd2021-05-06 14:09:50 +02001487 write('vlib_error_desc_t {}_error_counters[] = {{\n'.format(csetname))
Ole Troan148c7b72020-10-07 18:05:37 +02001488 for c in cnt.block:
1489 write(' {\n')
1490 write(' .name = "{}",\n'.format(c['name']))
1491 write(' .desc = "{}",\n'.format(c['description']))
1492 write(' .severity = {},\n'.format(severity[c['severity']]))
1493 write(' },\n')
1494 write('};\n')
Ole Troan2a1ca782019-09-19 01:08:30 +02001495
Ole Troandf87f802020-11-18 19:17:48 +01001496
1497def generate_c_test_boilerplate(services, defines, file_crc, module, plugin,
1498 stream):
1499 '''Generate code for legacy style VAT. To be deleted.'''
Ole Troan2a1ca782019-09-19 01:08:30 +02001500 write = stream.write
1501
Ole Troandf87f802020-11-18 19:17:48 +01001502 define_hash = {d.name: d for d in defines}
Ole Troan2a1ca782019-09-19 01:08:30 +02001503
1504 hdr = '''\
Ole Troandf87f802020-11-18 19:17:48 +01001505#define vl_endianfun /* define message structures */
Ole Troan2a1ca782019-09-19 01:08:30 +02001506#include "{module}.api.h"
1507#undef vl_endianfun
1508
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001509#define vl_calcsizefun
1510#include "{module}.api.h"
1511#undef vl_calsizefun
1512
Ole Troan2a1ca782019-09-19 01:08:30 +02001513/* instantiate all the print functions we know about */
1514#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
1515#define vl_printfun
1516#include "{module}.api.h"
1517#undef vl_printfun
1518
1519'''
1520
1521 write(hdr.format(module=module))
1522 for s in services:
1523 try:
1524 d = define_hash[s.reply]
Ole Troandf87f802020-11-18 19:17:48 +01001525 except KeyError:
Ole Troan2a1ca782019-09-19 01:08:30 +02001526 continue
1527 if d.manual_print:
Ole Troandf87f802020-11-18 19:17:48 +01001528 write('/*\n'
1529 ' * Manual definition requested for: \n'
1530 ' * vl_api_{n}_t_handler()\n'
1531 ' */\n'
Ole Troan2a1ca782019-09-19 01:08:30 +02001532 .format(n=s.reply))
1533 continue
1534 if not define_hash[s.caller].autoreply:
Ole Troandf87f802020-11-18 19:17:48 +01001535 write('/* Generation not supported (vl_api_{n}_t_handler()) */\n'
Ole Troan2a1ca782019-09-19 01:08:30 +02001536 .format(n=s.reply))
1537 continue
Paul Vinciguerra7c8803d2019-11-21 17:16:18 -05001538 write('#ifndef VL_API_{n}_T_HANDLER\n'.format(n=s.reply.upper()))
Ole Troan2a1ca782019-09-19 01:08:30 +02001539 write('static void\n')
Ole Troandf87f802020-11-18 19:17:48 +01001540 write('vl_api_{n}_t_handler (vl_api_{n}_t * mp) {{\n'
1541 .format(n=s.reply))
Ole Troan2a1ca782019-09-19 01:08:30 +02001542 write(' vat_main_t * vam = {}_test_main.vat_main;\n'.format(module))
1543 write(' i32 retval = ntohl(mp->retval);\n')
1544 write(' if (vam->async_mode) {\n')
1545 write(' vam->async_errors += (retval < 0);\n')
1546 write(' } else {\n')
1547 write(' vam->retval = retval;\n')
1548 write(' vam->result_ready = 1;\n')
1549 write(' }\n')
1550 write('}\n')
Ole Troan3ae9f5a2019-10-09 12:39:32 +02001551 write('#endif\n')
Ole Troan2a1ca782019-09-19 01:08:30 +02001552
Ole Troanb126ebc2019-10-07 16:22:00 +02001553 for e in s.events:
1554 if define_hash[e].manual_print:
1555 continue
1556 write('static void\n')
1557 write('vl_api_{n}_t_handler (vl_api_{n}_t * mp) {{\n'.format(n=e))
1558 write(' vl_print(0, "{n} event called:");\n'.format(n=e))
1559 write(' vl_api_{n}_t_print(mp, 0);\n'.format(n=e))
1560 write('}\n')
1561
Ole Troan2a1ca782019-09-19 01:08:30 +02001562 write('static void\n')
1563 write('setup_message_id_table (vat_main_t * vam, u16 msg_id_base) {\n')
1564 for s in services:
Ole Troandf87f802020-11-18 19:17:48 +01001565 write(' vl_msg_api_set_handlers(VL_API_{ID} + msg_id_base, '
1566 ' "{n}",\n'
1567 ' vl_api_{n}_t_handler, '
1568 ' vl_noop_handler,\n'
1569 ' vl_api_{n}_t_endian, '
1570 ' vl_api_{n}_t_print,\n'
Filip Tehlar36217e32021-07-23 08:51:10 +00001571 ' sizeof(vl_api_{n}_t), 1,\n'
1572 ' vl_api_{n}_t_print_json,\n'
1573 ' vl_api_{n}_t_tojson,\n'
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001574 ' vl_api_{n}_t_fromjson,\n'
1575 ' vl_api_{n}_t_calc_size);\n'
Ole Troan2a1ca782019-09-19 01:08:30 +02001576 .format(n=s.reply, ID=s.reply.upper()))
Ole Troandf87f802020-11-18 19:17:48 +01001577 write(' hash_set_mem (vam->function_by_name, "{n}", api_{n});\n'
1578 .format(n=s.caller))
Ole Troan2a1ca782019-09-19 01:08:30 +02001579 try:
1580 write(' hash_set_mem (vam->help_by_name, "{n}", "{help}");\n'
Ole Troandf87f802020-11-18 19:17:48 +01001581 .format(n=s.caller,
1582 help=define_hash[s.caller].options['vat_help']))
1583 except KeyError:
Ole Troan2a1ca782019-09-19 01:08:30 +02001584 pass
1585
Ole Troanb126ebc2019-10-07 16:22:00 +02001586 # Events
1587 for e in s.events:
Ole Troandf87f802020-11-18 19:17:48 +01001588 write(' vl_msg_api_set_handlers(VL_API_{ID} + msg_id_base, '
1589 ' "{n}",\n'
1590 ' vl_api_{n}_t_handler, '
1591 ' vl_noop_handler,\n'
1592 ' vl_api_{n}_t_endian, '
1593 ' vl_api_{n}_t_print,\n'
Filip Tehlar36217e32021-07-23 08:51:10 +00001594 ' sizeof(vl_api_{n}_t), 1,\n'
1595 ' vl_api_{n}_t_print_json,\n'
1596 ' vl_api_{n}_t_tojson,\n'
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001597 ' vl_api_{n}_t_fromjson,\n'
1598 ' vl_api_{n}_t_calc_size);\n'
Ole Troanb126ebc2019-10-07 16:22:00 +02001599 .format(n=e, ID=e.upper()))
1600
Ole Troan2a1ca782019-09-19 01:08:30 +02001601 write('}\n')
Florin Coras248210c2021-09-14 18:54:45 -07001602 write('clib_error_t * vat_plugin_register (vat_main_t *vam)\n')
Ole Troan2a1ca782019-09-19 01:08:30 +02001603 write('{\n')
1604 write(' {n}_test_main_t * mainp = &{n}_test_main;\n'.format(n=module))
1605 write(' mainp->vat_main = vam;\n')
Ole Troandf87f802020-11-18 19:17:48 +01001606 write(' mainp->msg_id_base = vl_client_get_first_plugin_msg_id '
1607 ' ("{n}_{crc:08x}");\n'
Ole Troan2a1ca782019-09-19 01:08:30 +02001608 .format(n=module, crc=file_crc))
1609 write(' if (mainp->msg_id_base == (u16) ~0)\n')
Ole Troandf87f802020-11-18 19:17:48 +01001610 write(' return clib_error_return (0, "{} plugin not loaded...");\n'
1611 .format(module))
Ole Troan2a1ca782019-09-19 01:08:30 +02001612 write(' setup_message_id_table (vam, mainp->msg_id_base);\n')
Ole Troan709dad32019-10-09 14:38:14 +02001613 write('#ifdef VL_API_LOCAL_SETUP_MESSAGE_ID_TABLE\n')
1614 write(' VL_API_LOCAL_SETUP_MESSAGE_ID_TABLE(vam);\n')
1615 write('#endif\n')
Ole Troan2a1ca782019-09-19 01:08:30 +02001616 write(' return 0;\n')
1617 write('}\n')
1618
Ole Troandf87f802020-11-18 19:17:48 +01001619
1620def apifunc(func):
1621 '''Check if a method is generated already.'''
1622 def _f(module, d, processed, *args):
1623 if d.name in processed:
1624 return None
1625 processed[d.name] = True
1626 return func(module, d, *args)
1627 return _f
1628
1629
1630def c_test_api_service(s, dump, stream):
1631 '''Generate JSON code for a service.'''
1632 write = stream.write
1633
1634 req_reply_template = '''\
1635static cJSON *
1636api_{n} (cJSON *o)
1637{{
1638 vl_api_{n}_t *mp;
1639 int len;
1640 if (!o) return 0;
1641 mp = vl_api_{n}_t_fromjson(o, &len);
1642 if (!mp) {{
1643 fprintf(stderr, "Failed converting JSON to API\\n");
1644 return 0;
1645 }}
1646
1647 mp->_vl_msg_id = vac_get_msg_index(VL_API_{N}_CRC);
1648 vl_api_{n}_t_endian(mp);
1649 vac_write((char *)mp, len);
Filip Tehlar36217e32021-07-23 08:51:10 +00001650 cJSON_free(mp);
Ole Troandf87f802020-11-18 19:17:48 +01001651
1652 /* Read reply */
1653 char *p;
1654 int l;
1655 vac_read(&p, &l, 5); // XXX: Fix timeout
Ole Troanedc73fd2021-02-17 13:26:53 +01001656 if (p == 0 || l == 0) return 0;
Ole Troandf87f802020-11-18 19:17:48 +01001657 // XXX Will fail in case of event received. Do loop
1658 if (ntohs(*((u16 *)p)) != vac_get_msg_index(VL_API_{R}_CRC)) {{
1659 fprintf(stderr, "Mismatched reply\\n");
1660 return 0;
1661 }}
1662 vl_api_{r}_t *rmp = (vl_api_{r}_t *)p;
1663 vl_api_{r}_t_endian(rmp);
1664 return vl_api_{r}_t_tojson(rmp);
1665}}
1666
1667'''
1668 dump_details_template = '''\
1669static cJSON *
1670api_{n} (cJSON *o)
1671{{
1672 u16 msg_id = vac_get_msg_index(VL_API_{N}_CRC);
1673 int len;
1674 if (!o) return 0;
1675 vl_api_{n}_t *mp = vl_api_{n}_t_fromjson(o, &len);
1676 if (!mp) {{
1677 fprintf(stderr, "Failed converting JSON to API\\n");
1678 return 0;
1679 }}
1680 mp->_vl_msg_id = msg_id;
1681 vl_api_{n}_t_endian(mp);
1682 vac_write((char *)mp, len);
Filip Tehlar36217e32021-07-23 08:51:10 +00001683 cJSON_free(mp);
Ole Troandf87f802020-11-18 19:17:48 +01001684
1685 vat2_control_ping(123); // FIX CONTEXT
1686 cJSON *reply = cJSON_CreateArray();
1687
1688 u16 ping_reply_msg_id = vac_get_msg_index(VL_API_CONTROL_PING_REPLY_CRC);
1689 u16 details_msg_id = vac_get_msg_index(VL_API_{R}_CRC);
1690
1691 while (1) {{
1692 /* Read reply */
1693 char *p;
1694 int l;
1695 vac_read(&p, &l, 5); // XXX: Fix timeout
Ole Troanedc73fd2021-02-17 13:26:53 +01001696 if (p == 0 || l == 0) {{
1697 cJSON_free(reply);
1698 return 0;
1699 }}
Ole Troandf87f802020-11-18 19:17:48 +01001700
1701 /* Message can be one of [_details, control_ping_reply
1702 * or unrelated event]
1703 */
1704 u16 reply_msg_id = ntohs(*((u16 *)p));
1705 if (reply_msg_id == ping_reply_msg_id) {{
1706 break;
1707 }}
1708
1709 if (reply_msg_id == details_msg_id) {{
Ole Troanedc73fd2021-02-17 13:26:53 +01001710 if (l < sizeof(vl_api_{r}_t)) {{
1711 cJSON_free(reply);
1712 return 0;
1713 }}
Ole Troandf87f802020-11-18 19:17:48 +01001714 vl_api_{r}_t *rmp = (vl_api_{r}_t *)p;
1715 vl_api_{r}_t_endian(rmp);
1716 cJSON_AddItemToArray(reply, vl_api_{r}_t_tojson(rmp));
1717 }}
1718 }}
1719 return reply;
1720}}
1721
1722'''
1723 gets_details_reply_template = '''\
1724static cJSON *
1725api_{n} (cJSON *o)
1726{{
1727 u16 msg_id = vac_get_msg_index(VL_API_{N}_CRC);
1728 int len = 0;
1729 if (!o) return 0;
1730 vl_api_{n}_t *mp = vl_api_{n}_t_fromjson(o, &len);
1731 if (!mp) {{
1732 fprintf(stderr, "Failed converting JSON to API\\n");
1733 return 0;
1734 }}
1735 mp->_vl_msg_id = msg_id;
1736
1737 vl_api_{n}_t_endian(mp);
1738 vac_write((char *)mp, len);
Filip Tehlar36217e32021-07-23 08:51:10 +00001739 cJSON_free(mp);
Ole Troandf87f802020-11-18 19:17:48 +01001740
1741 cJSON *reply = cJSON_CreateArray();
1742
1743 u16 reply_msg_id = vac_get_msg_index(VL_API_{R}_CRC);
1744 u16 details_msg_id = vac_get_msg_index(VL_API_{D}_CRC);
1745
1746 while (1) {{
1747 /* Read reply */
1748 char *p;
1749 int l;
1750 vac_read(&p, &l, 5); // XXX: Fix timeout
1751
1752 /* Message can be one of [_details, control_ping_reply
1753 * or unrelated event]
1754 */
1755 u16 msg_id = ntohs(*((u16 *)p));
1756 if (msg_id == reply_msg_id) {{
1757 vl_api_{r}_t *rmp = (vl_api_{r}_t *)p;
1758 vl_api_{r}_t_endian(rmp);
1759 cJSON_AddItemToArray(reply, vl_api_{r}_t_tojson(rmp));
1760 break;
1761 }}
1762
1763 if (msg_id == details_msg_id) {{
1764 vl_api_{d}_t *rmp = (vl_api_{d}_t *)p;
1765 vl_api_{d}_t_endian(rmp);
1766 cJSON_AddItemToArray(reply, vl_api_{d}_t_tojson(rmp));
1767 }}
1768 }}
1769 return reply;
1770}}
1771
1772'''
1773
1774 if dump:
1775 if s.stream_message:
1776 write(gets_details_reply_template
1777 .format(n=s.caller, r=s.reply, N=s.caller.upper(),
1778 R=s.reply.upper(), d=s.stream_message,
1779 D=s.stream_message.upper()))
1780 else:
1781 write(dump_details_template.format(n=s.caller, r=s.reply,
1782 N=s.caller.upper(),
1783 R=s.reply.upper()))
1784 else:
1785 write(req_reply_template.format(n=s.caller, r=s.reply,
1786 N=s.caller.upper(),
1787 R=s.reply.upper()))
1788
1789
1790def generate_c_test2_boilerplate(services, defines, module, stream):
1791 '''Generate code for VAT2 plugin.'''
1792 write = stream.write
1793
1794 define_hash = {d.name: d for d in defines}
1795 # replies = {}
1796
1797 hdr = '''\
1798#include <vlibapi/api.h>
1799#include <vlibmemory/api.h>
1800#include <vppinfra/error.h>
1801#include <vnet/ip/ip_format_fns.h>
1802#include <vnet/ethernet/ethernet_format_fns.h>
1803
1804#define vl_typedefs /* define message structures */
Filip Tehlarb7e4d442021-07-08 18:44:19 +00001805#include <vlibmemory/vl_memory_api_h.h>
Florin Corasa1400ce2021-09-15 09:02:08 -07001806#include <vlibmemory/vlib.api_types.h>
1807#include <vlibmemory/vlib.api.h>
Ole Troandf87f802020-11-18 19:17:48 +01001808#undef vl_typedefs
1809
1810#include "{module}.api_enum.h"
1811#include "{module}.api_types.h"
1812
1813#define vl_endianfun /* define message structures */
1814#include "{module}.api.h"
1815#undef vl_endianfun
1816
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001817#define vl_calcsizefun
1818#include "{module}.api.h"
1819#undef vl_calsizefun
1820
Ole Troandf87f802020-11-18 19:17:48 +01001821#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
1822#define vl_printfun
1823#include "{module}.api.h"
1824#undef vl_printfun
1825
1826#include "{module}.api_tojson.h"
1827#include "{module}.api_fromjson.h"
1828#include <vpp-api/client/vppapiclient.h>
1829
1830#include <vat2/vat2_helpers.h>
1831
1832'''
1833
1834 write(hdr.format(module=module))
1835
1836 for s in services:
1837 if s.reply not in define_hash:
1838 continue
1839 c_test_api_service(s, s.stream, stream)
1840
Filip Tehlar36217e32021-07-23 08:51:10 +00001841 write('void vat2_register_function(char *, cJSON * (*)(cJSON *), cJSON * (*)(void *), u32);\n')
Ole Troandf87f802020-11-18 19:17:48 +01001842 # write('__attribute__((constructor))')
1843 write('clib_error_t *\n')
1844 write('vat2_register_plugin (void) {\n')
1845 for s in services:
Filip Tehlar36217e32021-07-23 08:51:10 +00001846 if s.reply not in define_hash:
1847 continue
1848 crc = define_hash[s.caller].crc
1849 write(' vat2_register_function("{n}", api_{n}, (cJSON * (*)(void *))vl_api_{n}_t_tojson, 0x{crc:08x});\n'
1850 .format(n=s.caller, crc=crc))
Ole Troandf87f802020-11-18 19:17:48 +01001851 write(' return 0;\n')
1852 write('}\n')
1853
1854
Ole Troan9d420872017-10-12 13:06:35 +02001855#
1856# Plugin entry point
1857#
Ole Troandf87f802020-11-18 19:17:48 +01001858def run(args, apifilename, s):
1859 '''Main plugin entry point.'''
Ole Troan33a58172019-09-04 09:12:29 +02001860 stream = StringIO()
Ole Troan2a1ca782019-09-19 01:08:30 +02001861
1862 if not args.outputdir:
1863 sys.stderr.write('Missing --outputdir argument')
1864 return None
1865
Ole Troandf87f802020-11-18 19:17:48 +01001866 basename = os.path.basename(apifilename)
1867 filename, _ = os.path.splitext(basename)
Ole Troan33a58172019-09-04 09:12:29 +02001868 modulename = filename.replace('.', '_')
Ole Troan2a1ca782019-09-19 01:08:30 +02001869 filename_enum = os.path.join(args.outputdir + '/' + basename + '_enum.h')
1870 filename_types = os.path.join(args.outputdir + '/' + basename + '_types.h')
1871 filename_c = os.path.join(args.outputdir + '/' + basename + '.c')
1872 filename_c_test = os.path.join(args.outputdir + '/' + basename + '_test.c')
Ole Troandf87f802020-11-18 19:17:48 +01001873 filename_c_test2 = (os.path.join(args.outputdir + '/' + basename +
1874 '_test2.c'))
1875 filename_c_tojson = (os.path.join(args.outputdir +
1876 '/' + basename + '_tojson.h'))
1877 filename_c_fromjson = (os.path.join(args.outputdir + '/' +
1878 basename + '_fromjson.h'))
Ole Troan2a1ca782019-09-19 01:08:30 +02001879
1880 # Generate separate types file
1881 st = StringIO()
1882 generate_include_types(s, modulename, st)
Ole Troandf87f802020-11-18 19:17:48 +01001883 with open(filename_types, 'w') as fd:
1884 st.seek(0)
1885 shutil.copyfileobj(st, fd)
Ole Troan2a1ca782019-09-19 01:08:30 +02001886 st.close()
1887
1888 # Generate separate enum file
1889 st = StringIO()
Ole Troan148c7b72020-10-07 18:05:37 +02001890 st.write('#ifndef included_{}_api_enum_h\n'.format(modulename))
1891 st.write('#define included_{}_api_enum_h\n'.format(modulename))
Ole Troan2a1ca782019-09-19 01:08:30 +02001892 generate_include_enum(s, modulename, st)
Ole Troandf87f802020-11-18 19:17:48 +01001893 generate_include_counters(s['Counters'], st)
Ole Troan148c7b72020-10-07 18:05:37 +02001894 st.write('#endif\n')
Ole Troandf87f802020-11-18 19:17:48 +01001895 with open(filename_enum, 'w') as fd:
1896 st.seek(0)
1897 shutil.copyfileobj(st, fd)
Ole Troan2a1ca782019-09-19 01:08:30 +02001898 st.close()
1899
1900 # Generate separate C file
1901 st = StringIO()
Ole Troan148c7b72020-10-07 18:05:37 +02001902 generate_c_boilerplate(s['Service'], s['Define'], s['Counters'],
1903 s['file_crc'], modulename, st)
Ole Troandf87f802020-11-18 19:17:48 +01001904 with open(filename_c, 'w') as fd:
1905 st.seek(0)
Ole Troan2a1ca782019-09-19 01:08:30 +02001906 shutil.copyfileobj(st, fd)
1907 st.close()
1908
1909 # Generate separate C test file
Ole Troan2a1ca782019-09-19 01:08:30 +02001910 st = StringIO()
Ole Troandf87f802020-11-18 19:17:48 +01001911 plugin = bool('plugin' in apifilename)
1912 generate_c_test_boilerplate(s['Service'], s['Define'],
1913 s['file_crc'],
Ole Troan3d812672020-09-15 10:53:34 +02001914 modulename, plugin, st)
Ole Troandf87f802020-11-18 19:17:48 +01001915 with open(filename_c_test, 'w') as fd:
1916 st.seek(0)
Ole Troan2a1ca782019-09-19 01:08:30 +02001917 shutil.copyfileobj(st, fd)
1918 st.close()
Ole Troan33a58172019-09-04 09:12:29 +02001919
Ole Troandf87f802020-11-18 19:17:48 +01001920 # Fully autogenerated VATv2 C test file
1921 st = StringIO()
1922 generate_c_test2_boilerplate(s['Service'], s['Define'],
1923 modulename, st)
1924 with open(filename_c_test2, 'w') as fd:
1925 st.seek(0)
1926 shutil.copyfileobj(st, fd)
1927 st.close() #
1928
1929 # Generate separate JSON file
1930 st = StringIO()
1931 generate_tojson(s, modulename, st)
1932 with open(filename_c_tojson, 'w') as fd:
1933 st.seek(0)
1934 shutil.copyfileobj(st, fd)
1935 st.close()
1936 st = StringIO()
1937 generate_fromjson(s, modulename, st)
1938 with open(filename_c_fromjson, 'w') as fd:
1939 st.seek(0)
1940 shutil.copyfileobj(st, fd)
1941 st.close()
1942
1943 output = TOP_BOILERPLATE.format(datestring=DATESTRING,
Ole Troan9d420872017-10-12 13:06:35 +02001944 input_filename=basename)
Ole Troandf87f802020-11-18 19:17:48 +01001945 output += generate_imports(s['Import'])
Ole Troan9d420872017-10-12 13:06:35 +02001946 output += msg_ids(s)
1947 output += msg_names(s)
1948 output += msg_name_crc_list(s, filename)
Ole Troan2a1ca782019-09-19 01:08:30 +02001949 output += typedefs(modulename)
Ole Troan75761b92019-09-11 17:49:08 +02001950 printfun_types(s['types'], stream, modulename)
Ole Troan33a58172019-09-04 09:12:29 +02001951 printfun(s['Define'], stream, modulename)
1952 output += stream.getvalue()
Ole Troan2a1ca782019-09-19 01:08:30 +02001953 stream.close()
Ole Troan75761b92019-09-11 17:49:08 +02001954 output += endianfun(s['types'] + s['Define'], modulename)
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001955 output += calc_size_fun(s['types'] + s['Define'], modulename)
Ole Troan9d420872017-10-12 13:06:35 +02001956 output += version_tuple(s, basename)
Ole Troandf87f802020-11-18 19:17:48 +01001957 output += BOTTOM_BOILERPLATE.format(input_filename=basename,
Ole Troan8dbfb432019-04-24 14:31:18 +02001958 file_crc=s['file_crc'])
Ole Troan9d420872017-10-12 13:06:35 +02001959
1960 return output