vapi: Fix build when directory contains @
[vpp.git] / src / vpp-api / vapi / vapi_c_gen.py
index 047bb2c..debd734 100755 (executable)
@@ -1,6 +1,7 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python3
 
 import argparse
+import inspect
 import os
 import sys
 import logging
@@ -13,16 +14,20 @@ class CField(Field):
         return "vapi_type_%s" % self.name
 
     def get_c_def(self):
-        if self.len is not None:
-            try:
-                return "%s %s[%d];" % (self.type.get_c_name(), self.name, self.len)
-            except:
-                raise Exception("%s %s[%s];" % (self.type.get_c_name(), self.name, self.len))
+        if self.type.get_c_name() == 'vl_api_string_t':
+            if self.len:
+                return "u8 %s[%d];" % (self.name, self.len)
+            else:
+                return "vl_api_string_t %s;" % (self.name)
         else:
-            return "%s %s;" % (self.type.get_c_name(), self.name)
+            if self.len is not None and type(self.len) != dict:
+                return "%s %s[%d];" % (self.type.get_c_name(), self.name,
+                                       self.len)
+            else:
+                return "%s %s;" % (self.type.get_c_name(), self.name)
 
     def get_swap_to_be_code(self, struct, var):
-        if self.len is not None:
+        if self.len is not None and type(self.len) != dict:
             if self.len > 0:
                 return "do { unsigned i; for (i = 0; i < %d; ++i) { %s } }"\
                     " while(0);" % (
@@ -43,7 +48,7 @@ class CField(Field):
         return self.type.get_swap_to_be_code(struct, "%s" % var)
 
     def get_swap_to_host_code(self, struct, var):
-        if self.len is not None:
+        if self.len is not None and type(self.len) != dict:
             if self.len > 0:
                 return "do { unsigned i; for (i = 0; i < %d; ++i) { %s } }"\
                     " while(0);" % (
@@ -150,6 +155,12 @@ class CSimpleType (SimpleType):
         'i64': 'be64toh', 'u64': 'be64toh',
     }
 
+    __packed = "__attribute__((packed))"
+    pack_dict = {
+        'i8':  __packed, 'u8':  __packed,
+        'i16': __packed, 'u16': __packed,
+    }
+
     def get_c_name(self):
         return self.name
 
@@ -159,6 +170,9 @@ class CSimpleType (SimpleType):
     def get_swap_to_host_func_name(self):
         return self.swap_to_host_dict[self.name]
 
+    def get_packed_string(self):
+        return self.pack_dict[self.name]
+
     def get_swap_to_be_code(self, struct, var, cast=None):
         x = "%s%s" % (struct, var)
         return "%s = %s%s(%s);" % (x,
@@ -179,14 +193,18 @@ class CSimpleType (SimpleType):
             pass
         return False
 
+    def get_packed(self):
+        return self.pack_dict.get(self.name, "")
+
 
 class CEnum(Enum):
     def get_c_name(self):
         return "vapi_enum_%s" % self.name
 
     def get_c_def(self):
-        return "typedef enum {\n%s\n} %s;" % (
+        return "typedef enum {\n%s\n} %s %s;" % (
             "\n".join(["  %s = %s," % (i, j) for i, j in self.value_pairs]),
+            self.type.get_packed(),
             self.get_c_name()
         )
 
@@ -350,6 +368,37 @@ class CMessage (Message):
             "}",
         ])
 
+    def get_verify_msg_size_func_name(self):
+        return f"vapi_verify_{self.name}_msg_size"
+
+    def get_verify_msg_size_func_decl(self):
+        return "int %s(%s *msg, uword buf_size)" % (
+            self.get_verify_msg_size_func_name(),
+            self.get_c_name())
+
+    def get_verify_msg_size_func_def(self):
+        return inspect.cleandoc(
+            f"""
+            {self.get_verify_msg_size_func_decl()}
+            {{
+              if (sizeof({self.get_c_name()}) > buf_size)
+                {{
+                  VAPI_ERR("Truncated '{self.name}' msg received, received %lu"
+                    "bytes, expected %lu bytes.", buf_size,
+                    sizeof({self.get_c_name()}));
+                  return -1;
+                }}
+              if ({self.get_calc_msg_size_func_name()}(msg) > buf_size)
+                {{
+                  VAPI_ERR("Truncated '{self.name}' msg received, received %lu"
+                    "bytes, expected %lu bytes.", buf_size,
+                    sizeof({self.get_calc_msg_size_func_name()}));
+                  return -1;
+                }}
+              return 0;
+            }}
+        """)
+
     def get_c_def(self):
         if self.has_payload():
             return "\n".join([
@@ -584,7 +633,8 @@ class CMessage (Message):
             if has_context else '    0,',
             ('    offsetof(%s, payload),' % self.get_c_name())
             if self.has_payload() else '    VAPI_INVALID_MSG_ID,',
-            '    sizeof(%s),' % self.get_c_name(),
+            '    (verify_msg_size_fn_t)%s,' %
+            self.get_verify_msg_size_func_name(),
             '    (generic_swap_fn_t)%s,' % self.get_swap_to_be_func_name(),
             '    (generic_swap_fn_t)%s,' % self.get_swap_to_host_func_name(),
             '    VAPI_INVALID_MSG_ID,',
@@ -598,22 +648,6 @@ class CMessage (Message):
         ])
 
 
-vapi_send_with_control_ping = """
-static inline vapi_error_e
-vapi_send_with_control_ping (vapi_ctx_t ctx, void *msg, u32 context)
-{
-  vapi_msg_control_ping *ping = vapi_alloc_control_ping (ctx);
-  if (!ping)
-    {
-      return VAPI_ENOMEM;
-    }
-  ping->header.context = context;
-  vapi_msg_control_ping_hton (ping);
-  return vapi_send2 (ctx, msg, ping);
-}
-"""
-
-
 def emit_definition(parser, json_file, emitted, o):
     if o in emitted:
         return
@@ -650,6 +684,8 @@ def emit_definition(parser, json_file, emitted, o):
             print("%s%s" % (function_attrs, o.get_swap_to_host_func_def()))
             print("")
             print("%s%s" % (function_attrs, o.get_calc_msg_size_func_def()))
+            print("")
+            print("%s%s" % (function_attrs, o.get_verify_msg_size_func_def()))
             if not o.is_reply and not o.is_event:
                 print("")
                 print("%s%s" % (function_attrs, o.get_alloc_func_def()))
@@ -675,7 +711,8 @@ def gen_json_unified_header(parser, logger, j, io, name):
     orig_stdout = sys.stdout
     sys.stdout = io
     include_guard = "__included_%s" % (
-        j.replace(".", "_").replace("/", "_").replace("-", "_"))
+        j.replace(".", "_").replace("/", "_").replace("-", "_").replace(
+            "+", "_").replace("@", "_"))
     print("#ifndef %s" % include_guard)
     print("#define %s" % include_guard)
     print("")
