map gbp papi: match endianess of f64 81/19581/17
authorPaul Vinciguerra <pvinci@vinciconsulting.com>
Wed, 15 May 2019 01:01:28 +0000 (21:01 -0400)
committerNeale Ranns <nranns@cisco.com>
Mon, 8 Jul 2019 17:47:33 +0000 (17:47 +0000)
clib_net_to_host_f64, clib_host_to_net_f64 are now implemented as '=',
https://gerrit.fd.io/r/#/c/20406/  set papi to match.
- all f64 api references are now wrapped with
  clib_net_to_host_f64 or clib_host_to_net_f64.

IEEE f64 endianess is not defined.  If clib_net_to_host_f64 and
clib_host_to_net_f64 are later defined in VPP as big-endian, it is
a single character change in the papi vpp_serializer.

Note: This breaks the api in a manner that would not be detected by
the flag day initiative.  The scope is small.  This only impacts map.api,
which applied the u64 transformation, while the gbp api uses '='.

The implementation of "=" raises issues for the papi socket implementation
if used between systems of differing endianess.  See Vratko's comments.

- Added get_f64_endian_value() to api to allow client to verify endianess of f64's.

Type: fix
Depends-on: https://gerrit.fd.io/r/#/c/20484/

Change-Id: I00fc64a6557ba0190398df211aa0ea5c7eb101df
Signed-off-by: Paul Vinciguerra <pvinci@vinciconsulting.com>
src/plugins/gbp/gbp_api.c
src/plugins/map/map_api.c
src/vnet/api_errno.h
src/vpp-api/python/vpp_papi/vpp_serializer.py
src/vpp/api/api.c
src/vpp/api/vpe.api
test/test_endian.py [new file with mode: 0644]

index f487e16..7c7026a 100644 (file)
@@ -246,7 +246,9 @@ gbp_endpoint_send_details (index_t gei, void *args)
   mp->endpoint.n_ips = n_ips;
   mp->endpoint.flags = gbp_endpoint_flags_encode (gef->gef_flags);
   mp->handle = htonl (gei);
-  mp->age = vlib_time_now (vlib_get_main ()) - ge->ge_last_time;
+  mp->age =
+    clib_host_to_net_f64 (vlib_time_now (vlib_get_main ()) -
+                         ge->ge_last_time);
   mac_address_encode (&ge->ge_key.gek_mac, mp->endpoint.mac);
 
   vec_foreach_index (ii, ge->ge_key.gek_ips)
index 1d2614c..4a0834d 100644 (file)
@@ -461,7 +461,7 @@ static void
   int rv;
   f64 ht_ratio;
 
-  ht_ratio = (f64) clib_net_to_host_u64 (mp->ht_ratio);
+  ht_ratio = (f64) clib_net_to_host_f64 (mp->ht_ratio);
   if (ht_ratio == ~0)
     ht_ratio = MAP_IP6_REASS_CONF_HT_RATIO_MAX + 1;
 
@@ -587,15 +587,13 @@ vl_api_map_param_get_t_handler (vl_api_map_param_get_t * mp)
     clib_net_to_host_u16 (mm->ip4_reass_conf_lifetime_ms);
   rmp->ip4_pool_size = clib_net_to_host_u16 (mm->ip4_reass_conf_pool_size);
   rmp->ip4_buffers = clib_net_to_host_u32 (mm->ip4_reass_conf_buffers);
-  rmp->ip4_ht_ratio =
-    clib_net_to_host_u64 ((u64) mm->ip4_reass_conf_ht_ratio);
+  rmp->ip4_ht_ratio = clib_net_to_host_f64 (mm->ip4_reass_conf_ht_ratio);
 
   rmp->ip6_lifetime_ms =
     clib_net_to_host_u16 (mm->ip6_reass_conf_lifetime_ms);
   rmp->ip6_pool_size = clib_net_to_host_u16 (mm->ip6_reass_conf_pool_size);
   rmp->ip6_buffers = clib_net_to_host_u32 (mm->ip6_reass_conf_buffers);
-  rmp->ip6_ht_ratio =
-    clib_net_to_host_u64 ((u64) mm->ip6_reass_conf_ht_ratio);
+  rmp->ip6_ht_ratio = clib_net_to_host_f64 (mm->ip6_reass_conf_ht_ratio);
 
   rmp->sec_check_enable = mm->sec_check;
   rmp->sec_check_fragments = mm->sec_check_frag;
index 1429755..0702fd7 100644 (file)
@@ -149,8 +149,8 @@ _(INVALID_PROTOCOL, -153, "Invalid Protocol")                           \
 _(INVALID_ALGORITHM, -154, "Invalid Algorithm")                         \
 _(RSRC_IN_USE, -155, "Resource In Use")                                 \
 _(KEY_LENGTH, -156, "invalid Key Length")                               \
-_(FIB_PATH_UNSUPPORTED_NH_PROTO, -157, "Unsupported FIB Path protocol")
-
+_(FIB_PATH_UNSUPPORTED_NH_PROTO, -157, "Unsupported FIB Path protocol") \
+_(API_ENDIAN_FAILED, -159, "Endian mismatch detected")
 typedef enum
 {
 #define _(a,b,c) VNET_API_ERROR_##a = (b),
index fe9a083..9e17c4a 100644 (file)
@@ -74,7 +74,7 @@ class BaseTypes(object):
                       'u32': '>I',
                       'i32': '>i',
                       'u64': '>Q',
-                      'f64': '>d',
+                      'f64': '=d',
                       'bool': '>?',
                       'header': '>HI'}
 
