From da0d60997bce1e40cc0b1c7b7f4f58df56bbead3 Mon Sep 17 00:00:00 2001 From: Mauro Sardara Date: Fri, 20 Jan 2023 14:54:19 +0000 Subject: feat: implement set strategy API for hicn-plugin Ticket: HICN-829 Change-Id: I3dabc38e9cc2e06ebed14b9ed265d027f77b7e5f Signed-off-by: Mauro Sardara --- ctrl/libhicnctrl/src/modules/CMakeLists.txt | 8 +- ctrl/libhicnctrl/src/modules/hicn_plugin.c | 3 +- .../libhicnctrl/src/modules/hicn_plugin/strategy.c | 118 ++++++++++ .../libhicnctrl/src/modules/hicn_plugin/strategy.h | 28 +++ .../includes/vpp_plugins/hicn/CMakeLists.txt | 1 + hicn-plugin/includes/vpp_plugins/hicn/hicn_api.h | 3 - hicn-plugin/includes/vpp_plugins/hicn/hicn_enums.h | 22 ++ hicn-plugin/src/hicn.api | 39 +++- hicn-plugin/src/hicn_api.c | 24 +- hicn-plugin/src/hicn_api_test.c | 251 +++++++-------------- 10 files changed, 317 insertions(+), 180 deletions(-) create mode 100644 ctrl/libhicnctrl/src/modules/hicn_plugin/strategy.c create mode 100644 ctrl/libhicnctrl/src/modules/hicn_plugin/strategy.h create mode 100644 hicn-plugin/includes/vpp_plugins/hicn/hicn_enums.h diff --git a/ctrl/libhicnctrl/src/modules/CMakeLists.txt b/ctrl/libhicnctrl/src/modules/CMakeLists.txt index b1b63a5f9..f7bd2f83a 100644 --- a/ctrl/libhicnctrl/src/modules/CMakeLists.txt +++ b/ctrl/libhicnctrl/src/modules/CMakeLists.txt @@ -66,12 +66,14 @@ if(BUILD_HICNPLUGIN AND ${CMAKE_SYSTEM_NAME} MATCHES "Linux") ${CMAKE_CURRENT_SOURCE_DIR}/hicn_plugin.c ${CMAKE_CURRENT_SOURCE_DIR}/hicn_plugin/listener.c ${CMAKE_CURRENT_SOURCE_DIR}/hicn_plugin/route.c + ${CMAKE_CURRENT_SOURCE_DIR}/hicn_plugin/strategy.c ) list(APPEND HICN_PLUGIN_HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light/base.h - ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light/listener.h - ${CMAKE_CURRENT_SOURCE_DIR}/hicn_light/route.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn_plugin/base.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn_plugin/listener.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn_plugin/route.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn_plugin/strategy.h ) ############################################################## diff --git a/ctrl/libhicnctrl/src/modules/hicn_plugin.c b/ctrl/libhicnctrl/src/modules/hicn_plugin.c index b3963b46c..b8606daf7 100644 --- a/ctrl/libhicnctrl/src/modules/hicn_plugin.c +++ b/ctrl/libhicnctrl/src/modules/hicn_plugin.c @@ -39,6 +39,7 @@ #include "hicn_plugin/base.h" // hc_sock_vpp_data_t #include "hicn_plugin/listener.h" #include "hicn_plugin/route.h" +#include "hicn_plugin/strategy.h" /****************************************************************************** * Message helper types and aliases @@ -241,7 +242,7 @@ int hc_sock_initialize_module(hc_sock_t *s) { s->ops.object_vft[OBJECT_TYPE_WLDR] = HC_MODULE_OBJECT_OPS_EMPTY; s->ops.object_vft[OBJECT_TYPE_POLICY] = HC_MODULE_OBJECT_OPS_EMPTY; s->ops.object_vft[OBJECT_TYPE_ROUTE] = vpp_route_module_ops; - s->ops.object_vft[OBJECT_TYPE_STRATEGY] = HC_MODULE_OBJECT_OPS_EMPTY; + s->ops.object_vft[OBJECT_TYPE_STRATEGY] = vpp_strategy_module_ops; s->ops.object_vft[OBJECT_TYPE_SUBSCRIPTION] = HC_MODULE_OBJECT_OPS_EMPTY; return 0; } diff --git a/ctrl/libhicnctrl/src/modules/hicn_plugin/strategy.c b/ctrl/libhicnctrl/src/modules/hicn_plugin/strategy.c new file mode 100644 index 000000000..f8f6536ff --- /dev/null +++ b/ctrl/libhicnctrl/src/modules/hicn_plugin/strategy.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2023 Cisco and/or its affiliates. + * 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. + */ + +#include "base.h" +#include "strategy.h" + +#include + +static int _ip_prefix_encode(const hicn_ip_address_t *address, + int prefix_length, int family, + vapi_type_prefix *out) { + out->len = prefix_length; + int ret = 0; + + switch (family) { + case AF_INET: + memcpy(&out->address.un.ip4[0], &address->v4, 4); + out->address.af = ADDRESS_IP4; + break; + case AF_INET6: + memcpy(&out->address.un.ip6[0], &address->v6, 16); + out->address.af = ADDRESS_IP6; + break; + default: + // This should never happen + ret = -1; + } + + return ret; +} + +static vapi_enum_hicn_strategy _vpp_strategy_libhicn_to_hicnplugin_strategy( + strategy_type_t strategy) { + switch (strategy) { + case STRATEGY_TYPE_LOADBALANCER: + return HICN_STRATEGY_RR; + case STRATEGY_TYPE_LOCAL_REMOTE: + return HICN_STRATEGY_LR; + case STRATEGY_TYPE_REPLICATION: + return HICN_STRATEGY_RP; + case STRATEGY_TYPE_BESTPATH: + return HICN_STRATEGY_MW; + default: + return HICN_STRATEGY_NULL; + } +} + +static vapi_error_e _hicn_strategy_set_cb( + vapi_ctx_t ctx, void *callback_ctx, vapi_error_e rv, bool is_last, + vapi_payload_hicn_api_strategy_set_reply *reply) { + if (reply == NULL || rv != VAPI_OK) return rv; + return reply->retval; +} + +static int _vpp_strategy_set(hc_sock_vpp_data_t *s, + const hc_strategy_t *strategy) { + int ret = -1; + + // Convert libhicn strategy enum to hicnplugin strategy enum and make sure it + // is valid + vapi_enum_hicn_strategy strategy_id = + _vpp_strategy_libhicn_to_hicnplugin_strategy(strategy->type); + + if (strategy_id == HICN_STRATEGY_NULL) { + return -1; + } + + // Construct API message + vapi_msg_hicn_api_strategy_set *msg = + vapi_alloc_hicn_api_strategy_set(s->g_vapi_ctx_instance); + + // Fill it + msg->payload.strategy_id = clib_host_to_net_u32(strategy_id); + ret = _ip_prefix_encode(&strategy->address, strategy->len, strategy->family, + &msg->payload.prefix); + + if (ret != 0) { + return -1; + } + + vapi_lock(); + ret = vapi_hicn_api_strategy_set(s->g_vapi_ctx_instance, msg, + _hicn_strategy_set_cb, NULL); + vapi_unlock(); + + return ret; +} + +int vpp_strategy_create(hc_sock_t *sock, hc_object_t *object, hc_data_t *data) { + return -1; +} + +int vpp_strategy_delete(hc_sock_t *sock, hc_object_t *object, hc_data_t *data) { + return -1; +} + +int vpp_strategy_list(hc_sock_t *sock, hc_object_t *object, hc_data_t *data) { + return -1; +} + +int vpp_strategy_set(hc_sock_t *sock, hc_object_t *object, hc_data_t *data) { + hc_sock_vpp_data_t *s = (hc_sock_vpp_data_t *)sock->data; + return _vpp_strategy_set(s, &object->strategy); +} + +DECLARE_VPP_MODULE_OBJECT_OPS(vpp, strategy); diff --git a/ctrl/libhicnctrl/src/modules/hicn_plugin/strategy.h b/ctrl/libhicnctrl/src/modules/hicn_plugin/strategy.h new file mode 100644 index 000000000..6dd6df6e4 --- /dev/null +++ b/ctrl/libhicnctrl/src/modules/hicn_plugin/strategy.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Cisco and/or its affiliates. + * 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. + */ + +/** + * \file modules/hicn_plugin/route.h + * \brief route object VFT for hicn_plugin. + */ + +#ifndef HICNCTRL_MODULE_VPP_STRATEGY_H +#define HICNCTRL_MODULE_VPP_STRATEGY_H + +#include "../../module.h" + +DECLARE_MODULE_OBJECT_OPS_H(vpp, strategy); + +#endif /* HICNCTRL_MODULE_VPP_STRATEGY_H */ diff --git a/hicn-plugin/includes/vpp_plugins/hicn/CMakeLists.txt b/hicn-plugin/includes/vpp_plugins/hicn/CMakeLists.txt index 9b463e525..d498f5138 100644 --- a/hicn-plugin/includes/vpp_plugins/hicn/CMakeLists.txt +++ b/hicn-plugin/includes/vpp_plugins/hicn/CMakeLists.txt @@ -23,6 +23,7 @@ set(HICNPLUGIN_TO_INSTALL_HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/error.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn_all_api_h.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn_api.h + ${CMAKE_CURRENT_SOURCE_DIR}/hicn_enums.h ${CMAKE_CURRENT_SOURCE_DIR}/hicn_msg_enum.h "" CACHE INTERNAL "" FORCE diff --git a/hicn-plugin/includes/vpp_plugins/hicn/hicn_api.h b/hicn-plugin/includes/vpp_plugins/hicn/hicn_api.h index ac45fbf17..31d5e7736 100644 --- a/hicn-plugin/includes/vpp_plugins/hicn/hicn_api.h +++ b/hicn-plugin/includes/vpp_plugins/hicn/hicn_api.h @@ -20,9 +20,6 @@ * @file */ -#define HICN_STRATEGY_NULL ~0 -#define HICN_FIB_TABLE 10 - /* define message structures */ #define vl_typedefs #include diff --git a/hicn-plugin/includes/vpp_plugins/hicn/hicn_enums.h b/hicn-plugin/includes/vpp_plugins/hicn/hicn_enums.h new file mode 100644 index 000000000..8ad2e5d46 --- /dev/null +++ b/hicn-plugin/includes/vpp_plugins/hicn/hicn_enums.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2021 Cisco and/or its affiliates. + * 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. + */ + +#ifndef __HICN_ENUMS_H__ +#define __HICN_ENUMS_H__ + +#define HICN_STRATEGY_NULL ~0 +#define HICN_FIB_TABLE 10 + +#endif /* // __HICN_ENUMS_H__ */ \ No newline at end of file diff --git a/hicn-plugin/src/hicn.api b/hicn-plugin/src/hicn.api index 8c1c78eb0..2321e6622 100644 --- a/hicn-plugin/src/hicn.api +++ b/hicn-plugin/src/hicn.api @@ -22,6 +22,14 @@ enum hicn_action_type HICN_ENABLE, }; +enum hicn_strategy +{ + HICN_STRATEGY_MW = 0, + HICN_STRATEGY_RR, + HICN_STRATEGY_RP, + HICN_STRATEGY_LR, +}; + typedef hicn_face { /* IP local address */ @@ -360,6 +368,33 @@ define hicn_api_routes_dump u32 context; }; +define hicn_api_strategy_set +{ + /* Client identifier, set from api_main.my_client_index */ + u32 client_index; + + /* Arbitrary context, so client can match reply to request */ + u32 context; + + /* Fib prefix for the strategy */ + vl_api_prefix_t prefix; + + /* ID of the strategy to set for this prefix */ + vl_api_hicn_strategy_t strategy_id; +}; + +define hicn_api_strategy_set_reply +{ + /* Client identifier, set from api_main.my_client_index */ + u32 client_index; + + /* Arbitrary context, so client can match reply to request */ + u32 context; + + /* Return value, zero means all OK */ + i32 retval; +}; + define hicn_api_strategies_get { /* Client identifier, set from api_main.my_client_index */ @@ -381,7 +416,7 @@ define hicn_api_strategies_get_reply u8 n_strategies; /* Strategies */ - u32 strategy_id[256]; + vl_api_hicn_strategy_t strategy_id[256]; /* Return value, zero means all OK */ i32 retval; @@ -396,7 +431,7 @@ define hicn_api_strategy_get u32 context; /* Route prefix */ - u32 strategy_id; + vl_api_hicn_strategy_t strategy_id; }; define hicn_api_strategy_get_reply diff --git a/hicn-plugin/src/hicn_api.c b/hicn-plugin/src/hicn_api.c index 85279eb0b..16e32dd9b 100644 --- a/hicn-plugin/src/hicn_api.c +++ b/hicn-plugin/src/hicn_api.c @@ -450,6 +450,28 @@ vl_api_hicn_api_strategies_get_t_handler (vl_api_hicn_api_strategies_get_t *mp) })); } +static void +vl_api_hicn_api_strategy_set_t_handler (vl_api_hicn_api_strategy_set_t *mp) +{ + vl_api_hicn_api_strategy_set_reply_t *rmp; + int rv = HICN_ERROR_NONE; + fib_prefix_t prefix; + vl_api_hicn_strategy_t strategy_id; + + hicn_main_t *sm = &hicn_main; + + // Decode prefix + ip_prefix_decode (&mp->prefix, &prefix); + + // Decode strategy id + strategy_id = clib_net_to_host_u32 (mp->strategy_id); + + // Try to set the strategy + rv = hicn_route_set_strategy (&prefix, strategy_id); + + REPLY_MACRO (VL_API_HICN_API_STRATEGY_SET_REPLY); +} + static void vl_api_hicn_api_strategy_get_t_handler (vl_api_hicn_api_strategy_get_t *mp) { @@ -458,7 +480,7 @@ vl_api_hicn_api_strategy_get_t_handler (vl_api_hicn_api_strategy_get_t *mp) hicn_main_t *sm = &hicn_main; - u32 strategy_id = clib_net_to_host_u32 (mp->strategy_id); + vl_api_hicn_strategy_t strategy_id = clib_net_to_host_u32 (mp->strategy_id); rv = hicn_dpo_strategy_id_is_valid (strategy_id); REPLY_MACRO2 (VL_API_HICN_API_STRATEGY_GET_REPLY /* , rmp, mp, rv */, ({ diff --git a/hicn-plugin/src/hicn_api_test.c b/hicn-plugin/src/hicn_api_test.c index fbba5ffc3..cb5da09a4 100644 --- a/hicn-plugin/src/hicn_api_test.c +++ b/hicn-plugin/src/hicn_api_test.c @@ -33,179 +33,11 @@ #include #include +#include /* Declare message IDs */ #include -/* SUPPORTING FUNCTIONS NOT LOADED BY VPP_API_TEST */ -uword -unformat_ip46_address (unformat_input_t *input, va_list *args) -{ - ip46_address_t *ip46 = va_arg (*args, ip46_address_t *); - ip46_type_t type = va_arg (*args, ip46_type_t); - if ((type != IP46_TYPE_IP6) && - unformat (input, "%U", unformat_ip4_address, &ip46->ip4)) - { - ip46_address_mask_ip4 (ip46); - return 1; - } - else if ((type != IP46_TYPE_IP4) && - unformat (input, "%U", unformat_ip6_address, &ip46->ip6)) - { - return 1; - } - return 0; -} - -static ip46_type_t -ip_address_union_decode (const vl_api_address_union_t *in, - vl_api_address_family_t af, ip46_address_t *out) -{ - ip46_type_t type; - - switch (clib_net_to_host_u32 (af)) - { - case ADDRESS_IP4: - clib_memset (out, 0, sizeof (*out)); - clib_memcpy (&out->ip4, &in->ip4, sizeof (out->ip4)); - type = IP46_TYPE_IP4; - break; - case ADDRESS_IP6: - clib_memcpy (&out->ip6, &in->ip6, sizeof (out->ip6)); - type = IP46_TYPE_IP6; - break; - default: - ASSERT (!"Unkown address family in API address type"); - type = IP46_TYPE_ANY; - break; - } - - return type; -} - -void -ip6_address_encode (const ip6_address_t *in, vl_api_ip6_address_t out) -{ - clib_memcpy (out, in, sizeof (*in)); -} - -void -ip6_address_decode (const vl_api_ip6_address_t in, ip6_address_t *out) -{ - clib_memcpy (out, in, sizeof (*out)); -} - -void -ip4_address_encode (const ip4_address_t *in, vl_api_ip4_address_t out) -{ - clib_memcpy (out, in, sizeof (*in)); -} - -void -ip4_address_decode (const vl_api_ip4_address_t in, ip4_address_t *out) -{ - clib_memcpy (out, in, sizeof (*out)); -} - -static void -ip_address_union_encode (const ip46_address_t *in, vl_api_address_family_t af, - vl_api_address_union_t *out) -{ - if (ADDRESS_IP6 == clib_net_to_host_u32 (af)) - ip6_address_encode (&in->ip6, out->ip6); - else - ip4_address_encode (&in->ip4, out->ip4); -} - -ip46_type_t -ip_address_decode (const vl_api_address_t *in, ip46_address_t *out) -{ - return (ip_address_union_decode (&in->un, in->af, out)); -} - -void -ip_address_encode (const ip46_address_t *in, ip46_type_t type, - vl_api_address_t *out) -{ - switch (type) - { - case IP46_TYPE_IP4: - out->af = clib_net_to_host_u32 (ADDRESS_IP4); - break; - case IP46_TYPE_IP6: - out->af = clib_net_to_host_u32 (ADDRESS_IP6); - break; - case IP46_TYPE_ANY: - if (ip46_address_is_ip4 (in)) - out->af = clib_net_to_host_u32 (ADDRESS_IP4); - else - out->af = clib_net_to_host_u32 (ADDRESS_IP6); - break; - } - ip_address_union_encode (in, out->af, &out->un); -} - -fib_protocol_t -fib_proto_from_ip46 (ip46_type_t iproto) -{ - switch (iproto) - { - case IP46_TYPE_IP4: - return FIB_PROTOCOL_IP4; - case IP46_TYPE_IP6: - return FIB_PROTOCOL_IP6; - case IP46_TYPE_ANY: - ASSERT (0); - return FIB_PROTOCOL_IP4; - } - - ASSERT (0); - return FIB_PROTOCOL_IP4; -} - -ip46_type_t -fib_proto_to_ip46 (fib_protocol_t fproto) -{ - switch (fproto) - { - case FIB_PROTOCOL_IP4: - return (IP46_TYPE_IP4); - case FIB_PROTOCOL_IP6: - return (IP46_TYPE_IP6); - case FIB_PROTOCOL_MPLS: - return (IP46_TYPE_ANY); - } - ASSERT (0); - return (IP46_TYPE_ANY); -} - -void -ip_prefix_decode (const vl_api_prefix_t *in, fib_prefix_t *out) -{ - switch (clib_net_to_host_u32 (in->address.af)) - { - case ADDRESS_IP4: - out->fp_proto = FIB_PROTOCOL_IP4; - break; - case ADDRESS_IP6: - out->fp_proto = FIB_PROTOCOL_IP6; - break; - } - out->fp_len = in->len; - out->___fp___pad = 0; - ip_address_decode (&in->address, &out->fp_addr); -} - -void -ip_prefix_encode (const fib_prefix_t *in, vl_api_prefix_t *out) -{ - out->len = in->fp_len; - ip_address_encode (&in->fp_addr, fib_proto_to_ip46 (in->fp_proto), - &out->address); -} - -///////////////////////////////////////////////////// - #define HICN_FACE_NULL ~0 typedef struct @@ -256,6 +88,7 @@ foreach_standard_reply_retval_handler; _ (HICN_API_ROUTE_GET_REPLY, hicn_api_route_get_reply) \ _ (HICN_API_ROUTES_DETAILS, hicn_api_routes_details) \ _ (HICN_API_STRATEGIES_GET_REPLY, hicn_api_strategies_get_reply) \ + _ (HICN_API_STRATEGY_SET_REPLY, hicn_api_strategy_set_reply) \ _ (HICN_API_STRATEGY_GET_REPLY, hicn_api_strategy_get_reply) \ _ (HICN_API_ENABLE_DISABLE_REPLY, hicn_api_enable_disable_reply) \ _ (HICN_API_UDP_TUNNEL_ADD_DEL_REPLY, hicn_api_udp_tunnel_add_del_reply) @@ -899,6 +732,62 @@ vl_api_hicn_api_strategies_get_reply_t_handler ( fformat (vam->ofp, "%s", sbuf); } +static int +api_hicn_api_strategy_set (vat_main_t *vam) +{ + unformat_input_t *input = vam->input; + vl_api_hicn_api_strategy_set_t *mp; + int ret; + int addpfx = -1; + fib_prefix_t fib_prefix; + ip46_address_t address; + int plen; + + vl_api_hicn_strategy_t strategy_id = HICN_STRATEGY_NULL; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "strategy %d", &strategy_id)) + { + addpfx = 2; + } + else if (addpfx != -1 && + unformat (input, "prefix %U/%d", unformat_ip46_address, + &address, IP46_TYPE_ANY, &plen)) + { + ; + } + else + { + clib_warning ("Error parsing input string."); + return 1; + } + } + + if (strategy_id == HICN_STRATEGY_NULL) + { + clib_warning ("Please specify strategy id..."); + return 1; + } + + // Get fib prefix + fib_prefix_from_ip46_addr (&address, &fib_prefix); + fib_prefix.fp_len = plen; + + /* Construct the API message */ + M (HICN_API_STRATEGY_SET, mp); + mp->strategy_id = clib_host_to_net_u32 (strategy_id); + ip_prefix_encode (&fib_prefix, &mp->prefix); + + /* send it... */ + S (mp); + + /* Wait for a reply... */ + W (ret); + + return ret; +} + static int api_hicn_api_strategy_get (vat_main_t *vam) { @@ -906,7 +795,7 @@ api_hicn_api_strategy_get (vat_main_t *vam) vl_api_hicn_api_strategy_get_t *mp; int ret; - u32 strategy_id = HICN_STRATEGY_NULL; + vl_api_hicn_strategy_t strategy_id = HICN_STRATEGY_NULL; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { @@ -963,6 +852,28 @@ vl_api_hicn_api_strategy_get_reply_t_handler ( fformat (vam->ofp, "%s", mp->description); } +static void +vl_api_hicn_api_strategy_set_reply_t_handler ( + vl_api_hicn_api_strategy_set_reply_t *mp) +{ + vat_main_t *vam = hicn_test_main.vat_main; + i32 retval = ntohl (mp->retval); + + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + return; + } + + vam->retval = retval; + vam->result_ready = 1; + + if (vam->retval < 0) + { + fformat (vam->ofp, " (API call error: %d)\n", vam->retval); + } +} + static int api_hicn_api_enable_disable (vat_main_t *vam) { -- cgit 1.2.3-korg