blob: 2cd3c7989b330c890d7e5c41d1ba807f4bdb60a4 [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(
Ole Troan9aa833b2024-08-01 14:06:24 +0200174 ' char *s = format_c_string(0, "0x%U", format_hex_bytes_no_wrap, '
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200175 "&a->{n}, {lfield});\n".format(n=o.fieldname, lfield=lfield)
176 )
Ole Troan9aa833b2024-08-01 14:06:24 +0200177 write(' cJSON_AddStringToObject(o, "{n}", s);\n'.format(n=o.fieldname))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200178 write(" vec_free(s);\n")
179 write(" }\n")
Ole Troandf87f802020-11-18 19:17:48 +0100180 return
181
182 f, p = self.get_json_array_func(o.fieldtype)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200183 write(forloop.format(lfield=lfield, t=o.fieldtype, n=o.fieldname, f=f, p=p))
Ole Troandf87f802020-11-18 19:17:48 +0100184
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200185 _dispatch["Array"] = print_array
Ole Troandf87f802020-11-18 19:17:48 +0100186
187 def print_enum(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200188 """Create cJSON object (string) for VPP API enum"""
Ole Troandf87f802020-11-18 19:17:48 +0100189 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200190 write(
191 "static inline cJSON *vl_api_{name}_t_tojson "
192 "(vl_api_{name}_t a) {{\n".format(name=o.name)
193 )
Ole Troandf87f802020-11-18 19:17:48 +0100194
195 write(" switch(a) {\n")
196 for b in o.block:
197 write(" case %s:\n" % b[1])
198 write(' return cJSON_CreateString("{}");\n'.format(b[0]))
199 write(' default: return cJSON_CreateString("Invalid ENUM");\n')
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200200 write(" }\n")
201 write(" return 0;\n")
202 write("}\n")
Ole Troandf87f802020-11-18 19:17:48 +0100203
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200204 _dispatch["Enum"] = print_enum
Ole Troan793be462020-12-04 13:15:30 +0100205
206 def print_enum_flag(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200207 """Create cJSON object (string) for VPP API enum"""
Ole Troan793be462020-12-04 13:15:30 +0100208 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200209 write(
210 "static inline cJSON *vl_api_{name}_t_tojson "
211 "(vl_api_{name}_t a) {{\n".format(name=o.name)
212 )
213 write(" cJSON *array = cJSON_CreateArray();\n")
Ole Troan793be462020-12-04 13:15:30 +0100214
215 for b in o.block:
Ole Troan45517152021-11-23 10:49:36 +0100216 if b[1] == 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200217 continue
218 write(" if (a & {})\n".format(b[0]))
Klement Sekera9b7e8ac2021-11-22 21:26:20 +0100219 write(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200220 ' cJSON_AddItemToArray(array, cJSON_CreateString("{}"));\n'.format(
221 b[0]
222 )
223 )
224 write(" return array;\n")
225 write("}\n")
Ole Troan793be462020-12-04 13:15:30 +0100226
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200227 _dispatch["EnumFlag"] = print_enum_flag
Ole Troandf87f802020-11-18 19:17:48 +0100228
229 def print_typedef(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200230 """Create cJSON (dictionary) object from VPP API typedef"""
Ole Troandf87f802020-11-18 19:17:48 +0100231 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200232 write(
233 "static inline cJSON *vl_api_{name}_t_tojson "
234 "(vl_api_{name}_t *a) {{\n".format(name=o.name)
235 )
236 write(" cJSON *o = cJSON_CreateObject();\n")
Ole Troandf87f802020-11-18 19:17:48 +0100237
238 for t in o.block:
239 self._dispatch[t.type](self, t)
240
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200241 write(" return o;\n")
242 write("}\n")
Ole Troandf87f802020-11-18 19:17:48 +0100243
244 def print_define(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200245 """Create cJSON (dictionary) object from VPP API define"""
Ole Troandf87f802020-11-18 19:17:48 +0100246 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200247 write(
248 "static inline cJSON *vl_api_{name}_t_tojson "
249 "(vl_api_{name}_t *a) {{\n".format(name=o.name)
250 )
251 write(" cJSON *o = cJSON_CreateObject();\n")
252 write(' cJSON_AddStringToObject(o, "_msgname", "{}");\n'.format(o.name))
253 write(
254 ' cJSON_AddStringToObject(o, "_crc", "{crc:08x}");\n'.format(crc=o.crc)
255 )
Ole Troandf87f802020-11-18 19:17:48 +0100256
257 for t in o.block:
258 self._dispatch[t.type](self, t)
259
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200260 write(" return o;\n")
261 write("}\n")
Ole Troandf87f802020-11-18 19:17:48 +0100262
263 def print_using(self, o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200264 """Create cJSON (dictionary) object from VPP API aliased type"""
Ole Troandf87f802020-11-18 19:17:48 +0100265 if o.manual_print:
266 return
267
268 write = self.stream.write
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200269 write(
270 "static inline cJSON *vl_api_{name}_t_tojson "
271 "(vl_api_{name}_t *a) {{\n".format(name=o.name)
272 )
Ole Troandf87f802020-11-18 19:17:48 +0100273
Ole Troan9aa833b2024-08-01 14:06:24 +0200274 write(
275 ' char *s = format_c_string(0, "%U", format_vl_api_{}_t, a);\n'.format(
276 o.name
277 )
278 )
279 write(" cJSON *o = cJSON_CreateString(s);\n")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200280 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(
Ole Troan40138512024-05-06 11:34:17 +0200368 " {msgvar} = cJSON_realloc({msgvar}, {msgsize} + plen);\n".format(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200369 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;
Ole Troan40138512024-05-06 11:34:17 +0200437 {realloc} = cJSON_realloc({realloc}, {msgsize} + sizeof({t}) * size);
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} + "
Ole Troan40138512024-05-06 11:34:17 +0200464 "vec_len(s));\n".format(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200465 msgvar=msgvar, msgsize=msgsize, realloc=realloc
466 )
467 )
468 write(
Ole Troan40138512024-05-06 11:34:17 +0200469 " clib_memcpy((void *){realloc} + {msgsize}, s, "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200470 "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
Ole Troan1a319aa2024-04-26 14:11:20 +02001146def get_endian_string(o, fieldtype):
Dave Wallace39c40fa2023-06-06 12:05:30 -04001147 """Return proper endian string conversion function"""
Ole Troan1a319aa2024-04-26 14:11:20 +02001148 return ENDIAN_STRINGS[fieldtype]
Dave Wallace39c40fa2023-06-06 12:05:30 -04001149
1150
Ole Troan33a58172019-09-04 09:12:29 +02001151def endianfun_array(o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001152 """Generate endian functions for arrays"""
1153 forloop = """\
Dave Wallace39c40fa2023-06-06 12:05:30 -04001154 ASSERT((u32){length} <= (u32)VL_API_MAX_ARRAY_SIZE);
Ole Troan33a58172019-09-04 09:12:29 +02001155 for (i = 0; i < {length}; i++) {{
1156 a->{name}[i] = {format}(a->{name}[i]);
1157 }}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001158"""
Ole Troan33a58172019-09-04 09:12:29 +02001159
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001160 forloop_format = """\
Ole Troan33a58172019-09-04 09:12:29 +02001161 for (i = 0; i < {length}; i++) {{
Ole Troan1a319aa2024-04-26 14:11:20 +02001162 {type}_endian(&a->{name}[i], to_net);
Ole Troan33a58172019-09-04 09:12:29 +02001163 }}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001164"""
Ole Troan33a58172019-09-04 09:12:29 +02001165
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001166 output = ""
1167 if o.fieldtype == "u8" or o.fieldtype == "string" or o.fieldtype == "bool":
1168 output += " /* a->{n} = a->{n} (no-op) */\n".format(n=o.fieldname)
Ole Troan33a58172019-09-04 09:12:29 +02001169 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001170 lfield = "a->" + o.lengthfield if o.lengthfield else o.length
Ole Troan1a319aa2024-04-26 14:11:20 +02001171 if o.lengthfield:
1172 output += (
1173 f" u32 count = to_net ? clib_host_to_net_u32(a->{o.lengthfield}) : "
1174 f"a->{o.lengthfield};\n"
1175 )
1176 lfield = "count"
1177 else:
1178 lfield = o.length
1179
Ole Troandf87f802020-11-18 19:17:48 +01001180 if o.fieldtype in ENDIAN_STRINGS:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001181 output += forloop.format(
Dave Wallace39c40fa2023-06-06 12:05:30 -04001182 length=lfield,
1183 format=get_endian_string(o, o.fieldtype),
1184 name=o.fieldname,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001185 )
Ole Troan33a58172019-09-04 09:12:29 +02001186 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001187 output += forloop_format.format(
1188 length=lfield, type=o.fieldtype, name=o.fieldname
1189 )
Ole Troan33a58172019-09-04 09:12:29 +02001190 return output
1191
Ole Troandf87f802020-11-18 19:17:48 +01001192
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001193NO_ENDIAN_CONVERSION = {"client_index": None}
Ole Troandf87f802020-11-18 19:17:48 +01001194
Ole Troan33a58172019-09-04 09:12:29 +02001195
1196def endianfun_obj(o):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001197 """Generate endian conversion function for type"""
1198 output = ""
1199 if o.type == "Array":
Ole Troan33a58172019-09-04 09:12:29 +02001200 return endianfun_array(o)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001201 if o.type != "Field":
1202 output += ' s = format(s, "\\n{} {} {} (print not implemented");\n'.format(
1203 o.type, o.fieldtype, o.fieldname
1204 )
Ole Troan33a58172019-09-04 09:12:29 +02001205 return output
Ole Troandf87f802020-11-18 19:17:48 +01001206 if o.fieldname in NO_ENDIAN_CONVERSION:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001207 output += " /* a->{n} = a->{n} (no-op) */\n".format(n=o.fieldname)
Ole Troane796a182020-05-18 11:14:05 +02001208 return output
Ole Troandf87f802020-11-18 19:17:48 +01001209 if o.fieldtype in ENDIAN_STRINGS:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001210 output += " a->{name} = {format}(a->{name});\n".format(
Dave Wallace39c40fa2023-06-06 12:05:30 -04001211 name=o.fieldname, format=get_endian_string(o, o.fieldtype)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001212 )
1213 elif o.fieldtype.startswith("vl_api_"):
Ole Troan1a319aa2024-04-26 14:11:20 +02001214 output += " {type}_endian(&a->{name}, to_net);\n".format(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001215 type=o.fieldtype, name=o.fieldname
1216 )
Ole Troan33a58172019-09-04 09:12:29 +02001217 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001218 output += " /* a->{n} = a->{n} (no-op) */\n".format(n=o.fieldname)
Ole Troan33a58172019-09-04 09:12:29 +02001219
1220 return output
1221
1222
Ole Troan75761b92019-09-11 17:49:08 +02001223def endianfun(objs, modulename):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001224 """Main entry point for endian function generation"""
1225 output = """\
Ole Troan9d420872017-10-12 13:06:35 +02001226
1227/****** Endian swap functions *****/\n\
1228#ifdef vl_endianfun
Ole Troan33a58172019-09-04 09:12:29 +02001229#ifndef included_{module}_endianfun
1230#define included_{module}_endianfun
Ole Troan9d420872017-10-12 13:06:35 +02001231
1232#undef clib_net_to_host_uword
Dave Wallace39c40fa2023-06-06 12:05:30 -04001233#undef clib_host_to_net_uword
Ole Troan9d420872017-10-12 13:06:35 +02001234#ifdef LP64
1235#define clib_net_to_host_uword clib_net_to_host_u64
Dave Wallace39c40fa2023-06-06 12:05:30 -04001236#define clib_host_to_net_uword clib_host_to_net_u64
Ole Troan9d420872017-10-12 13:06:35 +02001237#else
1238#define clib_net_to_host_uword clib_net_to_host_u32
Dave Wallace39c40fa2023-06-06 12:05:30 -04001239#define clib_host_to_net_uword clib_host_to_net_u32
Ole Troan9d420872017-10-12 13:06:35 +02001240#endif
1241
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001242"""
Ole Troan33a58172019-09-04 09:12:29 +02001243 output = output.format(module=modulename)
1244
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001245 signature = """\
Ole Troan1a319aa2024-04-26 14:11:20 +02001246static inline void vl_api_{name}_t_endian (vl_api_{name}_t *a, bool to_net)
Ole Troan33a58172019-09-04 09:12:29 +02001247{{
1248 int i __attribute__((unused));
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001249"""
Ole Troan33a58172019-09-04 09:12:29 +02001250
Ole Troan2c2feab2018-04-24 00:02:37 -04001251 for t in objs:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001252 if t.__class__.__name__ == "Enum" or t.__class__.__name__ == "EnumFlag":
Ole Troan33a58172019-09-04 09:12:29 +02001253 output += signature.format(name=t.name)
Ole Troandf87f802020-11-18 19:17:48 +01001254 if t.enumtype in ENDIAN_STRINGS:
Dave Wallace39c40fa2023-06-06 12:05:30 -04001255 output += " *a = {}(*a);\n".format(get_endian_string(t, t.enumtype))
Ole Troan33a58172019-09-04 09:12:29 +02001256 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001257 output += " /* a->{name} = a->{name} (no-op) */\n".format(
1258 name=t.name
1259 )
Ole Troan33a58172019-09-04 09:12:29 +02001260
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001261 output += "}\n\n"
Ole Troan2c2feab2018-04-24 00:02:37 -04001262 continue
Ole Troan33a58172019-09-04 09:12:29 +02001263
Ole Troan9d420872017-10-12 13:06:35 +02001264 if t.manual_endian:
1265 output += "/***** manual: vl_api_%s_t_endian *****/\n\n" % t.name
1266 continue
Ole Troan33a58172019-09-04 09:12:29 +02001267
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001268 if t.__class__.__name__ == "Using":
Ole Troan75761b92019-09-11 17:49:08 +02001269 output += signature.format(name=t.name)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001270 if "length" in t.alias and t.alias["length"] and t.alias["type"] == "u8":
1271 output += " /* a->{name} = a->{name} (no-op) */\n".format(
1272 name=t.name
1273 )
1274 elif t.alias["type"] in FORMAT_STRINGS:
Dave Wallace39c40fa2023-06-06 12:05:30 -04001275 output += " *a = {}(*a);\n".format(
1276 get_endian_string(t, t.alias["type"])
1277 )
Ole Troan75761b92019-09-11 17:49:08 +02001278 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001279 output += " /* Not Implemented yet {} */".format(t.name)
1280 output += "}\n\n"
Ole Troan75761b92019-09-11 17:49:08 +02001281 continue
1282
Ole Troan33a58172019-09-04 09:12:29 +02001283 output += signature.format(name=t.name)
Ole Troan9d420872017-10-12 13:06:35 +02001284
1285 for o in t.block:
Ole Troan33a58172019-09-04 09:12:29 +02001286 output += endianfun_obj(o)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001287 output += "}\n\n"
Ole Troan33a58172019-09-04 09:12:29 +02001288
1289 output += "\n#endif"
Ole Troan9d420872017-10-12 13:06:35 +02001290 output += "\n#endif /* vl_endianfun */\n\n"
1291
1292 return output
1293
1294
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001295def calc_size_fun(objs, modulename):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001296 """Main entry point for calculate size function generation"""
1297 output = """\
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001298
1299/****** Calculate size functions *****/\n\
1300#ifdef vl_calcsizefun
1301#ifndef included_{module}_calcsizefun
1302#define included_{module}_calcsizefun
1303
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001304"""
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001305 output = output.format(module=modulename)
1306
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001307 signature = """\
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001308/* calculate message size of message in network byte order */
1309static inline uword vl_api_{name}_t_calc_size (vl_api_{name}_t *a)
1310{{
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001311"""
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001312
1313 for o in objs:
1314 tname = o.__class__.__name__
1315
1316 output += signature.format(name=o.name)
1317 output += f" return sizeof(*a)"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001318 if tname == "Using":
1319 if "length" in o.alias:
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001320 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001321 tmp = int(o.alias["length"])
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001322 if tmp == 0:
1323 raise (f"Unexpected length '0' for alias {o}")
1324 except:
1325 # output += f" + vl_api_{o.alias.name}_t_calc_size({o.name})"
1326 print("culprit:")
1327 print(o)
1328 print(dir(o.alias))
1329 print(o.alias)
1330 raise
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001331 elif tname == "Enum" or tname == "EnumFlag":
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001332 pass
1333 else:
1334 for b in o.block:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001335 if b.type == "Option":
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001336 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001337 elif b.type == "Field":
1338 if b.fieldtype.startswith("vl_api_"):
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001339 output += f" - sizeof(a->{b.fieldname})"
1340 output += f" + {b.fieldtype}_calc_size(&a->{b.fieldname})"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001341 elif b.type == "Array":
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001342 if b.lengthfield:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001343 m = list(
1344 filter(lambda x: x.fieldname == b.lengthfield, o.block)
1345 )
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001346 if len(m) != 1:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001347 raise Exception(
1348 f"Expected 1 match for field '{b.lengthfield}', got '{m}'"
1349 )
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001350 lf = m[0]
1351 if lf.fieldtype in ENDIAN_STRINGS:
Dave Wallace39c40fa2023-06-06 12:05:30 -04001352 output += f" + {get_endian_string(b, lf.fieldtype)}(a->{b.lengthfield}) * sizeof(a->{b.fieldname}[0])"
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001353 elif lf.fieldtype == "u8":
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001354 output += (
1355 f" + a->{b.lengthfield} * sizeof(a->{b.fieldname}[0])"
1356 )
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001357 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001358 raise Exception(
1359 f"Don't know how to endian swap {lf.fieldtype}"
1360 )
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001361 else:
1362 # Fixed length strings decay to nul terminated u8
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001363 if b.fieldtype == "string":
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001364 if b.modern_vla:
1365 output += f" + vl_api_string_len(&a->{b.fieldname})"
1366
1367 output += ";\n"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001368 output += "}\n\n"
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001369 output += "\n#endif"
1370 output += "\n#endif /* vl_calcsizefun */\n\n"
1371
1372 return output
1373
1374
Ole Troan9d420872017-10-12 13:06:35 +02001375def version_tuple(s, module):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001376 """Generate semantic version string"""
1377 output = """\
Ole Troan9d420872017-10-12 13:06:35 +02001378/****** Version tuple *****/
1379
1380#ifdef vl_api_version_tuple
1381
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001382"""
1383 if "version" in s["Option"]:
1384 v = s["Option"]["version"]
1385 (major, minor, patch) = v.split(".")
1386 output += "vl_api_version_tuple(%s, %s, %s, %s)\n" % (
1387 module,
1388 major,
1389 minor,
1390 patch,
1391 )
Ole Troan9d420872017-10-12 13:06:35 +02001392
1393 output += "\n#endif /* vl_api_version_tuple */\n\n"
1394
1395 return output
1396
1397
Ole Troan2a1ca782019-09-19 01:08:30 +02001398def generate_include_enum(s, module, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001399 """Generate <name>.api_enum.h"""
Ole Troan2a1ca782019-09-19 01:08:30 +02001400 write = stream.write
1401
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001402 if "Define" in s:
1403 write("typedef enum {\n")
1404 for t in s["Define"]:
1405 write(" VL_API_{},\n".format(t.name.upper()))
1406 write(" VL_MSG_{}_LAST\n".format(module.upper()))
1407 write("}} vl_api_{}_enum_t;\n".format(module))
Ole Troan2a1ca782019-09-19 01:08:30 +02001408
Paul Vinciguerra7c8803d2019-11-21 17:16:18 -05001409
Ole Troandf87f802020-11-18 19:17:48 +01001410def generate_include_counters(s, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001411 """Include file for the counter data model types."""
Ole Troan148c7b72020-10-07 18:05:37 +02001412 write = stream.write
1413
1414 for counters in s:
1415 csetname = counters.name
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001416 write("typedef enum {\n")
Ole Troan148c7b72020-10-07 18:05:37 +02001417 for c in counters.block:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001418 write(" {}_ERROR_{},\n".format(csetname.upper(), c["name"].upper()))
1419 write(" {}_N_ERROR\n".format(csetname.upper()))
1420 write("}} vl_counter_{}_enum_t;\n".format(csetname))
Ole Troan148c7b72020-10-07 18:05:37 +02001421
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001422 write("extern vlib_error_desc_t {}_error_counters[];\n".format(csetname))
Ole Troan148c7b72020-10-07 18:05:37 +02001423
Ole Troandf87f802020-11-18 19:17:48 +01001424
Ole Troan2a1ca782019-09-19 01:08:30 +02001425def generate_include_types(s, module, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001426 """Generate separate API _types file."""
Ole Troan2a1ca782019-09-19 01:08:30 +02001427 write = stream.write
1428
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001429 write("#ifndef included_{module}_api_types_h\n".format(module=module))
1430 write("#define included_{module}_api_types_h\n".format(module=module))
Ole Troan2a1ca782019-09-19 01:08:30 +02001431
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001432 if "version" in s["Option"]:
1433 v = s["Option"]["version"]
1434 (major, minor, patch) = v.split(".")
1435 write(
1436 "#define VL_API_{m}_API_VERSION_MAJOR {v}\n".format(
1437 m=module.upper(), v=major
1438 )
1439 )
1440 write(
1441 "#define VL_API_{m}_API_VERSION_MINOR {v}\n".format(
1442 m=module.upper(), v=minor
1443 )
1444 )
1445 write(
1446 "#define VL_API_{m}_API_VERSION_PATCH {v}\n".format(
1447 m=module.upper(), v=patch
1448 )
1449 )
Ole Troanf92bfb12020-02-28 13:45:42 +01001450
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001451 if "Import" in s:
1452 write("/* Imported API files */\n")
1453 for i in s["Import"]:
1454 filename = i.filename.replace("plugins/", "")
1455 write("#include <{}_types.h>\n".format(filename))
Ole Troan2a1ca782019-09-19 01:08:30 +02001456
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001457 for o in itertools.chain(s["types"], s["Define"]):
Ole Troan2a1ca782019-09-19 01:08:30 +02001458 tname = o.__class__.__name__
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001459 if tname == "Using":
1460 if "length" in o.alias:
1461 write(
1462 "typedef %s vl_api_%s_t[%s];\n"
1463 % (o.alias["type"], o.name, o.alias["length"])
1464 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001465 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001466 write("typedef %s vl_api_%s_t;\n" % (o.alias["type"], o.name))
1467 elif tname == "Enum" or tname == "EnumFlag":
1468 if o.enumtype == "u32":
Ole Troan2a1ca782019-09-19 01:08:30 +02001469 write("typedef enum {\n")
1470 else:
1471 write("typedef enum __attribute__((packed)) {\n")
1472
1473 for b in o.block:
1474 write(" %s = %s,\n" % (b[0], b[1]))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001475 write("} vl_api_%s_t;\n" % o.name)
1476 if o.enumtype != "u32":
1477 size1 = "sizeof(vl_api_%s_t)" % o.name
1478 size2 = "sizeof(%s)" % o.enumtype
1479 err_str = "size of API enum %s is wrong" % o.name
1480 write('STATIC_ASSERT(%s == %s, "%s");\n' % (size1, size2, err_str))
Ole Troan2a1ca782019-09-19 01:08:30 +02001481 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001482 if tname == "Union":
1483 write("typedef union __attribute__ ((packed)) _vl_api_%s {\n" % o.name)
Ole Troan2a1ca782019-09-19 01:08:30 +02001484 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001485 write(
1486 ("typedef struct __attribute__ ((packed)) _vl_api_%s {\n") % o.name
1487 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001488 for b in o.block:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001489 if b.type == "Option":
Ole Troan2a1ca782019-09-19 01:08:30 +02001490 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001491 if b.type == "Field":
1492 write(" %s %s;\n" % (api2c(b.fieldtype), b.fieldname))
1493 elif b.type == "Array":
Ole Troan2a1ca782019-09-19 01:08:30 +02001494 if b.lengthfield:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001495 write(" %s %s[0];\n" % (api2c(b.fieldtype), b.fieldname))
Ole Troan2a1ca782019-09-19 01:08:30 +02001496 else:
1497 # Fixed length strings decay to nul terminated u8
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001498 if b.fieldtype == "string":
Ole Troan2a1ca782019-09-19 01:08:30 +02001499 if b.modern_vla:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001500 write(
1501 " {} {};\n".format(
1502 api2c(b.fieldtype), b.fieldname
1503 )
1504 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001505 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001506 write(" u8 {}[{}];\n".format(b.fieldname, b.length))
Ole Troan2a1ca782019-09-19 01:08:30 +02001507 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001508 write(
1509 " %s %s[%s];\n"
1510 % (api2c(b.fieldtype), b.fieldname, b.length)
1511 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001512 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001513 raise ValueError(
1514 "Error in processing type {} for {}".format(b, o.name)
1515 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001516
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001517 write("} vl_api_%s_t;\n" % o.name)
1518 write(
1519 f"#define VL_API_{o.name.upper()}_IS_CONSTANT_SIZE ({0 if o.vla else 1})\n\n"
1520 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001521
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001522 for t in s["Define"]:
1523 write(
1524 '#define VL_API_{ID}_CRC "{n}_{crc:08x}"\n'.format(
1525 n=t.name, ID=t.name.upper(), crc=t.crc
1526 )
1527 )
Ole Troan3f2d5712019-12-07 00:39:49 +01001528
Ole Troan2a1ca782019-09-19 01:08:30 +02001529 write("\n#endif\n")
1530
1531
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001532def generate_c_boilerplate(services, defines, counters, file_crc, module, stream):
1533 """VPP side plugin."""
Ole Troan2a1ca782019-09-19 01:08:30 +02001534 write = stream.write
Ole Troan148c7b72020-10-07 18:05:37 +02001535 define_hash = {d.name: d for d in defines}
Ole Troan2a1ca782019-09-19 01:08:30 +02001536
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001537 hdr = """\
Ole Troan2a1ca782019-09-19 01:08:30 +02001538#define vl_endianfun /* define message structures */
1539#include "{module}.api.h"
1540#undef vl_endianfun
1541
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001542#define vl_calcsizefun
1543#include "{module}.api.h"
1544#undef vl_calsizefun
1545
Ole Troan2a1ca782019-09-19 01:08:30 +02001546/* instantiate all the print functions we know about */
Ole Troan2a1ca782019-09-19 01:08:30 +02001547#define vl_printfun
1548#include "{module}.api.h"
1549#undef vl_printfun
1550
Ole Troanac0babd2024-01-23 18:56:23 +01001551#include "{module}.api_json.h"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001552"""
Ole Troan2a1ca782019-09-19 01:08:30 +02001553
1554 write(hdr.format(module=module))
Ole Troan683bdb62023-05-11 22:02:30 +02001555 if len(defines) > 0:
1556 write("static u16\n")
1557 write("setup_message_id_table (void) {\n")
1558 write(" api_main_t *am = my_api_main;\n")
1559 write(" vl_msg_api_msg_config_t c;\n")
1560 write(
1561 ' u16 msg_id_base = vl_msg_api_get_msg_ids ("{}_{crc:08x}", '
1562 "VL_MSG_{m}_LAST);\n".format(module, crc=file_crc, m=module.upper())
1563 )
Ole Troanac0babd2024-01-23 18:56:23 +01001564 write(f" vec_add1(am->json_api_repr, (u8 *)json_api_repr_{module});\n")
Ole Troan2a1ca782019-09-19 01:08:30 +02001565
Ole Troan2a1ca782019-09-19 01:08:30 +02001566 for d in defines:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001567 write(
1568 ' vl_msg_api_add_msg_name_crc (am, "{n}_{crc:08x}",\n'
1569 " VL_API_{ID} + msg_id_base);\n".format(
1570 n=d.name, ID=d.name.upper(), crc=d.crc
1571 )
1572 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001573 for s in services:
Ole Troane796a182020-05-18 11:14:05 +02001574 d = define_hash[s.caller]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001575 write(
1576 " c = (vl_msg_api_msg_config_t) "
1577 " {{.id = VL_API_{ID} + msg_id_base,\n"
1578 ' .name = "{n}",\n'
1579 " .handler = vl_api_{n}_t_handler,\n"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001580 " .endian = vl_api_{n}_t_endian,\n"
Damjan Marionfe45f8f2022-05-20 16:01:22 +02001581 " .format_fn = vl_api_{n}_t_format,\n"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001582 " .traced = 1,\n"
1583 " .replay = 1,\n"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001584 " .tojson = vl_api_{n}_t_tojson,\n"
1585 " .fromjson = vl_api_{n}_t_fromjson,\n"
1586 " .calc_size = vl_api_{n}_t_calc_size,\n"
1587 " .is_autoendian = {auto}}};\n".format(
1588 n=s.caller, ID=s.caller.upper(), auto=d.autoendian
1589 )
1590 )
1591 write(" vl_msg_api_config (&c);\n")
Ole Troanbad67922020-08-24 12:22:01 +02001592 try:
1593 d = define_hash[s.reply]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001594 write(
1595 " c = (vl_msg_api_msg_config_t) "
1596 "{{.id = VL_API_{ID} + msg_id_base,\n"
1597 ' .name = "{n}",\n'
1598 " .handler = 0,\n"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001599 " .endian = vl_api_{n}_t_endian,\n"
Damjan Marionfe45f8f2022-05-20 16:01:22 +02001600 " .format_fn = vl_api_{n}_t_format,\n"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001601 " .traced = 1,\n"
1602 " .replay = 1,\n"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001603 " .tojson = vl_api_{n}_t_tojson,\n"
1604 " .fromjson = vl_api_{n}_t_fromjson,\n"
1605 " .calc_size = vl_api_{n}_t_calc_size,\n"
1606 " .is_autoendian = {auto}}};\n".format(
1607 n=s.reply, ID=s.reply.upper(), auto=d.autoendian
1608 )
1609 )
1610 write(" vl_msg_api_config (&c);\n")
Ole Troanbad67922020-08-24 12:22:01 +02001611 except KeyError:
1612 pass
Ole Troan2a1ca782019-09-19 01:08:30 +02001613
Stanislav Zaikin139b2da2022-07-21 19:06:26 +02001614 try:
1615 if s.stream:
1616 d = define_hash[s.stream_message]
1617 write(
1618 " c = (vl_msg_api_msg_config_t) "
1619 "{{.id = VL_API_{ID} + msg_id_base,\n"
1620 ' .name = "{n}",\n'
1621 " .handler = 0,\n"
1622 " .endian = vl_api_{n}_t_endian,\n"
1623 " .format_fn = vl_api_{n}_t_format,\n"
1624 " .traced = 1,\n"
1625 " .replay = 1,\n"
1626 " .tojson = vl_api_{n}_t_tojson,\n"
1627 " .fromjson = vl_api_{n}_t_fromjson,\n"
1628 " .calc_size = vl_api_{n}_t_calc_size,\n"
1629 " .is_autoendian = {auto}}};\n".format(
1630 n=s.stream_message,
1631 ID=s.stream_message.upper(),
1632 auto=d.autoendian,
1633 )
1634 )
1635 write(" vl_msg_api_config (&c);\n")
1636 except KeyError:
1637 pass
Ole Troan683bdb62023-05-11 22:02:30 +02001638 if len(defines) > 0:
1639 write(" return msg_id_base;\n")
1640 write("}\n")
Ole Troan2a1ca782019-09-19 01:08:30 +02001641
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001642 severity = {
1643 "error": "VL_COUNTER_SEVERITY_ERROR",
1644 "info": "VL_COUNTER_SEVERITY_INFO",
1645 "warn": "VL_COUNTER_SEVERITY_WARN",
1646 }
Ole Troan148c7b72020-10-07 18:05:37 +02001647
1648 for cnt in counters:
1649 csetname = cnt.name
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001650 write("vlib_error_desc_t {}_error_counters[] = {{\n".format(csetname))
Ole Troan148c7b72020-10-07 18:05:37 +02001651 for c in cnt.block:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001652 write(" {\n")
1653 write(' .name = "{}",\n'.format(c["name"]))
1654 write(' .desc = "{}",\n'.format(c["description"]))
1655 write(" .severity = {},\n".format(severity[c["severity"]]))
1656 write(" },\n")
1657 write("};\n")
Ole Troan2a1ca782019-09-19 01:08:30 +02001658
Ole Troandf87f802020-11-18 19:17:48 +01001659
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001660def generate_c_test_boilerplate(services, defines, file_crc, module, plugin, stream):
1661 """Generate code for legacy style VAT. To be deleted."""
Ole Troan2a1ca782019-09-19 01:08:30 +02001662 write = stream.write
1663
Ole Troandf87f802020-11-18 19:17:48 +01001664 define_hash = {d.name: d for d in defines}
Ole Troan2a1ca782019-09-19 01:08:30 +02001665
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001666 hdr = """\
Ole Troandf87f802020-11-18 19:17:48 +01001667#define vl_endianfun /* define message structures */
Ole Troan2a1ca782019-09-19 01:08:30 +02001668#include "{module}.api.h"
1669#undef vl_endianfun
1670
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01001671#define vl_calcsizefun
1672#include "{module}.api.h"
1673#undef vl_calsizefun
1674
Ole Troan2a1ca782019-09-19 01:08:30 +02001675/* instantiate all the print functions we know about */
Ole Troan2a1ca782019-09-19 01:08:30 +02001676#define vl_printfun
1677#include "{module}.api.h"
1678#undef vl_printfun
1679
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001680"""
Ole Troan2a1ca782019-09-19 01:08:30 +02001681
1682 write(hdr.format(module=module))
1683 for s in services:
1684 try:
1685 d = define_hash[s.reply]
Ole Troandf87f802020-11-18 19:17:48 +01001686 except KeyError:
Ole Troan2a1ca782019-09-19 01:08:30 +02001687 continue
1688 if d.manual_print:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001689 write(
1690 "/*\n"
1691 " * Manual definition requested for: \n"
1692 " * vl_api_{n}_t_handler()\n"
1693 " */\n".format(n=s.reply)
1694 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001695 continue
1696 if not define_hash[s.caller].autoreply:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001697 write(
1698 "/* Generation not supported (vl_api_{n}_t_handler()) */\n".format(
1699 n=s.reply
1700 )
1701 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001702 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001703 write("#ifndef VL_API_{n}_T_HANDLER\n".format(n=s.reply.upper()))
1704 write("static void\n")
1705 write("vl_api_{n}_t_handler (vl_api_{n}_t * mp) {{\n".format(n=s.reply))
1706 write(" vat_main_t * vam = {}_test_main.vat_main;\n".format(module))
1707 write(" i32 retval = ntohl(mp->retval);\n")
1708 write(" if (vam->async_mode) {\n")
1709 write(" vam->async_errors += (retval < 0);\n")
1710 write(" } else {\n")
1711 write(" vam->retval = retval;\n")
1712 write(" vam->result_ready = 1;\n")
1713 write(" }\n")
1714 write("}\n")
1715 write("#endif\n")
Ole Troan2a1ca782019-09-19 01:08:30 +02001716
Ole Troanb126ebc2019-10-07 16:22:00 +02001717 for e in s.events:
1718 if define_hash[e].manual_print:
1719 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001720 write("static void\n")
1721 write("vl_api_{n}_t_handler (vl_api_{n}_t * mp) {{\n".format(n=e))
Damjan Marionfe45f8f2022-05-20 16:01:22 +02001722 write(' vlib_cli_output(0, "{n} event called:");\n'.format(n=e))
1723 write(
1724 ' vlib_cli_output(0, "%U", vl_api_{n}_t_format, mp);\n'.format(n=e)
1725 )
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001726 write("}\n")
Ole Troanb126ebc2019-10-07 16:22:00 +02001727
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001728 write("static void\n")
1729 write("setup_message_id_table (vat_main_t * vam, u16 msg_id_base) {\n")
Ole Troan2a1ca782019-09-19 01:08:30 +02001730 for s in services:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001731 write(
Damjan Mariona2eb5072022-05-20 20:06:01 +02001732 " vl_msg_api_config (&(vl_msg_api_msg_config_t){{\n"
1733 " .id = VL_API_{ID} + msg_id_base,\n"
1734 ' .name = "{n}",\n'
1735 " .handler = vl_api_{n}_t_handler,\n"
1736 " .endian = vl_api_{n}_t_endian,\n"
1737 " .format_fn = vl_api_{n}_t_format,\n"
1738 " .size = sizeof(vl_api_{n}_t),\n"
1739 " .traced = 1,\n"
1740 " .tojson = vl_api_{n}_t_tojson,\n"
1741 " .fromjson = vl_api_{n}_t_fromjson,\n"
1742 " .calc_size = vl_api_{n}_t_calc_size,\n"
1743 " }});".format(n=s.reply, ID=s.reply.upper())
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001744 )
1745 write(
1746 ' hash_set_mem (vam->function_by_name, "{n}", api_{n});\n'.format(
1747 n=s.caller
1748 )
1749 )
Ole Troan2a1ca782019-09-19 01:08:30 +02001750 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001751 write(
1752 ' hash_set_mem (vam->help_by_name, "{n}", "{help}");\n'.format(
1753 n=s.caller, help=define_hash[s.caller].options["vat_help"]
1754 )
1755 )
Ole Troandf87f802020-11-18 19:17:48 +01001756 except KeyError:
Ole Troan2a1ca782019-09-19 01:08:30 +02001757 pass
1758
Ole Troanb126ebc2019-10-07 16:22:00 +02001759 # Events
1760 for e in s.events:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001761 write(
Damjan Mariona2eb5072022-05-20 20:06:01 +02001762 " vl_msg_api_config (&(vl_msg_api_msg_config_t){{\n"
1763 " .id = VL_API_{ID} + msg_id_base,\n"
1764 ' .name = "{n}",\n'
1765 " .handler = vl_api_{n}_t_handler,\n"
1766 " .endian = vl_api_{n}_t_endian,\n"
1767 " .format_fn = vl_api_{n}_t_format,\n"
1768 " .size = sizeof(vl_api_{n}_t),\n"
1769 " .traced = 1,\n"
1770 " .tojson = vl_api_{n}_t_tojson,\n"
1771 " .fromjson = vl_api_{n}_t_fromjson,\n"
1772 " .calc_size = vl_api_{n}_t_calc_size,\n"
1773 " }});".format(n=e, ID=e.upper())
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001774 )
Ole Troanb126ebc2019-10-07 16:22:00 +02001775
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001776 write("}\n")
1777 write("clib_error_t * vat_plugin_register (vat_main_t *vam)\n")
1778 write("{\n")
1779 write(" {n}_test_main_t * mainp = &{n}_test_main;\n".format(n=module))
1780 write(" mainp->vat_main = vam;\n")
1781 write(
1782 " mainp->msg_id_base = vl_client_get_first_plugin_msg_id "
1783 ' ("{n}_{crc:08x}");\n'.format(n=module, crc=file_crc)
1784 )
1785 write(" if (mainp->msg_id_base == (u16) ~0)\n")
1786 write(
1787 ' return clib_error_return (0, "{} plugin not loaded...");\n'.format(
1788 module
1789 )
1790 )
1791 write(" setup_message_id_table (vam, mainp->msg_id_base);\n")
1792 write("#ifdef VL_API_LOCAL_SETUP_MESSAGE_ID_TABLE\n")
1793 write(" VL_API_LOCAL_SETUP_MESSAGE_ID_TABLE(vam);\n")
1794 write("#endif\n")
1795 write(" return 0;\n")
1796 write("}\n")
Ole Troan2a1ca782019-09-19 01:08:30 +02001797
Ole Troandf87f802020-11-18 19:17:48 +01001798
1799def apifunc(func):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001800 """Check if a method is generated already."""
1801
Ole Troandf87f802020-11-18 19:17:48 +01001802 def _f(module, d, processed, *args):
1803 if d.name in processed:
1804 return None
1805 processed[d.name] = True
1806 return func(module, d, *args)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001807
Ole Troandf87f802020-11-18 19:17:48 +01001808 return _f
1809
1810
1811def c_test_api_service(s, dump, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001812 """Generate JSON code for a service."""
Ole Troandf87f802020-11-18 19:17:48 +01001813 write = stream.write
1814
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001815 req_reply_template = """\
Ole Troandf87f802020-11-18 19:17:48 +01001816static cJSON *
1817api_{n} (cJSON *o)
1818{{
1819 vl_api_{n}_t *mp;
1820 int len;
1821 if (!o) return 0;
1822 mp = vl_api_{n}_t_fromjson(o, &len);
1823 if (!mp) {{
1824 fprintf(stderr, "Failed converting JSON to API\\n");
1825 return 0;
1826 }}
1827
1828 mp->_vl_msg_id = vac_get_msg_index(VL_API_{N}_CRC);
Ole Troan1a319aa2024-04-26 14:11:20 +02001829 vl_api_{n}_t_endian(mp, 1);
Ole Troandf87f802020-11-18 19:17:48 +01001830 vac_write((char *)mp, len);
Filip Tehlar36217e32021-07-23 08:51:10 +00001831 cJSON_free(mp);
Ole Troandf87f802020-11-18 19:17:48 +01001832
1833 /* Read reply */
1834 char *p;
1835 int l;
1836 vac_read(&p, &l, 5); // XXX: Fix timeout
Ole Troanedc73fd2021-02-17 13:26:53 +01001837 if (p == 0 || l == 0) return 0;
Ole Troandf87f802020-11-18 19:17:48 +01001838 // XXX Will fail in case of event received. Do loop
1839 if (ntohs(*((u16 *)p)) != vac_get_msg_index(VL_API_{R}_CRC)) {{
1840 fprintf(stderr, "Mismatched reply\\n");
1841 return 0;
1842 }}
1843 vl_api_{r}_t *rmp = (vl_api_{r}_t *)p;
Ole Troan1a319aa2024-04-26 14:11:20 +02001844 vl_api_{r}_t_endian(rmp, 0);
Ole Troandf87f802020-11-18 19:17:48 +01001845 return vl_api_{r}_t_tojson(rmp);
1846}}
1847
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001848"""
1849 dump_details_template = """\
Ole Troandf87f802020-11-18 19:17:48 +01001850static cJSON *
1851api_{n} (cJSON *o)
1852{{
1853 u16 msg_id = vac_get_msg_index(VL_API_{N}_CRC);
1854 int len;
1855 if (!o) return 0;
1856 vl_api_{n}_t *mp = vl_api_{n}_t_fromjson(o, &len);
1857 if (!mp) {{
1858 fprintf(stderr, "Failed converting JSON to API\\n");
1859 return 0;
1860 }}
1861 mp->_vl_msg_id = msg_id;
Ole Troan1a319aa2024-04-26 14:11:20 +02001862 vl_api_{n}_t_endian(mp, 1);
Ole Troandf87f802020-11-18 19:17:48 +01001863 vac_write((char *)mp, len);
Filip Tehlar36217e32021-07-23 08:51:10 +00001864 cJSON_free(mp);
Ole Troandf87f802020-11-18 19:17:48 +01001865
1866 vat2_control_ping(123); // FIX CONTEXT
1867 cJSON *reply = cJSON_CreateArray();
1868
1869 u16 ping_reply_msg_id = vac_get_msg_index(VL_API_CONTROL_PING_REPLY_CRC);
1870 u16 details_msg_id = vac_get_msg_index(VL_API_{R}_CRC);
1871
1872 while (1) {{
1873 /* Read reply */
1874 char *p;
1875 int l;
1876 vac_read(&p, &l, 5); // XXX: Fix timeout
Ole Troanedc73fd2021-02-17 13:26:53 +01001877 if (p == 0 || l == 0) {{
1878 cJSON_free(reply);
1879 return 0;
1880 }}
Ole Troandf87f802020-11-18 19:17:48 +01001881
1882 /* Message can be one of [_details, control_ping_reply
1883 * or unrelated event]
1884 */
1885 u16 reply_msg_id = ntohs(*((u16 *)p));
1886 if (reply_msg_id == ping_reply_msg_id) {{
1887 break;
1888 }}
1889
1890 if (reply_msg_id == details_msg_id) {{
Ole Troanedc73fd2021-02-17 13:26:53 +01001891 if (l < sizeof(vl_api_{r}_t)) {{
1892 cJSON_free(reply);
1893 return 0;
1894 }}
Ole Troandf87f802020-11-18 19:17:48 +01001895 vl_api_{r}_t *rmp = (vl_api_{r}_t *)p;
Ole Troan1a319aa2024-04-26 14:11:20 +02001896 vl_api_{r}_t_endian(rmp, 0);
Ole Troandf87f802020-11-18 19:17:48 +01001897 cJSON_AddItemToArray(reply, vl_api_{r}_t_tojson(rmp));
1898 }}
1899 }}
1900 return reply;
1901}}
1902
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001903"""
1904 gets_details_reply_template = """\
Ole Troandf87f802020-11-18 19:17:48 +01001905static cJSON *
1906api_{n} (cJSON *o)
1907{{
1908 u16 msg_id = vac_get_msg_index(VL_API_{N}_CRC);
1909 int len = 0;
1910 if (!o) return 0;
1911 vl_api_{n}_t *mp = vl_api_{n}_t_fromjson(o, &len);
1912 if (!mp) {{
1913 fprintf(stderr, "Failed converting JSON to API\\n");
1914 return 0;
1915 }}
1916 mp->_vl_msg_id = msg_id;
1917
Ole Troan1a319aa2024-04-26 14:11:20 +02001918 vl_api_{n}_t_endian(mp, 1);
Ole Troandf87f802020-11-18 19:17:48 +01001919 vac_write((char *)mp, len);
Filip Tehlar36217e32021-07-23 08:51:10 +00001920 cJSON_free(mp);
Ole Troandf87f802020-11-18 19:17:48 +01001921
1922 cJSON *reply = cJSON_CreateArray();
1923
1924 u16 reply_msg_id = vac_get_msg_index(VL_API_{R}_CRC);
1925 u16 details_msg_id = vac_get_msg_index(VL_API_{D}_CRC);
1926
1927 while (1) {{
1928 /* Read reply */
1929 char *p;
1930 int l;
1931 vac_read(&p, &l, 5); // XXX: Fix timeout
1932
1933 /* Message can be one of [_details, control_ping_reply
1934 * or unrelated event]
1935 */
1936 u16 msg_id = ntohs(*((u16 *)p));
1937 if (msg_id == reply_msg_id) {{
1938 vl_api_{r}_t *rmp = (vl_api_{r}_t *)p;
Ole Troan1a319aa2024-04-26 14:11:20 +02001939 vl_api_{r}_t_endian(rmp, 0);
Ole Troandf87f802020-11-18 19:17:48 +01001940 cJSON_AddItemToArray(reply, vl_api_{r}_t_tojson(rmp));
1941 break;
1942 }}
1943
1944 if (msg_id == details_msg_id) {{
1945 vl_api_{d}_t *rmp = (vl_api_{d}_t *)p;
Ole Troan1a319aa2024-04-26 14:11:20 +02001946 vl_api_{d}_t_endian(rmp, 0);
Ole Troandf87f802020-11-18 19:17:48 +01001947 cJSON_AddItemToArray(reply, vl_api_{d}_t_tojson(rmp));
1948 }}
1949 }}
1950 return reply;
1951}}
1952
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001953"""
Ole Troandf87f802020-11-18 19:17:48 +01001954
1955 if dump:
1956 if s.stream_message:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001957 write(
1958 gets_details_reply_template.format(
1959 n=s.caller,
1960 r=s.reply,
1961 N=s.caller.upper(),
1962 R=s.reply.upper(),
1963 d=s.stream_message,
1964 D=s.stream_message.upper(),
1965 )
1966 )
Ole Troandf87f802020-11-18 19:17:48 +01001967 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001968 write(
1969 dump_details_template.format(
1970 n=s.caller, r=s.reply, N=s.caller.upper(), R=s.reply.upper()
1971 )
1972 )
Ole Troandf87f802020-11-18 19:17:48 +01001973 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001974 write(
1975 req_reply_template.format(
1976 n=s.caller, r=s.reply, N=s.caller.upper(), R=s.reply.upper()
1977 )
1978 )
Ole Troandf87f802020-11-18 19:17:48 +01001979
1980
1981def generate_c_test2_boilerplate(services, defines, module, stream):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001982 """Generate code for VAT2 plugin."""
Ole Troandf87f802020-11-18 19:17:48 +01001983 write = stream.write
1984
1985 define_hash = {d.name: d for d in defines}
1986 # replies = {}
1987
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001988 hdr = """\
Ole Troandf87f802020-11-18 19:17:48 +01001989#include <vlibapi/api.h>
1990#include <vlibmemory/api.h>
1991#include <vppinfra/error.h>
1992#include <vnet/ip/ip_format_fns.h>
1993#include <vnet/ethernet/ethernet_format_fns.h>
1994
1995#define vl_typedefs /* define message structures */
Filip Tehlarb7e4d442021-07-08 18:44:19 +00001996#include <vlibmemory/vl_memory_api_h.h>
Florin Corasa1400ce2021-09-15 09:02:08 -07001997#include <vlibmemory/vlib.api_types.h>
1998#include <vlibmemory/vlib.api.h>
Ole Troandf87f802020-11-18 19:17:48 +01001999#undef vl_typedefs
2000
2001#include "{module}.api_enum.h"
2002#include "{module}.api_types.h"
2003
2004#define vl_endianfun /* define message structures */
2005#include "{module}.api.h"
2006#undef vl_endianfun
2007
Klement Sekera9b7e8ac2021-11-22 21:26:20 +01002008#define vl_calcsizefun
2009#include "{module}.api.h"
2010#undef vl_calsizefun
2011
Ole Troandf87f802020-11-18 19:17:48 +01002012#define vl_printfun
2013#include "{module}.api.h"
2014#undef vl_printfun
2015
2016#include "{module}.api_tojson.h"
2017#include "{module}.api_fromjson.h"
2018#include <vpp-api/client/vppapiclient.h>
2019
2020#include <vat2/vat2_helpers.h>
2021
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002022"""
Ole Troandf87f802020-11-18 19:17:48 +01002023
2024 write(hdr.format(module=module))
2025
2026 for s in services:
2027 if s.reply not in define_hash:
2028 continue
2029 c_test_api_service(s, s.stream, stream)
2030
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002031 write(
2032 "void vat2_register_function(char *, cJSON * (*)(cJSON *), cJSON * (*)(void *), u32);\n"
2033 )
Ole Troandf87f802020-11-18 19:17:48 +01002034 # write('__attribute__((constructor))')
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002035 write("clib_error_t *\n")
2036 write("vat2_register_plugin (void) {\n")
Ole Troandf87f802020-11-18 19:17:48 +01002037 for s in services:
Filip Tehlar36217e32021-07-23 08:51:10 +00002038 if s.reply not in define_hash:
2039 continue
2040 crc = define_hash[s.caller].crc
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002041 write(
2042 ' vat2_register_function("{n}", api_{n}, (cJSON * (*)(void *))vl_api_{n}_t_tojson, 0x{crc:08x});\n'.format(
2043 n=s.caller, crc=crc
2044 )
2045 )
2046 write(" return 0;\n")
2047 write("}\n")
Ole Troandf87f802020-11-18 19:17:48 +01002048
2049
Ole Troan9d420872017-10-12 13:06:35 +02002050#
2051# Plugin entry point
2052#
Nathan Skrzypczak1b299fa2022-06-16 17:00:02 +02002053def run(output_dir, apifilename, s):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002054 """Main plugin entry point."""
Ole Troan33a58172019-09-04 09:12:29 +02002055 stream = StringIO()
Ole Troan2a1ca782019-09-19 01:08:30 +02002056
Nathan Skrzypczak1b299fa2022-06-16 17:00:02 +02002057 if not output_dir:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002058 sys.stderr.write("Missing --outputdir argument")
Ole Troan2a1ca782019-09-19 01:08:30 +02002059 return None
2060
Ole Troandf87f802020-11-18 19:17:48 +01002061 basename = os.path.basename(apifilename)
2062 filename, _ = os.path.splitext(basename)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002063 modulename = filename.replace(".", "_")
Nathan Skrzypczak1b299fa2022-06-16 17:00:02 +02002064 filename_enum = os.path.join(output_dir + "/" + basename + "_enum.h")
2065 filename_types = os.path.join(output_dir + "/" + basename + "_types.h")
2066 filename_c = os.path.join(output_dir + "/" + basename + ".c")
2067 filename_c_test = os.path.join(output_dir + "/" + basename + "_test.c")
2068 filename_c_test2 = os.path.join(output_dir + "/" + basename + "_test2.c")
2069 filename_c_tojson = os.path.join(output_dir + "/" + basename + "_tojson.h")
2070 filename_c_fromjson = os.path.join(output_dir + "/" + basename + "_fromjson.h")
Ole Troan2a1ca782019-09-19 01:08:30 +02002071
2072 # Generate separate types file
2073 st = StringIO()
2074 generate_include_types(s, modulename, st)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002075 with open(filename_types, "w") as fd:
Ole Troandf87f802020-11-18 19:17:48 +01002076 st.seek(0)
2077 shutil.copyfileobj(st, fd)
Ole Troan2a1ca782019-09-19 01:08:30 +02002078 st.close()
2079
2080 # Generate separate enum file
2081 st = StringIO()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002082 st.write("#ifndef included_{}_api_enum_h\n".format(modulename))
2083 st.write("#define included_{}_api_enum_h\n".format(modulename))
Ole Troan2a1ca782019-09-19 01:08:30 +02002084 generate_include_enum(s, modulename, st)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002085 generate_include_counters(s["Counters"], st)
2086 st.write("#endif\n")
2087 with open(filename_enum, "w") as fd:
Ole Troandf87f802020-11-18 19:17:48 +01002088 st.seek(0)
2089 shutil.copyfileobj(st, fd)
Ole Troan2a1ca782019-09-19 01:08:30 +02002090 st.close()
2091
2092 # Generate separate C file
2093 st = StringIO()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002094 generate_c_boilerplate(
2095 s["Service"], s["Define"], s["Counters"], s["file_crc"], modulename, st
2096 )
2097 with open(filename_c, "w") as fd:
Ole Troandf87f802020-11-18 19:17:48 +01002098 st.seek(0)
Ole Troan2a1ca782019-09-19 01:08:30 +02002099 shutil.copyfileobj(st, fd)
2100 st.close()
2101
2102 # Generate separate C test file
Ole Troan2a1ca782019-09-19 01:08:30 +02002103 st = StringIO()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002104 plugin = bool("plugin" in apifilename)
2105 generate_c_test_boilerplate(
2106 s["Service"], s["Define"], s["file_crc"], modulename, plugin, st
2107 )
2108 with open(filename_c_test, "w") as fd:
Ole Troandf87f802020-11-18 19:17:48 +01002109 st.seek(0)
Ole Troan2a1ca782019-09-19 01:08:30 +02002110 shutil.copyfileobj(st, fd)
2111 st.close()
Ole Troan33a58172019-09-04 09:12:29 +02002112
Ole Troandf87f802020-11-18 19:17:48 +01002113 # Fully autogenerated VATv2 C test file
2114 st = StringIO()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002115 generate_c_test2_boilerplate(s["Service"], s["Define"], modulename, st)
2116 with open(filename_c_test2, "w") as fd:
Ole Troandf87f802020-11-18 19:17:48 +01002117 st.seek(0)
2118 shutil.copyfileobj(st, fd)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002119 st.close() #
Ole Troandf87f802020-11-18 19:17:48 +01002120
2121 # Generate separate JSON file
2122 st = StringIO()
2123 generate_tojson(s, modulename, st)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002124 with open(filename_c_tojson, "w") as fd:
Ole Troandf87f802020-11-18 19:17:48 +01002125 st.seek(0)
2126 shutil.copyfileobj(st, fd)
2127 st.close()
2128 st = StringIO()
2129 generate_fromjson(s, modulename, st)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002130 with open(filename_c_fromjson, "w") as fd:
Ole Troandf87f802020-11-18 19:17:48 +01002131 st.seek(0)
2132 shutil.copyfileobj(st, fd)
2133 st.close()
2134
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002135 output = TOP_BOILERPLATE.format(datestring=DATESTRING, input_filename=basename)
2136 output += generate_imports(s["Import"])
Ole Troan9d420872017-10-12 13:06:35 +02002137 output += msg_ids(s)
2138 output += msg_names(s)
2139 output += msg_name_crc_list(s, filename)
Ole Troan2a1ca782019-09-19 01:08:30 +02002140 output += typedefs(modulename)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002141 printfun_types(s["types"], stream, modulename)
2142 printfun(s["Define"], stream, modulename)
Ole Troan33a58172019-09-04 09:12:29 +02002143 output += stream.getvalue()
Ole Troan2a1ca782019-09-19 01:08:30 +02002144 stream.close()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002145 output += endianfun(s["types"] + s["Define"], modulename)
2146 output += calc_size_fun(s["types"] + s["Define"], modulename)
Ole Troan9d420872017-10-12 13:06:35 +02002147 output += version_tuple(s, basename)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002148 output += BOTTOM_BOILERPLATE.format(input_filename=basename, file_crc=s["file_crc"])
Ole Troan9d420872017-10-12 13:06:35 +02002149
2150 return output