index 66857fb..9ae027d 100644 (file)
@@ -86,7 +86,9 @@ _(SHOW_THREADS, show_threads)                                                             \
 _(GET_NODE_GRAPH, get_node_graph)                                       \
 _(GET_NEXT_INDEX, get_next_index)                                       \
 _(LOG_DUMP, log_dump)                                                   \
-_(SHOW_VPE_SYSTEM_TIME_TICKS, show_vpe_system_time_ticks)
+_(SHOW_VPE_SYSTEM_TIME_TICKS, show_vpe_system_time_ticks)                              \
+_(GET_F64_ENDIAN_VALUE, get_f64_endian_value)                                                  \
+_(GET_F64_INCREMENT_BY_ONE, get_f64_increment_by_one)                                  \
 
 #define QUOTE_(x) #x
 #define QUOTE(x) QUOTE_(x)
@@ -554,6 +556,37 @@ static void
   /* *INDENT-ON* */
 }
 
+static void
+vl_api_get_f64_endian_value_t_handler (vl_api_get_f64_endian_value_t * mp)
+{
+  int rv = 0;
+  f64 one = 1.0;
+  vl_api_get_f64_endian_value_reply_t *rmp;
+  if (1.0 != clib_net_to_host_f64 (mp->f64_one))
+    rv = VNET_API_ERROR_API_ENDIAN_FAILED;
+
+  /* *INDENT-OFF* */
+  REPLY_MACRO2(VL_API_GET_F64_ENDIAN_VALUE_REPLY,
+  ({
+    rmp->f64_one_result = clib_host_to_net_f64 (one);
+  }));
+  /* *INDENT-ON* */
+}
+
+static void
+vl_api_get_f64_increment_by_one_t_handler (vl_api_get_f64_increment_by_one_t *
+                                          mp)
+{
+  int rv = 0;
+  vl_api_get_f64_increment_by_one_reply_t *rmp;
+
+  /* *INDENT-OFF* */
+  REPLY_MACRO2(VL_API_GET_F64_INCREMENT_BY_ONE_REPLY,
+  ({
+    rmp->f64_value = clib_host_to_net_f64 (clib_net_to_host_f64(mp->f64_value) + 1.0);
+  }));
+  /* *INDENT-ON* */
+}
 
 #define BOUNCE_HANDLER(nn)                                              \
 static void vl_api_##nn##_t_handler (                                   \
index bd6b9d5..7c466b9 100644 (file)
@@ -19,7 +19,7 @@
     called through a shared memory interface. 
 */
 
-option version = "1.3.0";
+option version = "1.4.0";
 
 /* 
  * Note: API placement cleanup in progress
@@ -332,6 +332,54 @@ define show_vpe_system_time_ticks_reply
   f64 vpe_system_time_ticks;
 };
 
+/** \brief f64 types are not standardized across the wire. Sense wire format in each direction by sending the f64 value 1.0.
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param f64_one - The constant of 1.0.  If you send a different value, expect an rv=VNET_API_ERROR_API_ENDIAN_FAILED.
+*/
+define get_f64_endian_value
+{
+  u32 client_index;
+  u32 context;
+  f64 f64_one [default=1.0];
+};
+
+/** \brief get_f64_endian_value reply message
+    @param context - sender context which was passed in the request
+    @param retval - return value - VNET_API_ERROR_API_ENDIAN_FAILED if f64_one != 1.0
+    @param f64_one_result - The value of 'f64 1.0'
+*/
+define get_f64_endian_value_reply
+{
+  u32 context;
+  u32 retval;
+  f64 f64_one_result;
+};
+
+/** \brief Verify f64 wire format by sending a value and receiving the value + 1.0
+    @param client_index - opaque cookie to identify the sender.
+    @param context - sender context, to match reply w/ request.
+    @param f64_value - The value you want to test.  Default: 1.0.
+*/
+define get_f64_increment_by_one
+{
+  u32 client_index;
+  u32 context;
+  f64 f64_value [default=1.0];
+};
+
+/** \brief get_f64_increment_by_one reply
+    @param client_index - opaque cookie to identify the sender.
+    @param context - sender context, to match reply w/ request.
+    @param f64_value - The input f64_value incremented by 1.0.
+*/
+define get_f64_increment_by_one_reply
+{
+  u32 context;
+  u32 retval;
+  f64 f64_value;
+};
+
 /*
  * Local Variables:
  * eval: (c-set-style "gnu")
diff --git a/test/test_endian.py b/test/test_endian.py
new file mode 100644 (file)
index 0000000..462ee2b
--- /dev/null
@@ -0,0 +1,38 @@
+#  Copyright (c) 2019. Vinci Consulting Corp. All Rights Reserved.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+import framework
+import vpp_papi_provider
+
+F64_ONE = 1.0
+
+
+class TestEndian(framework.VppTestCase):
+    """TestEndian"""
+
+    def test_f64_endian_value(self):
+        try:
+            rv = self.vapi.get_f64_endian_value(f64_one=F64_ONE)
+            self.assertEqual(rv.f64_one_result, F64_ONE,
+                             "client incorrectly deserializes f64 values.  "
+                             "Expected: %r. Received: %r." % (
+                                 F64_ONE, rv.f64_one_result))
+        except vpp_papi_provider.UnexpectedApiReturnValueError:
+            self.fail('client incorrectly serializes f64 values.')
+
+    def test_get_f64_increment_by_one(self):
+        expected = 43.0
+        rv = self.vapi.get_f64_increment_by_one(f64_value=42.0)
+        self.assertEqual(rv.f64_value, expected, 'Expected %r, received:%r.'
+                         % (expected, rv.f64_value))