vapi: improve vl_api_string_t handling

Define vl_api_string_t to correspond with vlibapi/api_types.h
Fix allocation and size calculation routine generation.

Type: improvement
Change-Id: I6b0a3eb3459d75d326e67bfb76dac8125e480afa
Signed-off-by: Klement Sekera <klement.sekera@gmail.com>
diff --git a/src/vpp-api/vapi/vapi_c_gen.py b/src/vpp-api/vapi/vapi_c_gen.py
index 37f5ac1..609f4bb 100755
--- a/src/vpp-api/vapi/vapi_c_gen.py
+++ b/src/vpp-api/vapi/vapi_c_gen.py
@@ -23,7 +23,7 @@
         return "vapi_type_%s" % self.name
 
     def get_c_def(self):
-        if self.type.get_c_name() == "vl_api_string_t":
+        if self.type.get_c_name() == "string":
             if self.len:
                 return "u8 %s[%d];" % (self.name, self.len)
             else:
@@ -85,12 +85,15 @@
     def needs_byte_swap(self):
         return self.type.needs_byte_swap()
 
-    def get_vla_field_length_name(self, path):
+    def get_vla_parameter_name(self, path):
         return "%s_%s_array_size" % ("_".join(path), self.name)
 
+    def get_vla_field_name(self, path):
+        return ".".join(path + [self.nelem_field.name])
+
     def get_alloc_vla_param_names(self, path):
         if self.is_vla():
-            result = [self.get_vla_field_length_name(path)]
+            result = [self.get_vla_parameter_name(path)]
         else:
             result = []
         if self.type.has_vla():
@@ -98,20 +101,22 @@
             result.extend(t)
         return result
 
-    def get_vla_calc_size_code(self, prefix, path):
+    def get_vla_calc_size_code(self, prefix, path, is_alloc):
         if self.is_vla():
             result = [
                 "sizeof(%s.%s[0]) * %s"
                 % (
                     ".".join([prefix] + path),
                     self.name,
-                    self.get_vla_field_length_name(path),
+                    self.get_vla_parameter_name(path)
+                    if is_alloc
+                    else "%s.%s" % (prefix, self.get_vla_field_name(path)),
                 )
             ]
         else:
             result = []
         if self.type.has_vla():
-            t = self.type.get_vla_calc_size_code(prefix, path + [self.name])
+            t = self.type.get_vla_calc_size_code(prefix, path + [self.name], is_alloc)
             result.extend(t)
         return result
 
@@ -123,7 +128,7 @@
                 % (
                     ".".join([prefix] + path),
                     self.nelem_field.name,
-                    self.get_vla_field_length_name(path),
+                    self.get_vla_parameter_name(path),
                 )
             )
         if self.type.has_vla():
@@ -173,12 +178,12 @@
             for x in f.get_alloc_vla_param_names(path)
         ]
 
-    def get_vla_calc_size_code(self, prefix, path):
+    def get_vla_calc_size_code(self, prefix, path, is_alloc):
         return [
             x
             for f in self.fields
             if f.has_vla()
-            for x in f.get_vla_calc_size_code(prefix, path)
+            for x in f.get_vla_calc_size_code(prefix, path, is_alloc)
         ]
 
 
@@ -288,6 +293,8 @@
 
 class CStructType(StructType, CStruct):
     def get_c_name(self):
+        if self.name == "vl_api_string_t":
+            return "vl_api_string_t"
         return "vapi_type_%s" % self.name
 
     def get_swap_to_be_func_name(self):
@@ -398,7 +405,9 @@
                             " + %s" % x
                             for f in self.fields
                             if f.has_vla()
-                            for x in f.get_vla_calc_size_code("msg->payload", [])
+                            for x in f.get_vla_calc_size_code(
+                                "msg->payload", [], is_alloc=True
+                            )
                         ]
                     ),
                 ),
@@ -442,10 +451,12 @@
                 "  return sizeof(*msg)%s;"
                 % "".join(
                     [
-                        "+ msg->payload.%s * sizeof(msg->payload.%s[0])"
-                        % (f.nelem_field.name, f.name)
+                        " + %s" % x
                         for f in self.fields
-                        if f.nelem_field is not None
+                        if f.has_vla()
+                        for x in f.get_vla_calc_size_code(
+                            "msg->payload", [], is_alloc=False
+                        )
                     ]
                 ),
                 "}",
