diff options
author | Hongjun Ni <hongjun.ni@intel.com> | 2018-11-27 23:07:20 +0800 |
---|---|---|
committer | Hongjun Ni <hongjun.ni@intel.com> | 2018-11-28 00:14:25 +0800 |
commit | 63e7bd9f2730b41f236e0b5d3731e6059210c4c4 (patch) | |
tree | 9211f9392925fcbd0067a540a6e70310e6810dfe /src | |
parent | 76c1926491edcc8a650cc3b5eb87e06d1530cabe (diff) |
Rework vpp connection based on vapi library
Change-Id: I3b41b4141fd7ef7577f4f2cc9193b9c623a9d6d7
Signed-off-by: Chuanguo Wang <wangchuanguo@huachentel.com>
Signed-off-by: Hongjun Ni <hongjun.ni@intel.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/plugins/CMakeLists.txt | 15 | ||||
-rw-r--r-- | src/plugins/sc_interface.c (renamed from src/plugins/vpp-interfaces.c) | 418 | ||||
-rw-r--r-- | src/plugins/sc_interface.h | 58 | ||||
-rw-r--r-- | src/plugins/sc_plugins.c | 164 | ||||
-rw-r--r-- | src/plugins/sc_plugins.h | 31 | ||||
-rw-r--r-- | src/scvpp/CMakeLists.txt (renamed from src/srvpp/CMakeLists.txt) | 6 | ||||
-rw-r--r-- | src/scvpp/libscvpp.pc.in (renamed from src/srvpp/libsrvpp.pc.in) | 20 | ||||
-rw-r--r-- | src/scvpp/src/CMakeLists.txt (renamed from src/srvpp/src/CMakeLists.txt) | 25 | ||||
-rw-r--r-- | src/scvpp/src/sc_vpp_operation.c | 73 | ||||
-rw-r--r-- | src/scvpp/src/sc_vpp_operation.h | 104 | ||||
-rw-r--r-- | src/scvpp/tests/CMakeLists.txt (renamed from src/srvpp/tests/CMakeLists.txt) | 4 | ||||
-rw-r--r-- | src/scvpp/tests/scvpp_test.c | 54 | ||||
-rw-r--r-- | src/srvpp/src/srvpp.c | 823 | ||||
-rw-r--r-- | src/srvpp/src/srvpp.h | 185 | ||||
-rw-r--r-- | src/srvpp/src/srvpp_logger.c | 83 | ||||
-rw-r--r-- | src/srvpp/src/srvpp_logger.h | 89 | ||||
-rw-r--r-- | src/srvpp/tests/srvpp_test.c | 160 |
18 files changed, 796 insertions, 1518 deletions
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/vpp-interfaces.c b/src/plugins/sc_interface.c index bb1f046..41fd535 100644 --- a/src/plugins/vpp-interfaces.c +++ b/src/plugins/sc_interface.c @@ -18,22 +18,15 @@ #include <netinet/in.h> #include <arpa/inet.h> +#include "sc_interface.h" #include <sysrepo.h> #include <sysrepo/plugins.h> #include <sysrepo/values.h> #include <sysrepo/xpath.h> -#include <srvpp.h> +#include <vnet/interface.h> +#include <vapi/interface.api.vapi.h> -/** 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; +DEFINE_VAPI_MSG_IDS_INTERFACE_API_JSON; /** * @brief Helper function for converting netmask into prefix length. @@ -73,69 +66,25 @@ ip_addr_str_to_binary(const char *ip_address_str, uint8_t *ip_address_bin, bool } /** - * @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) +interface_enable_disable(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); + 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; } - /* 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); - + /* 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; @@ -148,7 +97,7 @@ interface_enable_disable(plugin_ctx_t *plugin_ctx, const char *if_name, bool ena * @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) +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; @@ -180,10 +129,10 @@ interface_enable_disable_cb(sr_session_ctx_t *session, const char *xpath, sr_not switch (op) { case SR_OP_CREATED: case SR_OP_MODIFIED: - op_rc = interface_enable_disable(private_ctx, if_name, new_val->data.bool_val); + op_rc = interface_enable_disable(if_name, new_val->data.bool_val); break; case SR_OP_DELETED: - op_rc = interface_enable_disable(private_ctx, if_name, false /* !enable */); + op_rc = interface_enable_disable(if_name, false /* !enable */); break; default: break; @@ -204,34 +153,22 @@ interface_enable_disable_cb(sr_session_ctx_t *session, const char *xpath, sr_not * @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) +interface_ipv46_config_add_remove(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); + 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; } - /* 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); - + /* 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; @@ -239,12 +176,217 @@ interface_ipv46_config_add_remove(plugin_ctx_t *plugin_ctx, const char *if_name, 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(plugin_ctx_t *plugin_ctx, sr_session_ctx_t *session, const char *if_name, +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, }; @@ -268,7 +410,7 @@ interface_ipv46_config_modify(plugin_ctx_t *plugin_ctx, sr_session_ctx_t *sessio 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 */); + 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; @@ -282,7 +424,7 @@ interface_ipv46_config_modify(plugin_ctx_t *plugin_ctx, sr_session_ctx_t *sessio } /* set new IP config */ - rc = interface_ipv46_config_add_remove(plugin_ctx, if_name, addr, prefix, is_ipv6, true /* add */); + 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; @@ -296,7 +438,7 @@ interface_ipv46_config_modify(plugin_ctx_t *plugin_ctx, sr_session_ctx_t *sessio * 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) +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; @@ -354,12 +496,12 @@ interface_ipv46_address_change_cb(sr_session_ctx_t *session, const char *xpath, 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 */); + 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(private_ctx, session, if_name, old_val, new_val, is_ipv6); + 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) { @@ -377,7 +519,7 @@ interface_ipv46_address_change_cb(sr_session_ctx_t *session, const char *xpath, 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 */); + op_rc = interface_ipv46_config_add_remove(if_name, addr, prefix, is_ipv6, false /* !add */); } } break; @@ -401,7 +543,7 @@ interface_ipv46_address_change_cb(sr_session_ctx_t *session, const char *xpath, * 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) +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); @@ -412,55 +554,62 @@ interface_change_cb(sr_session_ctx_t *session, const char *xpath, sr_notif_event * @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) +sc_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; + 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 */ - *values_cnt = 0; - return SR_ERR_OK; + printf("============= you want %s ?\n ", xpath); + *values = NULL; + *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) { + 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 = details_cnt * 5; + 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); - for (size_t i = 0; i < details_cnt; i++) { - if_details = (vl_api_sw_interface_details_t *) details[i]; + 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, "local") ? "iana-if-type:propVirtual" : "iana-if-type:ethernetCsmacd"); + 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) { @@ -468,19 +617,30 @@ interface_state_cb(const char *xpath, sr_val_t **values, size_t *values_cnt, voi 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 = get_if_link_speed(if_details->link_speed); + 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; } @@ -488,84 +648,52 @@ interface_state_cb(const char *xpath, sr_val_t **values, size_t *values_cnt, voi * @brief Callback to be called by plugin daemon upon plugin load. */ int -sr_plugin_init_cb(sr_session_ctx_t *session, void **private_ctx) +sc_interface_subscribe_events(sr_session_ctx_t *session, + sr_subscription_ctx_t **subscription) { - 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); + 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", - interface_enable_disable_cb, ctx, 100, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_EV_ENABLED, &ctx->sr_subscription); + 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", - interface_ipv46_address_change_cb, ctx, 99, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_EV_ENABLED, &ctx->sr_subscription); + 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", - interface_ipv46_address_change_cb, ctx, 98, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_EV_ENABLED, &ctx->sr_subscription); + 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", - interface_state_cb, ctx, SR_SUBSCR_CTX_REUSE, &ctx->sr_subscription); + sc_interface_state_cb, g_vapi_ctx_instance, SR_SUBSCR_DEFAULT/*SR_SUBSCR_CTX_REUSE*/, subscription); if (SR_ERR_OK != rc) { goto error; } - *private_ctx = ctx; 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 vpp-interfaces plugin."); - sr_plugin_cleanup_cb(session, ctx); + SRP_LOG_ERR_MSG("Error by initialization of the sc_interfaces plugin."); + sr_plugin_cleanup_cb(session, g_vapi_ctx_instance); 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/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 <vapi/interface.api.vapi.h> + +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 <vapi/vapi.h> +#include <vapi/vpe.api.vapi.h> +#include <vapi/interface.api.vapi.h> +#include <vapi/l2.api.vapi.h> +#include <vapi/stats.api.vapi.h> +#include <vapi/ip.api.vapi.h> +#include <vapi/tap.api.vapi.h> +#include <vapi/ipsec.api.vapi.h> +#include <vapi/vxlan.api.vapi.h> +#include <vapi/hc.api.vapi.h> +#include <vnet/interface.h> +#include <vnet/mpls/mpls_types.h> +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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <inttypes.h> +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 <sysrepo.h> +#include <sysrepo/values.h> +#include <sysrepo/plugins.h> + +//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/srvpp/CMakeLists.txt b/src/scvpp/CMakeLists.txt index 539675d..1256fc8 100644 --- a/src/srvpp/CMakeLists.txt +++ b/src/scvpp/CMakeLists.txt @@ -14,7 +14,7 @@ # cmake_minimum_required(VERSION 2.8) -project(srvpp) +project(scvpp) # add subdirectories add_subdirectory(src) @@ -35,6 +35,6 @@ 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") + 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/srvpp/libsrvpp.pc.in b/src/scvpp/libscvpp.pc.in index c57c267..ce996e3 100644 --- a/src/srvpp/libsrvpp.pc.in +++ b/src/scvpp/libscvpp.pc.in @@ -1,10 +1,10 @@ -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} - +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/srvpp/src/CMakeLists.txt b/src/scvpp/src/CMakeLists.txt index 8cc0a04..3961971 100644 --- a/src/srvpp/src/CMakeLists.txt +++ b/src/scvpp/src/CMakeLists.txt @@ -15,15 +15,14 @@ include(GNUInstallDirs) -# srvpp sources -set(SRVPP_SOURCES - srvpp_logger.c - srvpp.c +# scvpp sources +set(SCVPP_SOURCES + sc_vpp_operation.c ) -# srvpp public headers -set(SRVPP_HEADERS - srvpp.h +# 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") @@ -32,13 +31,13 @@ set(CMAKE_C_FLAGS " -g -O0 -fpic -fPIC -std=gnu99 -Wl,-rpath-link=/usr/lib") 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}) +add_library(scvpp SHARED ${SCVPP_SOURCES}) +add_library(scvpp_a ${SCVPP_SOURCES}) # linker instructions -target_link_libraries(srvpp ${LINK_LIBRARIES}) -target_link_libraries(srvpp_a ${LINK_LIBRARIES}) +target_link_libraries(scvpp ${LINK_LIBRARIES}) +target_link_libraries(scvpp_a ${LINK_LIBRARIES}) # install rules -install(TARGETS srvpp DESTINATION ${CMAKE_INSTALL_LIBDIR}) -install(FILES ${SRVPP_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +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 <vapi/vapi.h> +#include <vapi/vpe.api.vapi.h> +DEFINE_VAPI_MSG_IDS_VPE_API_JSON; + +#include <sysrepo.h> +#include <sysrepo/values.h> +#include <sysrepo/plugins.h> //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/srvpp/tests/CMakeLists.txt b/src/scvpp/tests/CMakeLists.txt index dc14ffb..bd135bf 100644 --- a/src/srvpp/tests/CMakeLists.txt +++ b/src/scvpp/tests/CMakeLists.txt @@ -24,7 +24,7 @@ macro(ADD_UNIT_TEST TEST_NAME) ${TEST_NAME}.c ) add_executable(${TEST_NAME} ${TEST_SRC}) - target_link_libraries(${TEST_NAME} ${CMOCKA_LIBRARIES} srvpp_a) + target_link_libraries(${TEST_NAME} ${CMOCKA_LIBRARIES} scvpp_a) add_test(${TEST_NAME} ${TEST_NAME}) if(valgrind_FOUND) @@ -37,4 +37,4 @@ macro(ADD_UNIT_TEST TEST_NAME) endmacro(ADD_UNIT_TEST) # add individual unit-tests -ADD_UNIT_TEST(srvpp_test)
\ No newline at end of file +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 <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <setjmp.h> +#include <cmocka.h> + +#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/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 <stdlib.h> -#include <stdint.h> -#include <stdbool.h> -#include <pthread.h> - -#include "srvpp.h" -#include "srvpp_logger.h" - -#undef vl_api_version -#define vl_api_version(n,v) static u32 vpe_api_version = v; -#include <vpp/api/vpe.api.h> -#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 <stddef.h> - -#include <vlibapi/api.h> -#include <vlibmemory/api.h> -#include <vapi/vpe.api.vapi.h> - -#include <vpp/api/vpe_msg_enum.h> - -#define vl_typedefs /* define message structures */ -#include <vpp/api/vpe_all_api_h.h> -#undef vl_typedefs - -#define vl_endianfun -#include <vpp/api/vpe_all_api_h.h> -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) -#define vl_printfun -#include <vpp/api/vpe_all_api_h.h> -#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 <stdlib.h> -#include <pthread.h> - -#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/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 <stdlib.h> -#include <stdio.h> -#include <unistd.h> -#include <setjmp.h> -#include <cmocka.h> - -#include "srvpp.h" - -#include <vpp/api/vpe_msg_enum.h> - -#define vl_typedefs /* define message structures */ -#include <vpp/api/vpe_all_api_h.h> -#undef vl_typedefs - -#define vl_endianfun -#include <vpp/api/vpe_all_api_h.h> -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) -#define vl_printfun -#include <vpp/api/vpe_all_api_h.h> -#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); -} |