@@ -689,12 +726,14 @@ def gen_json_unified_header(parser, logger, j, io, name):
     print("#ifdef __cplusplus")
     print("extern \"C\" {")
     print("#endif")
-    if name == "vpe.api.vapi.h":
+    if name == "memclnt.api.vapi.h":
         print("")
         print("static inline vapi_error_e vapi_send_with_control_ping "
               "(vapi_ctx_t ctx, void * msg, u32 context);")
+    elif name == "vlib.api.vapi.h":
+        print("#include <vapi/memclnt.api.vapi.h>")
     else:
-        print("#include <vapi/vpe.api.vapi.h>")
+        print("#include <vapi/vlib.api.vapi.h>")
     print("")
     for m in parser.messages_by_json[j].values():
         print("extern vapi_msg_id_t %s;" % m.get_msg_id_name())
@@ -710,19 +749,33 @@ def gen_json_unified_header(parser, logger, j, io, name):
     emitted = []
     for e in parser.enums_by_json[j]:
         emit_definition(parser, j, emitted, e)
-    for a in parser.aliases_by_json[j]:
-        emit_definition(parser, j, emitted, a)
     for u in parser.unions_by_json[j]:
         emit_definition(parser, j, emitted, u)
     for t in parser.types_by_json[j]:
         emit_definition(parser, j, emitted, t)
+    for a in parser.aliases_by_json[j]:
+        emit_definition(parser, j, emitted, a)
     for m in parser.messages_by_json[j].values():
         emit_definition(parser, j, emitted, m)
 
     print("")
 
-    if name == "vpe.api.vapi.h":
-        print("%s" % vapi_send_with_control_ping)
+    if name == "vlib.api.vapi.h":
+        vapi_send_with_control_ping_function = """
+static inline vapi_error_e
+vapi_send_with_control_ping (vapi_ctx_t ctx, void *msg, u32 context)
+{
+  vapi_msg_control_ping *ping = vapi_alloc_control_ping (ctx);
+  if (!ping)
+    {
+      return VAPI_ENOMEM;
+    }
+  ping->header.context = context;
+  vapi_msg_control_ping_hton (ping);
+  return vapi_send2 (ctx, msg, ping);
+}
+"""
+        print("%s" % vapi_send_with_control_ping_function)
         print("")
 
     print("#ifdef __cplusplus")