From 63e7bd9f2730b41f236e0b5d3731e6059210c4c4 Mon Sep 17 00:00:00 2001 From: Hongjun Ni Date: Tue, 27 Nov 2018 23:07:20 +0800 Subject: Rework vpp connection based on vapi library Change-Id: I3b41b4141fd7ef7577f4f2cc9193b9c623a9d6d7 Signed-off-by: Chuanguo Wang Signed-off-by: Hongjun Ni --- Makefile | 4 + src/CMakeLists.txt | 2 +- src/plugins/CMakeLists.txt | 15 +- src/plugins/sc_interface.c | 699 +++++++++++++++++++++++++++++++++ src/plugins/sc_interface.h | 58 +++ src/plugins/sc_plugins.c | 164 ++++++++ src/plugins/sc_plugins.h | 31 ++ src/plugins/vpp-interfaces.c | 571 --------------------------- src/scvpp/CMakeLists.txt | 40 ++ src/scvpp/libscvpp.pc.in | 10 + src/scvpp/src/CMakeLists.txt | 43 ++ src/scvpp/src/sc_vpp_operation.c | 73 ++++ src/scvpp/src/sc_vpp_operation.h | 104 +++++ src/scvpp/tests/CMakeLists.txt | 40 ++ src/scvpp/tests/scvpp_test.c | 54 +++ src/srvpp/CMakeLists.txt | 40 -- src/srvpp/libsrvpp.pc.in | 10 - src/srvpp/src/CMakeLists.txt | 44 --- src/srvpp/src/srvpp.c | 823 --------------------------------------- src/srvpp/src/srvpp.h | 185 --------- src/srvpp/src/srvpp_logger.c | 83 ---- src/srvpp/src/srvpp_logger.h | 89 ----- src/srvpp/tests/CMakeLists.txt | 40 -- src/srvpp/tests/srvpp_test.c | 160 -------- 24 files changed, 1332 insertions(+), 2050 deletions(-) create mode 100644 src/plugins/sc_interface.c create mode 100644 src/plugins/sc_interface.h create mode 100644 src/plugins/sc_plugins.c create mode 100644 src/plugins/sc_plugins.h delete mode 100644 src/plugins/vpp-interfaces.c create mode 100644 src/scvpp/CMakeLists.txt create mode 100644 src/scvpp/libscvpp.pc.in create mode 100644 src/scvpp/src/CMakeLists.txt create mode 100644 src/scvpp/src/sc_vpp_operation.c create mode 100644 src/scvpp/src/sc_vpp_operation.h create mode 100644 src/scvpp/tests/CMakeLists.txt create mode 100644 src/scvpp/tests/scvpp_test.c delete mode 100644 src/srvpp/CMakeLists.txt delete mode 100644 src/srvpp/libsrvpp.pc.in delete mode 100644 src/srvpp/src/CMakeLists.txt delete mode 100644 src/srvpp/src/srvpp.c delete mode 100644 src/srvpp/src/srvpp.h delete mode 100644 src/srvpp/src/srvpp_logger.c delete mode 100644 src/srvpp/src/srvpp_logger.h delete mode 100644 src/srvpp/tests/CMakeLists.txt delete mode 100644 src/srvpp/tests/srvpp_test.c diff --git a/Makefile b/Makefile index 4383135..0a6c1a1 100644 --- a/Makefile +++ b/Makefile @@ -110,3 +110,7 @@ checkstyle: fixstyle: @build-root/scripts/checkstyle.sh --fix +build_scvpp: + @mkdir $(BR)/build-scvpp/;cd $(BR)/build-scvpp;cmake $(WS_ROOT)/src/scvpp/;make install; +build: + @mkdir $(BR)/build-plugins/;cd $(BR)/build-plugins/;cmake $(WS_ROOT)/src/plugins/;make install; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8d31550..6937746 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,5 +31,5 @@ set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG -O2") set(CMAKE_C_FLAGS_DEBUG "-g -O0") # add subdirectories -add_subdirectory(srvpp) +add_subdirectory(scvpp) add_subdirectory(plugins) diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index 41915a1..0c39258 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -18,7 +18,7 @@ project(sysrepo-vpp-plugins) find_package(PkgConfig) pkg_check_modules(SYSREPO REQUIRED libsysrepo) -pkg_check_modules(SRVPP REQUIRED libsrvpp) +pkg_check_modules(SCVPP REQUIRED libscvpp) # get sysrepo plugins directory from pkgconfig if (NOT SR_PLUGINS_DIR) @@ -31,9 +31,16 @@ if (NOT SR_PLUGINS_DIR) message(FATAL_ERROR "Cannot get sysrepo plugins directory due to missing pkg-config, set SR_PLUGINS_DIR manually.") endif() +# plugins sources +set(PLUGINS_SOURCES + sc_interface.c + sc_plugins.c +) + + # build the source code into shared library -add_library(vpp-interfaces SHARED vpp-interfaces.c) -target_link_libraries(vpp-interfaces ${SYSREPO_LIBRARIES} ${SRVPP_LIBRARIES}) +add_library(vpp-plugins SHARED ${PLUGINS_SOURCES}) +target_link_libraries(vpp-plugins ${SYSREPO_LIBRARIES} ${SCVPP_LIBRARIES}) # install the plugin into plugins dir -install(TARGETS vpp-interfaces DESTINATION ${SR_PLUGINS_DIR}) +install(TARGETS vpp-plugins DESTINATION ${SR_PLUGINS_DIR}) diff --git a/src/plugins/sc_interface.c b/src/plugins/sc_interface.c new file mode 100644 index 0000000..41fd535 --- /dev/null +++ b/src/plugins/sc_interface.c @@ -0,0 +1,699 @@ +/* + * Copyright (c) 2016 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 +#include +#include +#include + +#include "sc_interface.h" +#include +#include +#include +#include +#include +#include + +DEFINE_VAPI_MSG_IDS_INTERFACE_API_JSON; + +/** + * @brief Helper function for converting netmask into prefix length. + */ +static uint8_t +netmask_to_prefix(const char *netmask) +{ + in_addr_t n = 0; + uint8_t i = 0; + + inet_pton(AF_INET, netmask, &n); + + while (n > 0) { + n = n >> 1; + i++; + } + + return i; +} + +/** + * @brief Helper function for converting IPv4/IPv6 address string into binary representation. + */ +static void +ip_addr_str_to_binary(const char *ip_address_str, uint8_t *ip_address_bin, bool is_ipv6) +{ + struct in6_addr addr6 = { 0, }; + struct in_addr addr4 = { 0, }; + + if (is_ipv6) { + inet_pton(AF_INET6, ip_address_str, &(addr6)); + memcpy(ip_address_bin, &addr6, sizeof(addr6)); + } else { + inet_pton(AF_INET, ip_address_str, &(addr4)); + memcpy(ip_address_bin, &addr4, sizeof(addr4)); + } +} + +/** + * @brief Enable or disable given interface. + */ +static int +interface_enable_disable(const char *if_name, bool enable) +{ + uint32_t if_index = ~0; + int rc = 0; + + SRP_LOG_DBG("%s interface '%s'", enable ? "Enabling" : "Disabling", if_name); + + /* get interface index */ + rc = sc_interface_name2index(if_name, &if_index); + if (0 != rc) { + SRP_LOG_ERR("Invalid interface name: %s", if_name); + return SR_ERR_INVAL_ARG; + } + + /* enable/disable interface */ + rc = sc_setInterfaceFlags(if_index, (uint8_t)enable); + if (0 != rc) { + SRP_LOG_ERR("Error by processing of the sw_interface_set_flags request, rc=%d", rc); + return SR_ERR_OPERATION_FAILED; + } else { + return SR_ERR_OK; + } +} + +/** + * @brief Callback to be called by any config change of "/ietf-interfaces:interfaces/interface/enabled" leaf. + */ +static int +sc_interface_enable_disable_cb(sr_session_ctx_t *session, const char *xpath, sr_notif_event_t event, void *private_ctx) +{ + char *if_name = NULL; + sr_change_iter_t *iter = NULL; + sr_change_oper_t op = SR_OP_CREATED; + sr_val_t *old_val = NULL; + sr_val_t *new_val = NULL; + sr_xpath_ctx_t xpath_ctx = { 0, }; + int rc = SR_ERR_OK, op_rc = SR_ERR_OK; + + /* no-op for apply, we only care about SR_EV_ENABLED, SR_EV_VERIFY, SR_EV_ABORT */ + if (SR_EV_APPLY == event) { + return SR_ERR_OK; + } + SRP_LOG_DBG("'%s' modified, event=%d", xpath, event); + + /* get changes iterator */ + rc = sr_get_changes_iter(session, xpath, &iter); + if (SR_ERR_OK != rc) { + SRP_LOG_ERR("Unable to retrieve change iterator: %s", sr_strerror(rc)); + return rc; + } + + /* iterate over all changes */ + while ((SR_ERR_OK == op_rc || event == SR_EV_ABORT) && + (SR_ERR_OK == (rc = sr_get_change_next(session, iter, &op, &old_val, &new_val)))) { + + SRP_LOG_DBG("A change detected in '%s', op=%d", new_val ? new_val->xpath : old_val->xpath, op); + if_name = sr_xpath_key_value(new_val ? new_val->xpath : old_val->xpath, "interface", "name", &xpath_ctx); + switch (op) { + case SR_OP_CREATED: + case SR_OP_MODIFIED: + op_rc = interface_enable_disable(if_name, new_val->data.bool_val); + break; + case SR_OP_DELETED: + op_rc = interface_enable_disable(if_name, false /* !enable */); + break; + default: + break; + } + sr_xpath_recover(&xpath_ctx); + if (SR_ERR_INVAL_ARG == op_rc) { + sr_set_error(session, "Invalid interface name.", new_val ? new_val->xpath : old_val->xpath); + } + sr_free_val(old_val); + sr_free_val(new_val); + } + sr_free_change_iter(iter); + + return op_rc; +} + +/** + * @brief Add or remove IPv4/IPv6 address to/from an interface. + */ +static int +interface_ipv46_config_add_remove(const char *if_name, uint8_t *addr, uint8_t prefix, bool is_ipv6, bool add) +{ + uint32_t if_index = ~0; + int rc = 0; + + SRP_LOG_DBG("%s IP config on interface '%s'.", add ? "Adding" : "Removing", if_name); + + /* get interface index */ + rc = sc_interface_name2index(if_name, &if_index); + if (0 != rc) { + SRP_LOG_ERR("Invalid interface name: %s", if_name); + return SR_ERR_INVAL_ARG; + } + + /* add del addr */ + rc = sc_interface_add_del_addr(if_index, (uint8_t)add, (uint8_t)is_ipv6, 0, prefix, addr); + if (0 != rc) { + SRP_LOG_ERR("Error by processing of the sw_interface_set_flags request, rc=%d", rc); + return SR_ERR_OPERATION_FAILED; + } else { + return SR_ERR_OK; + } +} +int sc_initSwInterfaceDumpCTX(sc_sw_interface_dump_ctx * dctx) +{ + if(dctx == NULL) + return -1; + + dctx->intfcArray = NULL; + dctx->last_called = false; + dctx->capacity = 0; + dctx->num_ifs = 0; + return 0; +} +int sc_freeSwInterfaceDumpCTX(sc_sw_interface_dump_ctx * dctx) +{ + if(dctx == NULL) + return -1; + + if(dctx->intfcArray != NULL) + { + printf("free intfcArray %p\n", dctx->intfcArray); + free(dctx->intfcArray); + } + + return sc_initSwInterfaceDumpCTX(dctx); +} +vapi_error_e +sc_sw_interface_dump_cb (struct vapi_ctx_s *ctx, void *callback_ctx, + vapi_error_e rv, bool is_last, + vapi_payload_sw_interface_details * reply) +{ + sc_sw_interface_dump_ctx *dctx = callback_ctx; + if (is_last) + { + dctx->last_called = true; + } + else + { + //printf ("Interface dump entry: [%u]: %s\n", reply->sw_if_index, + // reply->interface_name); + if(dctx->capacity == 0 && dctx->intfcArray == NULL) + { + dctx->capacity = 10; + dctx->intfcArray = (scVppIntfc*)malloc( sizeof(scVppIntfc)*dctx->capacity ); + } + if(dctx->num_ifs >= dctx->capacity-1) + { + + dctx->capacity += 10; + dctx->intfcArray = (scVppIntfc*)realloc(dctx->intfcArray, sizeof(scVppIntfc)*dctx->capacity ); + } + + dctx->intfcArray[dctx->num_ifs].sw_if_index = reply->sw_if_index; + strncpy(dctx->intfcArray[dctx->num_ifs].interface_name, reply->interface_name, VPP_INTFC_NAME_LEN); + dctx->intfcArray[dctx->num_ifs].l2_address_length = reply->l2_address_length; + memcpy(dctx->intfcArray[dctx->num_ifs].l2_address, reply->l2_address, reply->l2_address_length ); + //dctx->intfcArray[dctx->num_ifs].link_speed = reply->link_speed; +#define ONE_MEGABIT (uint64_t)1000000 + switch (reply->link_speed << VNET_HW_INTERFACE_FLAG_SPEED_SHIFT) + { + case VNET_HW_INTERFACE_FLAG_SPEED_10M: + dctx->intfcArray[dctx->num_ifs].link_speed = 10 * ONE_MEGABIT; + break; + case VNET_HW_INTERFACE_FLAG_SPEED_100M: + dctx->intfcArray[dctx->num_ifs].link_speed = 100 * ONE_MEGABIT; + break; + case VNET_HW_INTERFACE_FLAG_SPEED_1G: + dctx->intfcArray[dctx->num_ifs].link_speed = 1000 * ONE_MEGABIT; + break; + case VNET_HW_INTERFACE_FLAG_SPEED_2_5G: + dctx->intfcArray[dctx->num_ifs].link_speed = 2500 * ONE_MEGABIT; + break; + case VNET_HW_INTERFACE_FLAG_SPEED_5G: + dctx->intfcArray[dctx->num_ifs].link_speed = 5000 * ONE_MEGABIT; + break; + case VNET_HW_INTERFACE_FLAG_SPEED_10G: + dctx->intfcArray[dctx->num_ifs].link_speed = 10000 * ONE_MEGABIT; + break; + case VNET_HW_INTERFACE_FLAG_SPEED_20G: + dctx->intfcArray[dctx->num_ifs].link_speed = 20000 * ONE_MEGABIT; + break; + case VNET_HW_INTERFACE_FLAG_SPEED_25G: + dctx->intfcArray[dctx->num_ifs].link_speed = 25000 * ONE_MEGABIT; + break; + case VNET_HW_INTERFACE_FLAG_SPEED_40G: + dctx->intfcArray[dctx->num_ifs].link_speed = 40000 * ONE_MEGABIT; + break; + case VNET_HW_INTERFACE_FLAG_SPEED_50G: + dctx->intfcArray[dctx->num_ifs].link_speed = 50000 * ONE_MEGABIT; + break; + case VNET_HW_INTERFACE_FLAG_SPEED_56G: + dctx->intfcArray[dctx->num_ifs].link_speed = 56000 * ONE_MEGABIT; + break; + case VNET_HW_INTERFACE_FLAG_SPEED_100G: + dctx->intfcArray[dctx->num_ifs].link_speed = 100000 * ONE_MEGABIT; + break; + default: + dctx->intfcArray[dctx->num_ifs].link_speed = 0; + break; + } + + dctx->intfcArray[dctx->num_ifs].link_mtu = reply->link_mtu; + dctx->intfcArray[dctx->num_ifs].admin_up_down = reply->admin_up_down; + dctx->intfcArray[dctx->num_ifs].link_up_down = reply->link_up_down; + + dctx->num_ifs += 1; + } + return VAPI_OK; +} +int sc_swInterfaceDump(sc_sw_interface_dump_ctx * dctx) +{ + if(dctx == NULL) + { + return -1; + } + + //sc_sw_interface_dump_ctx dctx = { false, 0, 0, 0 }; + vapi_msg_sw_interface_dump *dump; + vapi_error_e rv; + // dctx->last_called = false; + sc_initSwInterfaceDumpCTX(dctx); + dump = vapi_alloc_sw_interface_dump (g_vapi_ctx_instance); + dump->payload.name_filter_valid = 0; + memset (dump->payload.name_filter, 0, sizeof (dump->payload.name_filter)); + while (VAPI_EAGAIN == + (rv = + vapi_sw_interface_dump (g_vapi_ctx_instance, dump, sc_sw_interface_dump_cb, + dctx))); + + return dctx->num_ifs; +} + +u32 sc_interface_name2index(const char *name, u32* if_index) +{ + u32 ret = -1; + sc_sw_interface_dump_ctx dctx = {false, 0, 0, 0}; + vapi_msg_sw_interface_dump *dump; + vapi_error_e rv; + dctx.last_called = false; + dump = vapi_alloc_sw_interface_dump(g_vapi_ctx_instance); + dump->payload.name_filter_valid = 0; + memset(dump->payload.name_filter, 0, sizeof(dump->payload.name_filter)); + while (VAPI_EAGAIN == (rv = vapi_sw_interface_dump(g_vapi_ctx_instance, dump, sc_sw_interface_dump_cb, &dctx))) + ; + printf("interface dump over, there are %d intfc\n", dctx.num_ifs); + int i = 0; + for (; i < dctx.num_ifs; ++i) + { + printf("Index[%d] %s\n", dctx.intfcArray[i].sw_if_index, dctx.intfcArray[i].interface_name); + if (strcmp(dctx.intfcArray[i].interface_name, name) == 0) + { + *if_index = dctx.intfcArray[i].sw_if_index; + ret = 0; + break; + } + } + sc_freeSwInterfaceDumpCTX(&dctx); + + return ret; +} + +i32 sc_interface_add_del_addr( u32 sw_if_index, u8 is_add, u8 is_ipv6, u8 del_all, + u8 address_length, u8 address[VPP_IP6_ADDRESS_LEN] ) +{ + i32 ret = -1; + vapi_msg_sw_interface_add_del_address *msg = vapi_alloc_sw_interface_add_del_address(g_vapi_ctx_instance); + msg->payload.sw_if_index = sw_if_index; + msg->payload.is_add = is_add; + msg->payload.is_ipv6 = is_ipv6; + msg->payload.del_all = del_all; + msg->payload.address_length = address_length; + memcpy(msg->payload.address, address, VPP_IP6_ADDRESS_LEN); + vapi_msg_sw_interface_add_del_address_hton (msg); + + vapi_error_e rv = vapi_send (g_vapi_ctx_instance, msg); + + vapi_msg_sw_interface_add_del_address_reply *resp; + + SC_VPP_VAPI_RECV; + + vapi_msg_sw_interface_add_del_address_reply_hton(resp); + printf("addDelInterfaceAddr : %d \n", resp->payload.retval); + ret = resp->payload.retval; + vapi_msg_free (g_vapi_ctx_instance, resp); + return ret; +} +i32 sc_setInterfaceFlags(u32 sw_if_index, u8 admin_up_down) +{ + i32 ret = -1; + vapi_msg_sw_interface_set_flags *msg = vapi_alloc_sw_interface_set_flags(g_vapi_ctx_instance); + msg->payload.sw_if_index = sw_if_index; + msg->payload.admin_up_down = admin_up_down; + vapi_msg_sw_interface_set_flags_hton (msg); + + vapi_error_e rv = vapi_send (g_vapi_ctx_instance, msg); + + vapi_msg_sw_interface_set_flags_reply *resp; + + SC_VPP_VAPI_RECV; + + vapi_msg_sw_interface_set_flags_reply_ntoh(resp); + printf("setInterfaceFlags:%d \n", resp->payload.retval); + ret = resp->payload.retval; + vapi_msg_free (g_vapi_ctx_instance, resp); + return ret; +} + + +/** + * @brief Modify existing IPv4/IPv6 config on an interface. + */ +static int +interface_ipv46_config_modify(sr_session_ctx_t *session, const char *if_name, + sr_val_t *old_val, sr_val_t *new_val, bool is_ipv6) +{ + sr_xpath_ctx_t xpath_ctx = { 0, }; + char *addr_str = NULL; + uint8_t addr[16] = { 0, }; + uint8_t prefix = 0; + int rc = SR_ERR_OK; + + SRP_LOG_DBG("Updating IP config on interface '%s'.", if_name); + + /* get old config to be deleted */ + if (SR_UINT8_T == old_val->type) { + prefix = old_val->data.uint8_val; + } else if (SR_STRING_T == old_val->type) { + prefix = netmask_to_prefix(old_val->data.string_val); + } else { + return SR_ERR_INVAL_ARG; + } + addr_str = sr_xpath_key_value((char*)old_val->xpath, "address", "ip", &xpath_ctx); + ip_addr_str_to_binary(addr_str, addr, is_ipv6); + sr_xpath_recover(&xpath_ctx); + + /* delete old IP config */ + rc = interface_ipv46_config_add_remove(if_name, addr, prefix, is_ipv6, false /* remove */); + if (SR_ERR_OK != rc) { + SRP_LOG_ERR("Unable to remove old IP address config, rc=%d", rc); + return rc; + } + + /* update the config with the new value */ + if (sr_xpath_node_name_eq(new_val->xpath, "prefix-length")) { + prefix = new_val->data.uint8_val; + } else if (sr_xpath_node_name_eq(new_val->xpath, "netmask")) { + prefix = netmask_to_prefix(new_val->data.string_val); + } + + /* set new IP config */ + rc = interface_ipv46_config_add_remove(if_name, addr, prefix, is_ipv6, true /* add */); + if (SR_ERR_OK != rc) { + SRP_LOG_ERR("Unable to remove old IP address config, rc=%d", rc); + return rc; + } + + return rc; +} + +/** + * @brief Callback to be called by any config change in subtrees "/ietf-interfaces:interfaces/interface/ietf-ip:ipv4/address" + * or "/ietf-interfaces:interfaces/interface/ietf-ip:ipv6/address". + */ +static int +sc_interface_ipv46_address_change_cb(sr_session_ctx_t *session, const char *xpath, sr_notif_event_t event, void *private_ctx) +{ + sr_change_iter_t *iter = NULL; + sr_change_oper_t op = SR_OP_CREATED; + sr_val_t *old_val = NULL; + sr_val_t *new_val = NULL; + sr_xpath_ctx_t xpath_ctx = { 0, }; + bool is_ipv6 = false, has_addr = false, has_prefix = false; + uint8_t addr[16] = { 0, }; + uint8_t prefix = 0; + char *node_name = NULL, *if_name = NULL; + int rc = SR_ERR_OK, op_rc = SR_ERR_OK; + + /* no-op for apply, we only care about SR_EV_ENABLED, SR_EV_VERIFY, SR_EV_ABORT */ + if (SR_EV_APPLY == event) { + return SR_ERR_OK; + } + SRP_LOG_DBG("'%s' modified, event=%d", xpath, event); + + /* check whether we are handling ipv4 or ipv6 config */ + node_name = sr_xpath_node_idx((char*)xpath, 2, &xpath_ctx); + if (NULL != node_name && 0 == strcmp(node_name, "ipv6")) { + is_ipv6 = true; + } + sr_xpath_recover(&xpath_ctx); + + /* get changes iterator */ + rc = sr_get_changes_iter(session, xpath, &iter); + if (SR_ERR_OK != rc) { + SRP_LOG_ERR("Unable to retrieve change iterator: %s", sr_strerror(rc)); + return rc; + } + + /* iterate over all changes */ + while ((SR_ERR_OK == op_rc || event == SR_EV_ABORT) && + (SR_ERR_OK == (rc = sr_get_change_next(session, iter, &op, &old_val, &new_val)))) { + + SRP_LOG_DBG("A change detected in '%s', op=%d", new_val ? new_val->xpath : old_val->xpath, op); + if_name = strdup(sr_xpath_key_value(new_val ? new_val->xpath : old_val->xpath, "interface", "name", &xpath_ctx)); + sr_xpath_recover(&xpath_ctx); + + switch (op) { + case SR_OP_CREATED: + if (SR_LIST_T == new_val->type) { + /* create on list item - reset state vars */ + has_addr = has_prefix = false; + } else { + if (sr_xpath_node_name_eq(new_val->xpath, "ip")) { + ip_addr_str_to_binary(new_val->data.string_val, addr, is_ipv6); + has_addr = true; + } else if (sr_xpath_node_name_eq(new_val->xpath, "prefix-length")) { + prefix = new_val->data.uint8_val; + has_prefix = true; + } else if (sr_xpath_node_name_eq(new_val->xpath, "netmask")) { + prefix = netmask_to_prefix(new_val->data.string_val); + has_prefix = true; + } + if (has_addr && has_prefix) { + op_rc = interface_ipv46_config_add_remove(if_name, addr, prefix, is_ipv6, true /* add */); + } + } + break; + case SR_OP_MODIFIED: + op_rc = interface_ipv46_config_modify(session, if_name, old_val, new_val, is_ipv6); + break; + case SR_OP_DELETED: + if (SR_LIST_T == old_val->type) { + /* delete on list item - reset state vars */ + has_addr = has_prefix = false; + } else { + if (sr_xpath_node_name_eq(old_val->xpath, "ip")) { + ip_addr_str_to_binary(old_val->data.string_val, addr, is_ipv6); + has_addr = true; + } else if (sr_xpath_node_name_eq(old_val->xpath, "prefix-length")) { + prefix = old_val->data.uint8_val; + has_prefix = true; + } else if (sr_xpath_node_name_eq(old_val->xpath, "netmask")) { + prefix = netmask_to_prefix(old_val->data.string_val); + has_prefix = true; + } + if (has_addr && has_prefix) { + op_rc = interface_ipv46_config_add_remove(if_name, addr, prefix, is_ipv6, false /* !add */); + } + } + break; + default: + break; + } + if (SR_ERR_INVAL_ARG == op_rc) { + sr_set_error(session, "Invalid interface name.", new_val ? new_val->xpath : old_val->xpath); + } + free(if_name); + sr_free_val(old_val); + sr_free_val(new_val); + } + sr_free_change_iter(iter); + + return op_rc; +} + +/** + * @brief Callback to be called by any config change under "/ietf-interfaces:interfaces-state/interface" path. + * Does not provide any functionality, needed just to cover not supported config leaves. + */ +static int +sc_interface_change_cb(sr_session_ctx_t *session, const char *xpath, sr_notif_event_t event, void *private_ctx) +{ + SRP_LOG_DBG("'%s' modified, event=%d", xpath, event); + + return SR_ERR_OK; +} + +/** + * @brief Callback to be called by any request for state data under "/ietf-interfaces:interfaces-state/interface" path. + */ +static int +sc_interface_state_cb(const char *xpath, sr_val_t **values, size_t *values_cnt, void *private_ctx) +{ + sr_val_t *values_arr = NULL; + size_t values_arr_size = 0, values_arr_cnt = 0; + sc_sw_interface_dump_ctx dctx; + scVppIntfc* if_details; + int rc = 0; + + SRP_LOG_DBG("Requesting state data for '%s'", xpath); +printf("%d\n", __LINE__); + printf("Requesting state data for '%s'\n", xpath); + + if (! sr_xpath_node_name_eq(xpath, "interface")) { + /* statistics, ipv4 and ipv6 state data not supported */ + printf("============= you want %s ?\n ", xpath); + *values = NULL; + *values_cnt = 0; + return SR_ERR_OK; + } + + /* dump interfaces */ + rc = sc_swInterfaceDump(&dctx); + if (rc <= 0) { + SRP_LOG_ERR_MSG("Error by processing of a interface dump request."); + sc_freeSwInterfaceDumpCTX(&dctx); + return SR_ERR_INTERNAL; + } + + /* allocate array of values to be returned */ + values_arr_size = dctx.num_ifs * 5; + rc = sr_new_values(values_arr_size, &values_arr); + if (0 != rc) { + sc_freeSwInterfaceDumpCTX(&dctx); + return rc; + } + printf("create %d sr vals\n", values_arr_size); + + size_t i = 0; + for (; i < dctx.num_ifs; i++) { + if_details = dctx.intfcArray+i; + + /* currently the only supported interface types are propVirtual / ethernetCsmacd */ + sr_val_build_xpath(&values_arr[values_arr_cnt], "%s[name='%s']/type", xpath, if_details->interface_name); + sr_val_set_str_data(&values_arr[values_arr_cnt], SR_IDENTITYREF_T, + strstr((char*)if_details->interface_name, "local0") ? "iana-if-type:propVirtual" : "iana-if-type:ethernetCsmacd"); +printf("\nset %s 's data\n",values_arr[values_arr_cnt].xpath); + values_arr_cnt++; + + sr_val_build_xpath(&values_arr[values_arr_cnt], "%s[name='%s']/admin-status", xpath, if_details->interface_name); + sr_val_set_str_data(&values_arr[values_arr_cnt], SR_ENUM_T, if_details->admin_up_down ? "up" : "down"); +printf("\nset %s 's data\n",values_arr[values_arr_cnt].xpath); + values_arr_cnt++; + + sr_val_build_xpath(&values_arr[values_arr_cnt], "%s[name='%s']/oper-status", xpath, if_details->interface_name); + sr_val_set_str_data(&values_arr[values_arr_cnt], SR_ENUM_T, if_details->link_up_down ? "up" : "down"); +printf("\nset %s 's data\n",values_arr[values_arr_cnt].xpath); + values_arr_cnt++; + + if (if_details->l2_address_length > 0) { + sr_val_build_xpath(&values_arr[values_arr_cnt], "%s[name='%s']/phys-address", xpath, if_details->interface_name); + sr_val_build_str_data(&values_arr[values_arr_cnt], SR_STRING_T, "%02x:%02x:%02x:%02x:%02x:%02x", + if_details->l2_address[0], if_details->l2_address[1], if_details->l2_address[2], + if_details->l2_address[3], if_details->l2_address[4], if_details->l2_address[5]); +printf("\nset %s 's data\n",values_arr[values_arr_cnt].xpath); + values_arr_cnt++; + } else { + sr_val_build_xpath(&values_arr[values_arr_cnt], "%s[name='%s']/phys-address", xpath, if_details->interface_name); + sr_val_build_str_data(&values_arr[values_arr_cnt], SR_STRING_T, "%02x:%02x:%02x:%02x:%02x:%02x", 0,0,0,0,0,0); + printf("\nset %s 's data\n",values_arr[values_arr_cnt].xpath); + values_arr_cnt++; + } + + sr_val_build_xpath(&values_arr[values_arr_cnt], "%s[name='%s']/speed", xpath, if_details->interface_name); + values_arr[values_arr_cnt].type = SR_UINT64_T; + values_arr[values_arr_cnt].data.uint64_val = if_details->link_speed; +printf("\nset %s 's data\n",values_arr[values_arr_cnt].xpath); + values_arr_cnt++; + } + + SRP_LOG_DBG("Returning %zu state data elements for '%s'", values_arr, xpath); + printf("\nReturning %d data elements for '%s'\n", values_arr_cnt, xpath); + + *values = values_arr; + *values_cnt = values_arr_cnt; + + sc_freeSwInterfaceDumpCTX(&dctx); + + return SR_ERR_OK; +} + +/** + * @brief Callback to be called by plugin daemon upon plugin load. + */ +int +sc_interface_subscribe_events(sr_session_ctx_t *session, + sr_subscription_ctx_t **subscription) +{ + int rc = SR_ERR_OK; + + SRP_LOG_DBG_MSG("Initializing vpp-interfaces plugin."); + + rc = sr_subtree_change_subscribe(session, "/ietf-interfaces:interfaces/interface", + sc_interface_change_cb, g_vapi_ctx_instance, 0, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_EV_ENABLED, subscription); + if (SR_ERR_OK != rc) { + goto error; + } + + rc = sr_subtree_change_subscribe(session, "/ietf-interfaces:interfaces/interface/enabled", + sc_interface_enable_disable_cb, g_vapi_ctx_instance, 100, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_EV_ENABLED, subscription); + if (SR_ERR_OK != rc) { + goto error; + } + + rc = sr_subtree_change_subscribe(session, "/ietf-interfaces:interfaces/interface/ietf-ip:ipv4/address", + sc_interface_ipv46_address_change_cb, g_vapi_ctx_instance, 99, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_EV_ENABLED, subscription); + if (SR_ERR_OK != rc) { + goto error; + } + + rc = sr_subtree_change_subscribe(session, "/ietf-interfaces:interfaces/interface/ietf-ip:ipv6/address", + sc_interface_ipv46_address_change_cb, g_vapi_ctx_instance, 98, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_EV_ENABLED, subscription); + if (SR_ERR_OK != rc) { + goto error; + } + + rc = sr_dp_get_items_subscribe(session, "/ietf-interfaces:interfaces-state", + sc_interface_state_cb, g_vapi_ctx_instance, SR_SUBSCR_DEFAULT/*SR_SUBSCR_CTX_REUSE*/, subscription); + if (SR_ERR_OK != rc) { + goto error; + } + + + SRP_LOG_INF_MSG("vpp-interfaces plugin initialized successfully."); + printf("vpp-interfaces plugin initialized successfully.\n"); + + return SR_ERR_OK; + +error: + SRP_LOG_ERR_MSG("Error by initialization of the sc_interfaces plugin."); + sr_plugin_cleanup_cb(session, g_vapi_ctx_instance); + return rc; +} + diff --git a/src/plugins/sc_interface.h b/src/plugins/sc_interface.h new file mode 100644 index 0000000..f346565 --- /dev/null +++ b/src/plugins/sc_interface.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2018 HUACHENTEL 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 SC_INTERFACE_H +#define SC_INTERFACE_H + +#include "sc_vpp_operation.h" + +#include + +typedef struct _s_vpp_interface_ +{ + u32 sw_if_index; + char interface_name[VPP_INTFC_NAME_LEN]; + u8 l2_address[VPP_MAC_ADDRESS_LEN]; + u32 l2_address_length; + u64 link_speed; + u16 link_mtu; + u8 admin_up_down; + u8 link_up_down; +}scVppIntfc; + +typedef struct _sc_sw_interface_dump_ctx +{ + u8 last_called; + size_t num_ifs; + size_t capacity; + scVppIntfc * intfcArray; +} sc_sw_interface_dump_ctx; + +int sc_initSwInterfaceDumpCTX(sc_sw_interface_dump_ctx * dctx); +int sc_freeSwInterfaceDumpCTX(sc_sw_interface_dump_ctx * dctx); +int sc_swInterfaceDump(sc_sw_interface_dump_ctx * dctx); +u32 sc_interface_name2index(const char *name, u32* if_index); + +i32 sc_interface_add_del_addr( u32 sw_if_index, u8 is_add, u8 is_ipv6, u8 del_all, + u8 address_length, u8 address[VPP_IP6_ADDRESS_LEN] ); +i32 sc_setInterfaceFlags(u32 sw_if_index, u8 admin_up_down); + + +int +sc_interface_subscribe_events(sr_session_ctx_t *session, + sr_subscription_ctx_t **subscription); + +#endif /* SC_INTERFACE_H */ + diff --git a/src/plugins/sc_plugins.c b/src/plugins/sc_plugins.c new file mode 100644 index 0000000..29d75bb --- /dev/null +++ b/src/plugins/sc_plugins.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2018 HUACHENTEL 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +DEFINE_VAPI_MSG_IDS_VPE_API_JSON; +DEFINE_VAPI_MSG_IDS_INTERFACE_API_JSON; +DEFINE_VAPI_MSG_IDS_L2_API_JSON; +DEFINE_VAPI_MSG_IDS_STATS_API_JSON; +DEFINE_VAPI_MSG_IDS_IP_API_JSON; +DEFINE_VAPI_MSG_IDS_TAP_API_JSON; +DEFINE_VAPI_MSG_IDS_IPSEC_API_JSON; +DEFINE_VAPI_MSG_IDS_VXLAN_API_JSON; +DEFINE_VAPI_MSG_IDS_HC_API_JSON; + + +#include "sc_plugins.h" +//#include "sc_ip.h" +#include "sc_interface.h" +//#include "sc_l2.h" +//#include "sc_vxlan.h" + +int sr_plugin_init_cb(sr_session_ctx_t *session, void **private_ctx) +{ + SC_INVOKE_BEGIN; + sr_subscription_ctx_t *subscription = NULL; + int rc = SR_ERR_OK; + rc = sc_connect_vpp(); + if (-1 == rc) + { + SC_LOG_ERR("vpp connect error , with return %d.", SR_ERR_INTERNAL); + return SR_ERR_INTERNAL; + } + + //SC_REGISTER_RPC_EVT_HANDLER(sc_ip_subscribe_route_events); + //SC_REGISTER_RPC_EVT_HANDLER(sc_vxlan_subscribe_tunnel_events); + //SC_REGISTER_RPC_EVT_HANDLER(sc_l2_bridge_domain_add_del_subscribe_events); + //SC_REGISTER_RPC_EVT_HANDLER(sc_l2_interface_set_l2_bridge_subscribe_events); + + //INTERFACE + sc_interface_subscribe_events(session, &subscription); + + /* set subscription as our private context */ + *private_ctx = subscription; + SC_INVOKE_END; + return SR_ERR_OK; +} + +void sr_plugin_cleanup_cb(sr_session_ctx_t *session, void *private_ctx) +{ + SC_INVOKE_BEGIN; + /* subscription was set as our private context */ + sr_unsubscribe(session, private_ctx); + SC_LOG_DBG_MSG("unload plugin ok."); + sc_disconnect_vpp(); + SC_LOG_DBG_MSG("plugin disconnect vpp ok."); + SC_INVOKE_END; +} + + +///############################# +#include +#include +#include +#include +#include +sr_subscription_ctx_t *subscription = NULL; +volatile int exit_application = 0; + +static void +sigint_handler(int signum) +{ + exit_application = 1; +} +int +subscribe_all_module_events(sr_session_ctx_t *session) +{ + sr_plugin_init_cb(session, (void**)&subscription); + +} +int +main(int argc, char **argv) +{ + sr_conn_ctx_t *connection = NULL; + sr_session_ctx_t *session = NULL; + int time_now; + int reg_time; + time_t now; + int rc = SR_ERR_OK; + int i = 0; + + /* connect to vpp */ + rc = sc_connect_vpp(); + if (-1 == rc){ + fprintf(stderr, "vpp connect error"); + return -1; + } + + /* connect to sysrepo */ + rc = sr_connect("cpe_application", SR_CONN_DEFAULT, &connection); + if (SR_ERR_OK != rc) { + fprintf(stderr, "Error by sr_connect: %s\n", sr_strerror(rc)); + goto cleanup; + } + + /* start session */ + rc = sr_session_start(connection, SR_DS_STARTUP, SR_SESS_DEFAULT, &session); + if (SR_ERR_OK != rc) { + fprintf(stderr, "Error by sr_session_start: %s\n", sr_strerror(rc)); + goto cleanup; + } + + /* subscribe all module events */ + rc = subscribe_all_module_events(session); + if (SR_ERR_OK != rc) { + fprintf(stderr, "Error by subscribe module events: %s\n", sr_strerror(rc)); + goto cleanup; + } + + /* loop until ctrl-c is pressed / SIGINT is received */ + signal(SIGINT, sigint_handler); + signal(SIGPIPE, SIG_IGN); + + int loopCount = 11; + while (!exit_application) { + sleep(2); + } + + printf("Application exit requested, exiting.\n"); + + cleanup: + if (NULL != subscription) { + sr_unsubscribe(session, subscription); + } + if (NULL != session) { + sr_session_stop(session); + } + if (NULL != connection) { + sr_disconnect(connection); + } + sc_disconnect_vpp(); + return rc; +} diff --git a/src/plugins/sc_plugins.h b/src/plugins/sc_plugins.h new file mode 100644 index 0000000..8b76a37 --- /dev/null +++ b/src/plugins/sc_plugins.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2018 HUACHENTEL 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 __SWEETCOMB_SYSREPO_PLUGINS__ +#define __SWEETCOMB_SYSREPO_PLUGINS__ + +#include +#include +#include + +//functions that sysrepo-plugin need +int sr_plugin_init_cb(sr_session_ctx_t *session, void **private_ctx); +void sr_plugin_cleanup_cb(sr_session_ctx_t *session, void *private_ctx); + +#endif //__SWEETCOMB_SYSREPO_PLUGINS__ + + + + diff --git a/src/plugins/vpp-interfaces.c b/src/plugins/vpp-interfaces.c deleted file mode 100644 index bb1f046..0000000 --- a/src/plugins/vpp-interfaces.c +++ /dev/null @@ -1,571 +0,0 @@ -/* - * Copyright (c) 2016 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 -#include -#include -#include - -#include -#include -#include -#include -#include - -/** forward declaration */ -void sr_plugin_cleanup_cb(sr_session_ctx_t *session, void *private_ctx); - -/** - * @brief Plugin context structure. - */ -typedef struct plugin_ctx_s { - srvpp_ctx_t *srvpp_ctx; /**< srvpp context. */ - sr_subscription_ctx_t *sr_subscription; /**< Sysrepo subscription context. */ -} plugin_ctx_t; - -/** - * @brief Helper function for converting netmask into prefix length. - */ -static uint8_t -netmask_to_prefix(const char *netmask) -{ - in_addr_t n = 0; - uint8_t i = 0; - - inet_pton(AF_INET, netmask, &n); - - while (n > 0) { - n = n >> 1; - i++; - } - - return i; -} - -/** - * @brief Helper function for converting IPv4/IPv6 address string into binary representation. - */ -static void -ip_addr_str_to_binary(const char *ip_address_str, uint8_t *ip_address_bin, bool is_ipv6) -{ - struct in6_addr addr6 = { 0, }; - struct in_addr addr4 = { 0, }; - - if (is_ipv6) { - inet_pton(AF_INET6, ip_address_str, &(addr6)); - memcpy(ip_address_bin, &addr6, sizeof(addr6)); - } else { - inet_pton(AF_INET, ip_address_str, &(addr4)); - memcpy(ip_address_bin, &addr4, sizeof(addr4)); - } -} - -/** - * @brief Helper function for converting VPP interface speed information into actual number in bits per second. - */ -static uint64_t -get_if_link_speed(uint8_t speed) -{ -#define ONE_MEGABIT (uint64_t)1000000 - switch (speed) { - case 1: - /* 10M */ - return 10 * ONE_MEGABIT; - break; - case 2: - /* 100M */ - return 100 * ONE_MEGABIT; - break; - case 4: - /* 1G */ - return 1000 * ONE_MEGABIT; - break; - case 8: - /* 10G */ - return 10000 * ONE_MEGABIT; - break; - case 16: - /* 40 G */ - return 40000 * ONE_MEGABIT; - break; - case 32: - /* 100G */ - return 100000 * ONE_MEGABIT; - break; - default: - return 0; - } -} - -/** - * @brief Enable or disable given interface. - */ -static int -interface_enable_disable(plugin_ctx_t *plugin_ctx, const char *if_name, bool enable) -{ - vl_api_sw_interface_set_flags_t *if_set_flags_req = NULL; - uint32_t if_index = ~0; - int rc = 0; - - SRP_LOG_DBG("%s interface '%s'", enable ? "Enabling" : "Disabling", if_name); - - /* get interface index */ - rc = srvpp_get_if_index(plugin_ctx->srvpp_ctx, if_name, &if_index); - if (0 != rc) { - SRP_LOG_ERR("Invalid interface name: %s", if_name); - return SR_ERR_INVAL_ARG; - } - - /* process VPP API request */ - if_set_flags_req = srvpp_alloc_msg(VL_API_SW_INTERFACE_SET_FLAGS, sizeof(*if_set_flags_req)); - - if_set_flags_req->sw_if_index = ntohl(if_index); - if_set_flags_req->admin_up_down = (uint8_t)enable; - - rc = srvpp_send_request(plugin_ctx->srvpp_ctx, if_set_flags_req, NULL); - - if (0 != rc) { - SRP_LOG_ERR("Error by processing of the sw_interface_set_flags request, rc=%d", rc); - return SR_ERR_OPERATION_FAILED; - } else { - return SR_ERR_OK; - } -} - -/** - * @brief Callback to be called by any config change of "/ietf-interfaces:interfaces/interface/enabled" leaf. - */ -static int -interface_enable_disable_cb(sr_session_ctx_t *session, const char *xpath, sr_notif_event_t event, void *private_ctx) -{ - char *if_name = NULL; - sr_change_iter_t *iter = NULL; - sr_change_oper_t op = SR_OP_CREATED; - sr_val_t *old_val = NULL; - sr_val_t *new_val = NULL; - sr_xpath_ctx_t xpath_ctx = { 0, }; - int rc = SR_ERR_OK, op_rc = SR_ERR_OK; - - /* no-op for apply, we only care about SR_EV_ENABLED, SR_EV_VERIFY, SR_EV_ABORT */ - if (SR_EV_APPLY == event) { - return SR_ERR_OK; - } - SRP_LOG_DBG("'%s' modified, event=%d", xpath, event); - - /* get changes iterator */ - rc = sr_get_changes_iter(session, xpath, &iter); - if (SR_ERR_OK != rc) { - SRP_LOG_ERR("Unable to retrieve change iterator: %s", sr_strerror(rc)); - return rc; - } - - /* iterate over all changes */ - while ((SR_ERR_OK == op_rc || event == SR_EV_ABORT) && - (SR_ERR_OK == (rc = sr_get_change_next(session, iter, &op, &old_val, &new_val)))) { - - SRP_LOG_DBG("A change detected in '%s', op=%d", new_val ? new_val->xpath : old_val->xpath, op); - if_name = sr_xpath_key_value(new_val ? new_val->xpath : old_val->xpath, "interface", "name", &xpath_ctx); - switch (op) { - case SR_OP_CREATED: - case SR_OP_MODIFIED: - op_rc = interface_enable_disable(private_ctx, if_name, new_val->data.bool_val); - break; - case SR_OP_DELETED: - op_rc = interface_enable_disable(private_ctx, if_name, false /* !enable */); - break; - default: - break; - } - sr_xpath_recover(&xpath_ctx); - if (SR_ERR_INVAL_ARG == op_rc) { - sr_set_error(session, "Invalid interface name.", new_val ? new_val->xpath : old_val->xpath); - } - sr_free_val(old_val); - sr_free_val(new_val); - } - sr_free_change_iter(iter); - - return op_rc; -} - -/** - * @brief Add or remove IPv4/IPv6 address to/from an interface. - */ -static int -interface_ipv46_config_add_remove(plugin_ctx_t *plugin_ctx, const char *if_name, uint8_t *addr, uint8_t prefix, - bool is_ipv6, bool add) -{ - vl_api_sw_interface_add_del_address_t *add_del_req = NULL; - uint32_t if_index = ~0; - int rc = 0; - - SRP_LOG_DBG("%s IP config on interface '%s'.", add ? "Adding" : "Removing", if_name); - - /* get interface index */ - rc = srvpp_get_if_index(plugin_ctx->srvpp_ctx, if_name, &if_index); - if (0 != rc) { - SRP_LOG_ERR("Invalid interface name: %s", if_name); - return SR_ERR_INVAL_ARG; - } - - /* process VPP API request */ - add_del_req = srvpp_alloc_msg(VL_API_SW_INTERFACE_ADD_DEL_ADDRESS, sizeof(*add_del_req)); - - memcpy(&add_del_req->address, addr, is_ipv6 ? 16 : 4); - add_del_req->is_ipv6 = (uint32_t)is_ipv6; - add_del_req->address_length = prefix; - - add_del_req->sw_if_index = ntohl(if_index); - add_del_req->is_add = (uint32_t)add; - - rc = srvpp_send_request(plugin_ctx->srvpp_ctx, add_del_req, NULL); - - if (0 != rc) { - SRP_LOG_ERR("Error by processing of the sw_interface_set_flags request, rc=%d", rc); - return SR_ERR_OPERATION_FAILED; - } else { - return SR_ERR_OK; - } -} - -/** - * @brief Modify existing IPv4/IPv6 config on an interface. - */ -static int -interface_ipv46_config_modify(plugin_ctx_t *plugin_ctx, sr_session_ctx_t *session, const char *if_name, - sr_val_t *old_val, sr_val_t *new_val, bool is_ipv6) -{ - sr_xpath_ctx_t xpath_ctx = { 0, }; - char *addr_str = NULL; - uint8_t addr[16] = { 0, }; - uint8_t prefix = 0; - int rc = SR_ERR_OK; - - SRP_LOG_DBG("Updating IP config on interface '%s'.", if_name); - - /* get old config to be deleted */ - if (SR_UINT8_T == old_val->type) { - prefix = old_val->data.uint8_val; - } else if (SR_STRING_T == old_val->type) { - prefix = netmask_to_prefix(old_val->data.string_val); - } else { - return SR_ERR_INVAL_ARG; - } - addr_str = sr_xpath_key_value((char*)old_val->xpath, "address", "ip", &xpath_ctx); - ip_addr_str_to_binary(addr_str, addr, is_ipv6); - sr_xpath_recover(&xpath_ctx); - - /* delete old IP config */ - rc = interface_ipv46_config_add_remove(plugin_ctx, if_name, addr, prefix, is_ipv6, false /* remove */); - if (SR_ERR_OK != rc) { - SRP_LOG_ERR("Unable to remove old IP address config, rc=%d", rc); - return rc; - } - - /* update the config with the new value */ - if (sr_xpath_node_name_eq(new_val->xpath, "prefix-length")) { - prefix = new_val->data.uint8_val; - } else if (sr_xpath_node_name_eq(new_val->xpath, "netmask")) { - prefix = netmask_to_prefix(new_val->data.string_val); - } - - /* set new IP config */ - rc = interface_ipv46_config_add_remove(plugin_ctx, if_name, addr, prefix, is_ipv6, true /* add */); - if (SR_ERR_OK != rc) { - SRP_LOG_ERR("Unable to remove old IP address config, rc=%d", rc); - return rc; - } - - return rc; -} - -/** - * @brief Callback to be called by any config change in subtrees "/ietf-interfaces:interfaces/interface/ietf-ip:ipv4/address" - * or "/ietf-interfaces:interfaces/interface/ietf-ip:ipv6/address". - */ -static int -interface_ipv46_address_change_cb(sr_session_ctx_t *session, const char *xpath, sr_notif_event_t event, void *private_ctx) -{ - sr_change_iter_t *iter = NULL; - sr_change_oper_t op = SR_OP_CREATED; - sr_val_t *old_val = NULL; - sr_val_t *new_val = NULL; - sr_xpath_ctx_t xpath_ctx = { 0, }; - bool is_ipv6 = false, has_addr = false, has_prefix = false; - uint8_t addr[16] = { 0, }; - uint8_t prefix = 0; - char *node_name = NULL, *if_name = NULL; - int rc = SR_ERR_OK, op_rc = SR_ERR_OK; - - /* no-op for apply, we only care about SR_EV_ENABLED, SR_EV_VERIFY, SR_EV_ABORT */ - if (SR_EV_APPLY == event) { - return SR_ERR_OK; - } - SRP_LOG_DBG("'%s' modified, event=%d", xpath, event); - - /* check whether we are handling ipv4 or ipv6 config */ - node_name = sr_xpath_node_idx((char*)xpath, 2, &xpath_ctx); - if (NULL != node_name && 0 == strcmp(node_name, "ipv6")) { - is_ipv6 = true; - } - sr_xpath_recover(&xpath_ctx); - - /* get changes iterator */ - rc = sr_get_changes_iter(session, xpath, &iter); - if (SR_ERR_OK != rc) { - SRP_LOG_ERR("Unable to retrieve change iterator: %s", sr_strerror(rc)); - return rc; - } - - /* iterate over all changes */ - while ((SR_ERR_OK == op_rc || event == SR_EV_ABORT) && - (SR_ERR_OK == (rc = sr_get_change_next(session, iter, &op, &old_val, &new_val)))) { - - SRP_LOG_DBG("A change detected in '%s', op=%d", new_val ? new_val->xpath : old_val->xpath, op); - if_name = strdup(sr_xpath_key_value(new_val ? new_val->xpath : old_val->xpath, "interface", "name", &xpath_ctx)); - sr_xpath_recover(&xpath_ctx); - - switch (op) { - case SR_OP_CREATED: - if (SR_LIST_T == new_val->type) { - /* create on list item - reset state vars */ - has_addr = has_prefix = false; - } else { - if (sr_xpath_node_name_eq(new_val->xpath, "ip")) { - ip_addr_str_to_binary(new_val->data.string_val, addr, is_ipv6); - has_addr = true; - } else if (sr_xpath_node_name_eq(new_val->xpath, "prefix-length")) { - prefix = new_val->data.uint8_val; - has_prefix = true; - } else if (sr_xpath_node_name_eq(new_val->xpath, "netmask")) { - prefix = netmask_to_prefix(new_val->data.string_val); - has_prefix = true; - } - if (has_addr && has_prefix) { - op_rc = interface_ipv46_config_add_remove(private_ctx, if_name, addr, prefix, is_ipv6, true /* add */); - } - } - break; - case SR_OP_MODIFIED: - op_rc = interface_ipv46_config_modify(private_ctx, session, if_name, old_val, new_val, is_ipv6); - break; - case SR_OP_DELETED: - if (SR_LIST_T == old_val->type) { - /* delete on list item - reset state vars */ - has_addr = has_prefix = false; - } else { - if (sr_xpath_node_name_eq(old_val->xpath, "ip")) { - ip_addr_str_to_binary(old_val->data.string_val, addr, is_ipv6); - has_addr = true; - } else if (sr_xpath_node_name_eq(old_val->xpath, "prefix-length")) { - prefix = old_val->data.uint8_val; - has_prefix = true; - } else if (sr_xpath_node_name_eq(old_val->xpath, "netmask")) { - prefix = netmask_to_prefix(old_val->data.string_val); - has_prefix = true; - } - if (has_addr && has_prefix) { - op_rc = interface_ipv46_config_add_remove(private_ctx, if_name, addr, prefix, is_ipv6, false /* !add */); - } - } - break; - default: - break; - } - if (SR_ERR_INVAL_ARG == op_rc) { - sr_set_error(session, "Invalid interface name.", new_val ? new_val->xpath : old_val->xpath); - } - free(if_name); - sr_free_val(old_val); - sr_free_val(new_val); - } - sr_free_change_iter(iter); - - return op_rc; -} - -/** - * @brief Callback to be called by any config change under "/ietf-interfaces:interfaces-state/interface" path. - * Does not provide any functionality, needed just to cover not supported config leaves. - */ -static int -interface_change_cb(sr_session_ctx_t *session, const char *xpath, sr_notif_event_t event, void *private_ctx) -{ - SRP_LOG_DBG("'%s' modified, event=%d", xpath, event); - - return SR_ERR_OK; -} - -/** - * @brief Callback to be called by any request for state data under "/ietf-interfaces:interfaces-state/interface" path. - */ -static int -interface_state_cb(const char *xpath, sr_val_t **values, size_t *values_cnt, void *private_ctx) -{ - plugin_ctx_t *plugin_ctx = private_ctx; - vl_api_sw_interface_dump_t *if_dump_req = NULL; - vl_api_sw_interface_details_t *if_details = NULL; - void **details = NULL; - size_t details_cnt = 0; - sr_val_t *values_arr = NULL; - size_t values_arr_size = 0, values_arr_cnt = 0; - int rc = 0; - - SRP_LOG_DBG("Requesting state data for '%s'", xpath); - - if (! sr_xpath_node_name_eq(xpath, "interface")) { - /* statistics, ipv4 and ipv6 state data not supported */ - *values_cnt = 0; - return SR_ERR_OK; - } - - /* dump interfaces */ - if_dump_req = srvpp_alloc_msg(VL_API_SW_INTERFACE_DUMP, sizeof(*if_dump_req)); - rc = srvpp_send_dumprequest(plugin_ctx->srvpp_ctx, if_dump_req, &details, &details_cnt); - if (0 != rc) { - SRP_LOG_ERR_MSG("Error by processing of a interface dump request."); - return SR_ERR_INTERNAL; - } - - /* allocate array of values to be returned */ - values_arr_size = details_cnt * 5; - rc = sr_new_values(values_arr_size, &values_arr); - if (0 != rc) { - return rc; - } - - for (size_t i = 0; i < details_cnt; i++) { - if_details = (vl_api_sw_interface_details_t *) details[i]; - - /* currently the only supported interface types are propVirtual / ethernetCsmacd */ - sr_val_build_xpath(&values_arr[values_arr_cnt], "%s[name='%s']/type", xpath, if_details->interface_name); - sr_val_set_str_data(&values_arr[values_arr_cnt], SR_IDENTITYREF_T, - strstr((char*)if_details->interface_name, "local") ? "iana-if-type:propVirtual" : "iana-if-type:ethernetCsmacd"); - values_arr_cnt++; - - sr_val_build_xpath(&values_arr[values_arr_cnt], "%s[name='%s']/admin-status", xpath, if_details->interface_name); - sr_val_set_str_data(&values_arr[values_arr_cnt], SR_ENUM_T, if_details->admin_up_down ? "up" : "down"); - values_arr_cnt++; - - sr_val_build_xpath(&values_arr[values_arr_cnt], "%s[name='%s']/oper-status", xpath, if_details->interface_name); - sr_val_set_str_data(&values_arr[values_arr_cnt], SR_ENUM_T, if_details->link_up_down ? "up" : "down"); - values_arr_cnt++; - - if (if_details->l2_address_length > 0) { - sr_val_build_xpath(&values_arr[values_arr_cnt], "%s[name='%s']/phys-address", xpath, if_details->interface_name); - sr_val_build_str_data(&values_arr[values_arr_cnt], SR_STRING_T, "%02x:%02x:%02x:%02x:%02x:%02x", - if_details->l2_address[0], if_details->l2_address[1], if_details->l2_address[2], - if_details->l2_address[3], if_details->l2_address[4], if_details->l2_address[5]); - values_arr_cnt++; - } - - sr_val_build_xpath(&values_arr[values_arr_cnt], "%s[name='%s']/speed", xpath, if_details->interface_name); - values_arr[values_arr_cnt].type = SR_UINT64_T; - values_arr[values_arr_cnt].data.uint64_val = get_if_link_speed(if_details->link_speed); - values_arr_cnt++; - } - - SRP_LOG_DBG("Returning %zu state data elements for '%s'", values_arr, xpath); - - *values = values_arr; - *values_cnt = values_arr_cnt; - return SR_ERR_OK; -} - -/** - * @brief Callback to be called by plugin daemon upon plugin load. - */ -int -sr_plugin_init_cb(sr_session_ctx_t *session, void **private_ctx) -{ - plugin_ctx_t *ctx = NULL; - int rc = SR_ERR_OK; - - SRP_LOG_DBG_MSG("Initializing vpp-interfaces plugin."); - - /* allocate the plugin context */ - ctx = calloc(1, sizeof(*ctx)); - if (NULL == ctx) { - return SR_ERR_NOMEM; - } - - /* get srvpp context */ - ctx->srvpp_ctx = srvpp_get_ctx(); - if (NULL == ctx->srvpp_ctx) { - return SR_ERR_INIT_FAILED; - } - - /* setup handlers for required VPP API messages */ - srvpp_setup_handler(SW_INTERFACE_SET_FLAGS_REPLY, sw_interface_set_flags_reply); - srvpp_setup_handler(SW_INTERFACE_ADD_DEL_ADDRESS_REPLY, sw_interface_add_del_address_reply); - - rc = sr_subtree_change_subscribe(session, "/ietf-interfaces:interfaces/interface", - interface_change_cb, ctx, 0, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_EV_ENABLED, &ctx->sr_subscription); - if (SR_ERR_OK != rc) { - goto error; - } - - rc = sr_subtree_change_subscribe(session, "/ietf-interfaces:interfaces/interface/enabled", - interface_enable_disable_cb, ctx, 100, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_EV_ENABLED, &ctx->sr_subscription); - if (SR_ERR_OK != rc) { - goto error; - } - - rc = sr_subtree_change_subscribe(session, "/ietf-interfaces:interfaces/interface/ietf-ip:ipv4/address", - interface_ipv46_address_change_cb, ctx, 99, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_EV_ENABLED, &ctx->sr_subscription); - if (SR_ERR_OK != rc) { - goto error; - } - - rc = sr_subtree_change_subscribe(session, "/ietf-interfaces:interfaces/interface/ietf-ip:ipv6/address", - interface_ipv46_address_change_cb, ctx, 98, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_EV_ENABLED, &ctx->sr_subscription); - if (SR_ERR_OK != rc) { - goto error; - } - - rc = sr_dp_get_items_subscribe(session, "/ietf-interfaces:interfaces-state", - interface_state_cb, ctx, SR_SUBSCR_CTX_REUSE, &ctx->sr_subscription); - if (SR_ERR_OK != rc) { - goto error; - } - - *private_ctx = ctx; - - SRP_LOG_INF_MSG("vpp-interfaces plugin initialized successfully."); - - return SR_ERR_OK; - -error: - SRP_LOG_ERR_MSG("Error by initialization of the vpp-interfaces plugin."); - sr_plugin_cleanup_cb(session, ctx); - return rc; -} - -/** - * @brief Callback to be called by plugin daemon upon plugin unload. - */ -void -sr_plugin_cleanup_cb(sr_session_ctx_t *session, void *private_ctx) -{ - plugin_ctx_t *ctx = (plugin_ctx_t *) private_ctx; - - SRP_LOG_DBG_MSG("Cleanup of vpp-interfaces plugin requested."); - - sr_unsubscribe(session, ctx->sr_subscription); - - srvpp_release_ctx(ctx->srvpp_ctx); - free(ctx); -} - diff --git a/src/scvpp/CMakeLists.txt b/src/scvpp/CMakeLists.txt new file mode 100644 index 0000000..1256fc8 --- /dev/null +++ b/src/scvpp/CMakeLists.txt @@ -0,0 +1,40 @@ +# +# Copyright (c) 2018 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. +# + +cmake_minimum_required(VERSION 2.8) +project(scvpp) + +# add subdirectories +add_subdirectory(src) + +# enable testing if requested and possible +SET(ENABLE_TESTS 1 CACHE BOOL "Enable unit tests.") +if(ENABLE_TESTS) + find_package(CMOCKA) + if(CMOCKA_FOUND) + MESSAGE(STATUS "CMocka found, tests are enabled.") + enable_testing() + add_subdirectory(tests) + else(CMOCKA_FOUND) + MESSAGE(WARNING "CMocka not found, tests are disabled.") + endif(CMOCKA_FOUND) +endif(ENABLE_TESTS) + +find_package(PkgConfig QUIET) +if(PKG_CONFIG_FOUND) + # generate and install pkg-config file + configure_file("libscvpp.pc.in" "libscvpp.pc" @ONLY) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libscvpp.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") +endif() diff --git a/src/scvpp/libscvpp.pc.in b/src/scvpp/libscvpp.pc.in new file mode 100644 index 0000000..ce996e3 --- /dev/null +++ b/src/scvpp/libscvpp.pc.in @@ -0,0 +1,10 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ +libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ + +Name: scvpp +Description: VPP-Sweetcomb-Sysrepo integration library +Version: 0.0.1 +Libs: -L${libdir} -lscvpp +Cflags: -I${includedir} + diff --git a/src/scvpp/src/CMakeLists.txt b/src/scvpp/src/CMakeLists.txt new file mode 100644 index 0000000..3961971 --- /dev/null +++ b/src/scvpp/src/CMakeLists.txt @@ -0,0 +1,43 @@ +# +# Copyright (c) 2018 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(GNUInstallDirs) + +# scvpp sources +set(SCVPP_SOURCES + sc_vpp_operation.c +) + +# scvpp public headers +set(SCVPP_HEADERS + sc_vpp_operation.h +) + +set(CMAKE_C_FLAGS " -g -O0 -fpic -fPIC -std=gnu99 -Wl,-rpath-link=/usr/lib") + +# libraries to link with +set(LINK_LIBRARIES sysrepo vlibmemoryclient vapiclient vppapiclient svm vppinfra pthread rt dl) + +# build instructions +add_library(scvpp SHARED ${SCVPP_SOURCES}) +add_library(scvpp_a ${SCVPP_SOURCES}) + +# linker instructions +target_link_libraries(scvpp ${LINK_LIBRARIES}) +target_link_libraries(scvpp_a ${LINK_LIBRARIES}) + +# install rules +install(TARGETS scvpp DESTINATION ${CMAKE_INSTALL_LIBDIR}) +install(FILES ${SCVPP_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) diff --git a/src/scvpp/src/sc_vpp_operation.c b/src/scvpp/src/sc_vpp_operation.c new file mode 100644 index 0000000..3232403 --- /dev/null +++ b/src/scvpp/src/sc_vpp_operation.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2018 HUACHENTEL 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 "sc_vpp_operation.h" + +#define APP_NAME "sweetcomb_vpp" +#define MAX_OUTSTANDING_REQUESTS 4 +#define RESPONSE_QUEUE_SIZE 2 + +vapi_ctx_t g_vapi_ctx_instance = NULL; +////////////////////////// + +int sc_connect_vpp() +{ + SC_INVOKE_BEGIN; + // SC_LOG_DBG("*******cts %p \n", g_vapi_ctx_instance); + if (g_vapi_ctx_instance == NULL) + { + vapi_error_e rv = vapi_ctx_alloc(&g_vapi_ctx_instance); + rv = vapi_connect(g_vapi_ctx_instance, APP_NAME, NULL, MAX_OUTSTANDING_REQUESTS, RESPONSE_QUEUE_SIZE, VAPI_MODE_BLOCKING, true); + if (rv != VAPI_OK) + { + SC_LOG_ERR("*connect %s faild,with return %d", APP_NAME, rv); + return -1; + } + SC_LOG_DBG("*connected %s ok", APP_NAME); + } + else + { + SC_LOG_DBG("connection %s keeping", APP_NAME); + } + SC_INVOKE_END; + return 0; +} + +int sc_disconnect_vpp() +{ + if (NULL != g_vapi_ctx_instance) + { + vapi_disconnect(g_vapi_ctx_instance); + vapi_ctx_free(g_vapi_ctx_instance); + g_vapi_ctx_instance = NULL; + } + return 0; +} + +int sc_end_with(const char* str, const char* end) +{ + if (str != NULL && end != NULL) + { + int l1 = strlen(str); + int l2 = strlen(end); + if (l1 >= l2) + { + if (strcmp(str + l1 - l2, end) == 0) + return 1; + } + } + return 0; +} + + diff --git a/src/scvpp/src/sc_vpp_operation.h b/src/scvpp/src/sc_vpp_operation.h new file mode 100644 index 0000000..497b704 --- /dev/null +++ b/src/scvpp/src/sc_vpp_operation.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2018 HUACHENTEL 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 __SWEETCOMB_VPP_OPERATION__ +#define __SWEETCOMB_VPP_OPERATION__ +#include +#include +DEFINE_VAPI_MSG_IDS_VPE_API_JSON; + +#include +#include +#include //for SC_LOG_DBG + +#define VPP_INTFC_NAME_LEN 64 +#define VPP_TAP_NAME_LEN VPP_INTFC_NAME_LEN +#define VPP_IP4_ADDRESS_LEN 4 +#define VPP_IP6_ADDRESS_LEN 16 +#define VPP_IP4_ADDRESS_STRING_LEN 16 +#define VPP_IP6_ADDRESS_STRING_LEN 46 +#define VPP_MAC_ADDRESS_LEN 8 +#define VPP_TAG_LEN VPP_INTFC_NAME_LEN +#define VPP_IKEV2_PROFILE_NAME_LEN VPP_INTFC_NAME_LEN +#define VPP_IKEV2_PSK_LEN VPP_INTFC_NAME_LEN +#define VPP_IKEV2_ID_LEN 32 + +#ifndef SC_THIS_FUNC +#ifdef __FUNCTION__ +#define SC_THIS_FUNC __FUNCTION__ +#else +#define SC_THIS_FUNC __func__ +#endif +#endif + +#ifndef SC_NOLOG +#define SC_LOG_DBG SRP_LOG_DBG +#define SC_LOG_ERR SRP_LOG_ERR +#define SC_LOG_DBG_MSG SRP_LOG_DBG_MSG +#define SC_LOG_ERR_MSG SRP_LOG_ERR_MSG +#else +#define SC_LOG_DBG //printf +#define SC_LOG_DBG //SRP_LOG_DBG +#define SC_LOG_ERR //SRP_LOG_ERR +#define SC_LOG_DBG_MSG //SRP_LOG_DBG_MSG +#define SC_LOG_ERR_MSG //SRP_LOG_ERR_MSG +#endif + +#define SC_INVOKE_BEGIN SC_LOG_DBG("inovke %s bein.",SC_THIS_FUNC); +#define SC_INVOKE_END SC_LOG_DBG("inovke %s end,with return OK.",SC_THIS_FUNC); +#define SC_INVOKE_ENDX(...) SC_LOG_DBG("inovke %s end,with %s.",SC_THIS_FUNC, ##__VA_ARGS__) + +/** + * when use tihs must fist DEFINE_VAPI_MSG_IDS_VXLAN_API_JSON + */ +#define SC_VPP_VAPI_RECV \ +do { \ + size_t size; \ + int recv_vapimsgid = -1; \ + rv = vapi_recv (g_vapi_ctx_instance, (void *) &resp, &size, 0, 0); \ + recv_vapimsgid = vapi_lookup_vapi_msg_id_t(g_vapi_ctx_instance, ntohs(resp->header._vl_msg_id) ); \ + if(recv_vapimsgid <= vapi_msg_id_get_next_index_reply \ + || recv_vapimsgid >= vapi_get_message_count ()) { \ + SC_LOG_DBG("***recv error msgid[%d] not in [0-%d) ,try again!***\n", \ + recv_vapimsgid, vapi_get_message_count ()); \ + } else { \ + SC_LOG_DBG("recv msgid [%d]\n", recv_vapimsgid); \ + break; \ + } \ + } while(1); + +#define SC_REGISTER_RPC_EVT_HANDLER(rpc_evt_handle) \ +do { \ + sr_error_t rc = rpc_evt_handle(session, &subscription); \ + if (SR_ERR_OK != rc) \ + { \ + SC_LOG_ERR("load plugin failed: %s", sr_strerror(rc)); \ + sr_unsubscribe(session, subscription); \ + SC_INVOKE_ENDX(sr_strerror(rc)); \ + return rc; \ + } \ +} while(0); + +/////////////////////////// +//VPP接口 +int sc_connect_vpp(); +int sc_disconnect_vpp(); +int sc_end_with(const char* str, const char* end); +extern vapi_ctx_t g_vapi_ctx_instance; +#endif //__SWEETCOMB_VPP_OPERATION__ + + + + diff --git a/src/scvpp/tests/CMakeLists.txt b/src/scvpp/tests/CMakeLists.txt new file mode 100644 index 0000000..bd135bf --- /dev/null +++ b/src/scvpp/tests/CMakeLists.txt @@ -0,0 +1,40 @@ +# +# Copyright (c) 2018 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_directories ("${PROJECT_SOURCE_DIR}/src") + +# check whether valgrind is installed +find_program(valgrind_FOUND valgrind) + +# macro for adding of an unit test +macro(ADD_UNIT_TEST TEST_NAME) + set(TEST_SRC + ${TEST_NAME}.c + ) + add_executable(${TEST_NAME} ${TEST_SRC}) + target_link_libraries(${TEST_NAME} ${CMOCKA_LIBRARIES} scvpp_a) + add_test(${TEST_NAME} ${TEST_NAME}) + + if(valgrind_FOUND) + add_test(${TEST_NAME}_valgrind valgrind + --error-exitcode=1 --read-var-info=yes + --leak-check=full --show-leak-kinds=all + ./${TEST_NAME} + ) + endif(valgrind_FOUND) +endmacro(ADD_UNIT_TEST) + +# add individual unit-tests +ADD_UNIT_TEST(scvpp_test) diff --git a/src/scvpp/tests/scvpp_test.c b/src/scvpp/tests/scvpp_test.c new file mode 100644 index 0000000..114d190 --- /dev/null +++ b/src/scvpp/tests/scvpp_test.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2016 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 +#include +#include +#include +#include + +#include "sc_vpp_operation.h" + + +static int +scvpp_test_setup(void **state) +{ + //sc_vpp_connect + return 0; +} + +static int +scvpp_test_teardown(void **state) +{ + //sc_vpp_disconnect + return 0; +} + +static void +scvpp_interface_test(void **state) +{ + //call interface functions +} + + +int +main() +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(scvpp_interface_test, scvpp_test_setup, scvpp_test_teardown), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/src/srvpp/CMakeLists.txt b/src/srvpp/CMakeLists.txt deleted file mode 100644 index 539675d..0000000 --- a/src/srvpp/CMakeLists.txt +++ /dev/null @@ -1,40 +0,0 @@ -# -# Copyright (c) 2018 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. -# - -cmake_minimum_required(VERSION 2.8) -project(srvpp) - -# add subdirectories -add_subdirectory(src) - -# enable testing if requested and possible -SET(ENABLE_TESTS 1 CACHE BOOL "Enable unit tests.") -if(ENABLE_TESTS) - find_package(CMOCKA) - if(CMOCKA_FOUND) - MESSAGE(STATUS "CMocka found, tests are enabled.") - enable_testing() - add_subdirectory(tests) - else(CMOCKA_FOUND) - MESSAGE(WARNING "CMocka not found, tests are disabled.") - endif(CMOCKA_FOUND) -endif(ENABLE_TESTS) - -find_package(PkgConfig QUIET) -if(PKG_CONFIG_FOUND) - # generate and install pkg-config file - configure_file("libsrvpp.pc.in" "libsrvpp.pc" @ONLY) - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libsrvpp.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") -endif() diff --git a/src/srvpp/libsrvpp.pc.in b/src/srvpp/libsrvpp.pc.in deleted file mode 100644 index c57c267..0000000 --- a/src/srvpp/libsrvpp.pc.in +++ /dev/null @@ -1,10 +0,0 @@ -prefix=@CMAKE_INSTALL_PREFIX@ -includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ -libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ - -Name: srvpp -Description: VPP-Sysrepo integration library -Version: 0.0.1 -Libs: -L${libdir} -lsrvpp -Cflags: -I${includedir} - diff --git a/src/srvpp/src/CMakeLists.txt b/src/srvpp/src/CMakeLists.txt deleted file mode 100644 index 8cc0a04..0000000 --- a/src/srvpp/src/CMakeLists.txt +++ /dev/null @@ -1,44 +0,0 @@ -# -# Copyright (c) 2018 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(GNUInstallDirs) - -# srvpp sources -set(SRVPP_SOURCES - srvpp_logger.c - srvpp.c -) - -# srvpp public headers -set(SRVPP_HEADERS - srvpp.h -) - -set(CMAKE_C_FLAGS " -g -O0 -fpic -fPIC -std=gnu99 -Wl,-rpath-link=/usr/lib") - -# libraries to link with -set(LINK_LIBRARIES sysrepo vlibmemoryclient vapiclient vppapiclient svm vppinfra pthread rt dl) - -# build instructions -add_library(srvpp SHARED ${SRVPP_SOURCES}) -add_library(srvpp_a ${SRVPP_SOURCES}) - -# linker instructions -target_link_libraries(srvpp ${LINK_LIBRARIES}) -target_link_libraries(srvpp_a ${LINK_LIBRARIES}) - -# install rules -install(TARGETS srvpp DESTINATION ${CMAKE_INSTALL_LIBDIR}) -install(FILES ${SRVPP_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) diff --git a/src/srvpp/src/srvpp.c b/src/srvpp/src/srvpp.c deleted file mode 100644 index 9b3467b..0000000 --- a/src/srvpp/src/srvpp.c +++ /dev/null @@ -1,823 +0,0 @@ -/* - * Copyright (c) 2016 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 -#include -#include -#include - -#include "srvpp.h" -#include "srvpp_logger.h" - -#undef vl_api_version -#define vl_api_version(n,v) static u32 vpe_api_version = v; -#include -#undef vl_api_version - - -#define SRVPP_RESPONSE_TIMEOUT 2 /**< Maximum time (in seconds) that a client waits for the response(s) to a request or dumprequest. */ - -#define CHECK_NULL(ARG) \ - if (NULL == ARG) { \ - SRVPP_LOG_ERR("NULL value detected for %s argument of %s", #ARG, __func__); \ - return -1; \ - } \ - -#define CHECK_NULL_RET(ARG, RET) \ - if (NULL == ARG) { \ - SRVPP_LOG_ERR("NULL value detected for %s argument of %s", #ARG, __func__); \ - return RET; \ - } \ - -/** - * @brief Type of the response expected from VPP. - */ -typedef enum srvpp_response_type_e { - SRVPP_REPLY, /**< A reply message (single message). */ - SRVPP_DETAILS, /**< Multiple details messages. */ -} srvpp_response_type_t; - -/** - * @brief srvpp request context structure. - */ -typedef struct srvpp_request_ctx_s { - struct srvpp_request_ctx_s *_next; /**< Pointer to the next request context in the linked-list. */ - u32 ctx_id; /**< Context ID used to map responses with requests. */ - srvpp_response_type_t resp_type; /**< Type of the response expected from VPP. */ - - i32 resp_retval; /**< Return value of the last response (0 = success). */ - bool resp_data_copy; /**< Controls whether data of the responses shall be copied (returned) or ignored. */ - void **resp_msg_arr; /**< Array of the pointers to response messages. */ - size_t *resp_msg_sizes; /**< Array of sizes of messages in the ::resp_msg_arr. */ - size_t resp_msg_arr_size; /**< Size of the ::resp_msg_arr array. */ - size_t resp_msg_cnt; /**< Count of the messages currently stored in ::resp_msg_arr array. */ - - bool resp_ready; /**< Signals that the expected response has arrived and is ready to be returned. */ - pthread_cond_t resp_cv; /**< Condition variable for ::resp_ready. */ - pthread_mutex_t lock; /**< Mutex to protect shared access to the context. */ -} srvpp_request_ctx_t; - -/** - * @brief srvpp interface info context structure. - */ -typedef struct srvpp_if_info_s { - struct srvpp_if_info_s *_next; - const char *if_name; - u32 if_index; -} srvpp_if_info_t; - -/** - * @brief srvpp context structure. - */ -typedef struct srvpp_ctx_s { - size_t ref_cnt; /**< Context reference counter. */ - unix_shared_memory_queue_t *vlib_input_queue; /**< VPP Library input queue. */ - u32 vlib_client_index; /**< VPP Library client index. */ - srvpp_request_ctx_t *request_ctx_list; /**< Linked-list of request contexts. */ - srvpp_if_info_t *if_info_list; /**< Linked-list of VPP interfaces information. */ - pthread_key_t request_key; /**< Key to the thread-specific request context. */ -} srvpp_ctx_t; - -/** - * @brief Generic VPP request structure. - */ -typedef struct __attribute__ ((packed)) vl_generic_request_s { - unsigned short _vl_msg_id; - unsigned int client_index; - unsigned int context; -} vl_generic_request_t; - -/** - * @brief Generic VPP response structure. - */ -typedef struct __attribute__ ((packed)) vl_generic_response_s { - u16 _vl_msg_id; - u32 context; -} vl_generic_response_t; - -/** - * @brief Generic VPP reply structure (response with a single message). - */ -typedef struct __attribute__ ((packed)) vl_generic_reply_s { - u16 _vl_msg_id; - u32 context; - i32 retval; -} vl_generic_reply_t; - -/** - * @brief Global srvpp context. - */ -static srvpp_ctx_t *srvpp_ctx = NULL; - -/** - * @brief Mutex for the global context. - */ -static pthread_mutex_t srvpp_ctx_lock = PTHREAD_MUTEX_INITIALIZER; - -/** - * @brief Not used, just to satisfy external references when -lvlib is not available. - */ -void -vlib_cli_output(struct vlib_main_t *vm, char *fmt, ...) -{ - SRVPP_LOG_WRN_MSG("vlib_cli_output callled!"); -} - -/** - * @brief Sets correct VPP API version. - */ -void -vl_client_add_api_signatures(vl_api_memclnt_create_t *mp) -{ - /* - * Send the main API signature in slot 0. This bit of code must - * match the checks in ../vpe/api/api.c: vl_msg_api_version_check(). - */ - mp->api_versions[0] = clib_host_to_net_u32(vpe_api_version); -} - -/** - * @brief Returns the request context assigned to the active thread. - * If no request context exists for the thread, it will be automatically created. - */ -static srvpp_request_ctx_t * -srvpp_get_thread_request_ctx(srvpp_ctx_t *ctx) -{ - srvpp_request_ctx_t *req_ctx = NULL; - - CHECK_NULL_RET(ctx, NULL); - - if (NULL == (req_ctx = pthread_getspecific(ctx->request_key))) { - /* allocate a new request context */ - req_ctx = calloc(1, sizeof(*req_ctx)); - if (NULL != req_ctx) { - /* initialize the new context */ - req_ctx->ctx_id = (u32)(((uintptr_t)req_ctx) & 0xFFFFFFFF) << 16; - SRVPP_LOG_DBG("Creating new request ctx with id=%u", req_ctx->ctx_id); - - pthread_mutex_init(&req_ctx->lock, NULL); - pthread_cond_init (&req_ctx->resp_cv, NULL); - - /* save the request ctx in the srvpp context */ - pthread_mutex_lock(&srvpp_ctx_lock); - req_ctx->_next = ctx->request_ctx_list; - ctx->request_ctx_list = req_ctx; - pthread_mutex_unlock(&srvpp_ctx_lock); - - /* save the request ctx in the thread-local memory */ - pthread_setspecific(ctx->request_key, req_ctx); - } else { - SRVPP_LOG_ERR_MSG("Unable to allocate new request context."); - } - } - - return req_ctx; -} - -/** - * @brief Returns the request context matching with the provided context id. - */ -static srvpp_request_ctx_t * -srvpp_get_request_ctx(srvpp_ctx_t *ctx, u32 req_ctx_id) -{ - srvpp_request_ctx_t *req_ctx = NULL, *match = NULL; - - CHECK_NULL_RET(ctx, NULL); - - pthread_mutex_lock(&srvpp_ctx_lock); - - req_ctx = ctx->request_ctx_list; - - while (NULL != req_ctx) { - if (req_ctx->ctx_id == req_ctx_id) { - match = req_ctx; - break; - } - req_ctx = req_ctx->_next; - } - - pthread_mutex_unlock(&srvpp_ctx_lock); - - return match; -} - -/** - * @brief Copy data of the message into the provided request context. - */ -static int -srvpp_msg_data_copy(srvpp_request_ctx_t *req_ctx, void *msg, size_t msg_size) -{ - void **msg_arr = NULL; - size_t *sizes_arr = NULL; - void *msg_space = NULL; - - CHECK_NULL(req_ctx); - - if (req_ctx->resp_msg_arr_size < (req_ctx->resp_msg_cnt + 1)) { - /* reallocate arrays to fit one new message */ - msg_arr = realloc(req_ctx->resp_msg_arr, (req_ctx->resp_msg_cnt + 1) * sizeof(*req_ctx->resp_msg_arr)); - if (NULL == msg_arr) { - SRVPP_LOG_ERR_MSG("Unable to reallocate message array."); - return -1; - } - sizes_arr = realloc(req_ctx->resp_msg_sizes, (req_ctx->resp_msg_cnt + 1) * sizeof(*req_ctx->resp_msg_sizes)); - if (NULL == sizes_arr) { - SRVPP_LOG_ERR_MSG("Unable to reallocate message sizes array."); - return -1; - } - req_ctx->resp_msg_arr = msg_arr; - req_ctx->resp_msg_sizes = sizes_arr; - req_ctx->resp_msg_arr_size = req_ctx->resp_msg_cnt + 1; - - req_ctx->resp_msg_arr[req_ctx->resp_msg_cnt] = NULL; - req_ctx->resp_msg_sizes[req_ctx->resp_msg_cnt] = 0; - } - - if (req_ctx->resp_msg_sizes[req_ctx->resp_msg_cnt] < msg_size) { - /* reallocate space for the message */ - msg_space = realloc(req_ctx->resp_msg_arr[req_ctx->resp_msg_cnt], msg_size); - if (NULL == msg_space) { - SRVPP_LOG_ERR_MSG("Unable to reallocate message space."); - return -1; - } - req_ctx->resp_msg_arr[req_ctx->resp_msg_cnt] = msg_space; - req_ctx->resp_msg_sizes[req_ctx->resp_msg_cnt] = msg_size; - } - - /* copy the message content */ - memcpy(req_ctx->resp_msg_arr[req_ctx->resp_msg_cnt], msg, msg_size); - - req_ctx->resp_msg_cnt++; - - return 0; -} - -/** - * @brief Processes a reply to a single VPP request. - */ -static int -srvpp_process_reply_msg(srvpp_request_ctx_t *req_ctx, u16 msg_id, void *msg, size_t msg_size) -{ - vl_generic_reply_t *reply = NULL; - int rc = 0; - - CHECK_NULL(req_ctx); - - reply = (vl_generic_reply_t *) msg; - - if (req_ctx->ctx_id != reply->context) { - SRVPP_LOG_ERR_MSG("Invalid request context for provided message, ignoring the message."); - return -1; - } - - if (req_ctx->resp_data_copy) { - /* copy msg data into req_ctx */ - rc = srvpp_msg_data_copy(req_ctx, msg, msg_size); - } - - if (0 == rc) { - req_ctx->resp_retval = reply->retval; - } else { - req_ctx->resp_retval = rc; - } - - /* signal the requesting thread */ - req_ctx->resp_ready = true; - pthread_cond_signal(&req_ctx->resp_cv); - - return rc; -} - -/** - * @brief Processes a reply to a dump request to VPP (response consisting of multiple messages). - */ -static int -srvpp_process_details_msg(srvpp_request_ctx_t *req_ctx, u16 msg_id, void *msg, size_t msg_size) -{ - vl_generic_response_t *response = NULL; - int rc = 0; - - CHECK_NULL(req_ctx); - - response = (vl_generic_response_t *) msg; - - if (req_ctx->ctx_id != response->context) { - SRVPP_LOG_ERR_MSG("Invalid request context for provided message, ignoring the message."); - return -1; - } - - if (VL_API_CONTROL_PING_REPLY != msg_id) { - /* details message - copy message data into req contex*/ - rc = srvpp_msg_data_copy(req_ctx, msg, msg_size); - if (0 != rc && 0 == req_ctx->resp_retval) { - /* in case of error, propagate it to the req context */ - req_ctx->resp_retval = rc; - } - } else { - /* control ping reply, signal the requesting thread */ - req_ctx->resp_ready = true; - pthread_cond_signal(&req_ctx->resp_cv); - } - - return req_ctx->resp_retval; -} - -/** - * @brief Internal callback automatically called by VPP library when a message - * from VPP is received. - */ -void -_srvpp_receive_msg_handler(void *msg) -{ - srvpp_request_ctx_t *req_ctx = NULL; - vl_generic_response_t *response = NULL; - msgbuf_t *msg_header = NULL; - size_t msg_size = 0; - u16 msg_id = 0; - - if (NULL == msg) { - SRVPP_LOG_WRN_MSG("NULL message received, ignoring."); - return; - } - - response = (vl_generic_response_t *) msg; - - /* get message details */ - msg_header = (msgbuf_t *) (((u8 *) msg) - offsetof(msgbuf_t, data)); - msg_size = ntohl(msg_header->data_len); - msg_id = ntohs(*((u16 *)msg)); - - SRVPP_LOG_DBG("New message received from VPP (id=%d, size=%zu).", msg_id, msg_size); - - /* get request context matching with context id */ - req_ctx = srvpp_get_request_ctx(srvpp_ctx, response->context); - if (NULL == req_ctx) { - SRVPP_LOG_WRN("Unexpected context id=%d within the received message, ignoring.", response->context); - return; - } - - pthread_mutex_lock(&req_ctx->lock); - - if (SRVPP_REPLY == req_ctx->resp_type) { - srvpp_process_reply_msg(req_ctx, msg_id, msg, msg_size); - } else { - srvpp_process_details_msg(req_ctx, msg_id, msg, msg_size); - } - - pthread_mutex_unlock(&req_ctx->lock); -} - -/** - * @brief Blocks the thread until a response from VPP comes or until a timeout expires. - */ -static int -srvpp_wait_response(srvpp_request_ctx_t *req_ctx) -{ - struct timespec ts = { 0, }; - int retval = 0, rc = 0; - - CHECK_NULL(req_ctx); - - pthread_mutex_lock(&req_ctx->lock); - - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += SRVPP_RESPONSE_TIMEOUT; - - while (!req_ctx->resp_ready && (0 == rc)) { - rc = pthread_cond_timedwait(&req_ctx->resp_cv, &req_ctx->lock, &ts); - } - if (0 == rc) { - SRVPP_LOG_DBG("Received the response from VPP, retval=%d", req_ctx->resp_retval); - retval = req_ctx->resp_retval; - } else { - SRVPP_LOG_ERR("Response not received from VPP within the timeout period (%d sec).", SRVPP_RESPONSE_TIMEOUT); - retval = -1; - } - - /* invalidate previous context id */ - ++req_ctx->ctx_id; - - pthread_mutex_unlock(&req_ctx->lock); - - return retval; -} - -/** - * @brief Connects to VPP. - */ -static int -srvpp_vlib_connect(srvpp_ctx_t *ctx) -{ - api_main_t *am = &api_main; - int rc = 0; - - CHECK_NULL(ctx); - - SRVPP_LOG_DBG_MSG("Connecting to VPP..."); - - rc = vl_client_connect_to_vlib("/vpe-api", "srvpp", 32); - - if (rc < 0) { - SRVPP_LOG_ERR("Unable to connect to VPP, rc=%d.", rc); - } else { - SRVPP_LOG_DBG("Connection to VPP established, client index=%d.", am->my_client_index); - ctx->vlib_client_index = am->my_client_index; - ctx->vlib_input_queue = am->shmem_hdr->vl_input_queue; - } - - return rc; -} - -/** - * @brief Disconnects from VPP. - */ -static void -srvpp_vlib_disconnect() -{ - vl_client_disconnect_from_vlib(); -} - -/** - * @brief Adds a new interface into interfaces list. - */ -static int -srvpp_if_info_add(srvpp_ctx_t *ctx, const char *if_name, u32 if_index) -{ - srvpp_if_info_t *tmp = NULL, *if_info = NULL; - - SRVPP_LOG_DBG("Adding interface '%s', id=%d", if_name, if_index); - - if_info = calloc(1, sizeof(*if_info)); - if (NULL == if_info) { - return 1; - } - - if_info->if_name = strdup(if_name); - if (NULL == if_info->if_name) { - return 1; - } - - if_info->if_index = if_index; - - if (NULL == ctx->if_info_list) { - ctx->if_info_list = if_info; - } else { - tmp = ctx->if_info_list; - while (NULL != tmp->_next) { - tmp = tmp->_next; - } - tmp->_next = if_info; - } - - return 0; -} - -/** - * @brief Loads VPP interfaces information. - */ -static int -srvpp_if_info_load(srvpp_ctx_t *ctx) -{ - vl_api_sw_interface_dump_t *if_dump_req = NULL; - vl_api_sw_interface_details_t *if_details = NULL; - void **details = NULL; - size_t details_cnt = 0; - int ret = 0; - - SRVPP_LOG_DBG_MSG("Loading VPP interfaces information"); - - /* dump interfaces */ - if_dump_req = srvpp_alloc_msg(VL_API_SW_INTERFACE_DUMP, sizeof(*if_dump_req)); - - ret = srvpp_send_dumprequest(ctx, if_dump_req, &details, &details_cnt); - if (0 != ret) { - return ret; - } - - pthread_mutex_lock(&srvpp_ctx_lock); - - for (size_t i = 0; i < details_cnt; i++) { - if_details = (vl_api_sw_interface_details_t *) details[i]; - ret = srvpp_if_info_add(ctx, (char*)if_details->interface_name, ntohl(if_details->sw_if_index)); - } - - pthread_mutex_unlock(&srvpp_ctx_lock); - - return 0; -} - -/** - * @brief Cleans up VPP interfaces information. - */ -static void -srvpp_if_info_cleanup(srvpp_ctx_t *ctx) -{ - srvpp_if_info_t *tmp = NULL, *if_info = NULL; - - if (NULL != ctx) { - if_info = ctx->if_info_list; - - while (NULL != if_info) { - tmp = if_info; - if_info = if_info->_next; - free((void*)tmp->if_name); - free(tmp); - } - } -} - -/** - * @brief Initializes the srvpp context. - */ -srvpp_ctx_t * -srvpp_ctx_init() -{ - srvpp_ctx_t *ctx = NULL; - int rc = 0; - - srvpp_logger_init(); - - ctx = calloc(1, sizeof(*ctx)); - if (NULL == ctx) { - SRVPP_LOG_ERR_MSG("Unable to allocate srvpp context."); - return NULL; - } - - rc = srvpp_vlib_connect(ctx); - if (0 != rc) { - SRVPP_LOG_ERR_MSG("Unable to initialize srvpp context."); - free(ctx); - return NULL; - } - - while (pthread_key_create(&ctx->request_key, NULL) == EAGAIN); - pthread_setspecific(ctx->request_key, NULL); - - ctx->ref_cnt = 1; - - SRVPP_LOG_INF_MSG("srvpp context initialized successfully."); - - return ctx; -} - -/** - * @brief Cleans up the srvpp context. - */ -static void -srvpp_ctx_cleanup(srvpp_ctx_t *ctx) -{ - srvpp_request_ctx_t *tmp = NULL, *req_ctx = NULL; - - if (NULL != ctx) { - srvpp_vlib_disconnect(); - - srvpp_if_info_cleanup(ctx); - - req_ctx = ctx->request_ctx_list; - while (NULL != req_ctx) { - tmp = req_ctx; - req_ctx = req_ctx->_next; - - pthread_mutex_destroy(&tmp->lock); - pthread_cond_destroy(&tmp->resp_cv); - - for (size_t i = 0; i < tmp->resp_msg_arr_size; i++) { - free(tmp->resp_msg_arr[i]); - } - free(tmp->resp_msg_arr); - free(tmp->resp_msg_sizes); - - free(tmp); - } - free(ctx); - - srvpp_logger_cleanup(); - - SRVPP_LOG_INF_MSG("srvpp context cleaned up successfully."); - } -} - -srvpp_ctx_t * -srvpp_get_ctx() -{ - bool setup_handlers = false; - - pthread_mutex_lock(&srvpp_ctx_lock); - - if (NULL == srvpp_ctx) { - /* initialize a new context */ - SRVPP_LOG_DBG_MSG("Initializing a new srvpp context."); - srvpp_ctx = srvpp_ctx_init(); - setup_handlers = true; - } else { - /* increment ref. count */ - srvpp_ctx->ref_cnt++; - SRVPP_LOG_DBG("Reusing existing srvpp context, new refcount=%zu.", srvpp_ctx->ref_cnt); - } - - pthread_mutex_unlock(&srvpp_ctx_lock); - - if (setup_handlers) { - /* setup required handlers */ - srvpp_setup_handler(CONTROL_PING_REPLY, control_ping_reply); - srvpp_setup_handler(SW_INTERFACE_DETAILS, sw_interface_details); - - /* load VPP interfaces information */ - srvpp_if_info_load(srvpp_ctx); - } - - return srvpp_ctx; -} - -void -srvpp_release_ctx(srvpp_ctx_t *ctx) -{ - pthread_mutex_lock(&srvpp_ctx_lock); - - if (ctx != srvpp_ctx) { - SRVPP_LOG_ERR_MSG("Invalid srvpp context passed in, unable to release."); - pthread_mutex_unlock(&srvpp_ctx_lock); - return; - } - - if (srvpp_ctx->ref_cnt > 1) { - /* there are still some other references */ - srvpp_ctx->ref_cnt--; - SRVPP_LOG_DBG("Releasing a reference to srvpp context, new refcount=%zu.", srvpp_ctx->ref_cnt); - } else { - /* last reference - cleanup */ - SRVPP_LOG_DBG_MSG("Releasing srvpp context (last ctx reference)."); - srvpp_ctx_cleanup(srvpp_ctx); - srvpp_ctx = NULL; - } - - pthread_mutex_unlock(&srvpp_ctx_lock); -} - -void * -srvpp_alloc_msg(uint16_t msg_id, size_t msg_size) -{ - vl_generic_request_t *req = NULL; - - req = vl_msg_api_alloc(msg_size); - if (NULL != req) { - memset(req, 0, msg_size); - req->_vl_msg_id = ntohs(msg_id); - } - - return req; -} - -int -srvpp_send_request(srvpp_ctx_t *ctx, void *request, void **response) -{ - vl_generic_request_t *req = NULL; - srvpp_request_ctx_t *req_ctx = NULL; - int retval = 0; - - CHECK_NULL(ctx); - CHECK_NULL(request); - - req_ctx = srvpp_get_thread_request_ctx(ctx); - if (NULL == req_ctx) { - SRVPP_LOG_ERR_MSG("Unable to obtain a request context."); - return -1; - } - - req = (vl_generic_request_t *) request; - req->client_index = ctx->vlib_client_index; - - pthread_mutex_lock(&req_ctx->lock); - - if (NULL != response) { - /* response data is requested */ - req_ctx->resp_data_copy = true; - req_ctx->resp_msg_cnt = 0; - } else { - /* not interested in response data */ - req_ctx->resp_data_copy = false; - } - - req_ctx->resp_type = SRVPP_REPLY; - req_ctx->resp_ready = false; - req_ctx->resp_retval = 0; - req->context = ++req_ctx->ctx_id; - - pthread_mutex_unlock(&req_ctx->lock); - - SRVPP_LOG_DBG_MSG("Sending a request to VPP."); - - vl_msg_api_send_shmem(ctx->vlib_input_queue, (u8*)&req); - - /* wait for expected response */ - retval = srvpp_wait_response(req_ctx); - - if (0 == retval) { - if (NULL != response && req_ctx->resp_msg_cnt > 0) { - *response = req_ctx->resp_msg_arr[0]; - } - SRVPP_LOG_DBG_MSG("VPP request successfully processed."); - } else { - SRVPP_LOG_ERR_MSG("Error by handling of a VPP request."); - } - - return retval; -} - -int -srvpp_send_dumprequest(srvpp_ctx_t *ctx, void *request, void ***response_arr, size_t *response_cnt) -{ - vl_generic_request_t *req = NULL; - srvpp_request_ctx_t *req_ctx = NULL; - vl_api_control_ping_t *ping = NULL; - int retval = 0; - - CHECK_NULL(ctx); - CHECK_NULL(request); - CHECK_NULL(response_arr); - CHECK_NULL(response_cnt); - - req_ctx = srvpp_get_thread_request_ctx(ctx); - if (NULL == req_ctx) { - SRVPP_LOG_ERR_MSG("Unable to obtain a request context."); - return -1; - } - - req = (vl_generic_request_t *) request; - req->client_index = ctx->vlib_client_index; - - /* allocate control ping request */ - ping = srvpp_alloc_msg(VL_API_CONTROL_PING, sizeof(*ping)); - if (NULL == ping) { - SRVPP_LOG_ERR_MSG("Unable to allocate control ping message."); - return -1; - } - ping->client_index = ctx->vlib_client_index; - - pthread_mutex_lock(&req_ctx->lock); - - req_ctx->resp_data_copy = true; - req_ctx->resp_msg_cnt = 0; - - req_ctx->resp_type = SRVPP_DETAILS; - req_ctx->resp_ready = false; - req_ctx->resp_retval = 0; - - req_ctx->ctx_id++; - req->context = req_ctx->ctx_id; - ping->context = req_ctx->ctx_id; - - pthread_mutex_unlock(&req_ctx->lock); - - SRVPP_LOG_DBG_MSG("Sending a dumprequest to VPP."); - - vl_msg_api_send_shmem(ctx->vlib_input_queue, (u8*)&req); - - vl_msg_api_send_shmem(ctx->vlib_input_queue, (u8*)&ping); - - /* wait for expected response */ - retval = srvpp_wait_response(req_ctx); - - if (0 == retval) { - *response_arr = req_ctx->resp_msg_arr; - *response_cnt = req_ctx->resp_msg_cnt; - SRVPP_LOG_DBG_MSG("VPP dumprequest successfully processed."); - } else { - SRVPP_LOG_ERR_MSG("Error by handling of a VPP dumprequest."); - } - - return retval; -} - -int -srvpp_get_if_index(srvpp_ctx_t *ctx, const char *if_name, uint32_t *if_index) -{ - CHECK_NULL(if_name); - CHECK_NULL(if_index); - - srvpp_if_info_t *if_info = NULL; - - if_info = ctx->if_info_list; - - while ((NULL != if_info) && (NULL != if_info->if_name)) { - if (0 == strcmp(if_info->if_name, if_name)) { - *if_index = if_info->if_index; - return 0; - } - if_info = if_info->_next; - } - - return 1; -} diff --git a/src/srvpp/src/srvpp.h b/src/srvpp/src/srvpp.h deleted file mode 100644 index 4830d7b..0000000 --- a/src/srvpp/src/srvpp.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2016 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 INC_SRVPP_H_ -#define INC_SRVPP_H_ - -/** - * @defgroup srvpp Sysrepo-VPP Integration Library - * @{ - * - * @brief Provides synchronous interface to VPP binary API aimed primarily for - * the integration of VPP with Sysrepo datastore. - * - * The library is thread-safe - can be used to communicate with VPP from multiple - * threads simultaneously. - */ - -#include - -#include -#include -#include - -#include - -#define vl_typedefs /* define message structures */ -#include -#undef vl_typedefs - -#define vl_endianfun -#include -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) -#define vl_printfun -#include -#undef vl_printfun - -/** - * @brief Sysrepo - VPP interface context. - */ -typedef struct srvpp_ctx_s srvpp_ctx_t; - -/** - * @brief srvpp logger severity levels. - */ -typedef enum srvpp_log_level_e { - SRVPP_NONE, /**< Do not print any messages. */ - SRVPP_ERR, /**< Print only error messages. */ - SRVPP_WRN, /**< Print error and warning messages. */ - SRVPP_INF, /**< Besides errors and warnings, print some other informational messages. */ - SRVPP_DBG, /**< Print all messages including some development debug messages. */ -} srvpp_log_level_t; - -/** - * @brief Sets callback that will be called when a log entry would be populated. - * - * @param[in] level Severity level of the log entry. - * @param[in] message Message of the log entry. - */ -typedef void (*srvpp_log_cb)(srvpp_log_level_t level, const char *message); - -/** - * @brief Returns a reference to the global srvpp context. If the global context - * does not exists yet, it will be automatically created (a connection to VPP - * will be established). - * - * @note The caller is supposed to call ::srvpp_release_ctx after it finishes - * the work with VPP. - * - * @return srvpp context to be used for subsequent API calls. - */ -srvpp_ctx_t* srvpp_get_ctx(); - -/** - * @brief Releases a reference to the global srvpp context. If this is the last - * reference, the context will be released (the connection to the VPP will be closed). - * - * @param[in] ctx srvpp context acquired using ::srvpp_get_ctx call. - */ -void srvpp_release_ctx(srvpp_ctx_t *ctx); - -/** - * @brief Allocates a VPP API message of specified type and size. - * - * @param[in] msg_id Message ID. - * @param[in] msg_size Size of the message. - * - * @return Space allocated for the message. - */ -void* srvpp_alloc_msg(uint16_t msg_id, size_t msg_size); - -/** - * @brief Sends a simple request to VPP and receive the response. - * - * @note Subsequent ::srvpp_send_request or ::srvpp_send_dumprequest calls from the same - * thread may overwrite the content of ::response, therefore it is not safe to call - * them until the response is fully consumed / processed by the caller. - * - * @param[in] ctx srvpp context acquired using ::srvpp_get_ctx call. - * @param[in] request Message with the request to be sent to VPP. - * @param[out] response (optional) Response to the request received from VPP. - * Caller must not free it - to save memory allocations, response is always - * placed into the same thread-local buffer owned by the library. - * - * @return 0 on success, non-zero in case of error. - */ -int srvpp_send_request(srvpp_ctx_t *ctx, void *request, void **response); - -/** - * @brief Sends a dump request to VPP and receives all responses with details. - * - * @note Subsequent ::srvpp_send_request or ::srvpp_send_dumprequest calls from the same - * thread may overwrite the content of ::response_arr, therefore it is not safe to call - * them until the response array is fully consumed / processed by the caller. - * - * @param[in] ctx srvpp context acquired using ::srvpp_get_ctx call. - * @param[in] request Message with the request to be sent to VPP. - * @param[out] response_arr Array of responses to the request received from VPP. - * Caller must not free it - to save memory allocations, response_arr is always - * placed into the same thread-local buffer owned by the library. - * @param[out] response_cnt Count of the response messages in the response_arr array. - * - * @return 0 on success, non-zero in case of error. - */ -int srvpp_send_dumprequest(srvpp_ctx_t *ctx, void *request, void ***response_arr, size_t *response_cnt); - -/** - * @brief Get interface index for provided interface name. - * - * @param[in] ctx srvpp context acquired using ::srvpp_get_ctx call. - * @param[in] if_name Name of an existing VPP interface. - * @param[out] if_index Index of the interface. - * - * @return 0 on success, non-zero in case of error. - */ -int srvpp_get_if_index(srvpp_ctx_t *ctx, const char *if_name, uint32_t *if_index); - -/** - * @brief Sets callback that will be called when a log entry would be populated. - * Callback will be called for each message with any log level. - * - * @param[in] log_callback Callback to be called when a log entry would populated. - */ -void srvpp_set_log_cb(srvpp_log_cb log_callback); - -/** - * @brief Setups message handler to provided VPP API call. Needs to be called - * for each VPP API function that can arrive as response from VPP. - * - * @param[in] ID VPP API function ID. - * @param[in] NAME VPP API function name. - */ -#define srvpp_setup_handler(ID, NAME) \ - do { \ - vl_msg_api_set_handlers(VL_API_##ID, #NAME, \ - (void*)_srvpp_receive_msg_handler, \ - (void*)vl_noop_handler, \ - (void*)vl_api_##NAME##_t_endian, \ - (void*)vl_api_##NAME##_t_print, \ - sizeof(vl_api_##NAME##_t), 1); \ - } while(0) - -/** - * @brief Internal callback automatically called by VPP library when a message - * from VPP is received. - */ -void _srvpp_receive_msg_handler(void *message); - -/**@} srvpp */ - -#endif /* INC_SRVPP_H_ */ diff --git a/src/srvpp/src/srvpp_logger.c b/src/srvpp/src/srvpp_logger.c deleted file mode 100644 index ee03a4b..0000000 --- a/src/srvpp/src/srvpp_logger.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2016 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 -#include - -#include "srvpp_logger.h" - -#define MAX_LOG_MSG_SIZE 2048 /**< Maximum size of one log entry. */ - -volatile srvpp_log_cb srvpp_log_callback = NULL; /**< Global variable used to store logging callback, if set. */ - -static pthread_once_t srvpp_log_buff_create_key_once = PTHREAD_ONCE_INIT; /** Used to control that ::srvpp_log_buff_create_key is called only once per thread. */ -static pthread_key_t srvpp_log_buff_key; /**< Key for thread-specific buffer data. */ - -/** - * @brief Create key for thread-specific buffer data. Should be called only once per thread. - */ -static void -srvpp_log_buff_create_key(void) -{ - while (pthread_key_create(&srvpp_log_buff_key, free) == EAGAIN); - pthread_setspecific(srvpp_log_buff_key, NULL); -} - -void -srvpp_logger_init() -{ - /* no init needed */ -} - -void -srvpp_logger_cleanup() -{ - /* since the thread-specific data for the main thread seems to be not auto-freed, - * (at least on Linux), we explicitly release it here for the thread from which - * sr_logger_cleanup has been called (which should be always the main thread). */ - pthread_once(&srvpp_log_buff_create_key_once, srvpp_log_buff_create_key); - char *msg_buff = pthread_getspecific(srvpp_log_buff_key); - if (NULL != msg_buff) { - free(msg_buff); - pthread_setspecific(srvpp_log_buff_key, NULL); - } -} - -void -srvpp_log_to_cb(srvpp_log_level_t level, const char *format, ...) -{ - char *msg_buff = NULL; - va_list arg_list; - - if (NULL != srvpp_log_callback) { - /* get thread-local message buffer */ - pthread_once(&srvpp_log_buff_create_key_once, srvpp_log_buff_create_key); - msg_buff = pthread_getspecific(srvpp_log_buff_key); - if (NULL == msg_buff) { - msg_buff = calloc(MAX_LOG_MSG_SIZE, sizeof(*msg_buff)); - pthread_setspecific(srvpp_log_buff_key, msg_buff); - } - /* print the message into buffer and call callback */ - if (NULL != msg_buff) { - va_start(arg_list, format); - vsnprintf(msg_buff, MAX_LOG_MSG_SIZE - 1, format, arg_list); - va_end(arg_list); - msg_buff[MAX_LOG_MSG_SIZE - 1] = '\0'; - /* call the callback */ - srvpp_log_callback(level, msg_buff); - } - } -} - diff --git a/src/srvpp/src/srvpp_logger.h b/src/srvpp/src/srvpp_logger.h deleted file mode 100644 index 3a1c947..0000000 --- a/src/srvpp/src/srvpp_logger.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2016 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 SRC_SRVPP_LOGGER_H_ -#define SRC_SRVPP_LOGGER_H_ - -#include "srvpp.h" - -/** - * @brief Pointer to logging callback, if set. - */ -extern volatile srvpp_log_cb srvpp_log_callback; - -/** - * @brief Returns the string representing the specified log level. - */ -#define _SRVPP_LL_STR(LL) \ - ((SRVPP_ERR == LL) ? "ERR" : \ - (SRVPP_WRN == LL) ? "WRN" : \ - (SRVPP_INF == LL) ? "INF" : \ - (SRVPP_DBG == LL) ? "DBG" : \ - "") - -/** - * @brief Internal logging macro for formatted messages. - */ -#ifdef NDEBUG -#define _SRVPP_LOG_FMT(LL, MSG, ...) \ - do { \ - if (NULL != srvpp_log_callback) { \ - srvpp_log_to_cb(LL, MSG, __VA_ARGS__); \ - } else { \ - fprintf(stderr, "[%s] " MSG "\n", _SRVPP_LL_STR(LL), __VA_ARGS__); \ - } \ -} while(0) -#else -#define _SRVPP_LOG_FMT(LL, MSG, ...) \ - do { \ - if (NULL != srvpp_log_callback) { \ - srvpp_log_to_cb(LL, "(%s:%d) " MSG, __func__, __LINE__, __VA_ARGS__); \ - } else { \ - fprintf(stderr, "[%s] (%s:%d) " MSG "\n", _SRVPP_LL_STR(LL), __func__, __LINE__, __VA_ARGS__); \ - } \ -} while(0) -#endif - -/* Logging macros for formatted messages. */ -#define SRVPP_LOG_ERR(MSG, ...) _SRVPP_LOG_FMT(SRVPP_ERR, MSG, __VA_ARGS__); -#define SRVPP_LOG_WRN(MSG, ...) _SRVPP_LOG_FMT(SRVPP_WRN, MSG, __VA_ARGS__); -#define SRVPP_LOG_INF(MSG, ...) _SRVPP_LOG_FMT(SRVPP_INF, MSG, __VA_ARGS__); -#define SRVPP_LOG_DBG(MSG, ...) _SRVPP_LOG_FMT(SRVPP_DBG, MSG, __VA_ARGS__); - -/* Logging macros for unformatted messages. */ -#define SRVPP_LOG_ERR_MSG(MSG) _SRVPP_LOG_FMT(SRVPP_ERR, MSG "%s", ""); -#define SRVPP_LOG_WRN_MSG(MSG) _SRVPP_LOG_FMT(SRVPP_WRN, MSG "%s", ""); -#define SRVPP_LOG_INF_MSG(MSG) _SRVPP_LOG_FMT(SRVPP_INF, MSG "%s", ""); -#define SRVPP_LOG_DBG_MSG(MSG) _SRVPP_LOG_FMT(SRVPP_DBG, MSG "%s", ""); - -/** - * @brief Initializes logger. - */ -void srvpp_logger_init(); - -/** - * @brief Cleans up resources used by he logger. - */ -void srvpp_logger_cleanup(); - -/** - * @brief Logs into the callback pre-specified by ::srvpp_set_log_cb. - * - * @param[in] level Log level. - * @param[in] format Format message. - */ -void srvpp_log_to_cb(srvpp_log_level_t level, const char *format, ...); - -#endif /* SRC_SRVPP_LOGGER_H_ */ diff --git a/src/srvpp/tests/CMakeLists.txt b/src/srvpp/tests/CMakeLists.txt deleted file mode 100644 index dc14ffb..0000000 --- a/src/srvpp/tests/CMakeLists.txt +++ /dev/null @@ -1,40 +0,0 @@ -# -# Copyright (c) 2018 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_directories ("${PROJECT_SOURCE_DIR}/src") - -# check whether valgrind is installed -find_program(valgrind_FOUND valgrind) - -# macro for adding of an unit test -macro(ADD_UNIT_TEST TEST_NAME) - set(TEST_SRC - ${TEST_NAME}.c - ) - add_executable(${TEST_NAME} ${TEST_SRC}) - target_link_libraries(${TEST_NAME} ${CMOCKA_LIBRARIES} srvpp_a) - add_test(${TEST_NAME} ${TEST_NAME}) - - if(valgrind_FOUND) - add_test(${TEST_NAME}_valgrind valgrind - --error-exitcode=1 --read-var-info=yes - --leak-check=full --show-leak-kinds=all - ./${TEST_NAME} - ) - endif(valgrind_FOUND) -endmacro(ADD_UNIT_TEST) - -# add individual unit-tests -ADD_UNIT_TEST(srvpp_test) \ No newline at end of file diff --git a/src/srvpp/tests/srvpp_test.c b/src/srvpp/tests/srvpp_test.c deleted file mode 100644 index 89e56db..0000000 --- a/src/srvpp/tests/srvpp_test.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2016 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 -#include -#include -#include -#include - -#include "srvpp.h" - -#include - -#define vl_typedefs /* define message structures */ -#include -#undef vl_typedefs - -#define vl_endianfun -#include -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) -#define vl_printfun -#include -#undef vl_printfun - -static int -srvpp_test_setup(void **state) -{ - srvpp_ctx_t *ctx = NULL; - - ctx = srvpp_get_ctx(); - assert_non_null(ctx); - - srvpp_setup_handler(CONTROL_PING_REPLY, control_ping_reply); - srvpp_setup_handler(CREATE_LOOPBACK_REPLY, create_loopback_reply); - srvpp_setup_handler(DELETE_LOOPBACK_REPLY, delete_loopback_reply); - srvpp_setup_handler(SW_INTERFACE_DETAILS, sw_interface_details); - - *state = ctx; - return 0; -} - -static int -srvpp_test_teardown(void **state) -{ - srvpp_ctx_t *ctx = *state; - - srvpp_release_ctx(ctx); - - return 0; -} - -static void -srvpp_ctx_test(void **state) -{ - srvpp_ctx_t *ctx = *state; - assert_non_null(ctx); - - srvpp_ctx_t *ctx1 = NULL, *ctx2 = NULL; - vl_api_control_ping_t *msg = NULL; - int ret = 0; - - /* try to get additional contexts */ - ctx1 = srvpp_get_ctx(); - assert_non_null(ctx1); - - ctx2 = srvpp_get_ctx(); - assert_non_null(ctx2); - - assert_true(ctx == ctx1); - assert_true(ctx1 == ctx2); - - /* send a control ping */ - msg = srvpp_alloc_msg(VL_API_CONTROL_PING, sizeof(*msg)); - assert_non_null(msg); - - ret = srvpp_send_request(ctx1, msg, NULL); - assert_int_equal(ret, 0); - - /* release not needed contexts */ - srvpp_release_ctx(ctx1); - srvpp_release_ctx(ctx2); -} - -static void -srvpp_msg_test(void **state) -{ - srvpp_ctx_t *ctx = *state; - assert_non_null(ctx); - - vl_api_create_loopback_t *create_loop_req = NULL; - vl_api_create_loopback_reply_t *create_loop_reply = NULL; - vl_api_delete_loopback_t *del_loop_req = NULL; - vl_api_sw_interface_dump_t *if_dump_req = NULL; - vl_api_sw_interface_details_t *if_details = NULL; - void **details = NULL; - size_t details_cnt = 0; - u8 mac[6] = { 0, 10, 11, 12, 13, 14}; - int if_index = -1; - int ret = 0; - - /* create a loopback interface */ - create_loop_req = srvpp_alloc_msg(VL_API_CREATE_LOOPBACK, sizeof(*create_loop_req)); - assert_non_null(create_loop_req); - - memcpy(create_loop_req->mac_address, mac, sizeof(mac)); - - ret = srvpp_send_request(ctx, create_loop_req, (void**)&create_loop_reply); - assert_int_equal(ret, 0); - assert_non_null(create_loop_reply); - if_index = ntohl(create_loop_reply->sw_if_index); - - printf("connected loopback interface, ifindex=%d\n", if_index); - - /* dump interfaces */ - if_dump_req = srvpp_alloc_msg(VL_API_SW_INTERFACE_DUMP, sizeof(*if_dump_req)); - assert_non_null(if_dump_req); - - ret = srvpp_send_dumprequest(ctx, if_dump_req, &details, &details_cnt); - assert_int_equal(ret, 0); - - for (size_t i = 0; i < details_cnt; i++) { - if_details = (vl_api_sw_interface_details_t *) details[i]; - printf("interface %s id=%d %s\n", if_details->interface_name, ntohl(if_details->sw_if_index), if_details->admin_up_down ? "up" : "down"); - } - - /* delete a loopback interface */ - del_loop_req = srvpp_alloc_msg(VL_API_DELETE_LOOPBACK, sizeof(*del_loop_req)); - assert_non_null(del_loop_req); - - del_loop_req->sw_if_index = htonl(if_index); - - ret = srvpp_send_request(ctx, del_loop_req, NULL); - assert_int_equal(ret, 0); -} - -int -main() -{ - const struct CMUnitTest tests[] = { - cmocka_unit_test_setup_teardown(srvpp_ctx_test, srvpp_test_setup, srvpp_test_teardown), - cmocka_unit_test_setup_teardown(srvpp_msg_test, srvpp_test_setup, srvpp_test_teardown), - }; - - return cmocka_run_group_tests(tests, NULL, NULL); -} -- cgit 1.2.3-korg