From 888640a398f974cf388bdc983d10e78591275b37 Mon Sep 17 00:00:00 2001 From: Paul Vinciguerra Date: Tue, 14 May 2019 21:01:28 -0400 Subject: [PATCH] map gbp papi: match endianess of f64 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 --- src/plugins/gbp/gbp_api.c | 4 ++- src/plugins/map/map_api.c | 8 ++--- src/vnet/api_errno.h | 4 +-- src/vpp-api/python/vpp_papi/vpp_serializer.py | 2 +- src/vpp/api/api.c | 35 ++++++++++++++++++- src/vpp/api/vpe.api | 50 ++++++++++++++++++++++++++- test/test_endian.py | 38 ++++++++++++++++++++ 7 files changed, 130 insertions(+), 11 deletions(-) create mode 100644 test/test_endian.py diff --git a/src/plugins/gbp/gbp_api.c b/src/plugins/gbp/gbp_api.c index f487e160808..7c7026aae84 100644 --- a/src/plugins/gbp/gbp_api.c +++ b/src/plugins/gbp/gbp_api.c @@ -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) diff --git a/src/plugins/map/map_api.c b/src/plugins/map/map_api.c index 1d2614ccb5d..4a0834d786b 100644 --- a/src/plugins/map/map_api.c +++ b/src/plugins/map/map_api.c @@ -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; diff --git a/src/vnet/api_errno.h b/src/vnet/api_errno.h index 14297558405..0702fd7ec9e 100644 --- a/src/vnet/api_errno.h +++ b/src/vnet/api_errno.h @@ -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), diff --git a/src/vpp-api/python/vpp_papi/vpp_serializer.py b/src/vpp-api/python/vpp_papi/vpp_serializer.py index fe9a083d6c8..9e17c4a2b8c 100644 --- a/src/vpp-api/python/vpp_papi/vpp_serializer.py +++ b/src/vpp-api/python/vpp_papi/vpp_serializer.py @@ -74,7 +74,7 @@ class BaseTypes(object): 'u32': '>I', 'i32': '>i', 'u64': '>Q', - 'f64': '>d', + 'f64': '=d', 'bool': '>?', 'header': '>HI'} diff --git a/src/vpp/api/api.c b/src/vpp/api/api.c index 66857fbac9f..9ae027dab9b 100644 --- a/src/vpp/api/api.c +++ b/src/vpp/api/api.c @@ -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 ( \ diff --git a/src/vpp/api/vpe.api b/src/vpp/api/vpe.api index bd6b9d5638f..7c466b9a7a4 100644 --- a/src/vpp/api/vpe.api +++ b/src/vpp/api/vpe.api @@ -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 index 00000000000..462ee2b6b57 --- /dev/null +++ b/test/test_endian.py @@ -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)) -- 2.16.6