blob: 64327887c0e5b8669fd8058fa3cbb04742dcde60 [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:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200126 write(
127 ' cJSON_AddStringToObject(o, "{n}", (char *)a->{n});\n'.format(
128 n=o.fieldname
129 )
130 )
Ole Troandf87f802020-11-18 19:17:48 +0100131
132 def print_field(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200133 """Called for every field in a typedef or define."""
Ole Troandf87f802020-11-18 19:17:48 +0100134 write = self.stream.write
135 if o.fieldname in self.noprint_fields:
136 return
137
138 f, p, newobj = self.get_json_func(o.fieldtype)
139
140 if newobj:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200141 write(
142 ' cJSON_AddItemToObject(o, "{n}", {f}({p}a->{n}));\n'.format(
143 f=f, p=p, n=o.fieldname
144 )
145 )
Ole Troandf87f802020-11-18 19:17:48 +0100146 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200147 write(' {f}(o, "{n}", {p}a->{n});\n'.format(f=f, p=p, n=o.fieldname))
Ole Troandf87f802020-11-18 19:17:48 +0100148
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200149 _dispatch["Field"] = print_field
Ole Troandf87f802020-11-18 19:17:48 +0100150
151 def print_array(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200152 """Converts a VPP API array to cJSON array."""
Ole Troandf87f802020-11-18 19:17:48 +0100153 write = self.stream.write
154
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200155 forloop = """\
Ole Troandf87f802020-11-18 19:17:48 +0100156 {{
157 int i;
158 cJSON *array = cJSON_AddArrayToObject(o, "{n}");
159 for (i = 0; i < {lfield}; i++) {{
160 cJSON_AddItemToArray(array, {f}({p}a->{n}[i]));
161 }}
162 }}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200163"""
Ole Troandf87f802020-11-18 19:17:48 +0100164
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200165 if o.fieldtype == "string":
Ole Troandf87f802020-11-18 19:17:48 +0100166 self.print_string(o)
167 return
168
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200169 lfield = "a->" + o.lengthfield if o.lengthfield else o.length
170 if o.fieldtype == "u8":
171 write(" {\n")
Ole Troandf87f802020-11-18 19:17:48 +0100172 # What is length field doing here?
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200173 write(
174 ' u8 *s = format(0, "0x%U", format_hex_bytes, '
175 "&a->{n}, {lfield});\n".format(n=o.fieldname, lfield=lfield)
176 )
177 write(
178 ' cJSON_AddStringToObject(o, "{n}", (char *)s);\n'.format(
179 n=o.fieldname
180 )
181 )
182 write(" vec_free(s);\n")
183 write(" }\n")
Ole Troandf87f802020-11-18 19:17:48 +0100184 return
185
186 f, p = self.get_json_array_func(o.fieldtype)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200187 write(forloop.format(lfield=lfield, t=o.fieldtype, n=o.fieldname, f=f, p=p))
Ole Troandf87f802020-11-18 19:17:48 +0100188
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200189 _dispatch["Array"] = print_array
Ole Troandf87f802020-11-18 19:17:48 +0100190
191 def print_enum(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200192 """Create cJSON object (string) for VPP API enum"""
Ole Troandf87f802020-11-18 19:17:48 +0100193 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200194 write(
195 "static inline cJSON *vl_api_{name}_t_tojson "
196 "(vl_api_{name}_t a) {{\n".format(name=o.name)
197 )
Ole Troandf87f802020-11-18 19:17:48 +0100198
199 write(" switch(a) {\n")
200 for b in o.block:
201 write(" case %s:\n" % b[1])
202 write(' return cJSON_CreateString("{}");\n'.format(b[0]))
203 write(' default: return cJSON_CreateString("Invalid ENUM");\n')
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200204 write(" }\n")
205 write(" return 0;\n")
206 write("}\n")
Ole Troandf87f802020-11-18 19:17:48 +0100207
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200208 _dispatch["Enum"] = print_enum
Ole Troan793be462020-12-04 13:15:30 +0100209
210 def print_enum_flag(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200211 """Create cJSON object (string) for VPP API enum"""
Ole Troan793be462020-12-04 13:15:30 +0100212 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200213 write(
214 "static inline cJSON *vl_api_{name}_t_tojson "
215 "(vl_api_{name}_t a) {{\n".format(name=o.name)
216 )
217 write(" cJSON *array = cJSON_CreateArray();\n")
Ole Troan793be462020-12-04 13:15:30 +0100218
219 for b in o.block:
Ole Troan45517152021-11-23 10:49:36 +0100220 if b[1] == 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200221 continue
222 write(" if (a & {})\n".format(b[0]))
Klement Sekera9b7e8ac2021-11-22 21:26:20 +0100223 write(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200224 ' cJSON_AddItemToArray(array, cJSON_CreateString("{}"));\n'.format(
225 b[0]
226 )
227 )
228 write(" return array;\n")
229 write("}\n")
Ole Troan793be462020-12-04 13:15:30 +0100230
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200231 _dispatch["EnumFlag"] = print_enum_flag
Ole Troandf87f802020-11-18 19:17:48 +0100232
233 def print_typedef(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200234 """Create cJSON (dictionary) object from VPP API typedef"""
Ole Troandf87f802020-11-18 19:17:48 +0100235 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200236 write(
237 "static inline cJSON *vl_api_{name}_t_tojson "
238 "(vl_api_{name}_t *a) {{\n".format(name=o.name)
239 )
240 write(" cJSON *o = cJSON_CreateObject();\n")
Ole Troandf87f802020-11-18 19:17:48 +0100241
242 for t in o.block:
243 self._dispatch[t.type](self, t)
244
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200245 write(" return o;\n")
246 write("}\n")
Ole Troandf87f802020-11-18 19:17:48 +0100247
248 def print_define(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200249 """Create cJSON (dictionary) object from VPP API define"""
Ole Troandf87f802020-11-18 19:17:48 +0100250 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200251 write(
252 "static inline cJSON *vl_api_{name}_t_tojson "
253 "(vl_api_{name}_t *a) {{\n".format(name=o.name)
254 )
255 write(" cJSON *o = cJSON_CreateObject();\n")
256 write(' cJSON_AddStringToObject(o, "_msgname", "{}");\n'.format(o.name))
257 write(
258 ' cJSON_AddStringToObject(o, "_crc", "{crc:08x}");\n'.format(crc=o.crc)
259 )
Ole Troandf87f802020-11-18 19:17:48 +0100260
261 for t in o.block:
262 self._dispatch[t.type](self, t)
263
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200264 write(" return o;\n")
265 write("}\n")
Ole Troandf87f802020-11-18 19:17:48 +0100266
267 def print_using(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200268 """Create cJSON (dictionary) object from VPP API aliased type"""
Ole Troandf87f802020-11-18 19:17:48 +0100269 if o.manual_print:
270 return
271
272 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200273 write(
274 "static inline cJSON *vl_api_{name}_t_tojson "
275 "(vl_api_{name}_t *a) {{\n".format(name=o.name)
276 )
Ole Troandf87f802020-11-18 19:17:48 +0100277
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200278 write(' u8 *s = format(0, "%U", format_vl_api_{}_t, a);\n'.format(o.name))
279 write(" cJSON *o = cJSON_CreateString((char *)s);\n")
280 write(" vec_free(s);\n")
281 write(" return o;\n")
282 write("}\n")
Ole Troandf87f802020-11-18 19:17:48 +0100283
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200284 _dispatch["Typedef"] = print_typedef
285 _dispatch["Define"] = print_define
286 _dispatch["Using"] = print_using
287 _dispatch["Union"] = print_typedef
Ole Troandf87f802020-11-18 19:17:48 +0100288
289 def generate_function(self, t):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200290 """Main entry point"""
Ole Troandf87f802020-11-18 19:17:48 +0100291 write = self.stream.write
292 if t.manual_print:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200293 write("/* Manual print {} */\n".format(t.name))
Ole Troandf87f802020-11-18 19:17:48 +0100294 return
295 self._dispatch[t.type](self, t)
296
297 def generate_types(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200298 """Main entry point"""
Ole Troandf87f802020-11-18 19:17:48 +0100299 for t in self.types:
300 self.generate_function(t)
301
302 def generate_defines(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200303 """Main entry point"""
Ole Troandf87f802020-11-18 19:17:48 +0100304 for t in self.defines:
305 self.generate_function(t)
306
307
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200308class FromJSON:
309 """
Ole Troandf87f802020-11-18 19:17:48 +0100310 Parse JSON objects into VPP API binary message structures.
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200311 """
312
Ole Troandf87f802020-11-18 19:17:48 +0100313 _dispatch = {}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200314 noprint_fields = {"_vl_msg_id": None, "client_index": None, "context": None}
315 is_number = {
316 "u8": None,
317 "i8": None,
318 "u16": None,
319 "i16": None,
320 "u32": None,
321 "i32": None,
322 "u64": None,
323 "i64": None,
324 "f64": None,
325 }
Ole Troandf87f802020-11-18 19:17:48 +0100326
327 def __init__(self, module, types, defines, imported_types, stream):
328 self.stream = stream
329 self.module = module
330 self.defines = defines
331 self.types = types
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200332 self.types_hash = {"vl_api_" + d.name + "_t": d for d in types + imported_types}
Ole Troandf87f802020-11-18 19:17:48 +0100333 self.defines_hash = {d.name: d for d in defines}
334
335 def header(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200336 """Output the top boilerplate."""
Ole Troandf87f802020-11-18 19:17:48 +0100337 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200338 write("#ifndef included_{}_api_fromjson_h\n".format(self.module))
339 write("#define included_{}_api_fromjson_h\n".format(self.module))
340 write("#include <vppinfra/cJSON.h>\n\n")
341 write("#include <vppinfra/jsonformat.h>\n\n")
Ole Troanfb0afab2021-02-11 11:13:46 +0100342 write('#pragma GCC diagnostic ignored "-Wunused-label"\n')
Ole Troandf87f802020-11-18 19:17:48 +0100343
344 def is_base_type(self, t):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200345 """Check if a type is one of the VPP API base types"""
Ole Troandf87f802020-11-18 19:17:48 +0100346 if t in self.is_number:
347 return True
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200348 if t == "bool":
Ole Troandf87f802020-11-18 19:17:48 +0100349 return True
350 return False
351
352 def footer(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200353 """Output the bottom boilerplate."""
Ole Troandf87f802020-11-18 19:17:48 +0100354 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200355 write("#endif\n")
Ole Troandf87f802020-11-18 19:17:48 +0100356
357 def print_string(self, o, toplevel=False):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200358 """Convert JSON string to vl_api_string_t"""
Ole Troandf87f802020-11-18 19:17:48 +0100359 write = self.stream.write
360
Ole Troanfb0afab2021-02-11 11:13:46 +0100361 msgvar = "a" if toplevel else "*mp"
Ole Troandf87f802020-11-18 19:17:48 +0100362 msgsize = "l" if toplevel else "*len"
363
364 if o.modern_vla:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200365 write(" char *p = cJSON_GetStringValue(item);\n")
366 write(" size_t plen = strlen(p);\n")
367 write(
368 " {msgvar} = cJSON_realloc({msgvar}, {msgsize} + plen, {msgsize});\n".format(
369 msgvar=msgvar, msgsize=msgsize
370 )
371 )
372 write(" if ({msgvar} == 0) goto error;\n".format(msgvar=msgvar))
373 write(
374 " vl_api_c_string_to_api_string(p, (void *){msgvar} + "
375 "{msgsize} - sizeof(vl_api_string_t));\n".format(
376 msgvar=msgvar, msgsize=msgsize
377 )
378 )
379 write(" {msgsize} += plen;\n".format(msgsize=msgsize))
Ole Troandf87f802020-11-18 19:17:48 +0100380 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200381 write(
382 " strncpy_s((char *)a->{n}, sizeof(a->{n}), "
383 "cJSON_GetStringValue(item), sizeof(a->{n}) - 1);\n".format(
384 n=o.fieldname
385 )
386 )
Ole Troandf87f802020-11-18 19:17:48 +0100387
388 def print_field(self, o, toplevel=False):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200389 """Called for every field in a typedef or define."""
Ole Troandf87f802020-11-18 19:17:48 +0100390 write = self.stream.write
Ole Troandf87f802020-11-18 19:17:48 +0100391 if o.fieldname in self.noprint_fields:
392 return
393 is_bt = self.is_base_type(o.fieldtype)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200394 t = "vl_api_{}".format(o.fieldtype) if is_bt else o.fieldtype
Ole Troandf87f802020-11-18 19:17:48 +0100395
Ole Troanfb0afab2021-02-11 11:13:46 +0100396 msgvar = "(void **)&a" if toplevel else "mp"
Ole Troandf87f802020-11-18 19:17:48 +0100397 msgsize = "&l" if toplevel else "len"
398
399 if is_bt:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200400 write(
401 " vl_api_{t}_fromjson(item, &a->{n});\n".format(
402 t=o.fieldtype, n=o.fieldname
403 )
404 )
Ole Troandf87f802020-11-18 19:17:48 +0100405 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200406 write(
407 " if ({t}_fromjson({msgvar}, "
408 "{msgsize}, item, &a->{n}) < 0) goto error;\n".format(
409 t=t, n=o.fieldname, msgvar=msgvar, msgsize=msgsize
410 )
411 )
Ole Troandf87f802020-11-18 19:17:48 +0100412
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200413 _dispatch["Field"] = print_field
Ole Troandf87f802020-11-18 19:17:48 +0100414
415 def print_array(self, o, toplevel=False):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200416 """Convert JSON array to VPP API array"""
Ole Troandf87f802020-11-18 19:17:48 +0100417 write = self.stream.write
418
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200419 forloop = """\
Ole Troandf87f802020-11-18 19:17:48 +0100420 {{
421 int i;
422 cJSON *array = cJSON_GetObjectItem(o, "{n}");
423 int size = cJSON_GetArraySize(array);
Ole Troan384c72f2021-02-17 13:46:54 +0100424 if (size != {lfield}) goto error;
Ole Troandf87f802020-11-18 19:17:48 +0100425 for (i = 0; i < size; i++) {{
426 cJSON *e = cJSON_GetArrayItem(array, i);
427 {call}
428 }}
429 }}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200430"""
431 forloop_vla = """\
Ole Troandf87f802020-11-18 19:17:48 +0100432 {{
433 int i;
434 cJSON *array = cJSON_GetObjectItem(o, "{n}");
435 int size = cJSON_GetArraySize(array);
436 {lfield} = size;
Filip Tehlar36217e32021-07-23 08:51:10 +0000437 {realloc} = cJSON_realloc({realloc}, {msgsize} + sizeof({t}) * size, {msgsize});
Ole Troancf0102b2021-02-12 11:48:12 +0100438 {t} *d = (void *){realloc} + {msgsize};
Ole Troandf87f802020-11-18 19:17:48 +0100439 {msgsize} += sizeof({t}) * size;
440 for (i = 0; i < size; i++) {{
441 cJSON *e = cJSON_GetArrayItem(array, i);
442 {call}
443 }}
444 }}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200445"""
Ole Troandf87f802020-11-18 19:17:48 +0100446 t = o.fieldtype
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200447 if o.fieldtype == "string":
Ole Troandf87f802020-11-18 19:17:48 +0100448 self.print_string(o, toplevel)
449 return
450
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200451 lfield = "a->" + o.lengthfield if o.lengthfield else o.length
Ole Troanfb0afab2021-02-11 11:13:46 +0100452 msgvar = "(void **)&a" if toplevel else "mp"
Ole Troancf0102b2021-02-12 11:48:12 +0100453 realloc = "a" if toplevel else "*mp"
Ole Troandf87f802020-11-18 19:17:48 +0100454 msgsize = "l" if toplevel else "*len"
455
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200456 if o.fieldtype == "u8":
Ole Troandf87f802020-11-18 19:17:48 +0100457 if o.lengthfield:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200458 write(' s = u8string_fromjson(o, "{}");\n'.format(o.fieldname))
459 write(" if (!s) goto error;\n")
460 write(" {} = vec_len(s);\n".format(lfield))
Ole Troandf87f802020-11-18 19:17:48 +0100461
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200462 write(
463 " {realloc} = cJSON_realloc({realloc}, {msgsize} + "
464 "vec_len(s), {msgsize});\n".format(
465 msgvar=msgvar, msgsize=msgsize, realloc=realloc
466 )
467 )
468 write(
469 " memcpy((void *){realloc} + {msgsize}, s, "
470 "vec_len(s));\n".format(realloc=realloc, msgsize=msgsize)
471 )
472 write(" {msgsize} += vec_len(s);\n".format(msgsize=msgsize))
Ole Troandf87f802020-11-18 19:17:48 +0100473
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200474 write(" vec_free(s);\n")
Ole Troandf87f802020-11-18 19:17:48 +0100475 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200476 write(
477 ' if (u8string_fromjson2(o, "{n}", a->{n}) < 0) goto error;\n'.format(
478 n=o.fieldname
479 )
480 )
Ole Troandf87f802020-11-18 19:17:48 +0100481 return
482
483 is_bt = self.is_base_type(o.fieldtype)
484
485 if o.lengthfield:
486 if is_bt:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200487 call = "vl_api_{t}_fromjson(e, &d[i]);".format(t=o.fieldtype)
Ole Troandf87f802020-11-18 19:17:48 +0100488 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200489 call = "if ({t}_fromjson({msgvar}, len, e, &d[i]) < 0) goto error; ".format(
490 t=o.fieldtype, msgvar=msgvar
491 )
492 write(
493 forloop_vla.format(
494 lfield=lfield,
495 t=o.fieldtype,
496 n=o.fieldname,
497 call=call,
498 realloc=realloc,
499 msgsize=msgsize,
500 )
501 )
Ole Troandf87f802020-11-18 19:17:48 +0100502 else:
503 if is_bt:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200504 call = "vl_api_{t}_fromjson(e, &a->{n}[i]);".format(t=t, n=o.fieldname)
Ole Troandf87f802020-11-18 19:17:48 +0100505 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200506 call = "if ({}_fromjson({}, len, e, &a->{}[i]) < 0) goto error;".format(
507 t, msgvar, o.fieldname
508 )
509 write(
510 forloop.format(
511 lfield=lfield,
512 t=t,
513 n=o.fieldname,
514 call=call,
515 msgvar=msgvar,
516 realloc=realloc,
517 msgsize=msgsize,
518 )
519 )
Ole Troandf87f802020-11-18 19:17:48 +0100520
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200521 _dispatch["Array"] = print_array
Ole Troandf87f802020-11-18 19:17:48 +0100522
523 def print_enum(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200524 """Convert to JSON enum(string) to VPP API enum (int)"""
Ole Troandf87f802020-11-18 19:17:48 +0100525 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200526 write(
527 "static inline int vl_api_{n}_t_fromjson"
528 "(void **mp, int *len, cJSON *o, vl_api_{n}_t *a) {{\n".format(n=o.name)
529 )
530 write(" char *p = cJSON_GetStringValue(o);\n")
Ole Troandf87f802020-11-18 19:17:48 +0100531 for b in o.block:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200532 write(
533 ' if (strcmp(p, "{}") == 0) {{*a = {}; return 0;}}\n'.format(
534 b[0], b[1]
535 )
536 )
537 write(" *a = 0;\n")
538 write(" return -1;\n")
539 write("}\n")
Ole Troandf87f802020-11-18 19:17:48 +0100540
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200541 _dispatch["Enum"] = print_enum
Ole Troan793be462020-12-04 13:15:30 +0100542
543 def print_enum_flag(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200544 """Convert to JSON enum(string) to VPP API enum (int)"""
Ole Troan793be462020-12-04 13:15:30 +0100545 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200546 write(
547 "static inline int vl_api_{n}_t_fromjson "
548 "(void **mp, int *len, cJSON *o, vl_api_{n}_t *a) {{\n".format(n=o.name)
549 )
550 write(" int i;\n")
551 write(" *a = 0;\n")
552 write(" for (i = 0; i < cJSON_GetArraySize(o); i++) {\n")
553 write(" cJSON *e = cJSON_GetArrayItem(o, i);\n")
554 write(" char *p = cJSON_GetStringValue(e);\n")
555 write(" if (!p) return -1;\n")
Ole Troan793be462020-12-04 13:15:30 +0100556 for b in o.block:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200557 write(' if (strcmp(p, "{}") == 0) *a |= {};\n'.format(b[0], b[1]))
558 write(" }\n")
559 write(" return 0;\n")
560 write("}\n")
Ole Troan793be462020-12-04 13:15:30 +0100561
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200562 _dispatch["EnumFlag"] = print_enum_flag
Ole Troandf87f802020-11-18 19:17:48 +0100563
564 def print_typedef(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200565 """Convert from JSON object to VPP API binary representation"""
Ole Troandf87f802020-11-18 19:17:48 +0100566 write = self.stream.write
567
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200568 write(
569 "static inline int vl_api_{name}_t_fromjson (void **mp, "
570 "int *len, cJSON *o, vl_api_{name}_t *a) {{\n".format(name=o.name)
571 )
572 write(" cJSON *item __attribute__ ((unused));\n")
573 write(" u8 *s __attribute__ ((unused));\n")
Ole Troandf87f802020-11-18 19:17:48 +0100574 for t in o.block:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200575 if t.type == "Field" and t.is_lengthfield:
Ole Troandf87f802020-11-18 19:17:48 +0100576 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200577 write('\n item = cJSON_GetObjectItem(o, "{}");\n'.format(t.fieldname))
578 write(" if (!item) goto error;\n")
Ole Troandf87f802020-11-18 19:17:48 +0100579 self._dispatch[t.type](self, t)
580
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200581 write("\n return 0;\n")
582 write("\n error:\n")
583 write(" return -1;\n")
584 write("}\n")
Ole Troandf87f802020-11-18 19:17:48 +0100585
586 def print_union(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200587 """Convert JSON object to VPP API binary union"""
Ole Troandf87f802020-11-18 19:17:48 +0100588 write = self.stream.write
589
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200590 write(
591 "static inline int vl_api_{name}_t_fromjson (void **mp, "
592 "int *len, cJSON *o, vl_api_{name}_t *a) {{\n".format(name=o.name)
593 )
594 write(" cJSON *item __attribute__ ((unused));\n")
595 write(" u8 *s __attribute__ ((unused));\n")
Ole Troandf87f802020-11-18 19:17:48 +0100596 for t in o.block:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200597 if t.type == "Field" and t.is_lengthfield:
Ole Troandf87f802020-11-18 19:17:48 +0100598 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200599 write(' item = cJSON_GetObjectItem(o, "{}");\n'.format(t.fieldname))
600 write(" if (item) {\n")
Ole Troandf87f802020-11-18 19:17:48 +0100601 self._dispatch[t.type](self, t)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200602 write(" };\n")
603 write("\n return 0;\n")
604 write("\n error:\n")
605 write(" return -1;\n")
606 write("}\n")
Ole Troandf87f802020-11-18 19:17:48 +0100607
608 def print_define(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200609 """Convert JSON object to VPP API message"""
Ole Troandf87f802020-11-18 19:17:48 +0100610 write = self.stream.write
Ole Troan93c4b1b2021-02-16 18:09:51 +0100611 error = 0
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200612 write(
613 "static inline vl_api_{name}_t *vl_api_{name}_t_fromjson "
614 "(cJSON *o, int *len) {{\n".format(name=o.name)
615 )
616 write(" cJSON *item __attribute__ ((unused));\n")
617 write(" u8 *s __attribute__ ((unused));\n")
618 write(" int l = sizeof(vl_api_{}_t);\n".format(o.name))
619 write(" vl_api_{}_t *a = cJSON_malloc(l);\n".format(o.name))
620 write("\n")
Ole Troandf87f802020-11-18 19:17:48 +0100621
622 for t in o.block:
623 if t.fieldname in self.noprint_fields:
624 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200625 if t.type == "Field" and t.is_lengthfield:
Ole Troandf87f802020-11-18 19:17:48 +0100626 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200627 write(' item = cJSON_GetObjectItem(o, "{}");\n'.format(t.fieldname))
628 write(" if (!item) goto error;\n")
Ole Troan93c4b1b2021-02-16 18:09:51 +0100629 error += 1
Ole Troandf87f802020-11-18 19:17:48 +0100630 self._dispatch[t.type](self, t, toplevel=True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200631 write("\n")
Ole Troandf87f802020-11-18 19:17:48 +0100632
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200633 write(" *len = l;\n")
634 write(" return a;\n")
Ole Troan93c4b1b2021-02-16 18:09:51 +0100635
636 if error:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200637 write("\n error:\n")
638 write(" cJSON_free(a);\n")
639 write(" return 0;\n")
640 write("}\n")
Ole Troandf87f802020-11-18 19:17:48 +0100641
642 def print_using(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200643 """Convert JSON field to VPP type alias"""
Ole Troandf87f802020-11-18 19:17:48 +0100644 write = self.stream.write
645
646 if o.manual_print:
647 return
648
649 t = o.using
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200650 write(
651 "static inline int vl_api_{name}_t_fromjson (void **mp, "
652 "int *len, cJSON *o, vl_api_{name}_t *a) {{\n".format(name=o.name)
653 )
654 if "length" in o.alias:
655 if t.fieldtype != "u8":
656 raise ValueError(
657 "Error in processing type {} for {}".format(t.fieldtype, o.name)
658 )
659 write(
660 " vl_api_u8_string_fromjson(o, (u8 *)a, {});\n".format(
661 o.alias["length"]
662 )
663 )
Ole Troandf87f802020-11-18 19:17:48 +0100664 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200665 write(" vl_api_{t}_fromjson(o, ({t} *)a);\n".format(t=t.fieldtype))
Ole Troandf87f802020-11-18 19:17:48 +0100666
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200667 write(" return 0;\n")
668 write("}\n")
Ole Troandf87f802020-11-18 19:17:48 +0100669
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200670 _dispatch["Typedef"] = print_typedef
671 _dispatch["Define"] = print_define
672 _dispatch["Using"] = print_using
673 _dispatch["Union"] = print_union
Ole Troandf87f802020-11-18 19:17:48 +0100674
675 def generate_function(self, t):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200676 """Main entry point"""
Ole Troandf87f802020-11-18 19:17:48 +0100677 write = self.stream.write
678 if t.manual_print:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200679 write("/* Manual print {} */\n".format(t.name))
Ole Troandf87f802020-11-18 19:17:48 +0100680 return
681 self._dispatch[t.type](self, t)
682
683 def generate_types(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200684 """Main entry point"""
Ole Troandf87f802020-11-18 19:17:48 +0100685 for t in self.types:
686 self.generate_function(t)
687
688 def generate_defines(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200689 """Main entry point"""
Ole Troandf87f802020-11-18 19:17:48 +0100690 for t in self.defines:
691 self.generate_function(t)
692
693
694def generate_tojson(s, modulename, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200695 """Generate all functions to convert from API to JSON"""
Ole Troandf87f802020-11-18 19:17:48 +0100696 write = stream.write
697
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200698 write("/* Imported API files */\n")
699 for i in s["Import"]:
700 f = i.filename.replace("plugins/", "")
701 write("#include <{}_tojson.h>\n".format(f))
Ole Troandf87f802020-11-18 19:17:48 +0100702
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200703 pp = ToJSON(modulename, s["types"], s["Define"], s["imported"]["types"], stream)
Ole Troandf87f802020-11-18 19:17:48 +0100704 pp.header()
705 pp.generate_types()
706 pp.generate_defines()
707 pp.footer()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200708 return ""
Ole Troandf87f802020-11-18 19:17:48 +0100709
710
711def generate_fromjson(s, modulename, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200712 """Generate all functions to convert from JSON to API"""
Ole Troandf87f802020-11-18 19:17:48 +0100713 write = stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200714 write("/* Imported API files */\n")
715 for i in s["Import"]:
716 f = i.filename.replace("plugins/", "")
717 write("#include <{}_fromjson.h>\n".format(f))
Ole Troandf87f802020-11-18 19:17:48 +0100718
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200719 pp = FromJSON(modulename, s["types"], s["Define"], s["imported"]["types"], stream)
Ole Troandf87f802020-11-18 19:17:48 +0100720 pp.header()
721 pp.generate_types()
722 pp.generate_defines()
723 pp.footer()
724
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200725 return ""
726
Ole Troandf87f802020-11-18 19:17:48 +0100727
728###############################################################################
729
730
731DATESTRING = datetime.datetime.utcfromtimestamp(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200732 int(os.environ.get("SOURCE_DATE_EPOCH", time.time()))
733)
734TOP_BOILERPLATE = """\
Ole Troan9d420872017-10-12 13:06:35 +0200735/*
736 * VLIB API definitions {datestring}
737 * Input file: {input_filename}
738 * Automatically generated: please edit the input file NOT this file!
739 */
740
Ole Troan288e0932019-05-29 12:30:05 +0200741#include <stdbool.h>
Ole Troan9d420872017-10-12 13:06:35 +0200742#if defined(vl_msg_id)||defined(vl_union_id) \\
743 || defined(vl_printfun) ||defined(vl_endianfun) \\
744 || defined(vl_api_version)||defined(vl_typedefs) \\
745 || defined(vl_msg_name)||defined(vl_msg_name_crc_list) \\
Klement Sekera9b7e8ac2021-11-22 21:26:20 +0100746 || defined(vl_api_version_tuple) || defined(vl_calcsizefun)
Ole Troan9d420872017-10-12 13:06:35 +0200747/* ok, something was selected */
748#else
749#warning no content included from {input_filename}
750#endif
751
752#define VL_API_PACKED(x) x __attribute__ ((packed))
Dave Wallace39c40fa2023-06-06 12:05:30 -0400753
754/*
755 * Note: VL_API_MAX_ARRAY_SIZE is set to an arbitrarily large limit.
756 *
757 * However, any message with a ~2 billion element array is likely to break the
758 * api handling long before this limit causes array element endian issues.
759 *
760 * Applications should be written to create reasonable api messages.
761 */
762#define VL_API_MAX_ARRAY_SIZE 0x7fffffff
763
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200764"""
Ole Troan9d420872017-10-12 13:06:35 +0200765
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200766BOTTOM_BOILERPLATE = """\
Ole Troan9d420872017-10-12 13:06:35 +0200767/****** API CRC (whole file) *****/
768
769#ifdef vl_api_version
770vl_api_version({input_filename}, {file_crc:#08x})
771
772#endif
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200773"""
Ole Troan9d420872017-10-12 13:06:35 +0200774
775
776def msg_ids(s):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200777 """Generate macro to map API message id to handler"""
778 output = """\
Ole Troan9d420872017-10-12 13:06:35 +0200779
780/****** Message ID / handler enum ******/
781
782#ifdef vl_msg_id
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200783"""
Ole Troan9d420872017-10-12 13:06:35 +0200784
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200785 for t in s["Define"]:
786 output += "vl_msg_id(VL_API_%s, vl_api_%s_t_handler)\n" % (
787 t.name.upper(),
788 t.name,
789 )
Ole Troan9d420872017-10-12 13:06:35 +0200790 output += "#endif"
791
792 return output
793
794
795def msg_names(s):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200796 """Generate calls to name mapping macro"""
797 output = """\
Ole Troan9d420872017-10-12 13:06:35 +0200798
799/****** Message names ******/
800
801#ifdef vl_msg_name
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200802"""
Ole Troan9d420872017-10-12 13:06:35 +0200803
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200804 for t in s["Define"]:
Ole Troan9d420872017-10-12 13:06:35 +0200805 dont_trace = 0 if t.dont_trace else 1
806 output += "vl_msg_name(vl_api_%s_t, %d)\n" % (t.name, dont_trace)
807 output += "#endif"
808
809 return output
810
811
812def msg_name_crc_list(s, suffix):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200813 """Generate list of names to CRC mappings"""
814 output = """\
Ole Troan9d420872017-10-12 13:06:35 +0200815
816/****** Message name, crc list ******/
817
818#ifdef vl_msg_name_crc_list
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200819"""
Ole Troan9d420872017-10-12 13:06:35 +0200820 output += "#define foreach_vl_msg_name_crc_%s " % suffix
821
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200822 for t in s["Define"]:
823 output += "\\\n_(VL_API_%s, %s, %08x) " % (t.name.upper(), t.name, t.crc)
Ole Troan9d420872017-10-12 13:06:35 +0200824 output += "\n#endif"
825
826 return output
827
828
Ole Troan413f4a52018-11-28 11:36:05 +0100829def api2c(fieldtype):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200830 """Map between API type names and internal VPP type names"""
831 mappingtable = {
832 "string": "vl_api_string_t",
833 }
Ole Troan413f4a52018-11-28 11:36:05 +0100834 if fieldtype in mappingtable:
835 return mappingtable[fieldtype]
836 return fieldtype
837
838
Ole Troan2a1ca782019-09-19 01:08:30 +0200839def typedefs(filename):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200840 """Include in the main files to the types file"""
841 output = """\
Ole Troan9d420872017-10-12 13:06:35 +0200842
843/****** Typedefs ******/
844
845#ifdef vl_typedefs
Ole Troan2a1ca782019-09-19 01:08:30 +0200846#include "{include}.api_types.h"
847#endif
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200848""".format(
849 include=filename
850 )
Ole Troan9d420872017-10-12 13:06:35 +0200851 return output
852
853
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200854FORMAT_STRINGS = {
855 "u8": "%u",
856 "bool": "%u",
857 "i8": "%d",
858 "u16": "%u",
859 "i16": "%d",
860 "u32": "%u",
861 "i32": "%ld",
862 "u64": "%llu",
863 "i64": "%lld",
864 "f64": "%.2f",
865}
Ole Troan33a58172019-09-04 09:12:29 +0200866
Ole Troan9d420872017-10-12 13:06:35 +0200867
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200868class Printfun:
869 """Functions for pretty printing VPP API messages"""
870
Ole Troan33a58172019-09-04 09:12:29 +0200871 _dispatch = {}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200872 noprint_fields = {"_vl_msg_id": None, "client_index": None, "context": None}
Ole Troan33a58172019-09-04 09:12:29 +0200873
874 def __init__(self, stream):
875 self.stream = stream
876
Ole Troandf87f802020-11-18 19:17:48 +0100877 @staticmethod
878 def print_string(o, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200879 """Pretty print a vl_api_string_t"""
Ole Troan33a58172019-09-04 09:12:29 +0200880 write = stream.write
881 if o.modern_vla:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200882 write(" if (vl_api_string_len(&a->{f}) > 0) {{\n".format(f=o.fieldname))
883 write(
884 ' s = format(s, "\\n%U{f}: %U", '
885 "format_white_space, indent, "
886 "vl_api_format_string, (&a->{f}));\n".format(f=o.fieldname)
887 )
888 write(" } else {\n")
889 write(
890 ' s = format(s, "\\n%U{f}:", '
891 "format_white_space, indent);\n".format(f=o.fieldname)
892 )
893 write(" }\n")
Ole Troan33a58172019-09-04 09:12:29 +0200894 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200895 write(
896 ' s = format(s, "\\n%U{f}: %s", '
897 "format_white_space, indent, a->{f});\n".format(f=o.fieldname)
898 )
Ole Troan33a58172019-09-04 09:12:29 +0200899
900 def print_field(self, o, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200901 """Pretty print API field"""
Ole Troan33a58172019-09-04 09:12:29 +0200902 write = stream.write
Ole Troandf87f802020-11-18 19:17:48 +0100903 if o.fieldname in self.noprint_fields:
Ole Troan33a58172019-09-04 09:12:29 +0200904 return
Ole Troandf87f802020-11-18 19:17:48 +0100905 if o.fieldtype in FORMAT_STRINGS:
906 f = FORMAT_STRINGS[o.fieldtype]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200907 write(
908 ' s = format(s, "\\n%U{n}: {f}", '
909 "format_white_space, indent, a->{n});\n".format(n=o.fieldname, f=f)
910 )
Ole Troan33a58172019-09-04 09:12:29 +0200911 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200912 write(
913 ' s = format(s, "\\n%U{n}: %U", '
914 "format_white_space, indent, "
915 "format_{t}, &a->{n}, indent);\n".format(n=o.fieldname, t=o.fieldtype)
916 )
Ole Troan33a58172019-09-04 09:12:29 +0200917
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200918 _dispatch["Field"] = print_field
Ole Troan33a58172019-09-04 09:12:29 +0200919
920 def print_array(self, o, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200921 """Pretty print API array"""
Ole Troan33a58172019-09-04 09:12:29 +0200922 write = stream.write
923
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200924 forloop = """\
Ole Troan33a58172019-09-04 09:12:29 +0200925 for (i = 0; i < {lfield}; i++) {{
926 s = format(s, "\\n%U{n}: %U",
927 format_white_space, indent, format_{t}, &a->{n}[i], indent);
928 }}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200929"""
Ole Troan33a58172019-09-04 09:12:29 +0200930
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200931 forloop_format = """\
Ole Troan33a58172019-09-04 09:12:29 +0200932 for (i = 0; i < {lfield}; i++) {{
933 s = format(s, "\\n%U{n}: {t}",
934 format_white_space, indent, a->{n}[i]);
935 }}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200936"""
Ole Troan33a58172019-09-04 09:12:29 +0200937
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200938 if o.fieldtype == "string":
Ole Troandf87f802020-11-18 19:17:48 +0100939 self.print_string(o, stream)
940 return
Ole Troan33a58172019-09-04 09:12:29 +0200941
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200942 if o.fieldtype == "u8":
Ole Troan33a58172019-09-04 09:12:29 +0200943 if o.lengthfield:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200944 write(
945 ' s = format(s, "\\n%U{n}: %U", format_white_space, '
946 "indent, format_hex_bytes, a->{n}, a->{lfield});\n".format(
947 n=o.fieldname, lfield=o.lengthfield
948 )
949 )
Ole Troan33a58172019-09-04 09:12:29 +0200950 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200951 write(
952 ' s = format(s, "\\n%U{n}: %U", format_white_space, '
953 "indent, format_hex_bytes, a, {lfield});\n".format(
954 n=o.fieldname, lfield=o.length
955 )
956 )
Ole Troan33a58172019-09-04 09:12:29 +0200957 return
958
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200959 lfield = "a->" + o.lengthfield if o.lengthfield else o.length
Ole Troandf87f802020-11-18 19:17:48 +0100960 if o.fieldtype in FORMAT_STRINGS:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200961 write(
962 forloop_format.format(
963 lfield=lfield, t=FORMAT_STRINGS[o.fieldtype], n=o.fieldname
964 )
965 )
Ole Troan33a58172019-09-04 09:12:29 +0200966 else:
967 write(forloop.format(lfield=lfield, t=o.fieldtype, n=o.fieldname))
968
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200969 _dispatch["Array"] = print_array
Ole Troan33a58172019-09-04 09:12:29 +0200970
Ole Troandf87f802020-11-18 19:17:48 +0100971 @staticmethod
972 def print_alias(k, v, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200973 """Pretty print type alias"""
Ole Troan33a58172019-09-04 09:12:29 +0200974 write = stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200975 if "length" in v.alias and v.alias["length"] and v.alias["type"] == "u8":
976 write(
977 ' return format(s, "%U", format_hex_bytes, a, {});\n'.format(
978 v.alias["length"]
979 )
980 )
981 elif v.alias["type"] in FORMAT_STRINGS:
982 write(
983 ' return format(s, "{}", *a);\n'.format(
984 FORMAT_STRINGS[v.alias["type"]]
985 )
986 )
Ole Troan33a58172019-09-04 09:12:29 +0200987 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200988 write(' return format(s, "{} (print not implemented)");\n'.format(k))
Ole Troan33a58172019-09-04 09:12:29 +0200989
Ole Troandf87f802020-11-18 19:17:48 +0100990 @staticmethod
991 def print_enum(o, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200992 """Pretty print API enum"""
Ole Troan33a58172019-09-04 09:12:29 +0200993 write = stream.write
994 write(" switch(*a) {\n")
995 for b in o:
996 write(" case %s:\n" % b[1])
997 write(' return format(s, "{}");\n'.format(b[0]))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200998 write(" }\n")
Ole Troan33a58172019-09-04 09:12:29 +0200999
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001000 _dispatch["Enum"] = print_enum
1001 _dispatch["EnumFlag"] = print_enum
Ole Troan33a58172019-09-04 09:12:29 +02001002
1003 def print_obj(self, o, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001004 """Entry point"""
Ole Troan33a58172019-09-04 09:12:29 +02001005 write = stream.write
1006
1007 if o.type in self._dispatch:
1008 self._dispatch[o.type](self, o, stream)
1009 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001010 write(
1011 ' s = format(s, "\\n{} {} {} (print not implemented");\n'.format(
1012 o.type, o.fieldtype, o.fieldname
1013 )
1014 )
Ole Troan33a58172019-09-04 09:12:29 +02001015
1016
1017def printfun(objs, stream, modulename):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001018 """Main entry point for pretty print function generation"""
Ole Troan33a58172019-09-04 09:12:29 +02001019 write = stream.write
1020
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001021 h = """\
Ole Troan9d420872017-10-12 13:06:35 +02001022/****** Print functions *****/
1023#ifdef vl_printfun
Ole Troan33a58172019-09-04 09:12:29 +02001024#ifndef included_{module}_printfun
1025#define included_{module}_printfun
Ole Troan9d420872017-10-12 13:06:35 +02001026
1027#ifdef LP64
1028#define _uword_fmt \"%lld\"
1029#define _uword_cast (long long)
1030#else
1031#define _uword_fmt \"%ld\"
1032#define _uword_cast long
1033#endif
1034
Filip Tehlar36217e32021-07-23 08:51:10 +00001035#include "{module}.api_tojson.h"
1036#include "{module}.api_fromjson.h"
1037
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001038"""
Ole Troan33a58172019-09-04 09:12:29 +02001039
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001040 signature = """\
Damjan Marionfe45f8f2022-05-20 16:01:22 +02001041static inline u8 *vl_api_{name}_t_format (u8 *s, va_list *args)
Ole Troan33a58172019-09-04 09:12:29 +02001042{{
Damjan Marionfe45f8f2022-05-20 16:01:22 +02001043 __attribute__((unused)) vl_api_{name}_t *a = va_arg (*args, vl_api_{name}_t *);
Ole Troan33a58172019-09-04 09:12:29 +02001044 u32 indent __attribute__((unused)) = 2;
1045 int i __attribute__((unused));
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001046"""
Ole Troan33a58172019-09-04 09:12:29 +02001047
1048 h = h.format(module=modulename)
1049 write(h)
1050
1051 pp = Printfun(stream)
1052 for t in objs:
1053 if t.manual_print:
Damjan Marionfe45f8f2022-05-20 16:01:22 +02001054 write("/***** manual: vl_api_%s_t_format *****/\n\n" % t.name)
Ole Troan33a58172019-09-04 09:12:29 +02001055 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001056 write(signature.format(name=t.name, suffix=""))
1057 write(" /* Message definition: vl_api_{}_t: */\n".format(t.name))
1058 write(' s = format(s, "vl_api_%s_t:");\n' % t.name)
Ole Troan33a58172019-09-04 09:12:29 +02001059 for o in t.block:
1060 pp.print_obj(o, stream)
Damjan Marionfe45f8f2022-05-20 16:01:22 +02001061 write(" return s;\n")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001062 write("}\n\n")
Filip Tehlar36217e32021-07-23 08:51:10 +00001063
Ole Troan33a58172019-09-04 09:12:29 +02001064 write("\n#endif")
1065 write("\n#endif /* vl_printfun */\n")
1066
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001067 return ""
Ole Troan33a58172019-09-04 09:12:29 +02001068
1069
Ole Troan75761b92019-09-11 17:49:08 +02001070def printfun_types(objs, stream, modulename):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001071 """Pretty print API types"""
Ole Troan33a58172019-09-04 09:12:29 +02001072 write = stream.write
1073 pp = Printfun(stream)
1074
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001075 h = """\
Ole Troan33a58172019-09-04 09:12:29 +02001076/****** Print functions *****/
1077#ifdef vl_printfun
1078#ifndef included_{module}_printfun_types
1079#define included_{module}_printfun_types
1080
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001081"""
Ole Troan33a58172019-09-04 09:12:29 +02001082 h = h.format(module=modulename)
1083 write(h)
1084
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001085 signature = """\
Ole Troan33a58172019-09-04 09:12:29 +02001086static inline u8 *format_vl_api_{name}_t (u8 *s, va_list * args)
1087{{
1088 vl_api_{name}_t *a = va_arg (*args, vl_api_{name}_t *);
1089 u32 indent __attribute__((unused)) = va_arg (*args, u32);
1090 int i __attribute__((unused));
1091 indent += 2;
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001092"""
Ole Troan33a58172019-09-04 09:12:29 +02001093
Ole Troan2c2feab2018-04-24 00:02:37 -04001094 for t in objs:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001095 if t.__class__.__name__ == "Enum" or t.__class__.__name__ == "EnumFlag":
Ole Troan33a58172019-09-04 09:12:29 +02001096 write(signature.format(name=t.name))
1097 pp.print_enum(t.block, stream)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001098 write(" return s;\n")
1099 write("}\n\n")
Ole Troan2c2feab2018-04-24 00:02:37 -04001100 continue
Ole Troan33a58172019-09-04 09:12:29 +02001101
Ole Troan9d420872017-10-12 13:06:35 +02001102 if t.manual_print:
Damjan Marionfe45f8f2022-05-20 16:01:22 +02001103 write("/***** manual: vl_api_%s_t_format *****/\n\n" % t.name)
Ole Troan9d420872017-10-12 13:06:35 +02001104 continue
Ole Troan9d420872017-10-12 13:06:35 +02001105
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001106 if t.__class__.__name__ == "Using":
Ole Troan75761b92019-09-11 17:49:08 +02001107 write(signature.format(name=t.name))
1108 pp.print_alias(t.name, t, stream)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001109 write("}\n\n")
Ole Troan75761b92019-09-11 17:49:08 +02001110 continue
1111
Ole Troan33a58172019-09-04 09:12:29 +02001112 write(signature.format(name=t.name))
Ole Troan9d420872017-10-12 13:06:35 +02001113 for o in t.block:
Ole Troan33a58172019-09-04 09:12:29 +02001114 pp.print_obj(o, stream)
Ole Troan9d420872017-10-12 13:06:35 +02001115
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001116 write(" return s;\n")
1117 write("}\n\n")
Ole Troan9d420872017-10-12 13:06:35 +02001118
Ole Troan33a58172019-09-04 09:12:29 +02001119 write("\n#endif")
1120 write("\n#endif /* vl_printfun_types */\n")
Ole Troan9d420872017-10-12 13:06:35 +02001121
Ole Troan33a58172019-09-04 09:12:29 +02001122
Ole Troandf87f802020-11-18 19:17:48 +01001123def generate_imports(imports):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001124 """Add #include matching the API import statements"""
1125 output = "/* Imported API files */\n"
1126 output += "#ifndef vl_api_version\n"
Ole Troan33a58172019-09-04 09:12:29 +02001127
1128 for i in imports:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001129 s = i.filename.replace("plugins/", "")
1130 output += "#include <{}.h>\n".format(s)
1131 output += "#endif\n"
Ole Troan9d420872017-10-12 13:06:35 +02001132 return output
1133
1134
Ole Troandf87f802020-11-18 19:17:48 +01001135ENDIAN_STRINGS = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001136 "u16": "clib_net_to_host_u16",
1137 "u32": "clib_net_to_host_u32",
1138 "u64": "clib_net_to_host_u64",
1139 "i16": "clib_net_to_host_i16",
1140 "i32": "clib_net_to_host_i32",
1141 "i64": "clib_net_to_host_i64",
1142 "f64": "clib_net_to_host_f64",
Ole Troan9d420872017-10-12 13:06:35 +02001143}
1144
1145
Dave Wallace39c40fa2023-06-06 12:05:30 -04001146def get_endian_string(o, type):
1147 """Return proper endian string conversion function"""
1148 try:
1149 if o.to_network:
1150 return ENDIAN_STRINGS[type].replace("net_to_host", "host_to_net")
1151 except:
1152 pass
1153 return ENDIAN_STRINGS[type]
1154
1155
Ole Troan33a58172019-09-04 09:12:29 +02001156def endianfun_array(o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001157 """Generate endian functions for arrays"""
1158 forloop = """\
Dave Wallace39c40fa2023-06-06 12:05:30 -04001159 {comment}
1160 ASSERT((u32){length} <= (u32)VL_API_MAX_ARRAY_SIZE);
Ole Troan33a58172019-09-04 09:12:29 +02001161 for (i = 0; i < {length}; i++) {{
1162 a->{name}[i] = {format}(a->{name}[i]);
1163 }}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001164"""
Ole Troan33a58172019-09-04 09:12:29 +02001165
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001166 forloop_format = """\
Ole Troan33a58172019-09-04 09:12:29 +02001167 for (i = 0; i < {length}; i++) {{
1168 {type}_endian(&a->{name}[i]);
1169 }}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001170"""
Ole Troan33a58172019-09-04 09:12:29 +02001171
Dave Wallace39c40fa2023-06-06 12:05:30 -04001172 to_network_comment = ""
1173 try:
1174 if o.to_network:
1175 to_network_comment = """/*
1176 * Array fields processed first to handle variable length arrays and size
1177 * field endian conversion in the proper order for to-network messages.
1178 * Message fields have been sorted by type in the code generator, thus fields
1179 * in this generated code may be converted in a different order than specified
1180 * in the *.api file.
1181 */"""
1182 except:
1183 pass
1184
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001185 output = ""
1186 if o.fieldtype == "u8" or o.fieldtype == "string" or o.fieldtype == "bool":
1187 output += " /* a->{n} = a->{n} (no-op) */\n".format(n=o.fieldname)
Ole Troan33a58172019-09-04 09:12:29 +02001188 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001189 lfield = "a->" + o.lengthfield if o.lengthfield else o.length
Ole Troandf87f802020-11-18 19:17:48 +01001190 if o.fieldtype in ENDIAN_STRINGS:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001191 output += forloop.format(
Dave Wallace39c40fa2023-06-06 12:05:30 -04001192 comment=to_network_comment,
1193 length=lfield,
1194 format=get_endian_string(o, o.fieldtype),
1195 name=o.fieldname,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001196 )
Ole Troan33a58172019-09-04 09:12:29 +02001197 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001198 output += forloop_format.format(
1199 length=lfield, type=o.fieldtype, name=o.fieldname
1200 )
Ole Troan33a58172019-09-04 09:12:29 +02001201 return output
1202
Ole Troandf87f802020-11-18 19:17:48 +01001203
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001204NO_ENDIAN_CONVERSION = {"client_index": None}
Ole Troandf87f802020-11-18 19:17:48 +01001205
Ole Troan33a58172019-09-04 09:12:29 +02001206
1207def endianfun_obj(o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001208 """Generate endian conversion function for type"""
1209 output = ""
1210 if o.type == "Array":
Ole Troan33a58172019-09-04 09:12:29 +02001211 return endianfun_array(o)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001212 if o.type != "Field":
1213 output += ' s = format(s, "\\n{} {} {} (print not implemented");\n'.format(
1214 o.type, o.fieldtype, o.fieldname
1215 )
Ole Troan33a58172019-09-04 09:12:29 +02001216 return output
Ole Troandf87f802020-11-18 19:17:48 +01001217 if o.fieldname in NO_ENDIAN_CONVERSION:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001218 output += " /* a->{n} = a->{n} (no-op) */\n".format(n=o.fieldname)
Ole Troane796a182020-05-18 11:14:05 +02001219 return output
Ole Troandf87f802020-11-18 19:17:48 +01001220 if o.fieldtype in ENDIAN_STRINGS:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001221 output += " a->{name} = {format}(a->{name});\n".format(
Dave Wallace39c40fa2023-06-06 12:05:30 -04001222 name=o.fieldname, format=get_endian_string(o, o.fieldtype)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001223 )
1224 elif o.fieldtype.startswith("vl_api_"):
1225 output += " {type}_endian(&a->{name});\n".format(
1226 type=o.fieldtype, name=o.fieldname
1227 )
Ole Troan33a58172019-09-04 09:12:29 +02001228 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001229 output += " /* a->{n} = a->{n} (no-op) */\n".format(n=o.fieldname)
Ole Troan33a58172019-09-04 09:12:29 +02001230
1231 return output
1232
1233
Ole Troan75761b92019-09-11 17:49:08 +02001234def endianfun(objs, modulename):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001235 """Main entry point for endian function generation"""
1236 output = """\
Ole Troan9d420872017-10-12 13:06:35 +02001237
1238/****** Endian swap functions *****/\n\
1239#ifdef vl_endianfun
Ole Troan33a58172019-09-04 09:12:29 +02001240#ifndef included_{module}_endianfun
1241#define included_{module}_endianfun
Ole Troan9d420872017-10-12 13:06:35 +02001242
1243#undef clib_net_to_host_uword
Dave Wallace39c40fa2023-06-06 12:05:30 -04001244#undef clib_host_to_net_uword
Ole Troan9d420872017-10-12 13:06:35 +02001245#ifdef LP64
1246#define clib_net_to_host_uword clib_net_to_host_u64
Dave Wallace39c40fa2023-06-06 12:05:30 -04001247#define clib_host_to_net_uword clib_host_to_net_u64
Ole Troan9d420872017-10-12 13:06:35 +02001248#else
1249#define clib_net_to_host_uword clib_net_to_host_u32
Dave Wallace39c40fa2023-06-06 12:05:30 -04001250#define clib_host_to_net_uword clib_host_to_net_u32
Ole Troan9d420872017-10-12 13:06:35 +02001251#endif
1252
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001253"""
Ole Troan33a58172019-09-04 09:12:29 +02001254 output = output.format(module=modulename)
1255
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001256 signature = """\
Ole Troan33a58172019-09-04 09:12:29 +02001257static inline void vl_api_{name}_t_endian (vl_api_{name}_t *a)
1258{{
1259 int i __attribute__((unused));
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001260"""
Ole Troan33a58172019-09-04 09:12:29 +02001261
Ole Troan2c2feab2018-04-24 00:02:37 -04001262 for t in objs:
Dave Wallace39c40fa2023-06-06 12:05:30 -04001263 # Outbound (to network) messages are identified by message nomenclature
1264 # i.e. message names ending with these suffixes are 'to network'
1265 if t.name.endswith("_reply") or t.name.endswith("_details"):
1266 t.to_network = True
1267 else:
1268 t.to_network = False
1269
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001270 if t.__class__.__name__ == "Enum" or t.__class__.__name__ == "EnumFlag":
Ole Troan33a58172019-09-04 09:12:29 +02001271 output += signature.format(name=t.name)
Ole Troandf87f802020-11-18 19:17:48 +01001272 if t.enumtype in ENDIAN_STRINGS:
Dave Wallace39c40fa2023-06-06 12:05:30 -04001273 output += " *a = {}(*a);\n".format(get_endian_string(t, t.enumtype))
Ole Troan33a58172019-09-04 09:12:29 +02001274 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001275 output += " /* a->{name} = a->{name} (no-op) */\n".format(
1276 name=t.name
1277 )
Ole Troan33a58172019-09-04 09:12:29 +02001278
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001279 output += "}\n\n"
Ole Troan2c2feab2018-04-24 00:02:37 -04001280 continue
Ole Troan33a58172019-09-04 09:12:29 +02001281
Ole Troan9d420872017-10-12 13:06:35 +02001282 if t.manual_endian:
1283 output += "/***** manual: vl_api_%s_t_endian *****/\n\n" % t.name
1284 continue
Ole Troan33a58172019-09-04 09:12:29 +02001285
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001286 if t.__class__.__name__ == "Using":
Ole Troan75761b92019-09-11 17:49:08 +02001287 output += signature.format(name=t.name)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001288 if "length" in t.alias and t.alias["length"] and t.alias["type"] == "u8":
1289 output += " /* a->{name} = a->{name} (no-op) */\n".format(
1290 name=t.name
1291 )
1292 elif t.alias["type"] in FORMAT_STRINGS:
Dave Wallace39c40fa2023-06-06 12:05:30 -04001293 output += " *a = {}(*a);\n".format(
1294 get_endian_string(t, t.alias["type"])
1295 )
Ole Troan75761b92019-09-11 17:49:08 +02001296 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001297 output += " /* Not Implemented yet {} */".format(t.name)
1298 output += "}\n\n"
Ole Troan75761b92019-09-11 17:49:08 +02001299 continue
1300
Ole Troan33a58172019-09-04 09:12:29 +02001301 output += signature.format(name=t.name)
Ole Troan9d420872017-10-12 13:06:35 +02001302
Dave Wallace39c40fa2023-06-06 12:05:30 -04001303 # For outbound (to network) messages:
1304 # some arrays have dynamic length -- iterate over
1305 # them before changing endianness for the length field
1306 # by making the Array types show up first
1307 if t.to_network:
1308 t.block.sort(key=lambda x: x.type)
Stanislav Zaikin139b2da2022-07-21 19:06:26 +02001309
Ole Troan9d420872017-10-12 13:06:35 +02001310 for o in t.block:
Dave Wallace39c40fa2023-06-06 12:05:30 -04001311 o.to_network = t.to_network
Ole Troan33a58172019-09-04 09:12:29 +02001312 output += endianfun_obj(o)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001313 output += "}\n\n"
Ole Troan33a58172019-09-04 09:12:29 +02001314
1315 output += "\n#endif"
Ole Troan9d420872017-10-12 13:06:35 +02001316 output += "\n#endif /* vl_endianfun */\n\n"
1317
1318 return output
1319
1320
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001321def calc_size_fun(objs, modulename):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001322 """Main entry point for calculate size function generation"""
1323 output = """\
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001324
1325/****** Calculate size functions *****/\n\
1326#ifdef vl_calcsizefun
1327#ifndef included_{module}_calcsizefun
1328#define included_{module}_calcsizefun
1329
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001330"""
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001331 output = output.format(module=modulename)
1332
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001333 signature = """\
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001334/* calculate message size of message in network byte order */
1335static inline uword vl_api_{name}_t_calc_size (vl_api_{name}_t *a)
1336{{
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001337"""
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001338
1339 for o in objs:
1340 tname = o.__class__.__name__
1341
1342 output += signature.format(name=o.name)
1343 output += f" return sizeof(*a)"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001344 if tname == "Using":
1345 if "length" in o.alias:
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001346 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001347 tmp = int(o.alias["length"])
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001348 if tmp == 0:
1349 raise (f"Unexpected length '0' for alias {o}")
1350 except:
1351 # output += f" + vl_api_{o.alias.name}_t_calc_size({o.name})"
1352 print("culprit:")
1353 print(o)
1354 print(dir(o.alias))
1355 print(o.alias)
1356 raise
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001357 elif tname == "Enum" or tname == "EnumFlag":
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001358 pass
1359 else:
1360 for b in o.block:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001361 if b.type == "Option":
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001362 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001363 elif b.type == "Field":
1364 if b.fieldtype.startswith("vl_api_"):
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001365 output += f" - sizeof(a->{b.fieldname})"
1366 output += f" + {b.fieldtype}_calc_size(&a->{b.fieldname})"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001367 elif b.type == "Array":
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001368 if b.lengthfield:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001369 m = list(
1370 filter(lambda x: x.fieldname == b.lengthfield, o.block)
1371 )
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001372 if len(m) != 1:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001373 raise Exception(
1374 f"Expected 1 match for field '{b.lengthfield}', got '{m}'"
1375 )
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001376 lf = m[0]
1377 if lf.fieldtype in ENDIAN_STRINGS:
Dave Wallace39c40fa2023-06-06 12:05:30 -04001378 output += f" + {get_endian_string(b, lf.fieldtype)}(a->{b.lengthfield}) * sizeof(a->{b.fieldname}[0])"
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001379 elif lf.fieldtype == "u8":
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001380 output += (
1381 f" + a->{b.lengthfield} * sizeof(a->{b.fieldname}[0])"
1382 )
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001383 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001384 raise Exception(
1385 f"Don't know how to endian swap {lf.fieldtype}"
1386 )
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001387 else:
1388 # Fixed length strings decay to nul terminated u8
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001389 if b.fieldtype == "string":
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001390 if b.modern_vla:
1391 output += f" + vl_api_string_len(&a->{b.fieldname})"
1392
1393 output += ";\n"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001394 output += "}\n\n"
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001395 output += "\n#endif"
1396 output += "\n#endif /* vl_calcsizefun */\n\n"
1397
1398 return output
1399
1400
Ole Troan9d420872017-10-12 13:06:35 +02001401def version_tuple(s, module):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001402 """Generate semantic version string"""
1403 output = """\
Ole Troan9d420872017-10-12 13:06:35 +02001404/****** Version tuple *****/
1405
1406#ifdef vl_api_version_tuple
1407
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001408"""
1409 if "version" in s["Option"]:
1410 v = s["Option"]["version"]
1411 (major, minor, patch) = v.split(".")
1412 output += "vl_api_version_tuple(%s, %s, %s, %s)\n" % (
1413 module,
1414 major,
1415 minor,
1416 patch,
1417 )
Ole Troan9d420872017-10-12 13:06:35 +02001418
1419 output += "\n#endif /* vl_api_version_tuple */\n\n"
1420
1421 return output
1422
1423
Ole Troan2a1ca782019-09-19 01:08:30 +02001424def generate_include_enum(s, module, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001425 """Generate <name>.api_enum.h"""
Ole Troan2a1ca782019-09-19 01:08:30 +02001426 write = stream.write
1427
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001428 if "Define" in s:
1429 write("typedef enum {\n")
1430 for t in s["Define"]:
1431 write(" VL_API_{},\n".format(t.name.upper()))
1432 write(" VL_MSG_{}_LAST\n".format(module.upper()))
1433 write("}} vl_api_{}_enum_t;\n".format(module))
Ole Troan2a1ca782019-09-19 01:08:30 +02001434
Paul Vinciguerra7c8803d2019-11-21 17:16:18 -05001435
Ole Troandf87f802020-11-18 19:17:48 +01001436def generate_include_counters(s, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001437 """Include file for the counter data model types."""
Ole Troan148c7b72020-10-07 18:05:37 +02001438 write = stream.write
1439
1440 for counters in s:
1441 csetname = counters.name
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001442 write("typedef enum {\n")
Ole Troan148c7b72020-10-07 18:05:37 +02001443 for c in counters.block:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001444 write(" {}_ERROR_{},\n".format(csetname.upper(), c["name"].upper()))
1445 write(" {}_N_ERROR\n".format(csetname.upper()))
1446 write("}} vl_counter_{}_enum_t;\n".format(csetname))
Ole Troan148c7b72020-10-07 18:05:37 +02001447
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001448 write("extern vlib_error_desc_t {}_error_counters[];\n".format(csetname))
Ole Troan148c7b72020-10-07 18:05:37 +02001449
Ole Troandf87f802020-11-18 19:17:48 +01001450
Ole Troan2a1ca782019-09-19 01:08:30 +02001451def generate_include_types(s, module, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001452 """Generate separate API _types file."""
Ole Troan2a1ca782019-09-19 01:08:30 +02001453 write = stream.write
1454
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001455 write("#ifndef included_{module}_api_types_h\n".format(module=module))
1456 write("#define included_{module}_api_types_h\n".format(module=module))
Ole Troan2a1ca782019-09-19 01:08:30 +02001457
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001458 if "version" in s["Option"]:
1459 v = s["Option"]["version"]
1460 (major, minor, patch) = v.split(".")
1461 write(
1462 "#define VL_API_{m}_API_VERSION_MAJOR {v}\n".format(
1463 m=module.upper(), v=major
1464 )
1465 )
1466 write(
1467 "#define VL_API_{m}_API_VERSION_MINOR {v}\n".format(
1468 m=module.upper(), v=minor
1469 )
1470 )
1471 write(
1472 "#define VL_API_{m}_API_VERSION_PATCH {v}\n".format(
1473 m=module.upper(), v=patch
1474 )
1475 )
Ole Troanf92bfb12020-02-28 13:45:42 +01001476
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001477 if "Import" in s:
1478 write("/* Imported API files */\n")
1479 for i in s["Import"]:
1480 filename = i.filename.replace("plugins/", "")
1481 write("#include <{}_types.h>\n".format(filename))
Ole Troan2a1ca782019-09-19 01:08:30 +02001482
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001483 for o in itertools.chain(s["types"], s["Define"]):
Ole Troan2a1ca782019-09-19 01:08:30 +02001484 tname = o.__class__.__name__
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001485 if tname == "Using":
1486 if "length" in o.alias:
1487 write(
1488 "typedef %s vl_api_%s_t[%s];\n"
1489 % (o.alias["type"], o.name, o.alias["length"])
1490 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001491 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001492 write("typedef %s vl_api_%s_t;\n" % (o.alias["type"], o.name))
1493 elif tname == "Enum" or tname == "EnumFlag":
1494 if o.enumtype == "u32":
Ole Troan2a1ca782019-09-19 01:08:30 +02001495 write("typedef enum {\n")
1496 else:
1497 write("typedef enum __attribute__((packed)) {\n")
1498
1499 for b in o.block:
1500 write(" %s = %s,\n" % (b[0], b[1]))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001501 write("} vl_api_%s_t;\n" % o.name)
1502 if o.enumtype != "u32":
1503 size1 = "sizeof(vl_api_%s_t)" % o.name
1504 size2 = "sizeof(%s)" % o.enumtype
1505 err_str = "size of API enum %s is wrong" % o.name
1506 write('STATIC_ASSERT(%s == %s, "%s");\n' % (size1, size2, err_str))
Ole Troan2a1ca782019-09-19 01:08:30 +02001507 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001508 if tname == "Union":
1509 write("typedef union __attribute__ ((packed)) _vl_api_%s {\n" % o.name)
Ole Troan2a1ca782019-09-19 01:08:30 +02001510 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001511 write(
1512 ("typedef struct __attribute__ ((packed)) _vl_api_%s {\n") % o.name
1513 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001514 for b in o.block:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001515 if b.type == "Option":
Ole Troan2a1ca782019-09-19 01:08:30 +02001516 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001517 if b.type == "Field":
1518 write(" %s %s;\n" % (api2c(b.fieldtype), b.fieldname))
1519 elif b.type == "Array":
Ole Troan2a1ca782019-09-19 01:08:30 +02001520 if b.lengthfield:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001521 write(" %s %s[0];\n" % (api2c(b.fieldtype), b.fieldname))
Ole Troan2a1ca782019-09-19 01:08:30 +02001522 else:
1523 # Fixed length strings decay to nul terminated u8
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001524 if b.fieldtype == "string":
Ole Troan2a1ca782019-09-19 01:08:30 +02001525 if b.modern_vla:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001526 write(
1527 " {} {};\n".format(
1528 api2c(b.fieldtype), b.fieldname
1529 )
1530 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001531 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001532 write(" u8 {}[{}];\n".format(b.fieldname, b.length))
Ole Troan2a1ca782019-09-19 01:08:30 +02001533 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001534 write(
1535 " %s %s[%s];\n"
1536 % (api2c(b.fieldtype), b.fieldname, b.length)
1537 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001538 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001539 raise ValueError(
1540 "Error in processing type {} for {}".format(b, o.name)
1541 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001542
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001543 write("} vl_api_%s_t;\n" % o.name)
1544 write(
1545 f"#define VL_API_{o.name.upper()}_IS_CONSTANT_SIZE ({0 if o.vla else 1})\n\n"
1546 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001547
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001548 for t in s["Define"]:
1549 write(
1550 '#define VL_API_{ID}_CRC "{n}_{crc:08x}"\n'.format(
1551 n=t.name, ID=t.name.upper(), crc=t.crc
1552 )
1553 )
Ole Troan3f2d5712019-12-07 00:39:49 +01001554
Ole Troan2a1ca782019-09-19 01:08:30 +02001555 write("\n#endif\n")
1556
1557
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001558def generate_c_boilerplate(services, defines, counters, file_crc, module, stream):
1559 """VPP side plugin."""
Ole Troan2a1ca782019-09-19 01:08:30 +02001560 write = stream.write
Ole Troan148c7b72020-10-07 18:05:37 +02001561 define_hash = {d.name: d for d in defines}
Ole Troan2a1ca782019-09-19 01:08:30 +02001562
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001563 hdr = """\
Ole Troan2a1ca782019-09-19 01:08:30 +02001564#define vl_endianfun /* define message structures */
1565#include "{module}.api.h"
1566#undef vl_endianfun
1567
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001568#define vl_calcsizefun
1569#include "{module}.api.h"
1570#undef vl_calsizefun
1571
Ole Troan2a1ca782019-09-19 01:08:30 +02001572/* instantiate all the print functions we know about */
Ole Troan2a1ca782019-09-19 01:08:30 +02001573#define vl_printfun
1574#include "{module}.api.h"
1575#undef vl_printfun
1576
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001577"""
Ole Troan2a1ca782019-09-19 01:08:30 +02001578
1579 write(hdr.format(module=module))
Ole Troan683bdb62023-05-11 22:02:30 +02001580 if len(defines) > 0:
1581 write("static u16\n")
1582 write("setup_message_id_table (void) {\n")
1583 write(" api_main_t *am = my_api_main;\n")
1584 write(" vl_msg_api_msg_config_t c;\n")
1585 write(
1586 ' u16 msg_id_base = vl_msg_api_get_msg_ids ("{}_{crc:08x}", '
1587 "VL_MSG_{m}_LAST);\n".format(module, crc=file_crc, m=module.upper())
1588 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001589
Ole Troan2a1ca782019-09-19 01:08:30 +02001590 for d in defines:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001591 write(
1592 ' vl_msg_api_add_msg_name_crc (am, "{n}_{crc:08x}",\n'
1593 " VL_API_{ID} + msg_id_base);\n".format(
1594 n=d.name, ID=d.name.upper(), crc=d.crc
1595 )
1596 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001597 for s in services:
Ole Troane796a182020-05-18 11:14:05 +02001598 d = define_hash[s.caller]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001599 write(
1600 " c = (vl_msg_api_msg_config_t) "
1601 " {{.id = VL_API_{ID} + msg_id_base,\n"
1602 ' .name = "{n}",\n'
1603 " .handler = vl_api_{n}_t_handler,\n"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001604 " .endian = vl_api_{n}_t_endian,\n"
Damjan Marionfe45f8f2022-05-20 16:01:22 +02001605 " .format_fn = vl_api_{n}_t_format,\n"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001606 " .traced = 1,\n"
1607 " .replay = 1,\n"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001608 " .tojson = vl_api_{n}_t_tojson,\n"
1609 " .fromjson = vl_api_{n}_t_fromjson,\n"
1610 " .calc_size = vl_api_{n}_t_calc_size,\n"
1611 " .is_autoendian = {auto}}};\n".format(
1612 n=s.caller, ID=s.caller.upper(), auto=d.autoendian
1613 )
1614 )
1615 write(" vl_msg_api_config (&c);\n")
Ole Troanbad67922020-08-24 12:22:01 +02001616 try:
1617 d = define_hash[s.reply]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001618 write(
1619 " c = (vl_msg_api_msg_config_t) "
1620 "{{.id = VL_API_{ID} + msg_id_base,\n"
1621 ' .name = "{n}",\n'
1622 " .handler = 0,\n"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001623 " .endian = vl_api_{n}_t_endian,\n"
Damjan Marionfe45f8f2022-05-20 16:01:22 +02001624 " .format_fn = vl_api_{n}_t_format,\n"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001625 " .traced = 1,\n"
1626 " .replay = 1,\n"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001627 " .tojson = vl_api_{n}_t_tojson,\n"
1628 " .fromjson = vl_api_{n}_t_fromjson,\n"
1629 " .calc_size = vl_api_{n}_t_calc_size,\n"
1630 " .is_autoendian = {auto}}};\n".format(
1631 n=s.reply, ID=s.reply.upper(), auto=d.autoendian
1632 )
1633 )
1634 write(" vl_msg_api_config (&c);\n")
Ole Troanbad67922020-08-24 12:22:01 +02001635 except KeyError:
1636 pass
Ole Troan2a1ca782019-09-19 01:08:30 +02001637
Stanislav Zaikin139b2da2022-07-21 19:06:26 +02001638 try:
1639 if s.stream:
1640 d = define_hash[s.stream_message]
1641 write(
1642 " c = (vl_msg_api_msg_config_t) "
1643 "{{.id = VL_API_{ID} + msg_id_base,\n"
1644 ' .name = "{n}",\n'
1645 " .handler = 0,\n"
1646 " .endian = vl_api_{n}_t_endian,\n"
1647 " .format_fn = vl_api_{n}_t_format,\n"
1648 " .traced = 1,\n"
1649 " .replay = 1,\n"
1650 " .tojson = vl_api_{n}_t_tojson,\n"
1651 " .fromjson = vl_api_{n}_t_fromjson,\n"
1652 " .calc_size = vl_api_{n}_t_calc_size,\n"
1653 " .is_autoendian = {auto}}};\n".format(
1654 n=s.stream_message,
1655 ID=s.stream_message.upper(),
1656 auto=d.autoendian,
1657 )
1658 )
1659 write(" vl_msg_api_config (&c);\n")
1660 except KeyError:
1661 pass
Ole Troan683bdb62023-05-11 22:02:30 +02001662 if len(defines) > 0:
1663 write(" return msg_id_base;\n")
1664 write("}\n")
Ole Troan2a1ca782019-09-19 01:08:30 +02001665
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001666 severity = {
1667 "error": "VL_COUNTER_SEVERITY_ERROR",
1668 "info": "VL_COUNTER_SEVERITY_INFO",
1669 "warn": "VL_COUNTER_SEVERITY_WARN",
1670 }
Ole Troan148c7b72020-10-07 18:05:37 +02001671
1672 for cnt in counters:
1673 csetname = cnt.name
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001674 write("vlib_error_desc_t {}_error_counters[] = {{\n".format(csetname))
Ole Troan148c7b72020-10-07 18:05:37 +02001675 for c in cnt.block:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001676 write(" {\n")
1677 write(' .name = "{}",\n'.format(c["name"]))
1678 write(' .desc = "{}",\n'.format(c["description"]))
1679 write(" .severity = {},\n".format(severity[c["severity"]]))
1680 write(" },\n")
1681 write("};\n")
Ole Troan2a1ca782019-09-19 01:08:30 +02001682
Ole Troandf87f802020-11-18 19:17:48 +01001683
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001684def generate_c_test_boilerplate(services, defines, file_crc, module, plugin, stream):
1685 """Generate code for legacy style VAT. To be deleted."""
Ole Troan2a1ca782019-09-19 01:08:30 +02001686 write = stream.write
1687
Ole Troandf87f802020-11-18 19:17:48 +01001688 define_hash = {d.name: d for d in defines}
Ole Troan2a1ca782019-09-19 01:08:30 +02001689
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001690 hdr = """\
Ole Troandf87f802020-11-18 19:17:48 +01001691#define vl_endianfun /* define message structures */
Ole Troan2a1ca782019-09-19 01:08:30 +02001692#include "{module}.api.h"
1693#undef vl_endianfun
1694
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001695#define vl_calcsizefun
1696#include "{module}.api.h"
1697#undef vl_calsizefun
1698
Ole Troan2a1ca782019-09-19 01:08:30 +02001699/* instantiate all the print functions we know about */
Ole Troan2a1ca782019-09-19 01:08:30 +02001700#define vl_printfun
1701#include "{module}.api.h"
1702#undef vl_printfun
1703
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001704"""
Ole Troan2a1ca782019-09-19 01:08:30 +02001705
1706 write(hdr.format(module=module))
1707 for s in services:
1708 try:
1709 d = define_hash[s.reply]
Ole Troandf87f802020-11-18 19:17:48 +01001710 except KeyError:
Ole Troan2a1ca782019-09-19 01:08:30 +02001711 continue
1712 if d.manual_print:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001713 write(
1714 "/*\n"
1715 " * Manual definition requested for: \n"
1716 " * vl_api_{n}_t_handler()\n"
1717 " */\n".format(n=s.reply)
1718 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001719 continue
1720 if not define_hash[s.caller].autoreply:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001721 write(
1722 "/* Generation not supported (vl_api_{n}_t_handler()) */\n".format(
1723 n=s.reply
1724 )
1725 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001726 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001727 write("#ifndef VL_API_{n}_T_HANDLER\n".format(n=s.reply.upper()))
1728 write("static void\n")
1729 write("vl_api_{n}_t_handler (vl_api_{n}_t * mp) {{\n".format(n=s.reply))
1730 write(" vat_main_t * vam = {}_test_main.vat_main;\n".format(module))
1731 write(" i32 retval = ntohl(mp->retval);\n")
1732 write(" if (vam->async_mode) {\n")
1733 write(" vam->async_errors += (retval < 0);\n")
1734 write(" } else {\n")
1735 write(" vam->retval = retval;\n")
1736 write(" vam->result_ready = 1;\n")
1737 write(" }\n")
1738 write("}\n")
1739 write("#endif\n")
Ole Troan2a1ca782019-09-19 01:08:30 +02001740
Ole Troanb126ebc2019-10-07 16:22:00 +02001741 for e in s.events:
1742 if define_hash[e].manual_print:
1743 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001744 write("static void\n")
1745 write("vl_api_{n}_t_handler (vl_api_{n}_t * mp) {{\n".format(n=e))
Damjan Marionfe45f8f2022-05-20 16:01:22 +02001746 write(' vlib_cli_output(0, "{n} event called:");\n'.format(n=e))
1747 write(
1748 ' vlib_cli_output(0, "%U", vl_api_{n}_t_format, mp);\n'.format(n=e)
1749 )
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001750 write("}\n")
Ole Troanb126ebc2019-10-07 16:22:00 +02001751
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001752 write("static void\n")
1753 write("setup_message_id_table (vat_main_t * vam, u16 msg_id_base) {\n")
Ole Troan2a1ca782019-09-19 01:08:30 +02001754 for s in services:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001755 write(
Damjan Mariona2eb5072022-05-20 20:06:01 +02001756 " vl_msg_api_config (&(vl_msg_api_msg_config_t){{\n"
1757 " .id = VL_API_{ID} + msg_id_base,\n"
1758 ' .name = "{n}",\n'
1759 " .handler = vl_api_{n}_t_handler,\n"
1760 " .endian = vl_api_{n}_t_endian,\n"
1761 " .format_fn = vl_api_{n}_t_format,\n"
1762 " .size = sizeof(vl_api_{n}_t),\n"
1763 " .traced = 1,\n"
1764 " .tojson = vl_api_{n}_t_tojson,\n"
1765 " .fromjson = vl_api_{n}_t_fromjson,\n"
1766 " .calc_size = vl_api_{n}_t_calc_size,\n"
1767 " }});".format(n=s.reply, ID=s.reply.upper())
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001768 )
1769 write(
1770 ' hash_set_mem (vam->function_by_name, "{n}", api_{n});\n'.format(
1771 n=s.caller
1772 )
1773 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001774 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001775 write(
1776 ' hash_set_mem (vam->help_by_name, "{n}", "{help}");\n'.format(
1777 n=s.caller, help=define_hash[s.caller].options["vat_help"]
1778 )
1779 )
Ole Troandf87f802020-11-18 19:17:48 +01001780 except KeyError:
Ole Troan2a1ca782019-09-19 01:08:30 +02001781 pass
1782
Ole Troanb126ebc2019-10-07 16:22:00 +02001783 # Events
1784 for e in s.events:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001785 write(
Damjan Mariona2eb5072022-05-20 20:06:01 +02001786 " vl_msg_api_config (&(vl_msg_api_msg_config_t){{\n"
1787 " .id = VL_API_{ID} + msg_id_base,\n"
1788 ' .name = "{n}",\n'
1789 " .handler = vl_api_{n}_t_handler,\n"
1790 " .endian = vl_api_{n}_t_endian,\n"
1791 " .format_fn = vl_api_{n}_t_format,\n"
1792 " .size = sizeof(vl_api_{n}_t),\n"
1793 " .traced = 1,\n"
1794 " .tojson = vl_api_{n}_t_tojson,\n"
1795 " .fromjson = vl_api_{n}_t_fromjson,\n"
1796 " .calc_size = vl_api_{n}_t_calc_size,\n"
1797 " }});".format(n=e, ID=e.upper())
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001798 )
Ole Troanb126ebc2019-10-07 16:22:00 +02001799
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001800 write("}\n")
1801 write("clib_error_t * vat_plugin_register (vat_main_t *vam)\n")
1802 write("{\n")
1803 write(" {n}_test_main_t * mainp = &{n}_test_main;\n".format(n=module))
1804 write(" mainp->vat_main = vam;\n")
1805 write(
1806 " mainp->msg_id_base = vl_client_get_first_plugin_msg_id "
1807 ' ("{n}_{crc:08x}");\n'.format(n=module, crc=file_crc)
1808 )
1809 write(" if (mainp->msg_id_base == (u16) ~0)\n")
1810 write(
1811 ' return clib_error_return (0, "{} plugin not loaded...");\n'.format(
1812 module
1813 )
1814 )
1815 write(" setup_message_id_table (vam, mainp->msg_id_base);\n")
1816 write("#ifdef VL_API_LOCAL_SETUP_MESSAGE_ID_TABLE\n")
1817 write(" VL_API_LOCAL_SETUP_MESSAGE_ID_TABLE(vam);\n")
1818 write("#endif\n")
1819 write(" return 0;\n")
1820 write("}\n")
Ole Troan2a1ca782019-09-19 01:08:30 +02001821
Ole Troandf87f802020-11-18 19:17:48 +01001822
1823def apifunc(func):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001824 """Check if a method is generated already."""
1825
Ole Troandf87f802020-11-18 19:17:48 +01001826 def _f(module, d, processed, *args):
1827 if d.name in processed:
1828 return None
1829 processed[d.name] = True
1830 return func(module, d, *args)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001831
Ole Troandf87f802020-11-18 19:17:48 +01001832 return _f
1833
1834
1835def c_test_api_service(s, dump, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001836 """Generate JSON code for a service."""
Ole Troandf87f802020-11-18 19:17:48 +01001837 write = stream.write
1838
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001839 req_reply_template = """\
Ole Troandf87f802020-11-18 19:17:48 +01001840static cJSON *
1841api_{n} (cJSON *o)
1842{{
1843 vl_api_{n}_t *mp;
1844 int len;
1845 if (!o) return 0;
1846 mp = vl_api_{n}_t_fromjson(o, &len);
1847 if (!mp) {{
1848 fprintf(stderr, "Failed converting JSON to API\\n");
1849 return 0;
1850 }}
1851
1852 mp->_vl_msg_id = vac_get_msg_index(VL_API_{N}_CRC);
1853 vl_api_{n}_t_endian(mp);
1854 vac_write((char *)mp, len);
Filip Tehlar36217e32021-07-23 08:51:10 +00001855 cJSON_free(mp);
Ole Troandf87f802020-11-18 19:17:48 +01001856
1857 /* Read reply */
1858 char *p;
1859 int l;
1860 vac_read(&p, &l, 5); // XXX: Fix timeout
Ole Troanedc73fd2021-02-17 13:26:53 +01001861 if (p == 0 || l == 0) return 0;
Ole Troandf87f802020-11-18 19:17:48 +01001862 // XXX Will fail in case of event received. Do loop
1863 if (ntohs(*((u16 *)p)) != vac_get_msg_index(VL_API_{R}_CRC)) {{
1864 fprintf(stderr, "Mismatched reply\\n");
1865 return 0;
1866 }}
1867 vl_api_{r}_t *rmp = (vl_api_{r}_t *)p;
1868 vl_api_{r}_t_endian(rmp);
1869 return vl_api_{r}_t_tojson(rmp);
1870}}
1871
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001872"""
1873 dump_details_template = """\
Ole Troandf87f802020-11-18 19:17:48 +01001874static cJSON *
1875api_{n} (cJSON *o)
1876{{
1877 u16 msg_id = vac_get_msg_index(VL_API_{N}_CRC);
1878 int len;
1879 if (!o) return 0;
1880 vl_api_{n}_t *mp = vl_api_{n}_t_fromjson(o, &len);
1881 if (!mp) {{
1882 fprintf(stderr, "Failed converting JSON to API\\n");
1883 return 0;
1884 }}
1885 mp->_vl_msg_id = msg_id;
1886 vl_api_{n}_t_endian(mp);
1887 vac_write((char *)mp, len);
Filip Tehlar36217e32021-07-23 08:51:10 +00001888 cJSON_free(mp);
Ole Troandf87f802020-11-18 19:17:48 +01001889
1890 vat2_control_ping(123); // FIX CONTEXT
1891 cJSON *reply = cJSON_CreateArray();
1892
1893 u16 ping_reply_msg_id = vac_get_msg_index(VL_API_CONTROL_PING_REPLY_CRC);
1894 u16 details_msg_id = vac_get_msg_index(VL_API_{R}_CRC);
1895
1896 while (1) {{
1897 /* Read reply */
1898 char *p;
1899 int l;
1900 vac_read(&p, &l, 5); // XXX: Fix timeout
Ole Troanedc73fd2021-02-17 13:26:53 +01001901 if (p == 0 || l == 0) {{
1902 cJSON_free(reply);
1903 return 0;
1904 }}
Ole Troandf87f802020-11-18 19:17:48 +01001905
1906 /* Message can be one of [_details, control_ping_reply
1907 * or unrelated event]
1908 */
1909 u16 reply_msg_id = ntohs(*((u16 *)p));
1910 if (reply_msg_id == ping_reply_msg_id) {{
1911 break;
1912 }}
1913
1914 if (reply_msg_id == details_msg_id) {{
Ole Troanedc73fd2021-02-17 13:26:53 +01001915 if (l < sizeof(vl_api_{r}_t)) {{
1916 cJSON_free(reply);
1917 return 0;
1918 }}
Ole Troandf87f802020-11-18 19:17:48 +01001919 vl_api_{r}_t *rmp = (vl_api_{r}_t *)p;
1920 vl_api_{r}_t_endian(rmp);
1921 cJSON_AddItemToArray(reply, vl_api_{r}_t_tojson(rmp));
1922 }}
1923 }}
1924 return reply;
1925}}
1926
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001927"""
1928 gets_details_reply_template = """\
Ole Troandf87f802020-11-18 19:17:48 +01001929static cJSON *
1930api_{n} (cJSON *o)
1931{{
1932 u16 msg_id = vac_get_msg_index(VL_API_{N}_CRC);
1933 int len = 0;
1934 if (!o) return 0;
1935 vl_api_{n}_t *mp = vl_api_{n}_t_fromjson(o, &len);
1936 if (!mp) {{
1937 fprintf(stderr, "Failed converting JSON to API\\n");
1938 return 0;
1939 }}
1940 mp->_vl_msg_id = msg_id;
1941
1942 vl_api_{n}_t_endian(mp);
1943 vac_write((char *)mp, len);
Filip Tehlar36217e32021-07-23 08:51:10 +00001944 cJSON_free(mp);
Ole Troandf87f802020-11-18 19:17:48 +01001945
1946 cJSON *reply = cJSON_CreateArray();
1947
1948 u16 reply_msg_id = vac_get_msg_index(VL_API_{R}_CRC);
1949 u16 details_msg_id = vac_get_msg_index(VL_API_{D}_CRC);
1950
1951 while (1) {{
1952 /* Read reply */
1953 char *p;
1954 int l;
1955 vac_read(&p, &l, 5); // XXX: Fix timeout
1956
1957 /* Message can be one of [_details, control_ping_reply
1958 * or unrelated event]
1959 */
1960 u16 msg_id = ntohs(*((u16 *)p));
1961 if (msg_id == reply_msg_id) {{
1962 vl_api_{r}_t *rmp = (vl_api_{r}_t *)p;
1963 vl_api_{r}_t_endian(rmp);
1964 cJSON_AddItemToArray(reply, vl_api_{r}_t_tojson(rmp));
1965 break;
1966 }}
1967
1968 if (msg_id == details_msg_id) {{
1969 vl_api_{d}_t *rmp = (vl_api_{d}_t *)p;
1970 vl_api_{d}_t_endian(rmp);
1971 cJSON_AddItemToArray(reply, vl_api_{d}_t_tojson(rmp));
1972 }}
1973 }}
1974 return reply;
1975}}
1976
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001977"""
Ole Troandf87f802020-11-18 19:17:48 +01001978
1979 if dump:
1980 if s.stream_message:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001981 write(
1982 gets_details_reply_template.format(
1983 n=s.caller,
1984 r=s.reply,
1985 N=s.caller.upper(),
1986 R=s.reply.upper(),
1987 d=s.stream_message,
1988 D=s.stream_message.upper(),
1989 )
1990 )
Ole Troandf87f802020-11-18 19:17:48 +01001991 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001992 write(
1993 dump_details_template.format(
1994 n=s.caller, r=s.reply, N=s.caller.upper(), R=s.reply.upper()
1995 )
1996 )
Ole Troandf87f802020-11-18 19:17:48 +01001997 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001998 write(
1999 req_reply_template.format(
2000 n=s.caller, r=s.reply, N=s.caller.upper(), R=s.reply.upper()
2001 )
2002 )
Ole Troandf87f802020-11-18 19:17:48 +01002003
2004
2005def generate_c_test2_boilerplate(services, defines, module, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002006 """Generate code for VAT2 plugin."""
Ole Troandf87f802020-11-18 19:17:48 +01002007 write = stream.write
2008
2009 define_hash = {d.name: d for d in defines}
2010 # replies = {}
2011
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002012 hdr = """\
Ole Troandf87f802020-11-18 19:17:48 +01002013#include <vlibapi/api.h>
2014#include <vlibmemory/api.h>
2015#include <vppinfra/error.h>
2016#include <vnet/ip/ip_format_fns.h>
2017#include <vnet/ethernet/ethernet_format_fns.h>
2018
2019#define vl_typedefs /* define message structures */
Filip Tehlarb7e4d442021-07-08 18:44:19 +00002020#include <vlibmemory/vl_memory_api_h.h>
Florin Corasa1400ce2021-09-15 09:02:08 -07002021#include <vlibmemory/vlib.api_types.h>
2022#include <vlibmemory/vlib.api.h>
Ole Troandf87f802020-11-18 19:17:48 +01002023#undef vl_typedefs
2024
2025#include "{module}.api_enum.h"
2026#include "{module}.api_types.h"
2027
2028#define vl_endianfun /* define message structures */
2029#include "{module}.api.h"
2030#undef vl_endianfun
2031
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01002032#define vl_calcsizefun
2033#include "{module}.api.h"
2034#undef vl_calsizefun
2035
Ole Troandf87f802020-11-18 19:17:48 +01002036#define vl_printfun
2037#include "{module}.api.h"
2038#undef vl_printfun
2039
2040#include "{module}.api_tojson.h"
2041#include "{module}.api_fromjson.h"
2042#include <vpp-api/client/vppapiclient.h>
2043
2044#include <vat2/vat2_helpers.h>
2045
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002046"""
Ole Troandf87f802020-11-18 19:17:48 +01002047
2048 write(hdr.format(module=module))
2049
2050 for s in services:
2051 if s.reply not in define_hash:
2052 continue
2053 c_test_api_service(s, s.stream, stream)
2054
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002055 write(
2056 "void vat2_register_function(char *, cJSON * (*)(cJSON *), cJSON * (*)(void *), u32);\n"
2057 )
Ole Troandf87f802020-11-18 19:17:48 +01002058 # write('__attribute__((constructor))')
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002059 write("clib_error_t *\n")
2060 write("vat2_register_plugin (void) {\n")
Ole Troandf87f802020-11-18 19:17:48 +01002061 for s in services:
Filip Tehlar36217e32021-07-23 08:51:10 +00002062 if s.reply not in define_hash:
2063 continue
2064 crc = define_hash[s.caller].crc
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002065 write(
2066 ' vat2_register_function("{n}", api_{n}, (cJSON * (*)(void *))vl_api_{n}_t_tojson, 0x{crc:08x});\n'.format(
2067 n=s.caller, crc=crc
2068 )
2069 )
2070 write(" return 0;\n")
2071 write("}\n")
Ole Troandf87f802020-11-18 19:17:48 +01002072
2073
Ole Troan9d420872017-10-12 13:06:35 +02002074#
2075# Plugin entry point
2076#
Nathan Skrzypczak1b299fa2022-06-16 17:00:02 +02002077def run(output_dir, apifilename, s):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002078 """Main plugin entry point."""
Ole Troan33a58172019-09-04 09:12:29 +02002079 stream = StringIO()
Ole Troan2a1ca782019-09-19 01:08:30 +02002080
Nathan Skrzypczak1b299fa2022-06-16 17:00:02 +02002081 if not output_dir:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002082 sys.stderr.write("Missing --outputdir argument")
Ole Troan2a1ca782019-09-19 01:08:30 +02002083 return None
2084
Ole Troandf87f802020-11-18 19:17:48 +01002085 basename = os.path.basename(apifilename)
2086 filename, _ = os.path.splitext(basename)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002087 modulename = filename.replace(".", "_")
Nathan Skrzypczak1b299fa2022-06-16 17:00:02 +02002088 filename_enum = os.path.join(output_dir + "/" + basename + "_enum.h")
2089 filename_types = os.path.join(output_dir + "/" + basename + "_types.h")
2090 filename_c = os.path.join(output_dir + "/" + basename + ".c")
2091 filename_c_test = os.path.join(output_dir + "/" + basename + "_test.c")
2092 filename_c_test2 = os.path.join(output_dir + "/" + basename + "_test2.c")
2093 filename_c_tojson = os.path.join(output_dir + "/" + basename + "_tojson.h")
2094 filename_c_fromjson = os.path.join(output_dir + "/" + basename + "_fromjson.h")
Ole Troan2a1ca782019-09-19 01:08:30 +02002095
2096 # Generate separate types file
2097 st = StringIO()
2098 generate_include_types(s, modulename, st)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002099 with open(filename_types, "w") as fd:
Ole Troandf87f802020-11-18 19:17:48 +01002100 st.seek(0)
2101 shutil.copyfileobj(st, fd)
Ole Troan2a1ca782019-09-19 01:08:30 +02002102 st.close()
2103
2104 # Generate separate enum file
2105 st = StringIO()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002106 st.write("#ifndef included_{}_api_enum_h\n".format(modulename))
2107 st.write("#define included_{}_api_enum_h\n".format(modulename))
Ole Troan2a1ca782019-09-19 01:08:30 +02002108 generate_include_enum(s, modulename, st)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002109 generate_include_counters(s["Counters"], st)
2110 st.write("#endif\n")
2111 with open(filename_enum, "w") as fd:
Ole Troandf87f802020-11-18 19:17:48 +01002112 st.seek(0)
2113 shutil.copyfileobj(st, fd)
Ole Troan2a1ca782019-09-19 01:08:30 +02002114 st.close()
2115
2116 # Generate separate C file
2117 st = StringIO()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002118 generate_c_boilerplate(
2119 s["Service"], s["Define"], s["Counters"], s["file_crc"], modulename, st
2120 )
2121 with open(filename_c, "w") as fd:
Ole Troandf87f802020-11-18 19:17:48 +01002122 st.seek(0)
Ole Troan2a1ca782019-09-19 01:08:30 +02002123 shutil.copyfileobj(st, fd)
2124 st.close()
2125
2126 # Generate separate C test file
Ole Troan2a1ca782019-09-19 01:08:30 +02002127 st = StringIO()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002128 plugin = bool("plugin" in apifilename)
2129 generate_c_test_boilerplate(
2130 s["Service"], s["Define"], s["file_crc"], modulename, plugin, st
2131 )
2132 with open(filename_c_test, "w") as fd:
Ole Troandf87f802020-11-18 19:17:48 +01002133 st.seek(0)
Ole Troan2a1ca782019-09-19 01:08:30 +02002134 shutil.copyfileobj(st, fd)
2135 st.close()
Ole Troan33a58172019-09-04 09:12:29 +02002136
Ole Troandf87f802020-11-18 19:17:48 +01002137 # Fully autogenerated VATv2 C test file
2138 st = StringIO()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002139 generate_c_test2_boilerplate(s["Service"], s["Define"], modulename, st)
2140 with open(filename_c_test2, "w") as fd:
Ole Troandf87f802020-11-18 19:17:48 +01002141 st.seek(0)
2142 shutil.copyfileobj(st, fd)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002143 st.close() #
Ole Troandf87f802020-11-18 19:17:48 +01002144
2145 # Generate separate JSON file
2146 st = StringIO()
2147 generate_tojson(s, modulename, st)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002148 with open(filename_c_tojson, "w") as fd:
Ole Troandf87f802020-11-18 19:17:48 +01002149 st.seek(0)
2150 shutil.copyfileobj(st, fd)
2151 st.close()
2152 st = StringIO()
2153 generate_fromjson(s, modulename, st)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002154 with open(filename_c_fromjson, "w") as fd:
Ole Troandf87f802020-11-18 19:17:48 +01002155 st.seek(0)
2156 shutil.copyfileobj(st, fd)
2157 st.close()
2158
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002159 output = TOP_BOILERPLATE.format(datestring=DATESTRING, input_filename=basename)
2160 output += generate_imports(s["Import"])
Ole Troan9d420872017-10-12 13:06:35 +02002161 output += msg_ids(s)
2162 output += msg_names(s)
2163 output += msg_name_crc_list(s, filename)
Ole Troan2a1ca782019-09-19 01:08:30 +02002164 output += typedefs(modulename)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002165 printfun_types(s["types"], stream, modulename)
2166 printfun(s["Define"], stream, modulename)
Ole Troan33a58172019-09-04 09:12:29 +02002167 output += stream.getvalue()
Ole Troan2a1ca782019-09-19 01:08:30 +02002168 stream.close()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002169 output += endianfun(s["types"] + s["Define"], modulename)
2170 output += calc_size_fun(s["types"] + s["Define"], modulename)
Ole Troan9d420872017-10-12 13:06:35 +02002171 output += version_tuple(s, basename)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002172 output += BOTTOM_BOILERPLATE.format(input_filename=basename, file_crc=s["file_crc"])
Ole Troan9d420872017-10-12 13:06:35 +02002173
2174 return output