blob: 5ca2ed51ff6b81ef38eb1b2b63cb44430de3001a [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
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020021"""
Ole Troandf87f802020-11-18 19:17:48 +010022This module creates C code for core VPP, VPP plugins and client side VAT and
23VAT2 tests.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020024"""
Ole Troandf87f802020-11-18 19:17:48 +010025
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###############################################################################
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020038class ToJSON:
39 """Class to generate functions converting from VPP binary API to JSON."""
40
Ole Troandf87f802020-11-18 19:17:48 +010041 _dispatch = {}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020042 noprint_fields = {"_vl_msg_id": None, "client_index": None, "context": None}
43 is_number = {
44 "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 }
Ole Troandf87f802020-11-18 19:17:48 +010054
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
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020060 self.types_hash = {"vl_api_" + d.name + "_t": d for d in types + imported_types}
Ole Troandf87f802020-11-18 19:17:48 +010061 self.defines_hash = {d.name: d for d in defines}
62
63 def header(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020064 """Output the top boilerplate."""
Ole Troandf87f802020-11-18 19:17:48 +010065 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020066 write("#ifndef included_{}_api_tojson_h\n".format(self.module))
67 write("#define included_{}_api_tojson_h\n".format(self.module))
68 write("#include <vppinfra/cJSON.h>\n\n")
69 write("#include <vppinfra/jsonformat.h>\n\n")
70 if self.module == "interface_types":
71 write("#define vl_printfun\n")
72 write("#include <vnet/interface_types.api.h>\n\n")
Ole Troandf87f802020-11-18 19:17:48 +010073
74 def footer(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020075 """Output the bottom boilerplate."""
Ole Troandf87f802020-11-18 19:17:48 +010076 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020077 write("#endif\n")
Ole Troandf87f802020-11-18 19:17:48 +010078
Ole Troan18327be2021-01-12 21:49:38 +010079 def get_base_type(self, t):
Ole Troandf87f802020-11-18 19:17:48 +010080 vt_type = None
81 try:
82 vt = self.types_hash[t]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020083 if vt.type == "Using" and "length" not in vt.alias:
84 vt_type = vt.alias["type"]
Ole Troandf87f802020-11-18 19:17:48 +010085 except KeyError:
86 vt = t
Ole Troan18327be2021-01-12 21:49:38 +010087 return vt, vt_type
88
89 def get_json_func(self, t):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020090 """Given the type, returns the function to use to create a
91 cJSON object"""
Ole Troan18327be2021-01-12 21:49:38 +010092 vt, vt_type = self.get_base_type(t)
Ole Troandf87f802020-11-18 19:17:48 +010093
94 if t in self.is_number or vt_type in self.is_number:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020095 return "cJSON_AddNumberToObject", "", False
96 if t == "bool":
97 return "cJSON_AddBoolToObject", "", False
Ole Troandf87f802020-11-18 19:17:48 +010098
99 # Lookup type name check if it's enum
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200100 if vt.type == "Enum" or vt.type == "EnumFlag":
101 return "{t}_tojson".format(t=t), "", True
102 return "{t}_tojson".format(t=t), "&", True
Ole Troandf87f802020-11-18 19:17:48 +0100103
104 def get_json_array_func(self, t):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200105 """Given a type returns the function to create a cJSON object
106 for arrays."""
Ole Troandf87f802020-11-18 19:17:48 +0100107 if t in self.is_number:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200108 return "cJSON_CreateNumber", ""
109 if t == "bool":
110 return "cJSON_CreateBool", ""
Ole Troan18327be2021-01-12 21:49:38 +0100111 vt, vt_type = self.get_base_type(t)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200112 if vt.type == "Enum" or vt.type == "EnumFlag":
113 return "{t}_tojson".format(t=t), ""
114 return "{t}_tojson".format(t=t), "&"
Ole Troandf87f802020-11-18 19:17:48 +0100115
116 def print_string(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200117 """Create cJSON object from vl_api_string_t"""
Ole Troandf87f802020-11-18 19:17:48 +0100118 write = self.stream.write
119 if o.modern_vla:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200120 write(
121 ' vl_api_string_cJSON_AddToObject(o, "{n}", &a->{n});\n'.format(
122 n=o.fieldname
123 )
124 )
Ole Troandf87f802020-11-18 19:17:48 +0100125 else:
126
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200127 write(
128 ' cJSON_AddStringToObject(o, "{n}", (char *)a->{n});\n'.format(
129 n=o.fieldname
130 )
131 )
Ole Troandf87f802020-11-18 19:17:48 +0100132
133 def print_field(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200134 """Called for every field in a typedef or define."""
Ole Troandf87f802020-11-18 19:17:48 +0100135 write = self.stream.write
136 if o.fieldname in self.noprint_fields:
137 return
138
139 f, p, newobj = self.get_json_func(o.fieldtype)
140
141 if newobj:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200142 write(
143 ' cJSON_AddItemToObject(o, "{n}", {f}({p}a->{n}));\n'.format(
144 f=f, p=p, n=o.fieldname
145 )
146 )
Ole Troandf87f802020-11-18 19:17:48 +0100147 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200148 write(' {f}(o, "{n}", {p}a->{n});\n'.format(f=f, p=p, n=o.fieldname))
Ole Troandf87f802020-11-18 19:17:48 +0100149
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200150 _dispatch["Field"] = print_field
Ole Troandf87f802020-11-18 19:17:48 +0100151
152 def print_array(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200153 """Converts a VPP API array to cJSON array."""
Ole Troandf87f802020-11-18 19:17:48 +0100154 write = self.stream.write
155
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200156 forloop = """\
Ole Troandf87f802020-11-18 19:17:48 +0100157 {{
158 int i;
159 cJSON *array = cJSON_AddArrayToObject(o, "{n}");
160 for (i = 0; i < {lfield}; i++) {{
161 cJSON_AddItemToArray(array, {f}({p}a->{n}[i]));
162 }}
163 }}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200164"""
Ole Troandf87f802020-11-18 19:17:48 +0100165
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200166 if o.fieldtype == "string":
Ole Troandf87f802020-11-18 19:17:48 +0100167 self.print_string(o)
168 return
169
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200170 lfield = "a->" + o.lengthfield if o.lengthfield else o.length
171 if o.fieldtype == "u8":
172 write(" {\n")
Ole Troandf87f802020-11-18 19:17:48 +0100173 # What is length field doing here?
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200174 write(
175 ' u8 *s = format(0, "0x%U", format_hex_bytes, '
176 "&a->{n}, {lfield});\n".format(n=o.fieldname, lfield=lfield)
177 )
178 write(
179 ' cJSON_AddStringToObject(o, "{n}", (char *)s);\n'.format(
180 n=o.fieldname
181 )
182 )
183 write(" vec_free(s);\n")
184 write(" }\n")
Ole Troandf87f802020-11-18 19:17:48 +0100185 return
186
187 f, p = self.get_json_array_func(o.fieldtype)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200188 write(forloop.format(lfield=lfield, t=o.fieldtype, n=o.fieldname, f=f, p=p))
Ole Troandf87f802020-11-18 19:17:48 +0100189
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200190 _dispatch["Array"] = print_array
Ole Troandf87f802020-11-18 19:17:48 +0100191
192 def print_enum(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200193 """Create cJSON object (string) for VPP API enum"""
Ole Troandf87f802020-11-18 19:17:48 +0100194 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200195 write(
196 "static inline cJSON *vl_api_{name}_t_tojson "
197 "(vl_api_{name}_t a) {{\n".format(name=o.name)
198 )
Ole Troandf87f802020-11-18 19:17:48 +0100199
200 write(" switch(a) {\n")
201 for b in o.block:
202 write(" case %s:\n" % b[1])
203 write(' return cJSON_CreateString("{}");\n'.format(b[0]))
204 write(' default: return cJSON_CreateString("Invalid ENUM");\n')
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200205 write(" }\n")
206 write(" return 0;\n")
207 write("}\n")
Ole Troandf87f802020-11-18 19:17:48 +0100208
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200209 _dispatch["Enum"] = print_enum
Ole Troan793be462020-12-04 13:15:30 +0100210
211 def print_enum_flag(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200212 """Create cJSON object (string) for VPP API enum"""
Ole Troan793be462020-12-04 13:15:30 +0100213 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200214 write(
215 "static inline cJSON *vl_api_{name}_t_tojson "
216 "(vl_api_{name}_t a) {{\n".format(name=o.name)
217 )
218 write(" cJSON *array = cJSON_CreateArray();\n")
Ole Troan793be462020-12-04 13:15:30 +0100219
220 for b in o.block:
Ole Troan45517152021-11-23 10:49:36 +0100221 if b[1] == 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200222 continue
223 write(" if (a & {})\n".format(b[0]))
Klement Sekera9b7e8ac2021-11-22 21:26:20 +0100224 write(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200225 ' cJSON_AddItemToArray(array, cJSON_CreateString("{}"));\n'.format(
226 b[0]
227 )
228 )
229 write(" return array;\n")
230 write("}\n")
Ole Troan793be462020-12-04 13:15:30 +0100231
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200232 _dispatch["EnumFlag"] = print_enum_flag
Ole Troandf87f802020-11-18 19:17:48 +0100233
234 def print_typedef(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200235 """Create cJSON (dictionary) object from VPP API typedef"""
Ole Troandf87f802020-11-18 19:17:48 +0100236 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200237 write(
238 "static inline cJSON *vl_api_{name}_t_tojson "
239 "(vl_api_{name}_t *a) {{\n".format(name=o.name)
240 )
241 write(" cJSON *o = cJSON_CreateObject();\n")
Ole Troandf87f802020-11-18 19:17:48 +0100242
243 for t in o.block:
244 self._dispatch[t.type](self, t)
245
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200246 write(" return o;\n")
247 write("}\n")
Ole Troandf87f802020-11-18 19:17:48 +0100248
249 def print_define(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200250 """Create cJSON (dictionary) object from VPP API define"""
Ole Troandf87f802020-11-18 19:17:48 +0100251 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200252 write(
253 "static inline cJSON *vl_api_{name}_t_tojson "
254 "(vl_api_{name}_t *a) {{\n".format(name=o.name)
255 )
256 write(" cJSON *o = cJSON_CreateObject();\n")
257 write(' cJSON_AddStringToObject(o, "_msgname", "{}");\n'.format(o.name))
258 write(
259 ' cJSON_AddStringToObject(o, "_crc", "{crc:08x}");\n'.format(crc=o.crc)
260 )
Ole Troandf87f802020-11-18 19:17:48 +0100261
262 for t in o.block:
263 self._dispatch[t.type](self, t)
264
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200265 write(" return o;\n")
266 write("}\n")
Ole Troandf87f802020-11-18 19:17:48 +0100267
268 def print_using(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200269 """Create cJSON (dictionary) object from VPP API aliased type"""
Ole Troandf87f802020-11-18 19:17:48 +0100270 if o.manual_print:
271 return
272
273 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200274 write(
275 "static inline cJSON *vl_api_{name}_t_tojson "
276 "(vl_api_{name}_t *a) {{\n".format(name=o.name)
277 )
Ole Troandf87f802020-11-18 19:17:48 +0100278
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200279 write(' u8 *s = format(0, "%U", format_vl_api_{}_t, a);\n'.format(o.name))
280 write(" cJSON *o = cJSON_CreateString((char *)s);\n")
281 write(" vec_free(s);\n")
282 write(" return o;\n")
283 write("}\n")
Ole Troandf87f802020-11-18 19:17:48 +0100284
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200285 _dispatch["Typedef"] = print_typedef
286 _dispatch["Define"] = print_define
287 _dispatch["Using"] = print_using
288 _dispatch["Union"] = print_typedef
Ole Troandf87f802020-11-18 19:17:48 +0100289
290 def generate_function(self, t):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200291 """Main entry point"""
Ole Troandf87f802020-11-18 19:17:48 +0100292 write = self.stream.write
293 if t.manual_print:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200294 write("/* Manual print {} */\n".format(t.name))
Ole Troandf87f802020-11-18 19:17:48 +0100295 return
296 self._dispatch[t.type](self, t)
297
298 def generate_types(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200299 """Main entry point"""
Ole Troandf87f802020-11-18 19:17:48 +0100300 for t in self.types:
301 self.generate_function(t)
302
303 def generate_defines(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200304 """Main entry point"""
Ole Troandf87f802020-11-18 19:17:48 +0100305 for t in self.defines:
306 self.generate_function(t)
307
308
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200309class FromJSON:
310 """
Ole Troandf87f802020-11-18 19:17:48 +0100311 Parse JSON objects into VPP API binary message structures.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200312 """
313
Ole Troandf87f802020-11-18 19:17:48 +0100314 _dispatch = {}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200315 noprint_fields = {"_vl_msg_id": None, "client_index": None, "context": None}
316 is_number = {
317 "u8": None,
318 "i8": None,
319 "u16": None,
320 "i16": None,
321 "u32": None,
322 "i32": None,
323 "u64": None,
324 "i64": None,
325 "f64": None,
326 }
Ole Troandf87f802020-11-18 19:17:48 +0100327
328 def __init__(self, module, types, defines, imported_types, stream):
329 self.stream = stream
330 self.module = module
331 self.defines = defines
332 self.types = types
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200333 self.types_hash = {"vl_api_" + d.name + "_t": d for d in types + imported_types}
Ole Troandf87f802020-11-18 19:17:48 +0100334 self.defines_hash = {d.name: d for d in defines}
335
336 def header(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200337 """Output the top boilerplate."""
Ole Troandf87f802020-11-18 19:17:48 +0100338 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200339 write("#ifndef included_{}_api_fromjson_h\n".format(self.module))
340 write("#define included_{}_api_fromjson_h\n".format(self.module))
341 write("#include <vppinfra/cJSON.h>\n\n")
342 write("#include <vppinfra/jsonformat.h>\n\n")
Ole Troanfb0afab2021-02-11 11:13:46 +0100343 write('#pragma GCC diagnostic ignored "-Wunused-label"\n')
Ole Troandf87f802020-11-18 19:17:48 +0100344
345 def is_base_type(self, t):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200346 """Check if a type is one of the VPP API base types"""
Ole Troandf87f802020-11-18 19:17:48 +0100347 if t in self.is_number:
348 return True
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200349 if t == "bool":
Ole Troandf87f802020-11-18 19:17:48 +0100350 return True
351 return False
352
353 def footer(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200354 """Output the bottom boilerplate."""
Ole Troandf87f802020-11-18 19:17:48 +0100355 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200356 write("#endif\n")
Ole Troandf87f802020-11-18 19:17:48 +0100357
358 def print_string(self, o, toplevel=False):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200359 """Convert JSON string to vl_api_string_t"""
Ole Troandf87f802020-11-18 19:17:48 +0100360 write = self.stream.write
361
Ole Troanfb0afab2021-02-11 11:13:46 +0100362 msgvar = "a" if toplevel else "*mp"
Ole Troandf87f802020-11-18 19:17:48 +0100363 msgsize = "l" if toplevel else "*len"
364
365 if o.modern_vla:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200366 write(" char *p = cJSON_GetStringValue(item);\n")
367 write(" size_t plen = strlen(p);\n")
368 write(
369 " {msgvar} = cJSON_realloc({msgvar}, {msgsize} + plen, {msgsize});\n".format(
370 msgvar=msgvar, msgsize=msgsize
371 )
372 )
373 write(" if ({msgvar} == 0) goto error;\n".format(msgvar=msgvar))
374 write(
375 " vl_api_c_string_to_api_string(p, (void *){msgvar} + "
376 "{msgsize} - sizeof(vl_api_string_t));\n".format(
377 msgvar=msgvar, msgsize=msgsize
378 )
379 )
380 write(" {msgsize} += plen;\n".format(msgsize=msgsize))
Ole Troandf87f802020-11-18 19:17:48 +0100381 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200382 write(
383 " strncpy_s((char *)a->{n}, sizeof(a->{n}), "
384 "cJSON_GetStringValue(item), sizeof(a->{n}) - 1);\n".format(
385 n=o.fieldname
386 )
387 )
Ole Troandf87f802020-11-18 19:17:48 +0100388
389 def print_field(self, o, toplevel=False):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200390 """Called for every field in a typedef or define."""
Ole Troandf87f802020-11-18 19:17:48 +0100391 write = self.stream.write
Ole Troandf87f802020-11-18 19:17:48 +0100392 if o.fieldname in self.noprint_fields:
393 return
394 is_bt = self.is_base_type(o.fieldtype)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200395 t = "vl_api_{}".format(o.fieldtype) if is_bt else o.fieldtype
Ole Troandf87f802020-11-18 19:17:48 +0100396
Ole Troanfb0afab2021-02-11 11:13:46 +0100397 msgvar = "(void **)&a" if toplevel else "mp"
Ole Troandf87f802020-11-18 19:17:48 +0100398 msgsize = "&l" if toplevel else "len"
399
400 if is_bt:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200401 write(
402 " vl_api_{t}_fromjson(item, &a->{n});\n".format(
403 t=o.fieldtype, n=o.fieldname
404 )
405 )
Ole Troandf87f802020-11-18 19:17:48 +0100406 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200407 write(
408 " if ({t}_fromjson({msgvar}, "
409 "{msgsize}, item, &a->{n}) < 0) goto error;\n".format(
410 t=t, n=o.fieldname, msgvar=msgvar, msgsize=msgsize
411 )
412 )
Ole Troandf87f802020-11-18 19:17:48 +0100413
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200414 _dispatch["Field"] = print_field
Ole Troandf87f802020-11-18 19:17:48 +0100415
416 def print_array(self, o, toplevel=False):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200417 """Convert JSON array to VPP API array"""
Ole Troandf87f802020-11-18 19:17:48 +0100418 write = self.stream.write
419
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200420 forloop = """\
Ole Troandf87f802020-11-18 19:17:48 +0100421 {{
422 int i;
423 cJSON *array = cJSON_GetObjectItem(o, "{n}");
424 int size = cJSON_GetArraySize(array);
Ole Troan384c72f2021-02-17 13:46:54 +0100425 if (size != {lfield}) goto error;
Ole Troandf87f802020-11-18 19:17:48 +0100426 for (i = 0; i < size; i++) {{
427 cJSON *e = cJSON_GetArrayItem(array, i);
428 {call}
429 }}
430 }}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200431"""
432 forloop_vla = """\
Ole Troandf87f802020-11-18 19:17:48 +0100433 {{
434 int i;
435 cJSON *array = cJSON_GetObjectItem(o, "{n}");
436 int size = cJSON_GetArraySize(array);
437 {lfield} = size;
Filip Tehlar36217e32021-07-23 08:51:10 +0000438 {realloc} = cJSON_realloc({realloc}, {msgsize} + sizeof({t}) * size, {msgsize});
Ole Troancf0102b2021-02-12 11:48:12 +0100439 {t} *d = (void *){realloc} + {msgsize};
Ole Troandf87f802020-11-18 19:17:48 +0100440 {msgsize} += sizeof({t}) * size;
441 for (i = 0; i < size; i++) {{
442 cJSON *e = cJSON_GetArrayItem(array, i);
443 {call}
444 }}
445 }}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200446"""
Ole Troandf87f802020-11-18 19:17:48 +0100447 t = o.fieldtype
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200448 if o.fieldtype == "string":
Ole Troandf87f802020-11-18 19:17:48 +0100449 self.print_string(o, toplevel)
450 return
451
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200452 lfield = "a->" + o.lengthfield if o.lengthfield else o.length
Ole Troanfb0afab2021-02-11 11:13:46 +0100453 msgvar = "(void **)&a" if toplevel else "mp"
Ole Troancf0102b2021-02-12 11:48:12 +0100454 realloc = "a" if toplevel else "*mp"
Ole Troandf87f802020-11-18 19:17:48 +0100455 msgsize = "l" if toplevel else "*len"
456
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200457 if o.fieldtype == "u8":
Ole Troandf87f802020-11-18 19:17:48 +0100458 if o.lengthfield:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200459 write(' s = u8string_fromjson(o, "{}");\n'.format(o.fieldname))
460 write(" if (!s) goto error;\n")
461 write(" {} = vec_len(s);\n".format(lfield))
Ole Troandf87f802020-11-18 19:17:48 +0100462
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200463 write(
464 " {realloc} = cJSON_realloc({realloc}, {msgsize} + "
465 "vec_len(s), {msgsize});\n".format(
466 msgvar=msgvar, msgsize=msgsize, realloc=realloc
467 )
468 )
469 write(
470 " memcpy((void *){realloc} + {msgsize}, s, "
471 "vec_len(s));\n".format(realloc=realloc, msgsize=msgsize)
472 )
473 write(" {msgsize} += vec_len(s);\n".format(msgsize=msgsize))
Ole Troandf87f802020-11-18 19:17:48 +0100474
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200475 write(" vec_free(s);\n")
Ole Troandf87f802020-11-18 19:17:48 +0100476 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200477 write(
478 ' if (u8string_fromjson2(o, "{n}", a->{n}) < 0) goto error;\n'.format(
479 n=o.fieldname
480 )
481 )
Ole Troandf87f802020-11-18 19:17:48 +0100482 return
483
484 is_bt = self.is_base_type(o.fieldtype)
485
486 if o.lengthfield:
487 if is_bt:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200488 call = "vl_api_{t}_fromjson(e, &d[i]);".format(t=o.fieldtype)
Ole Troandf87f802020-11-18 19:17:48 +0100489 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200490 call = "if ({t}_fromjson({msgvar}, len, e, &d[i]) < 0) goto error; ".format(
491 t=o.fieldtype, msgvar=msgvar
492 )
493 write(
494 forloop_vla.format(
495 lfield=lfield,
496 t=o.fieldtype,
497 n=o.fieldname,
498 call=call,
499 realloc=realloc,
500 msgsize=msgsize,
501 )
502 )
Ole Troandf87f802020-11-18 19:17:48 +0100503 else:
504 if is_bt:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200505 call = "vl_api_{t}_fromjson(e, &a->{n}[i]);".format(t=t, n=o.fieldname)
Ole Troandf87f802020-11-18 19:17:48 +0100506 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200507 call = "if ({}_fromjson({}, len, e, &a->{}[i]) < 0) goto error;".format(
508 t, msgvar, o.fieldname
509 )
510 write(
511 forloop.format(
512 lfield=lfield,
513 t=t,
514 n=o.fieldname,
515 call=call,
516 msgvar=msgvar,
517 realloc=realloc,
518 msgsize=msgsize,
519 )
520 )
Ole Troandf87f802020-11-18 19:17:48 +0100521
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200522 _dispatch["Array"] = print_array
Ole Troandf87f802020-11-18 19:17:48 +0100523
524 def print_enum(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200525 """Convert to JSON enum(string) to VPP API enum (int)"""
Ole Troandf87f802020-11-18 19:17:48 +0100526 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200527 write(
528 "static inline int vl_api_{n}_t_fromjson"
529 "(void **mp, int *len, cJSON *o, vl_api_{n}_t *a) {{\n".format(n=o.name)
530 )
531 write(" char *p = cJSON_GetStringValue(o);\n")
Ole Troandf87f802020-11-18 19:17:48 +0100532 for b in o.block:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200533 write(
534 ' if (strcmp(p, "{}") == 0) {{*a = {}; return 0;}}\n'.format(
535 b[0], b[1]
536 )
537 )
538 write(" *a = 0;\n")
539 write(" return -1;\n")
540 write("}\n")
Ole Troandf87f802020-11-18 19:17:48 +0100541
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200542 _dispatch["Enum"] = print_enum
Ole Troan793be462020-12-04 13:15:30 +0100543
544 def print_enum_flag(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200545 """Convert to JSON enum(string) to VPP API enum (int)"""
Ole Troan793be462020-12-04 13:15:30 +0100546 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200547 write(
548 "static inline int vl_api_{n}_t_fromjson "
549 "(void **mp, int *len, cJSON *o, vl_api_{n}_t *a) {{\n".format(n=o.name)
550 )
551 write(" int i;\n")
552 write(" *a = 0;\n")
553 write(" for (i = 0; i < cJSON_GetArraySize(o); i++) {\n")
554 write(" cJSON *e = cJSON_GetArrayItem(o, i);\n")
555 write(" char *p = cJSON_GetStringValue(e);\n")
556 write(" if (!p) return -1;\n")
Ole Troan793be462020-12-04 13:15:30 +0100557 for b in o.block:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200558 write(' if (strcmp(p, "{}") == 0) *a |= {};\n'.format(b[0], b[1]))
559 write(" }\n")
560 write(" return 0;\n")
561 write("}\n")
Ole Troan793be462020-12-04 13:15:30 +0100562
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200563 _dispatch["EnumFlag"] = print_enum_flag
Ole Troandf87f802020-11-18 19:17:48 +0100564
565 def print_typedef(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200566 """Convert from JSON object to VPP API binary representation"""
Ole Troandf87f802020-11-18 19:17:48 +0100567 write = self.stream.write
568
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200569 write(
570 "static inline int vl_api_{name}_t_fromjson (void **mp, "
571 "int *len, cJSON *o, vl_api_{name}_t *a) {{\n".format(name=o.name)
572 )
573 write(" cJSON *item __attribute__ ((unused));\n")
574 write(" u8 *s __attribute__ ((unused));\n")
Ole Troandf87f802020-11-18 19:17:48 +0100575 for t in o.block:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200576 if t.type == "Field" and t.is_lengthfield:
Ole Troandf87f802020-11-18 19:17:48 +0100577 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200578 write('\n item = cJSON_GetObjectItem(o, "{}");\n'.format(t.fieldname))
579 write(" if (!item) goto error;\n")
Ole Troandf87f802020-11-18 19:17:48 +0100580 self._dispatch[t.type](self, t)
581
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200582 write("\n return 0;\n")
583 write("\n error:\n")
584 write(" return -1;\n")
585 write("}\n")
Ole Troandf87f802020-11-18 19:17:48 +0100586
587 def print_union(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200588 """Convert JSON object to VPP API binary union"""
Ole Troandf87f802020-11-18 19:17:48 +0100589 write = self.stream.write
590
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200591 write(
592 "static inline int vl_api_{name}_t_fromjson (void **mp, "
593 "int *len, cJSON *o, vl_api_{name}_t *a) {{\n".format(name=o.name)
594 )
595 write(" cJSON *item __attribute__ ((unused));\n")
596 write(" u8 *s __attribute__ ((unused));\n")
Ole Troandf87f802020-11-18 19:17:48 +0100597 for t in o.block:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200598 if t.type == "Field" and t.is_lengthfield:
Ole Troandf87f802020-11-18 19:17:48 +0100599 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200600 write(' item = cJSON_GetObjectItem(o, "{}");\n'.format(t.fieldname))
601 write(" if (item) {\n")
Ole Troandf87f802020-11-18 19:17:48 +0100602 self._dispatch[t.type](self, t)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200603 write(" };\n")
604 write("\n return 0;\n")
605 write("\n error:\n")
606 write(" return -1;\n")
607 write("}\n")
Ole Troandf87f802020-11-18 19:17:48 +0100608
609 def print_define(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200610 """Convert JSON object to VPP API message"""
Ole Troandf87f802020-11-18 19:17:48 +0100611 write = self.stream.write
Ole Troan93c4b1b2021-02-16 18:09:51 +0100612 error = 0
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200613 write(
614 "static inline vl_api_{name}_t *vl_api_{name}_t_fromjson "
615 "(cJSON *o, int *len) {{\n".format(name=o.name)
616 )
617 write(" cJSON *item __attribute__ ((unused));\n")
618 write(" u8 *s __attribute__ ((unused));\n")
619 write(" int l = sizeof(vl_api_{}_t);\n".format(o.name))
620 write(" vl_api_{}_t *a = cJSON_malloc(l);\n".format(o.name))
621 write("\n")
Ole Troandf87f802020-11-18 19:17:48 +0100622
623 for t in o.block:
624 if t.fieldname in self.noprint_fields:
625 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200626 if t.type == "Field" and t.is_lengthfield:
Ole Troandf87f802020-11-18 19:17:48 +0100627 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200628 write(' item = cJSON_GetObjectItem(o, "{}");\n'.format(t.fieldname))
629 write(" if (!item) goto error;\n")
Ole Troan93c4b1b2021-02-16 18:09:51 +0100630 error += 1
Ole Troandf87f802020-11-18 19:17:48 +0100631 self._dispatch[t.type](self, t, toplevel=True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200632 write("\n")
Ole Troandf87f802020-11-18 19:17:48 +0100633
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200634 write(" *len = l;\n")
635 write(" return a;\n")
Ole Troan93c4b1b2021-02-16 18:09:51 +0100636
637 if error:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200638 write("\n error:\n")
639 write(" cJSON_free(a);\n")
640 write(" return 0;\n")
641 write("}\n")
Ole Troandf87f802020-11-18 19:17:48 +0100642
643 def print_using(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200644 """Convert JSON field to VPP type alias"""
Ole Troandf87f802020-11-18 19:17:48 +0100645 write = self.stream.write
646
647 if o.manual_print:
648 return
649
650 t = o.using
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200651 write(
652 "static inline int vl_api_{name}_t_fromjson (void **mp, "
653 "int *len, cJSON *o, vl_api_{name}_t *a) {{\n".format(name=o.name)
654 )
655 if "length" in o.alias:
656 if t.fieldtype != "u8":
657 raise ValueError(
658 "Error in processing type {} for {}".format(t.fieldtype, o.name)
659 )
660 write(
661 " vl_api_u8_string_fromjson(o, (u8 *)a, {});\n".format(
662 o.alias["length"]
663 )
664 )
Ole Troandf87f802020-11-18 19:17:48 +0100665 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200666 write(" vl_api_{t}_fromjson(o, ({t} *)a);\n".format(t=t.fieldtype))
Ole Troandf87f802020-11-18 19:17:48 +0100667
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200668 write(" return 0;\n")
669 write("}\n")
Ole Troandf87f802020-11-18 19:17:48 +0100670
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200671 _dispatch["Typedef"] = print_typedef
672 _dispatch["Define"] = print_define
673 _dispatch["Using"] = print_using
674 _dispatch["Union"] = print_union
Ole Troandf87f802020-11-18 19:17:48 +0100675
676 def generate_function(self, t):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200677 """Main entry point"""
Ole Troandf87f802020-11-18 19:17:48 +0100678 write = self.stream.write
679 if t.manual_print:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200680 write("/* Manual print {} */\n".format(t.name))
Ole Troandf87f802020-11-18 19:17:48 +0100681 return
682 self._dispatch[t.type](self, t)
683
684 def generate_types(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200685 """Main entry point"""
Ole Troandf87f802020-11-18 19:17:48 +0100686 for t in self.types:
687 self.generate_function(t)
688
689 def generate_defines(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200690 """Main entry point"""
Ole Troandf87f802020-11-18 19:17:48 +0100691 for t in self.defines:
692 self.generate_function(t)
693
694
695def generate_tojson(s, modulename, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200696 """Generate all functions to convert from API to JSON"""
Ole Troandf87f802020-11-18 19:17:48 +0100697 write = stream.write
698
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200699 write("/* Imported API files */\n")
700 for i in s["Import"]:
701 f = i.filename.replace("plugins/", "")
702 write("#include <{}_tojson.h>\n".format(f))
Ole Troandf87f802020-11-18 19:17:48 +0100703
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200704 pp = ToJSON(modulename, s["types"], s["Define"], s["imported"]["types"], stream)
Ole Troandf87f802020-11-18 19:17:48 +0100705 pp.header()
706 pp.generate_types()
707 pp.generate_defines()
708 pp.footer()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200709 return ""
Ole Troandf87f802020-11-18 19:17:48 +0100710
711
712def generate_fromjson(s, modulename, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200713 """Generate all functions to convert from JSON to API"""
Ole Troandf87f802020-11-18 19:17:48 +0100714 write = stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200715 write("/* Imported API files */\n")
716 for i in s["Import"]:
717 f = i.filename.replace("plugins/", "")
718 write("#include <{}_fromjson.h>\n".format(f))
Ole Troandf87f802020-11-18 19:17:48 +0100719
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200720 pp = FromJSON(modulename, s["types"], s["Define"], s["imported"]["types"], stream)
Ole Troandf87f802020-11-18 19:17:48 +0100721 pp.header()
722 pp.generate_types()
723 pp.generate_defines()
724 pp.footer()
725
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200726 return ""
727
Ole Troandf87f802020-11-18 19:17:48 +0100728
729###############################################################################
730
731
732DATESTRING = datetime.datetime.utcfromtimestamp(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200733 int(os.environ.get("SOURCE_DATE_EPOCH", time.time()))
734)
735TOP_BOILERPLATE = """\
Ole Troan9d420872017-10-12 13:06:35 +0200736/*
737 * VLIB API definitions {datestring}
738 * Input file: {input_filename}
739 * Automatically generated: please edit the input file NOT this file!
740 */
741
Ole Troan288e0932019-05-29 12:30:05 +0200742#include <stdbool.h>
Ole Troan9d420872017-10-12 13:06:35 +0200743#if defined(vl_msg_id)||defined(vl_union_id) \\
744 || defined(vl_printfun) ||defined(vl_endianfun) \\
745 || defined(vl_api_version)||defined(vl_typedefs) \\
746 || defined(vl_msg_name)||defined(vl_msg_name_crc_list) \\
Klement Sekera9b7e8ac2021-11-22 21:26:20 +0100747 || defined(vl_api_version_tuple) || defined(vl_calcsizefun)
Ole Troan9d420872017-10-12 13:06:35 +0200748/* ok, something was selected */
749#else
750#warning no content included from {input_filename}
751#endif
752
753#define VL_API_PACKED(x) x __attribute__ ((packed))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200754"""
Ole Troan9d420872017-10-12 13:06:35 +0200755
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200756BOTTOM_BOILERPLATE = """\
Ole Troan9d420872017-10-12 13:06:35 +0200757/****** API CRC (whole file) *****/
758
759#ifdef vl_api_version
760vl_api_version({input_filename}, {file_crc:#08x})
761
762#endif
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200763"""
Ole Troan9d420872017-10-12 13:06:35 +0200764
765
766def msg_ids(s):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200767 """Generate macro to map API message id to handler"""
768 output = """\
Ole Troan9d420872017-10-12 13:06:35 +0200769
770/****** Message ID / handler enum ******/
771
772#ifdef vl_msg_id
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200773"""
Ole Troan9d420872017-10-12 13:06:35 +0200774
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200775 for t in s["Define"]:
776 output += "vl_msg_id(VL_API_%s, vl_api_%s_t_handler)\n" % (
777 t.name.upper(),
778 t.name,
779 )
Ole Troan9d420872017-10-12 13:06:35 +0200780 output += "#endif"
781
782 return output
783
784
785def msg_names(s):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200786 """Generate calls to name mapping macro"""
787 output = """\
Ole Troan9d420872017-10-12 13:06:35 +0200788
789/****** Message names ******/
790
791#ifdef vl_msg_name
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200792"""
Ole Troan9d420872017-10-12 13:06:35 +0200793
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200794 for t in s["Define"]:
Ole Troan9d420872017-10-12 13:06:35 +0200795 dont_trace = 0 if t.dont_trace else 1
796 output += "vl_msg_name(vl_api_%s_t, %d)\n" % (t.name, dont_trace)
797 output += "#endif"
798
799 return output
800
801
802def msg_name_crc_list(s, suffix):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200803 """Generate list of names to CRC mappings"""
804 output = """\
Ole Troan9d420872017-10-12 13:06:35 +0200805
806/****** Message name, crc list ******/
807
808#ifdef vl_msg_name_crc_list
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200809"""
Ole Troan9d420872017-10-12 13:06:35 +0200810 output += "#define foreach_vl_msg_name_crc_%s " % suffix
811
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200812 for t in s["Define"]:
813 output += "\\\n_(VL_API_%s, %s, %08x) " % (t.name.upper(), t.name, t.crc)
Ole Troan9d420872017-10-12 13:06:35 +0200814 output += "\n#endif"
815
816 return output
817
818
Ole Troan413f4a52018-11-28 11:36:05 +0100819def api2c(fieldtype):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200820 """Map between API type names and internal VPP type names"""
821 mappingtable = {
822 "string": "vl_api_string_t",
823 }
Ole Troan413f4a52018-11-28 11:36:05 +0100824 if fieldtype in mappingtable:
825 return mappingtable[fieldtype]
826 return fieldtype
827
828
Ole Troan2a1ca782019-09-19 01:08:30 +0200829def typedefs(filename):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200830 """Include in the main files to the types file"""
831 output = """\
Ole Troan9d420872017-10-12 13:06:35 +0200832
833/****** Typedefs ******/
834
835#ifdef vl_typedefs
Ole Troan2a1ca782019-09-19 01:08:30 +0200836#include "{include}.api_types.h"
837#endif
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200838""".format(
839 include=filename
840 )
Ole Troan9d420872017-10-12 13:06:35 +0200841 return output
842
843
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200844FORMAT_STRINGS = {
845 "u8": "%u",
846 "bool": "%u",
847 "i8": "%d",
848 "u16": "%u",
849 "i16": "%d",
850 "u32": "%u",
851 "i32": "%ld",
852 "u64": "%llu",
853 "i64": "%lld",
854 "f64": "%.2f",
855}
Ole Troan33a58172019-09-04 09:12:29 +0200856
Ole Troan9d420872017-10-12 13:06:35 +0200857
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200858class Printfun:
859 """Functions for pretty printing VPP API messages"""
860
Ole Troan33a58172019-09-04 09:12:29 +0200861 _dispatch = {}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200862 noprint_fields = {"_vl_msg_id": None, "client_index": None, "context": None}
Ole Troan33a58172019-09-04 09:12:29 +0200863
864 def __init__(self, stream):
865 self.stream = stream
866
Ole Troandf87f802020-11-18 19:17:48 +0100867 @staticmethod
868 def print_string(o, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200869 """Pretty print a vl_api_string_t"""
Ole Troan33a58172019-09-04 09:12:29 +0200870 write = stream.write
871 if o.modern_vla:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200872 write(" if (vl_api_string_len(&a->{f}) > 0) {{\n".format(f=o.fieldname))
873 write(
874 ' s = format(s, "\\n%U{f}: %U", '
875 "format_white_space, indent, "
876 "vl_api_format_string, (&a->{f}));\n".format(f=o.fieldname)
877 )
878 write(" } else {\n")
879 write(
880 ' s = format(s, "\\n%U{f}:", '
881 "format_white_space, indent);\n".format(f=o.fieldname)
882 )
883 write(" }\n")
Ole Troan33a58172019-09-04 09:12:29 +0200884 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200885 write(
886 ' s = format(s, "\\n%U{f}: %s", '
887 "format_white_space, indent, a->{f});\n".format(f=o.fieldname)
888 )
Ole Troan33a58172019-09-04 09:12:29 +0200889
890 def print_field(self, o, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200891 """Pretty print API field"""
Ole Troan33a58172019-09-04 09:12:29 +0200892 write = stream.write
Ole Troandf87f802020-11-18 19:17:48 +0100893 if o.fieldname in self.noprint_fields:
Ole Troan33a58172019-09-04 09:12:29 +0200894 return
Ole Troandf87f802020-11-18 19:17:48 +0100895 if o.fieldtype in FORMAT_STRINGS:
896 f = FORMAT_STRINGS[o.fieldtype]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200897 write(
898 ' s = format(s, "\\n%U{n}: {f}", '
899 "format_white_space, indent, a->{n});\n".format(n=o.fieldname, f=f)
900 )
Ole Troan33a58172019-09-04 09:12:29 +0200901 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200902 write(
903 ' s = format(s, "\\n%U{n}: %U", '
904 "format_white_space, indent, "
905 "format_{t}, &a->{n}, indent);\n".format(n=o.fieldname, t=o.fieldtype)
906 )
Ole Troan33a58172019-09-04 09:12:29 +0200907
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200908 _dispatch["Field"] = print_field
Ole Troan33a58172019-09-04 09:12:29 +0200909
910 def print_array(self, o, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200911 """Pretty print API array"""
Ole Troan33a58172019-09-04 09:12:29 +0200912 write = stream.write
913
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200914 forloop = """\
Ole Troan33a58172019-09-04 09:12:29 +0200915 for (i = 0; i < {lfield}; i++) {{
916 s = format(s, "\\n%U{n}: %U",
917 format_white_space, indent, format_{t}, &a->{n}[i], indent);
918 }}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200919"""
Ole Troan33a58172019-09-04 09:12:29 +0200920
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200921 forloop_format = """\
Ole Troan33a58172019-09-04 09:12:29 +0200922 for (i = 0; i < {lfield}; i++) {{
923 s = format(s, "\\n%U{n}: {t}",
924 format_white_space, indent, a->{n}[i]);
925 }}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200926"""
Ole Troan33a58172019-09-04 09:12:29 +0200927
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200928 if o.fieldtype == "string":
Ole Troandf87f802020-11-18 19:17:48 +0100929 self.print_string(o, stream)
930 return
Ole Troan33a58172019-09-04 09:12:29 +0200931
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200932 if o.fieldtype == "u8":
Ole Troan33a58172019-09-04 09:12:29 +0200933 if o.lengthfield:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200934 write(
935 ' s = format(s, "\\n%U{n}: %U", format_white_space, '
936 "indent, format_hex_bytes, a->{n}, a->{lfield});\n".format(
937 n=o.fieldname, lfield=o.lengthfield
938 )
939 )
Ole Troan33a58172019-09-04 09:12:29 +0200940 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200941 write(
942 ' s = format(s, "\\n%U{n}: %U", format_white_space, '
943 "indent, format_hex_bytes, a, {lfield});\n".format(
944 n=o.fieldname, lfield=o.length
945 )
946 )
Ole Troan33a58172019-09-04 09:12:29 +0200947 return
948
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200949 lfield = "a->" + o.lengthfield if o.lengthfield else o.length
Ole Troandf87f802020-11-18 19:17:48 +0100950 if o.fieldtype in FORMAT_STRINGS:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200951 write(
952 forloop_format.format(
953 lfield=lfield, t=FORMAT_STRINGS[o.fieldtype], n=o.fieldname
954 )
955 )
Ole Troan33a58172019-09-04 09:12:29 +0200956 else:
957 write(forloop.format(lfield=lfield, t=o.fieldtype, n=o.fieldname))
958
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200959 _dispatch["Array"] = print_array
Ole Troan33a58172019-09-04 09:12:29 +0200960
Ole Troandf87f802020-11-18 19:17:48 +0100961 @staticmethod
962 def print_alias(k, v, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200963 """Pretty print type alias"""
Ole Troan33a58172019-09-04 09:12:29 +0200964 write = stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200965 if "length" in v.alias and v.alias["length"] and v.alias["type"] == "u8":
966 write(
967 ' return format(s, "%U", format_hex_bytes, a, {});\n'.format(
968 v.alias["length"]
969 )
970 )
971 elif v.alias["type"] in FORMAT_STRINGS:
972 write(
973 ' return format(s, "{}", *a);\n'.format(
974 FORMAT_STRINGS[v.alias["type"]]
975 )
976 )
Ole Troan33a58172019-09-04 09:12:29 +0200977 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200978 write(' return format(s, "{} (print not implemented)");\n'.format(k))
Ole Troan33a58172019-09-04 09:12:29 +0200979
Ole Troandf87f802020-11-18 19:17:48 +0100980 @staticmethod
981 def print_enum(o, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200982 """Pretty print API enum"""
Ole Troan33a58172019-09-04 09:12:29 +0200983 write = stream.write
984 write(" switch(*a) {\n")
985 for b in o:
986 write(" case %s:\n" % b[1])
987 write(' return format(s, "{}");\n'.format(b[0]))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200988 write(" }\n")
Ole Troan33a58172019-09-04 09:12:29 +0200989
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200990 _dispatch["Enum"] = print_enum
991 _dispatch["EnumFlag"] = print_enum
Ole Troan33a58172019-09-04 09:12:29 +0200992
993 def print_obj(self, o, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200994 """Entry point"""
Ole Troan33a58172019-09-04 09:12:29 +0200995 write = stream.write
996
997 if o.type in self._dispatch:
998 self._dispatch[o.type](self, o, stream)
999 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001000 write(
1001 ' s = format(s, "\\n{} {} {} (print not implemented");\n'.format(
1002 o.type, o.fieldtype, o.fieldname
1003 )
1004 )
Ole Troan33a58172019-09-04 09:12:29 +02001005
1006
1007def printfun(objs, stream, modulename):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001008 """Main entry point for pretty print function generation"""
Ole Troan33a58172019-09-04 09:12:29 +02001009 write = stream.write
1010
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001011 h = """\
Ole Troan9d420872017-10-12 13:06:35 +02001012/****** Print functions *****/
1013#ifdef vl_printfun
Ole Troan33a58172019-09-04 09:12:29 +02001014#ifndef included_{module}_printfun
1015#define included_{module}_printfun
Ole Troan9d420872017-10-12 13:06:35 +02001016
1017#ifdef LP64
1018#define _uword_fmt \"%lld\"
1019#define _uword_cast (long long)
1020#else
1021#define _uword_fmt \"%ld\"
1022#define _uword_cast long
1023#endif
1024
Filip Tehlar36217e32021-07-23 08:51:10 +00001025#include "{module}.api_tojson.h"
1026#include "{module}.api_fromjson.h"
1027
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001028"""
Ole Troan33a58172019-09-04 09:12:29 +02001029
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001030 signature = """\
Damjan Marionfe45f8f2022-05-20 16:01:22 +02001031static inline u8 *vl_api_{name}_t_format (u8 *s, va_list *args)
Ole Troan33a58172019-09-04 09:12:29 +02001032{{
Damjan Marionfe45f8f2022-05-20 16:01:22 +02001033 __attribute__((unused)) vl_api_{name}_t *a = va_arg (*args, vl_api_{name}_t *);
Ole Troan33a58172019-09-04 09:12:29 +02001034 u32 indent __attribute__((unused)) = 2;
1035 int i __attribute__((unused));
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001036"""
Ole Troan33a58172019-09-04 09:12:29 +02001037
1038 h = h.format(module=modulename)
1039 write(h)
1040
1041 pp = Printfun(stream)
1042 for t in objs:
1043 if t.manual_print:
Damjan Marionfe45f8f2022-05-20 16:01:22 +02001044 write("/***** manual: vl_api_%s_t_format *****/\n\n" % t.name)
Ole Troan33a58172019-09-04 09:12:29 +02001045 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001046 write(signature.format(name=t.name, suffix=""))
1047 write(" /* Message definition: vl_api_{}_t: */\n".format(t.name))
1048 write(' s = format(s, "vl_api_%s_t:");\n' % t.name)
Ole Troan33a58172019-09-04 09:12:29 +02001049 for o in t.block:
1050 pp.print_obj(o, stream)
Damjan Marionfe45f8f2022-05-20 16:01:22 +02001051 write(" return s;\n")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001052 write("}\n\n")
Filip Tehlar36217e32021-07-23 08:51:10 +00001053
Ole Troan33a58172019-09-04 09:12:29 +02001054 write("\n#endif")
1055 write("\n#endif /* vl_printfun */\n")
1056
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001057 return ""
Ole Troan33a58172019-09-04 09:12:29 +02001058
1059
Ole Troan75761b92019-09-11 17:49:08 +02001060def printfun_types(objs, stream, modulename):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001061 """Pretty print API types"""
Ole Troan33a58172019-09-04 09:12:29 +02001062 write = stream.write
1063 pp = Printfun(stream)
1064
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001065 h = """\
Ole Troan33a58172019-09-04 09:12:29 +02001066/****** Print functions *****/
1067#ifdef vl_printfun
1068#ifndef included_{module}_printfun_types
1069#define included_{module}_printfun_types
1070
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001071"""
Ole Troan33a58172019-09-04 09:12:29 +02001072 h = h.format(module=modulename)
1073 write(h)
1074
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001075 signature = """\
Ole Troan33a58172019-09-04 09:12:29 +02001076static inline u8 *format_vl_api_{name}_t (u8 *s, va_list * args)
1077{{
1078 vl_api_{name}_t *a = va_arg (*args, vl_api_{name}_t *);
1079 u32 indent __attribute__((unused)) = va_arg (*args, u32);
1080 int i __attribute__((unused));
1081 indent += 2;
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001082"""
Ole Troan33a58172019-09-04 09:12:29 +02001083
Ole Troan2c2feab2018-04-24 00:02:37 -04001084 for t in objs:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001085 if t.__class__.__name__ == "Enum" or t.__class__.__name__ == "EnumFlag":
Ole Troan33a58172019-09-04 09:12:29 +02001086 write(signature.format(name=t.name))
1087 pp.print_enum(t.block, stream)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001088 write(" return s;\n")
1089 write("}\n\n")
Ole Troan2c2feab2018-04-24 00:02:37 -04001090 continue
Ole Troan33a58172019-09-04 09:12:29 +02001091
Ole Troan9d420872017-10-12 13:06:35 +02001092 if t.manual_print:
Damjan Marionfe45f8f2022-05-20 16:01:22 +02001093 write("/***** manual: vl_api_%s_t_format *****/\n\n" % t.name)
Ole Troan9d420872017-10-12 13:06:35 +02001094 continue
Ole Troan9d420872017-10-12 13:06:35 +02001095
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001096 if t.__class__.__name__ == "Using":
Ole Troan75761b92019-09-11 17:49:08 +02001097 write(signature.format(name=t.name))
1098 pp.print_alias(t.name, t, stream)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001099 write("}\n\n")
Ole Troan75761b92019-09-11 17:49:08 +02001100 continue
1101
Ole Troan33a58172019-09-04 09:12:29 +02001102 write(signature.format(name=t.name))
Ole Troan9d420872017-10-12 13:06:35 +02001103 for o in t.block:
Ole Troan33a58172019-09-04 09:12:29 +02001104 pp.print_obj(o, stream)
Ole Troan9d420872017-10-12 13:06:35 +02001105
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001106 write(" return s;\n")
1107 write("}\n\n")
Ole Troan9d420872017-10-12 13:06:35 +02001108
Ole Troan33a58172019-09-04 09:12:29 +02001109 write("\n#endif")
1110 write("\n#endif /* vl_printfun_types */\n")
Ole Troan9d420872017-10-12 13:06:35 +02001111
Ole Troan33a58172019-09-04 09:12:29 +02001112
Ole Troandf87f802020-11-18 19:17:48 +01001113def generate_imports(imports):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001114 """Add #include matching the API import statements"""
1115 output = "/* Imported API files */\n"
1116 output += "#ifndef vl_api_version\n"
Ole Troan33a58172019-09-04 09:12:29 +02001117
1118 for i in imports:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001119 s = i.filename.replace("plugins/", "")
1120 output += "#include <{}.h>\n".format(s)
1121 output += "#endif\n"
Ole Troan9d420872017-10-12 13:06:35 +02001122 return output
1123
1124
Ole Troandf87f802020-11-18 19:17:48 +01001125ENDIAN_STRINGS = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001126 "u16": "clib_net_to_host_u16",
1127 "u32": "clib_net_to_host_u32",
1128 "u64": "clib_net_to_host_u64",
1129 "i16": "clib_net_to_host_i16",
1130 "i32": "clib_net_to_host_i32",
1131 "i64": "clib_net_to_host_i64",
1132 "f64": "clib_net_to_host_f64",
Ole Troan9d420872017-10-12 13:06:35 +02001133}
1134
1135
Ole Troan33a58172019-09-04 09:12:29 +02001136def endianfun_array(o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001137 """Generate endian functions for arrays"""
1138 forloop = """\
Ole Troan33a58172019-09-04 09:12:29 +02001139 for (i = 0; i < {length}; i++) {{
1140 a->{name}[i] = {format}(a->{name}[i]);
1141 }}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001142"""
Ole Troan33a58172019-09-04 09:12:29 +02001143
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001144 forloop_format = """\
Ole Troan33a58172019-09-04 09:12:29 +02001145 for (i = 0; i < {length}; i++) {{
1146 {type}_endian(&a->{name}[i]);
1147 }}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001148"""
Ole Troan33a58172019-09-04 09:12:29 +02001149
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001150 output = ""
1151 if o.fieldtype == "u8" or o.fieldtype == "string" or o.fieldtype == "bool":
1152 output += " /* a->{n} = a->{n} (no-op) */\n".format(n=o.fieldname)
Ole Troan33a58172019-09-04 09:12:29 +02001153 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001154 lfield = "a->" + o.lengthfield if o.lengthfield else o.length
Ole Troandf87f802020-11-18 19:17:48 +01001155 if o.fieldtype in ENDIAN_STRINGS:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001156 output += forloop.format(
1157 length=lfield, format=ENDIAN_STRINGS[o.fieldtype], name=o.fieldname
1158 )
Ole Troan33a58172019-09-04 09:12:29 +02001159 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001160 output += forloop_format.format(
1161 length=lfield, type=o.fieldtype, name=o.fieldname
1162 )
Ole Troan33a58172019-09-04 09:12:29 +02001163 return output
1164
Ole Troandf87f802020-11-18 19:17:48 +01001165
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001166NO_ENDIAN_CONVERSION = {"client_index": None}
Ole Troandf87f802020-11-18 19:17:48 +01001167
Ole Troan33a58172019-09-04 09:12:29 +02001168
1169def endianfun_obj(o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001170 """Generate endian conversion function for type"""
1171 output = ""
1172 if o.type == "Array":
Ole Troan33a58172019-09-04 09:12:29 +02001173 return endianfun_array(o)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001174 if o.type != "Field":
1175 output += ' s = format(s, "\\n{} {} {} (print not implemented");\n'.format(
1176 o.type, o.fieldtype, o.fieldname
1177 )
Ole Troan33a58172019-09-04 09:12:29 +02001178 return output
Ole Troandf87f802020-11-18 19:17:48 +01001179 if o.fieldname in NO_ENDIAN_CONVERSION:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001180 output += " /* a->{n} = a->{n} (no-op) */\n".format(n=o.fieldname)
Ole Troane796a182020-05-18 11:14:05 +02001181 return output
Ole Troandf87f802020-11-18 19:17:48 +01001182 if o.fieldtype in ENDIAN_STRINGS:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001183 output += " a->{name} = {format}(a->{name});\n".format(
1184 name=o.fieldname, format=ENDIAN_STRINGS[o.fieldtype]
1185 )
1186 elif o.fieldtype.startswith("vl_api_"):
1187 output += " {type}_endian(&a->{name});\n".format(
1188 type=o.fieldtype, name=o.fieldname
1189 )
Ole Troan33a58172019-09-04 09:12:29 +02001190 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001191 output += " /* a->{n} = a->{n} (no-op) */\n".format(n=o.fieldname)
Ole Troan33a58172019-09-04 09:12:29 +02001192
1193 return output
1194
1195
Ole Troan75761b92019-09-11 17:49:08 +02001196def endianfun(objs, modulename):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001197 """Main entry point for endian function generation"""
1198 output = """\
Ole Troan9d420872017-10-12 13:06:35 +02001199
1200/****** Endian swap functions *****/\n\
1201#ifdef vl_endianfun
Ole Troan33a58172019-09-04 09:12:29 +02001202#ifndef included_{module}_endianfun
1203#define included_{module}_endianfun
Ole Troan9d420872017-10-12 13:06:35 +02001204
1205#undef clib_net_to_host_uword
1206#ifdef LP64
1207#define clib_net_to_host_uword clib_net_to_host_u64
1208#else
1209#define clib_net_to_host_uword clib_net_to_host_u32
1210#endif
1211
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001212"""
Ole Troan33a58172019-09-04 09:12:29 +02001213 output = output.format(module=modulename)
1214
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001215 signature = """\
Ole Troan33a58172019-09-04 09:12:29 +02001216static inline void vl_api_{name}_t_endian (vl_api_{name}_t *a)
1217{{
1218 int i __attribute__((unused));
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001219"""
Ole Troan33a58172019-09-04 09:12:29 +02001220
Ole Troan2c2feab2018-04-24 00:02:37 -04001221 for t in objs:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001222 if t.__class__.__name__ == "Enum" or t.__class__.__name__ == "EnumFlag":
Ole Troan33a58172019-09-04 09:12:29 +02001223 output += signature.format(name=t.name)
Ole Troandf87f802020-11-18 19:17:48 +01001224 if t.enumtype in ENDIAN_STRINGS:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001225 output += " *a = {}(*a);\n".format(ENDIAN_STRINGS[t.enumtype])
Ole Troan33a58172019-09-04 09:12:29 +02001226 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001227 output += " /* a->{name} = a->{name} (no-op) */\n".format(
1228 name=t.name
1229 )
Ole Troan33a58172019-09-04 09:12:29 +02001230
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001231 output += "}\n\n"
Ole Troan2c2feab2018-04-24 00:02:37 -04001232 continue
Ole Troan33a58172019-09-04 09:12:29 +02001233
Ole Troan9d420872017-10-12 13:06:35 +02001234 if t.manual_endian:
1235 output += "/***** manual: vl_api_%s_t_endian *****/\n\n" % t.name
1236 continue
Ole Troan33a58172019-09-04 09:12:29 +02001237
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001238 if t.__class__.__name__ == "Using":
Ole Troan75761b92019-09-11 17:49:08 +02001239 output += signature.format(name=t.name)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001240 if "length" in t.alias and t.alias["length"] and t.alias["type"] == "u8":
1241 output += " /* a->{name} = a->{name} (no-op) */\n".format(
1242 name=t.name
1243 )
1244 elif t.alias["type"] in FORMAT_STRINGS:
1245 output += " *a = {}(*a);\n".format(ENDIAN_STRINGS[t.alias["type"]])
Ole Troan75761b92019-09-11 17:49:08 +02001246 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001247 output += " /* Not Implemented yet {} */".format(t.name)
1248 output += "}\n\n"
Ole Troan75761b92019-09-11 17:49:08 +02001249 continue
1250
Ole Troan33a58172019-09-04 09:12:29 +02001251 output += signature.format(name=t.name)
Ole Troan9d420872017-10-12 13:06:35 +02001252
1253 for o in t.block:
Ole Troan33a58172019-09-04 09:12:29 +02001254 output += endianfun_obj(o)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001255 output += "}\n\n"
Ole Troan33a58172019-09-04 09:12:29 +02001256
1257 output += "\n#endif"
Ole Troan9d420872017-10-12 13:06:35 +02001258 output += "\n#endif /* vl_endianfun */\n\n"
1259
1260 return output
1261
1262
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001263def calc_size_fun(objs, modulename):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001264 """Main entry point for calculate size function generation"""
1265 output = """\
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001266
1267/****** Calculate size functions *****/\n\
1268#ifdef vl_calcsizefun
1269#ifndef included_{module}_calcsizefun
1270#define included_{module}_calcsizefun
1271
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001272"""
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001273 output = output.format(module=modulename)
1274
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001275 signature = """\
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001276/* calculate message size of message in network byte order */
1277static inline uword vl_api_{name}_t_calc_size (vl_api_{name}_t *a)
1278{{
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001279"""
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001280
1281 for o in objs:
1282 tname = o.__class__.__name__
1283
1284 output += signature.format(name=o.name)
1285 output += f" return sizeof(*a)"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001286 if tname == "Using":
1287 if "length" in o.alias:
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001288 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001289 tmp = int(o.alias["length"])
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001290 if tmp == 0:
1291 raise (f"Unexpected length '0' for alias {o}")
1292 except:
1293 # output += f" + vl_api_{o.alias.name}_t_calc_size({o.name})"
1294 print("culprit:")
1295 print(o)
1296 print(dir(o.alias))
1297 print(o.alias)
1298 raise
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001299 elif tname == "Enum" or tname == "EnumFlag":
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001300 pass
1301 else:
1302 for b in o.block:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001303 if b.type == "Option":
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001304 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001305 elif b.type == "Field":
1306 if b.fieldtype.startswith("vl_api_"):
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001307 output += f" - sizeof(a->{b.fieldname})"
1308 output += f" + {b.fieldtype}_calc_size(&a->{b.fieldname})"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001309 elif b.type == "Array":
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001310 if b.lengthfield:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001311 m = list(
1312 filter(lambda x: x.fieldname == b.lengthfield, o.block)
1313 )
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001314 if len(m) != 1:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001315 raise Exception(
1316 f"Expected 1 match for field '{b.lengthfield}', got '{m}'"
1317 )
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001318 lf = m[0]
1319 if lf.fieldtype in ENDIAN_STRINGS:
1320 output += f" + {ENDIAN_STRINGS[lf.fieldtype]}(a->{b.lengthfield}) * sizeof(a->{b.fieldname}[0])"
1321 elif lf.fieldtype == "u8":
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001322 output += (
1323 f" + a->{b.lengthfield} * sizeof(a->{b.fieldname}[0])"
1324 )
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001325 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001326 raise Exception(
1327 f"Don't know how to endian swap {lf.fieldtype}"
1328 )
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001329 else:
1330 # Fixed length strings decay to nul terminated u8
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001331 if b.fieldtype == "string":
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001332 if b.modern_vla:
1333 output += f" + vl_api_string_len(&a->{b.fieldname})"
1334
1335 output += ";\n"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001336 output += "}\n\n"
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001337 output += "\n#endif"
1338 output += "\n#endif /* vl_calcsizefun */\n\n"
1339
1340 return output
1341
1342
Ole Troan9d420872017-10-12 13:06:35 +02001343def version_tuple(s, module):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001344 """Generate semantic version string"""
1345 output = """\
Ole Troan9d420872017-10-12 13:06:35 +02001346/****** Version tuple *****/
1347
1348#ifdef vl_api_version_tuple
1349
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001350"""
1351 if "version" in s["Option"]:
1352 v = s["Option"]["version"]
1353 (major, minor, patch) = v.split(".")
1354 output += "vl_api_version_tuple(%s, %s, %s, %s)\n" % (
1355 module,
1356 major,
1357 minor,
1358 patch,
1359 )
Ole Troan9d420872017-10-12 13:06:35 +02001360
1361 output += "\n#endif /* vl_api_version_tuple */\n\n"
1362
1363 return output
1364
1365
Ole Troan2a1ca782019-09-19 01:08:30 +02001366def generate_include_enum(s, module, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001367 """Generate <name>.api_enum.h"""
Ole Troan2a1ca782019-09-19 01:08:30 +02001368 write = stream.write
1369
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001370 if "Define" in s:
1371 write("typedef enum {\n")
1372 for t in s["Define"]:
1373 write(" VL_API_{},\n".format(t.name.upper()))
1374 write(" VL_MSG_{}_LAST\n".format(module.upper()))
1375 write("}} vl_api_{}_enum_t;\n".format(module))
Ole Troan2a1ca782019-09-19 01:08:30 +02001376
Paul Vinciguerra7c8803d2019-11-21 17:16:18 -05001377
Ole Troandf87f802020-11-18 19:17:48 +01001378def generate_include_counters(s, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001379 """Include file for the counter data model types."""
Ole Troan148c7b72020-10-07 18:05:37 +02001380 write = stream.write
1381
1382 for counters in s:
1383 csetname = counters.name
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001384 write("typedef enum {\n")
Ole Troan148c7b72020-10-07 18:05:37 +02001385 for c in counters.block:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001386 write(" {}_ERROR_{},\n".format(csetname.upper(), c["name"].upper()))
1387 write(" {}_N_ERROR\n".format(csetname.upper()))
1388 write("}} vl_counter_{}_enum_t;\n".format(csetname))
Ole Troan148c7b72020-10-07 18:05:37 +02001389
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001390 write("extern vlib_error_desc_t {}_error_counters[];\n".format(csetname))
Ole Troan148c7b72020-10-07 18:05:37 +02001391
Ole Troandf87f802020-11-18 19:17:48 +01001392
Ole Troan2a1ca782019-09-19 01:08:30 +02001393def generate_include_types(s, module, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001394 """Generate separate API _types file."""
Ole Troan2a1ca782019-09-19 01:08:30 +02001395 write = stream.write
1396
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001397 write("#ifndef included_{module}_api_types_h\n".format(module=module))
1398 write("#define included_{module}_api_types_h\n".format(module=module))
Ole Troan2a1ca782019-09-19 01:08:30 +02001399
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001400 if "version" in s["Option"]:
1401 v = s["Option"]["version"]
1402 (major, minor, patch) = v.split(".")
1403 write(
1404 "#define VL_API_{m}_API_VERSION_MAJOR {v}\n".format(
1405 m=module.upper(), v=major
1406 )
1407 )
1408 write(
1409 "#define VL_API_{m}_API_VERSION_MINOR {v}\n".format(
1410 m=module.upper(), v=minor
1411 )
1412 )
1413 write(
1414 "#define VL_API_{m}_API_VERSION_PATCH {v}\n".format(
1415 m=module.upper(), v=patch
1416 )
1417 )
Ole Troanf92bfb12020-02-28 13:45:42 +01001418
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001419 if "Import" in s:
1420 write("/* Imported API files */\n")
1421 for i in s["Import"]:
1422 filename = i.filename.replace("plugins/", "")
1423 write("#include <{}_types.h>\n".format(filename))
Ole Troan2a1ca782019-09-19 01:08:30 +02001424
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001425 for o in itertools.chain(s["types"], s["Define"]):
Ole Troan2a1ca782019-09-19 01:08:30 +02001426 tname = o.__class__.__name__
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001427 if tname == "Using":
1428 if "length" in o.alias:
1429 write(
1430 "typedef %s vl_api_%s_t[%s];\n"
1431 % (o.alias["type"], o.name, o.alias["length"])
1432 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001433 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001434 write("typedef %s vl_api_%s_t;\n" % (o.alias["type"], o.name))
1435 elif tname == "Enum" or tname == "EnumFlag":
1436 if o.enumtype == "u32":
Ole Troan2a1ca782019-09-19 01:08:30 +02001437 write("typedef enum {\n")
1438 else:
1439 write("typedef enum __attribute__((packed)) {\n")
1440
1441 for b in o.block:
1442 write(" %s = %s,\n" % (b[0], b[1]))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001443 write("} vl_api_%s_t;\n" % o.name)
1444 if o.enumtype != "u32":
1445 size1 = "sizeof(vl_api_%s_t)" % o.name
1446 size2 = "sizeof(%s)" % o.enumtype
1447 err_str = "size of API enum %s is wrong" % o.name
1448 write('STATIC_ASSERT(%s == %s, "%s");\n' % (size1, size2, err_str))
Ole Troan2a1ca782019-09-19 01:08:30 +02001449 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001450 if tname == "Union":
1451 write("typedef union __attribute__ ((packed)) _vl_api_%s {\n" % o.name)
Ole Troan2a1ca782019-09-19 01:08:30 +02001452 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001453 write(
1454 ("typedef struct __attribute__ ((packed)) _vl_api_%s {\n") % o.name
1455 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001456 for b in o.block:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001457 if b.type == "Option":
Ole Troan2a1ca782019-09-19 01:08:30 +02001458 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001459 if b.type == "Field":
1460 write(" %s %s;\n" % (api2c(b.fieldtype), b.fieldname))
1461 elif b.type == "Array":
Ole Troan2a1ca782019-09-19 01:08:30 +02001462 if b.lengthfield:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001463 write(" %s %s[0];\n" % (api2c(b.fieldtype), b.fieldname))
Ole Troan2a1ca782019-09-19 01:08:30 +02001464 else:
1465 # Fixed length strings decay to nul terminated u8
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001466 if b.fieldtype == "string":
Ole Troan2a1ca782019-09-19 01:08:30 +02001467 if b.modern_vla:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001468 write(
1469 " {} {};\n".format(
1470 api2c(b.fieldtype), b.fieldname
1471 )
1472 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001473 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001474 write(" u8 {}[{}];\n".format(b.fieldname, b.length))
Ole Troan2a1ca782019-09-19 01:08:30 +02001475 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001476 write(
1477 " %s %s[%s];\n"
1478 % (api2c(b.fieldtype), b.fieldname, b.length)
1479 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001480 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001481 raise ValueError(
1482 "Error in processing type {} for {}".format(b, o.name)
1483 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001484
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001485 write("} vl_api_%s_t;\n" % o.name)
1486 write(
1487 f"#define VL_API_{o.name.upper()}_IS_CONSTANT_SIZE ({0 if o.vla else 1})\n\n"
1488 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001489
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001490 for t in s["Define"]:
1491 write(
1492 '#define VL_API_{ID}_CRC "{n}_{crc:08x}"\n'.format(
1493 n=t.name, ID=t.name.upper(), crc=t.crc
1494 )
1495 )
Ole Troan3f2d5712019-12-07 00:39:49 +01001496
Ole Troan2a1ca782019-09-19 01:08:30 +02001497 write("\n#endif\n")
1498
1499
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001500def generate_c_boilerplate(services, defines, counters, file_crc, module, stream):
1501 """VPP side plugin."""
Ole Troan2a1ca782019-09-19 01:08:30 +02001502 write = stream.write
Ole Troan148c7b72020-10-07 18:05:37 +02001503 define_hash = {d.name: d for d in defines}
Ole Troan2a1ca782019-09-19 01:08:30 +02001504
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001505 hdr = """\
Ole Troan2a1ca782019-09-19 01:08:30 +02001506#define vl_endianfun /* define message structures */
1507#include "{module}.api.h"
1508#undef vl_endianfun
1509
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001510#define vl_calcsizefun
1511#include "{module}.api.h"
1512#undef vl_calsizefun
1513
Ole Troan2a1ca782019-09-19 01:08:30 +02001514/* instantiate all the print functions we know about */
Ole Troan2a1ca782019-09-19 01:08:30 +02001515#define vl_printfun
1516#include "{module}.api.h"
1517#undef vl_printfun
1518
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001519"""
Ole Troan2a1ca782019-09-19 01:08:30 +02001520
1521 write(hdr.format(module=module))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001522 write("static u16\n")
1523 write("setup_message_id_table (void) {\n")
1524 write(" api_main_t *am = my_api_main;\n")
1525 write(" vl_msg_api_msg_config_t c;\n")
1526 write(
1527 ' u16 msg_id_base = vl_msg_api_get_msg_ids ("{}_{crc:08x}", '
1528 "VL_MSG_{m}_LAST);\n".format(module, crc=file_crc, m=module.upper())
1529 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001530
Ole Troan2a1ca782019-09-19 01:08:30 +02001531 for d in defines:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001532 write(
1533 ' vl_msg_api_add_msg_name_crc (am, "{n}_{crc:08x}",\n'
1534 " VL_API_{ID} + msg_id_base);\n".format(
1535 n=d.name, ID=d.name.upper(), crc=d.crc
1536 )
1537 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001538 for s in services:
Ole Troane796a182020-05-18 11:14:05 +02001539 d = define_hash[s.caller]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001540 write(
1541 " c = (vl_msg_api_msg_config_t) "
1542 " {{.id = VL_API_{ID} + msg_id_base,\n"
1543 ' .name = "{n}",\n'
1544 " .handler = vl_api_{n}_t_handler,\n"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001545 " .endian = vl_api_{n}_t_endian,\n"
Damjan Marionfe45f8f2022-05-20 16:01:22 +02001546 " .format_fn = vl_api_{n}_t_format,\n"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001547 " .traced = 1,\n"
1548 " .replay = 1,\n"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001549 " .tojson = vl_api_{n}_t_tojson,\n"
1550 " .fromjson = vl_api_{n}_t_fromjson,\n"
1551 " .calc_size = vl_api_{n}_t_calc_size,\n"
1552 " .is_autoendian = {auto}}};\n".format(
1553 n=s.caller, ID=s.caller.upper(), auto=d.autoendian
1554 )
1555 )
1556 write(" vl_msg_api_config (&c);\n")
Ole Troanbad67922020-08-24 12:22:01 +02001557 try:
1558 d = define_hash[s.reply]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001559 write(
1560 " c = (vl_msg_api_msg_config_t) "
1561 "{{.id = VL_API_{ID} + msg_id_base,\n"
1562 ' .name = "{n}",\n'
1563 " .handler = 0,\n"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001564 " .endian = vl_api_{n}_t_endian,\n"
Damjan Marionfe45f8f2022-05-20 16:01:22 +02001565 " .format_fn = vl_api_{n}_t_format,\n"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001566 " .traced = 1,\n"
1567 " .replay = 1,\n"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001568 " .tojson = vl_api_{n}_t_tojson,\n"
1569 " .fromjson = vl_api_{n}_t_fromjson,\n"
1570 " .calc_size = vl_api_{n}_t_calc_size,\n"
1571 " .is_autoendian = {auto}}};\n".format(
1572 n=s.reply, ID=s.reply.upper(), auto=d.autoendian
1573 )
1574 )
1575 write(" vl_msg_api_config (&c);\n")
Ole Troanbad67922020-08-24 12:22:01 +02001576 except KeyError:
1577 pass
Ole Troan2a1ca782019-09-19 01:08:30 +02001578
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001579 write(" return msg_id_base;\n")
1580 write("}\n")
Ole Troan2a1ca782019-09-19 01:08:30 +02001581
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001582 severity = {
1583 "error": "VL_COUNTER_SEVERITY_ERROR",
1584 "info": "VL_COUNTER_SEVERITY_INFO",
1585 "warn": "VL_COUNTER_SEVERITY_WARN",
1586 }
Ole Troan148c7b72020-10-07 18:05:37 +02001587
1588 for cnt in counters:
1589 csetname = cnt.name
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001590 write("vlib_error_desc_t {}_error_counters[] = {{\n".format(csetname))
Ole Troan148c7b72020-10-07 18:05:37 +02001591 for c in cnt.block:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001592 write(" {\n")
1593 write(' .name = "{}",\n'.format(c["name"]))
1594 write(' .desc = "{}",\n'.format(c["description"]))
1595 write(" .severity = {},\n".format(severity[c["severity"]]))
1596 write(" },\n")
1597 write("};\n")
Ole Troan2a1ca782019-09-19 01:08:30 +02001598
Ole Troandf87f802020-11-18 19:17:48 +01001599
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001600def generate_c_test_boilerplate(services, defines, file_crc, module, plugin, stream):
1601 """Generate code for legacy style VAT. To be deleted."""
Ole Troan2a1ca782019-09-19 01:08:30 +02001602 write = stream.write
1603
Ole Troandf87f802020-11-18 19:17:48 +01001604 define_hash = {d.name: d for d in defines}
Ole Troan2a1ca782019-09-19 01:08:30 +02001605
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001606 hdr = """\
Ole Troandf87f802020-11-18 19:17:48 +01001607#define vl_endianfun /* define message structures */
Ole Troan2a1ca782019-09-19 01:08:30 +02001608#include "{module}.api.h"
1609#undef vl_endianfun
1610
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001611#define vl_calcsizefun
1612#include "{module}.api.h"
1613#undef vl_calsizefun
1614
Ole Troan2a1ca782019-09-19 01:08:30 +02001615/* instantiate all the print functions we know about */
Ole Troan2a1ca782019-09-19 01:08:30 +02001616#define vl_printfun
1617#include "{module}.api.h"
1618#undef vl_printfun
1619
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001620"""
Ole Troan2a1ca782019-09-19 01:08:30 +02001621
1622 write(hdr.format(module=module))
1623 for s in services:
1624 try:
1625 d = define_hash[s.reply]
Ole Troandf87f802020-11-18 19:17:48 +01001626 except KeyError:
Ole Troan2a1ca782019-09-19 01:08:30 +02001627 continue
1628 if d.manual_print:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001629 write(
1630 "/*\n"
1631 " * Manual definition requested for: \n"
1632 " * vl_api_{n}_t_handler()\n"
1633 " */\n".format(n=s.reply)
1634 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001635 continue
1636 if not define_hash[s.caller].autoreply:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001637 write(
1638 "/* Generation not supported (vl_api_{n}_t_handler()) */\n".format(
1639 n=s.reply
1640 )
1641 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001642 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001643 write("#ifndef VL_API_{n}_T_HANDLER\n".format(n=s.reply.upper()))
1644 write("static void\n")
1645 write("vl_api_{n}_t_handler (vl_api_{n}_t * mp) {{\n".format(n=s.reply))
1646 write(" vat_main_t * vam = {}_test_main.vat_main;\n".format(module))
1647 write(" i32 retval = ntohl(mp->retval);\n")
1648 write(" if (vam->async_mode) {\n")
1649 write(" vam->async_errors += (retval < 0);\n")
1650 write(" } else {\n")
1651 write(" vam->retval = retval;\n")
1652 write(" vam->result_ready = 1;\n")
1653 write(" }\n")
1654 write("}\n")
1655 write("#endif\n")
Ole Troan2a1ca782019-09-19 01:08:30 +02001656
Ole Troanb126ebc2019-10-07 16:22:00 +02001657 for e in s.events:
1658 if define_hash[e].manual_print:
1659 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001660 write("static void\n")
1661 write("vl_api_{n}_t_handler (vl_api_{n}_t * mp) {{\n".format(n=e))
Damjan Marionfe45f8f2022-05-20 16:01:22 +02001662 write(' vlib_cli_output(0, "{n} event called:");\n'.format(n=e))
1663 write(
1664 ' vlib_cli_output(0, "%U", vl_api_{n}_t_format, mp);\n'.format(n=e)
1665 )
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001666 write("}\n")
Ole Troanb126ebc2019-10-07 16:22:00 +02001667
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001668 write("static void\n")
1669 write("setup_message_id_table (vat_main_t * vam, u16 msg_id_base) {\n")
Ole Troan2a1ca782019-09-19 01:08:30 +02001670 for s in services:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001671 write(
Damjan Mariona2eb5072022-05-20 20:06:01 +02001672 " vl_msg_api_config (&(vl_msg_api_msg_config_t){{\n"
1673 " .id = VL_API_{ID} + msg_id_base,\n"
1674 ' .name = "{n}",\n'
1675 " .handler = vl_api_{n}_t_handler,\n"
1676 " .endian = vl_api_{n}_t_endian,\n"
1677 " .format_fn = vl_api_{n}_t_format,\n"
1678 " .size = sizeof(vl_api_{n}_t),\n"
1679 " .traced = 1,\n"
1680 " .tojson = vl_api_{n}_t_tojson,\n"
1681 " .fromjson = vl_api_{n}_t_fromjson,\n"
1682 " .calc_size = vl_api_{n}_t_calc_size,\n"
1683 " }});".format(n=s.reply, ID=s.reply.upper())
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001684 )
1685 write(
1686 ' hash_set_mem (vam->function_by_name, "{n}", api_{n});\n'.format(
1687 n=s.caller
1688 )
1689 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001690 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001691 write(
1692 ' hash_set_mem (vam->help_by_name, "{n}", "{help}");\n'.format(
1693 n=s.caller, help=define_hash[s.caller].options["vat_help"]
1694 )
1695 )
Ole Troandf87f802020-11-18 19:17:48 +01001696 except KeyError:
Ole Troan2a1ca782019-09-19 01:08:30 +02001697 pass
1698
Ole Troanb126ebc2019-10-07 16:22:00 +02001699 # Events
1700 for e in s.events:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001701 write(
Damjan Mariona2eb5072022-05-20 20:06:01 +02001702 " vl_msg_api_config (&(vl_msg_api_msg_config_t){{\n"
1703 " .id = VL_API_{ID} + msg_id_base,\n"
1704 ' .name = "{n}",\n'
1705 " .handler = vl_api_{n}_t_handler,\n"
1706 " .endian = vl_api_{n}_t_endian,\n"
1707 " .format_fn = vl_api_{n}_t_format,\n"
1708 " .size = sizeof(vl_api_{n}_t),\n"
1709 " .traced = 1,\n"
1710 " .tojson = vl_api_{n}_t_tojson,\n"
1711 " .fromjson = vl_api_{n}_t_fromjson,\n"
1712 " .calc_size = vl_api_{n}_t_calc_size,\n"
1713 " }});".format(n=e, ID=e.upper())
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001714 )
Ole Troanb126ebc2019-10-07 16:22:00 +02001715
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001716 write("}\n")
1717 write("clib_error_t * vat_plugin_register (vat_main_t *vam)\n")
1718 write("{\n")
1719 write(" {n}_test_main_t * mainp = &{n}_test_main;\n".format(n=module))
1720 write(" mainp->vat_main = vam;\n")
1721 write(
1722 " mainp->msg_id_base = vl_client_get_first_plugin_msg_id "
1723 ' ("{n}_{crc:08x}");\n'.format(n=module, crc=file_crc)
1724 )
1725 write(" if (mainp->msg_id_base == (u16) ~0)\n")
1726 write(
1727 ' return clib_error_return (0, "{} plugin not loaded...");\n'.format(
1728 module
1729 )
1730 )
1731 write(" setup_message_id_table (vam, mainp->msg_id_base);\n")
1732 write("#ifdef VL_API_LOCAL_SETUP_MESSAGE_ID_TABLE\n")
1733 write(" VL_API_LOCAL_SETUP_MESSAGE_ID_TABLE(vam);\n")
1734 write("#endif\n")
1735 write(" return 0;\n")
1736 write("}\n")
Ole Troan2a1ca782019-09-19 01:08:30 +02001737
Ole Troandf87f802020-11-18 19:17:48 +01001738
1739def apifunc(func):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001740 """Check if a method is generated already."""
1741
Ole Troandf87f802020-11-18 19:17:48 +01001742 def _f(module, d, processed, *args):
1743 if d.name in processed:
1744 return None
1745 processed[d.name] = True
1746 return func(module, d, *args)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001747
Ole Troandf87f802020-11-18 19:17:48 +01001748 return _f
1749
1750
1751def c_test_api_service(s, dump, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001752 """Generate JSON code for a service."""
Ole Troandf87f802020-11-18 19:17:48 +01001753 write = stream.write
1754
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001755 req_reply_template = """\
Ole Troandf87f802020-11-18 19:17:48 +01001756static cJSON *
1757api_{n} (cJSON *o)
1758{{
1759 vl_api_{n}_t *mp;
1760 int len;
1761 if (!o) return 0;
1762 mp = vl_api_{n}_t_fromjson(o, &len);
1763 if (!mp) {{
1764 fprintf(stderr, "Failed converting JSON to API\\n");
1765 return 0;
1766 }}
1767
1768 mp->_vl_msg_id = vac_get_msg_index(VL_API_{N}_CRC);
1769 vl_api_{n}_t_endian(mp);
1770 vac_write((char *)mp, len);
Filip Tehlar36217e32021-07-23 08:51:10 +00001771 cJSON_free(mp);
Ole Troandf87f802020-11-18 19:17:48 +01001772
1773 /* Read reply */
1774 char *p;
1775 int l;
1776 vac_read(&p, &l, 5); // XXX: Fix timeout
Ole Troanedc73fd2021-02-17 13:26:53 +01001777 if (p == 0 || l == 0) return 0;
Ole Troandf87f802020-11-18 19:17:48 +01001778 // XXX Will fail in case of event received. Do loop
1779 if (ntohs(*((u16 *)p)) != vac_get_msg_index(VL_API_{R}_CRC)) {{
1780 fprintf(stderr, "Mismatched reply\\n");
1781 return 0;
1782 }}
1783 vl_api_{r}_t *rmp = (vl_api_{r}_t *)p;
1784 vl_api_{r}_t_endian(rmp);
1785 return vl_api_{r}_t_tojson(rmp);
1786}}
1787
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001788"""
1789 dump_details_template = """\
Ole Troandf87f802020-11-18 19:17:48 +01001790static cJSON *
1791api_{n} (cJSON *o)
1792{{
1793 u16 msg_id = vac_get_msg_index(VL_API_{N}_CRC);
1794 int len;
1795 if (!o) return 0;
1796 vl_api_{n}_t *mp = vl_api_{n}_t_fromjson(o, &len);
1797 if (!mp) {{
1798 fprintf(stderr, "Failed converting JSON to API\\n");
1799 return 0;
1800 }}
1801 mp->_vl_msg_id = msg_id;
1802 vl_api_{n}_t_endian(mp);
1803 vac_write((char *)mp, len);
Filip Tehlar36217e32021-07-23 08:51:10 +00001804 cJSON_free(mp);
Ole Troandf87f802020-11-18 19:17:48 +01001805
1806 vat2_control_ping(123); // FIX CONTEXT
1807 cJSON *reply = cJSON_CreateArray();
1808
1809 u16 ping_reply_msg_id = vac_get_msg_index(VL_API_CONTROL_PING_REPLY_CRC);
1810 u16 details_msg_id = vac_get_msg_index(VL_API_{R}_CRC);
1811
1812 while (1) {{
1813 /* Read reply */
1814 char *p;
1815 int l;
1816 vac_read(&p, &l, 5); // XXX: Fix timeout
Ole Troanedc73fd2021-02-17 13:26:53 +01001817 if (p == 0 || l == 0) {{
1818 cJSON_free(reply);
1819 return 0;
1820 }}
Ole Troandf87f802020-11-18 19:17:48 +01001821
1822 /* Message can be one of [_details, control_ping_reply
1823 * or unrelated event]
1824 */
1825 u16 reply_msg_id = ntohs(*((u16 *)p));
1826 if (reply_msg_id == ping_reply_msg_id) {{
1827 break;
1828 }}
1829
1830 if (reply_msg_id == details_msg_id) {{
Ole Troanedc73fd2021-02-17 13:26:53 +01001831 if (l < sizeof(vl_api_{r}_t)) {{
1832 cJSON_free(reply);
1833 return 0;
1834 }}
Ole Troandf87f802020-11-18 19:17:48 +01001835 vl_api_{r}_t *rmp = (vl_api_{r}_t *)p;
1836 vl_api_{r}_t_endian(rmp);
1837 cJSON_AddItemToArray(reply, vl_api_{r}_t_tojson(rmp));
1838 }}
1839 }}
1840 return reply;
1841}}
1842
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001843"""
1844 gets_details_reply_template = """\
Ole Troandf87f802020-11-18 19:17:48 +01001845static cJSON *
1846api_{n} (cJSON *o)
1847{{
1848 u16 msg_id = vac_get_msg_index(VL_API_{N}_CRC);
1849 int len = 0;
1850 if (!o) return 0;
1851 vl_api_{n}_t *mp = vl_api_{n}_t_fromjson(o, &len);
1852 if (!mp) {{
1853 fprintf(stderr, "Failed converting JSON to API\\n");
1854 return 0;
1855 }}
1856 mp->_vl_msg_id = msg_id;
1857
1858 vl_api_{n}_t_endian(mp);
1859 vac_write((char *)mp, len);
Filip Tehlar36217e32021-07-23 08:51:10 +00001860 cJSON_free(mp);
Ole Troandf87f802020-11-18 19:17:48 +01001861
1862 cJSON *reply = cJSON_CreateArray();
1863
1864 u16 reply_msg_id = vac_get_msg_index(VL_API_{R}_CRC);
1865 u16 details_msg_id = vac_get_msg_index(VL_API_{D}_CRC);
1866
1867 while (1) {{
1868 /* Read reply */
1869 char *p;
1870 int l;
1871 vac_read(&p, &l, 5); // XXX: Fix timeout
1872
1873 /* Message can be one of [_details, control_ping_reply
1874 * or unrelated event]
1875 */
1876 u16 msg_id = ntohs(*((u16 *)p));
1877 if (msg_id == reply_msg_id) {{
1878 vl_api_{r}_t *rmp = (vl_api_{r}_t *)p;
1879 vl_api_{r}_t_endian(rmp);
1880 cJSON_AddItemToArray(reply, vl_api_{r}_t_tojson(rmp));
1881 break;
1882 }}
1883
1884 if (msg_id == details_msg_id) {{
1885 vl_api_{d}_t *rmp = (vl_api_{d}_t *)p;
1886 vl_api_{d}_t_endian(rmp);
1887 cJSON_AddItemToArray(reply, vl_api_{d}_t_tojson(rmp));
1888 }}
1889 }}
1890 return reply;
1891}}
1892
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001893"""
Ole Troandf87f802020-11-18 19:17:48 +01001894
1895 if dump:
1896 if s.stream_message:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001897 write(
1898 gets_details_reply_template.format(
1899 n=s.caller,
1900 r=s.reply,
1901 N=s.caller.upper(),
1902 R=s.reply.upper(),
1903 d=s.stream_message,
1904 D=s.stream_message.upper(),
1905 )
1906 )
Ole Troandf87f802020-11-18 19:17:48 +01001907 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001908 write(
1909 dump_details_template.format(
1910 n=s.caller, r=s.reply, N=s.caller.upper(), R=s.reply.upper()
1911 )
1912 )
Ole Troandf87f802020-11-18 19:17:48 +01001913 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001914 write(
1915 req_reply_template.format(
1916 n=s.caller, r=s.reply, N=s.caller.upper(), R=s.reply.upper()
1917 )
1918 )
Ole Troandf87f802020-11-18 19:17:48 +01001919
1920
1921def generate_c_test2_boilerplate(services, defines, module, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001922 """Generate code for VAT2 plugin."""
Ole Troandf87f802020-11-18 19:17:48 +01001923 write = stream.write
1924
1925 define_hash = {d.name: d for d in defines}
1926 # replies = {}
1927
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001928 hdr = """\
Ole Troandf87f802020-11-18 19:17:48 +01001929#include <vlibapi/api.h>
1930#include <vlibmemory/api.h>
1931#include <vppinfra/error.h>
1932#include <vnet/ip/ip_format_fns.h>
1933#include <vnet/ethernet/ethernet_format_fns.h>
1934
1935#define vl_typedefs /* define message structures */
Filip Tehlarb7e4d442021-07-08 18:44:19 +00001936#include <vlibmemory/vl_memory_api_h.h>
Florin Corasa1400ce2021-09-15 09:02:08 -07001937#include <vlibmemory/vlib.api_types.h>
1938#include <vlibmemory/vlib.api.h>
Ole Troandf87f802020-11-18 19:17:48 +01001939#undef vl_typedefs
1940
1941#include "{module}.api_enum.h"
1942#include "{module}.api_types.h"
1943
1944#define vl_endianfun /* define message structures */
1945#include "{module}.api.h"
1946#undef vl_endianfun
1947
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001948#define vl_calcsizefun
1949#include "{module}.api.h"
1950#undef vl_calsizefun
1951
Ole Troandf87f802020-11-18 19:17:48 +01001952#define vl_printfun
1953#include "{module}.api.h"
1954#undef vl_printfun
1955
1956#include "{module}.api_tojson.h"
1957#include "{module}.api_fromjson.h"
1958#include <vpp-api/client/vppapiclient.h>
1959
1960#include <vat2/vat2_helpers.h>
1961
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001962"""
Ole Troandf87f802020-11-18 19:17:48 +01001963
1964 write(hdr.format(module=module))
1965
1966 for s in services:
1967 if s.reply not in define_hash:
1968 continue
1969 c_test_api_service(s, s.stream, stream)
1970
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001971 write(
1972 "void vat2_register_function(char *, cJSON * (*)(cJSON *), cJSON * (*)(void *), u32);\n"
1973 )
Ole Troandf87f802020-11-18 19:17:48 +01001974 # write('__attribute__((constructor))')
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001975 write("clib_error_t *\n")
1976 write("vat2_register_plugin (void) {\n")
Ole Troandf87f802020-11-18 19:17:48 +01001977 for s in services:
Filip Tehlar36217e32021-07-23 08:51:10 +00001978 if s.reply not in define_hash:
1979 continue
1980 crc = define_hash[s.caller].crc
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001981 write(
1982 ' vat2_register_function("{n}", api_{n}, (cJSON * (*)(void *))vl_api_{n}_t_tojson, 0x{crc:08x});\n'.format(
1983 n=s.caller, crc=crc
1984 )
1985 )
1986 write(" return 0;\n")
1987 write("}\n")
Ole Troandf87f802020-11-18 19:17:48 +01001988
1989
Ole Troan9d420872017-10-12 13:06:35 +02001990#
1991# Plugin entry point
1992#
Nathan Skrzypczak1b299fa2022-06-16 17:00:02 +02001993def run(output_dir, apifilename, s):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001994 """Main plugin entry point."""
Ole Troan33a58172019-09-04 09:12:29 +02001995 stream = StringIO()
Ole Troan2a1ca782019-09-19 01:08:30 +02001996
Nathan Skrzypczak1b299fa2022-06-16 17:00:02 +02001997 if not output_dir:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001998 sys.stderr.write("Missing --outputdir argument")
Ole Troan2a1ca782019-09-19 01:08:30 +02001999 return None
2000
Ole Troandf87f802020-11-18 19:17:48 +01002001 basename = os.path.basename(apifilename)
2002 filename, _ = os.path.splitext(basename)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002003 modulename = filename.replace(".", "_")
Nathan Skrzypczak1b299fa2022-06-16 17:00:02 +02002004 filename_enum = os.path.join(output_dir + "/" + basename + "_enum.h")
2005 filename_types = os.path.join(output_dir + "/" + basename + "_types.h")
2006 filename_c = os.path.join(output_dir + "/" + basename + ".c")
2007 filename_c_test = os.path.join(output_dir + "/" + basename + "_test.c")
2008 filename_c_test2 = os.path.join(output_dir + "/" + basename + "_test2.c")
2009 filename_c_tojson = os.path.join(output_dir + "/" + basename + "_tojson.h")
2010 filename_c_fromjson = os.path.join(output_dir + "/" + basename + "_fromjson.h")
Ole Troan2a1ca782019-09-19 01:08:30 +02002011
2012 # Generate separate types file
2013 st = StringIO()
2014 generate_include_types(s, modulename, st)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002015 with open(filename_types, "w") as fd:
Ole Troandf87f802020-11-18 19:17:48 +01002016 st.seek(0)
2017 shutil.copyfileobj(st, fd)
Ole Troan2a1ca782019-09-19 01:08:30 +02002018 st.close()
2019
2020 # Generate separate enum file
2021 st = StringIO()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002022 st.write("#ifndef included_{}_api_enum_h\n".format(modulename))
2023 st.write("#define included_{}_api_enum_h\n".format(modulename))
Ole Troan2a1ca782019-09-19 01:08:30 +02002024 generate_include_enum(s, modulename, st)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002025 generate_include_counters(s["Counters"], st)
2026 st.write("#endif\n")
2027 with open(filename_enum, "w") as fd:
Ole Troandf87f802020-11-18 19:17:48 +01002028 st.seek(0)
2029 shutil.copyfileobj(st, fd)
Ole Troan2a1ca782019-09-19 01:08:30 +02002030 st.close()
2031
2032 # Generate separate C file
2033 st = StringIO()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002034 generate_c_boilerplate(
2035 s["Service"], s["Define"], s["Counters"], s["file_crc"], modulename, st
2036 )
2037 with open(filename_c, "w") as fd:
Ole Troandf87f802020-11-18 19:17:48 +01002038 st.seek(0)
Ole Troan2a1ca782019-09-19 01:08:30 +02002039 shutil.copyfileobj(st, fd)
2040 st.close()
2041
2042 # Generate separate C test file
Ole Troan2a1ca782019-09-19 01:08:30 +02002043 st = StringIO()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002044 plugin = bool("plugin" in apifilename)
2045 generate_c_test_boilerplate(
2046 s["Service"], s["Define"], s["file_crc"], modulename, plugin, st
2047 )
2048 with open(filename_c_test, "w") as fd:
Ole Troandf87f802020-11-18 19:17:48 +01002049 st.seek(0)
Ole Troan2a1ca782019-09-19 01:08:30 +02002050 shutil.copyfileobj(st, fd)
2051 st.close()
Ole Troan33a58172019-09-04 09:12:29 +02002052
Ole Troandf87f802020-11-18 19:17:48 +01002053 # Fully autogenerated VATv2 C test file
2054 st = StringIO()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002055 generate_c_test2_boilerplate(s["Service"], s["Define"], modulename, st)
2056 with open(filename_c_test2, "w") as fd:
Ole Troandf87f802020-11-18 19:17:48 +01002057 st.seek(0)
2058 shutil.copyfileobj(st, fd)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002059 st.close() #
Ole Troandf87f802020-11-18 19:17:48 +01002060
2061 # Generate separate JSON file
2062 st = StringIO()
2063 generate_tojson(s, modulename, st)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002064 with open(filename_c_tojson, "w") as fd:
Ole Troandf87f802020-11-18 19:17:48 +01002065 st.seek(0)
2066 shutil.copyfileobj(st, fd)
2067 st.close()
2068 st = StringIO()
2069 generate_fromjson(s, modulename, st)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002070 with open(filename_c_fromjson, "w") as fd:
Ole Troandf87f802020-11-18 19:17:48 +01002071 st.seek(0)
2072 shutil.copyfileobj(st, fd)
2073 st.close()
2074
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002075 output = TOP_BOILERPLATE.format(datestring=DATESTRING, input_filename=basename)
2076 output += generate_imports(s["Import"])
Ole Troan9d420872017-10-12 13:06:35 +02002077 output += msg_ids(s)
2078 output += msg_names(s)
2079 output += msg_name_crc_list(s, filename)
Ole Troan2a1ca782019-09-19 01:08:30 +02002080 output += typedefs(modulename)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002081 printfun_types(s["types"], stream, modulename)
2082 printfun(s["Define"], stream, modulename)
Ole Troan33a58172019-09-04 09:12:29 +02002083 output += stream.getvalue()
Ole Troan2a1ca782019-09-19 01:08:30 +02002084 stream.close()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002085 output += endianfun(s["types"] + s["Define"], modulename)
2086 output += calc_size_fun(s["types"] + s["Define"], modulename)
Ole Troan9d420872017-10-12 13:06:35 +02002087 output += version_tuple(s, basename)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002088 output += BOTTOM_BOILERPLATE.format(input_filename=basename, file_crc=s["file_crc"])
Ole Troan9d420872017-10-12 13:06:35 +02002089
2090 return output