@@ -885,6 +896,20 @@
     print("#ifdef __cplusplus")
     print('extern "C" {')
     print("#endif")
+
+    print("#ifndef __vl_api_string_swap_fns_defined__")
+    print("#define __vl_api_string_swap_fns_defined__")
+    print("")
+    print("#include <vlibapi/api_types.h>")
+    print("")
+    function_attrs = "static inline "
+    o = parser.types["vl_api_string_t"]
+    print("%s%s" % (function_attrs, o.get_swap_to_be_func_def()))
+    print("")
+    print("%s%s" % (function_attrs, o.get_swap_to_host_func_def()))
+    print("")
+    print("#endif //__vl_api_string_swap_fns_defined__")
+
     if name == "memclnt.api.vapi.h":
         print("")
         print(
diff --git a/src/vpp-api/vapi/vapi_c_test.c b/src/vpp-api/vapi/vapi_c_test.c
index 5eccb0f..3f88ded 100644
--- a/src/vpp-api/vapi/vapi_c_test.c
+++ b/src/vpp-api/vapi/vapi_c_test.c
@@ -605,7 +605,7 @@
     {
       dctx.last_called = false;
       clib_memset (&seen, 0, sizeof (seen));
-      dump = vapi_alloc_sw_interface_dump (ctx);
+      dump = vapi_alloc_sw_interface_dump (ctx, 0);
       while (VAPI_EAGAIN ==
 	     (rv =
 	      vapi_sw_interface_dump (ctx, dump, sw_interface_dump_cb,
@@ -634,7 +634,7 @@
     }
   dctx.last_called = false;
   clib_memset (&seen, 0, sizeof (seen));
-  dump = vapi_alloc_sw_interface_dump (ctx);
+  dump = vapi_alloc_sw_interface_dump (ctx, 0);
   while (VAPI_EAGAIN ==
 	 (rv =
 	  vapi_sw_interface_dump (ctx, dump, sw_interface_dump_cb, &dctx)))
@@ -763,7 +763,7 @@
   bool seen[num_ifs];
   clib_memset (&seen, 0, sizeof (seen));
   sw_interface_dump_ctx dctx = { false, num_ifs, sw_if_indexes, seen, 0 };
-  vapi_msg_sw_interface_dump *dump = vapi_alloc_sw_interface_dump (ctx);
+  vapi_msg_sw_interface_dump *dump = vapi_alloc_sw_interface_dump (ctx, 0);
   while (VAPI_EAGAIN ==
 	 (rv =
 	  vapi_sw_interface_dump (ctx, dump, sw_interface_dump_cb, &dctx)))
@@ -803,7 +803,7 @@
     }
   clib_memset (&seen, 0, sizeof (seen));
   dctx.last_called = false;
-  dump = vapi_alloc_sw_interface_dump (ctx);
+  dump = vapi_alloc_sw_interface_dump (ctx, 0);
   while (VAPI_EAGAIN ==
 	 (rv =
 	  vapi_sw_interface_dump (ctx, dump, sw_interface_dump_cb, &dctx)))
@@ -922,7 +922,7 @@
 {
   printf ("--- Simulate no response to dump message ---\n");
   vapi_error_e rv;
-  vapi_msg_sw_interface_dump *dump = vapi_alloc_sw_interface_dump (ctx);
+  vapi_msg_sw_interface_dump *dump = vapi_alloc_sw_interface_dump (ctx, 0);
   dump->header._vl_msg_id = ~0;	/* malformed ID causes vpp to drop the msg */
   int no_called = 0;
   while (VAPI_EAGAIN ==
diff --git a/src/vpp-api/vapi/vapi_cpp_test.cpp b/src/vpp-api/vapi/vapi_cpp_test.cpp
index 25df5b7..56ebb39 100644
--- a/src/vpp-api/vapi/vapi_cpp_test.cpp
+++ b/src/vpp-api/vapi/vapi_cpp_test.cpp
@@ -193,7 +193,7 @@
 
   { // new context
     bool seen[num_ifs] = {0};
-    Sw_interface_dump d (con);
+    Sw_interface_dump d (con, 0);
     auto rv = d.execute ();
     ck_assert_int_eq (VAPI_OK, rv);
     WAIT_FOR_RESPONSE (d, rv);
@@ -232,7 +232,7 @@
     }
 
   { // new context
-    Sw_interface_dump d (con);
+    Sw_interface_dump d (con, 0);
     auto rv = d.execute ();
     ck_assert_int_eq (VAPI_OK, rv);
     WAIT_FOR_RESPONSE (d, rv);
@@ -347,7 +347,7 @@
     }
 
   Sw_interface_dump_cb<num_ifs> swdcb (ccbs);
-  Sw_interface_dump d (con, std::ref (swdcb));
+  Sw_interface_dump d (con, 0, std::ref (swdcb));
   auto rv = d.execute ();
   ck_assert_int_eq (VAPI_OK, rv);
   WAIT_FOR_RESPONSE (d, rv);
@@ -373,7 +373,7 @@
     }
 
   { // new context
-    Sw_interface_dump d (con);
+    Sw_interface_dump d (con, 0);
     auto rv = d.execute ();
     ck_assert_int_eq (VAPI_OK, rv);
     WAIT_FOR_RESPONSE (d, rv);
diff --git a/src/vpp-api/vapi/vapi_json_parser.py b/src/vpp-api/vapi/vapi_json_parser.py
index 00c234f..c06cb8c 100644
--- a/src/vpp-api/vapi/vapi_json_parser.py
+++ b/src/vpp-api/vapi/vapi_json_parser.py
@@ -197,12 +197,18 @@
                             "array `%s' doesn't have reference to member "
                             "containing the actual length" % (name, field[1])
                         )
-                    if field[0] == "string" and field[2] > 0:
-                        field_type = json_parser.lookup_type_like_id("u8")
+                    if field[0] == "string" and field[2] == 0:
+                        field_type = json_parser.lookup_type_like_id("vl_api_string_t")
+                        p = field_class(field_name=field[1], field_type=field_type)
+                    else:
+                        if field[0] == "string" and field[2] > 0:
+                            field_type = json_parser.lookup_type_like_id("u8")
 
-                    p = field_class(
-                        field_name=field[1], field_type=field_type, array_len=field[2]
-                    )
+                        p = field_class(
+                            field_name=field[1],
+                            field_type=field_type,
+                            array_len=field[2],
+                        )
                 elif l == 4:
                     nelem_field = None
                     for f in fields:
@@ -255,13 +261,31 @@
                 p = field_class(field_name=field[1], field_type=field_type)
             elif len(field) == 3:
                 if field[2] == 0:
-                    raise ParseError(
-                        "While parsing type `%s': array `%s' has "
-                        "variable length" % (name, field[1])
+                    if name == "vl_api_string_t":
+                        p = None
+                        for f in fields:
+                            if f.name == "length":
+                                nelem_field = f
+                                p = field_class(
+                                    field_name=field[1],
+                                    field_type=field_type,
+                                    array_len=field[2],
+                                    nelem_field=nelem_field,
+                                )
+                                break
+                        if p is None:
+                            raise ParseError(
+                                "While parsing type `%s': missing `length'" % name
+                            )
+                    else:
+                        raise ParseError(
+                            "While parsing type `%s': array `%s' has "
+                            "variable length" % (name, field[1])
+                        )
+                else:
+                    p = field_class(
+                        field_name=field[1], field_type=field_type, array_len=field[2]
                     )
-                p = field_class(
-                    field_name=field[1], field_type=field_type, array_len=field[2]
-                )
             elif len(field) == 4:
                 nelem_field = None
                 for f in fields:
@@ -344,7 +368,13 @@
             ]
         }
 
-        self.types["string"] = simple_type_class("vl_api_string_t")
+        self.types["string"] = simple_type_class("u8")
+        self.types["vl_api_string_t"] = struct_type_class(
+            ["vl_api_string_t", ["u32", "length"], ["u8", "buf", 0]],
+            self,
+            field_class,
+            logger,
+        )
         self.replies = set()
         self.events = set()
         self.streams = set()