diff options
Diffstat (limited to 'src/scvpp')
-rw-r--r-- | src/scvpp/CMakeLists.txt | 66 | ||||
-rw-r--r-- | src/scvpp/inc/scvpp/comm.h (renamed from src/scvpp/src/sc_vpp_comm.h) | 107 | ||||
-rw-r--r-- | src/scvpp/inc/scvpp/interface.h | 69 | ||||
-rw-r--r-- | src/scvpp/inc/scvpp/ip.h | 77 | ||||
-rw-r--r-- | src/scvpp/inc/scvpp/nat.h (renamed from src/scvpp/src/sc_vpp_nat.h) | 0 | ||||
-rw-r--r-- | src/scvpp/inc/scvpp/v3po.h | 54 | ||||
-rw-r--r-- | src/scvpp/src/CMakeLists.txt | 57 | ||||
-rw-r--r-- | src/scvpp/src/comm.c (renamed from src/scvpp/src/sc_vpp_comm.c) | 22 | ||||
-rw-r--r-- | src/scvpp/src/interface.c | 176 | ||||
-rw-r--r-- | src/scvpp/src/ip.c (renamed from src/scvpp/src/sc_vpp_ip.c) | 185 | ||||
-rw-r--r-- | src/scvpp/src/nat.c (renamed from src/scvpp/src/sc_vpp_nat.c) | 133 | ||||
-rw-r--r-- | src/scvpp/src/sc_vpp_interface.c | 252 | ||||
-rw-r--r-- | src/scvpp/src/sc_vpp_interface.h | 61 | ||||
-rw-r--r-- | src/scvpp/src/sc_vpp_ip.h | 36 | ||||
-rw-r--r-- | src/scvpp/src/sc_vpp_v3po.h | 26 | ||||
-rw-r--r-- | src/scvpp/src/v3po.c (renamed from src/scvpp/src/sc_vpp_v3po.c) | 66 | ||||
-rw-r--r-- | src/scvpp/tests/CMakeLists.txt | 37 | ||||
-rw-r--r-- | src/scvpp/tests/scvpp_iface_test.c | 130 | ||||
-rw-r--r-- | src/scvpp/tests/scvpp_ip_test.c | 184 | ||||
-rw-r--r-- | src/scvpp/tests/scvpp_nat_test.c | 51 | ||||
-rw-r--r-- | src/scvpp/tests/scvpp_test.c | 160 | ||||
-rw-r--r-- | src/scvpp/tests/scvpp_test.h (renamed from src/scvpp/tests/scvpp_nat_test.h) | 17 |
22 files changed, 1164 insertions, 802 deletions
diff --git a/src/scvpp/CMakeLists.txt b/src/scvpp/CMakeLists.txt index 2dc42d6..8d04085 100644 --- a/src/scvpp/CMakeLists.txt +++ b/src/scvpp/CMakeLists.txt @@ -16,8 +16,57 @@ cmake_minimum_required(VERSION 2.8) project(scvpp) -# DEPENDENCIES -############## +# COMPILER & LINKER +################### + +# scvpp sources +set(SCVPP_SOURCES + src/comm.c + src/interface.c + src/ip.c + src/v3po.c + src/nat.c +) + +# scvpp public headers +set(SCVPP_HEADERS + inc/scvpp/comm.h + inc/scvpp/interface.h + inc/scvpp/ip.h + inc/scvpp/v3po.h + inc/scvpp/nat.h +) + +#define CMAKE_INSTALL_LIBDIR/INCLUDEDIR +include(GNUInstallDirs) + +# Generate a compile_commands.json with compile options +set(CMAKE_EXPORT_COMPILE_COMMANDS 1) + +#set compiler and linker flags +set(RIGOROUS_C_FLAGS "-Wlogical-op -Wformat=2") +set(CMAKE_C_FLAGS "-Wall -Wextra -std=gnu99 ${RIGOROUS_C_FLAGS}") +set(CMAKE_C_FLAGS_DEBUG "-Wall -Wextra -std=gnu99 -g -O0 ${RIGOROUS_C_FLAGS}") +#NDEBUG to skip assert checks +set(CMAKE_C_FLAGS_RELEASE "-Wall -Wextra -std=gnu99 -DNDEBUG -O2 ${RIGOROUS_C_FLAGS}") + +# libraries to link with +set(LINK_LIBRARIES 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}) + +# to build shared and static library for scvpp, include project private directory inc before installing header file +target_include_directories(scvpp PRIVATE inc) +target_include_directories(scvpp_a PRIVATE inc) + +# TESTING +######### # enable testing if requested and possible SET(ENABLE_TESTS 1 CACHE BOOL "Enable unit tests.") @@ -32,16 +81,13 @@ if(ENABLE_TESTS) endif(CMOCKA_FOUND) endif(ENABLE_TESTS) -# COMPILER & LINKER & INSTALL -############################# - -#define CMAKE_INSTALL_LIBDIR/INCLUDEDIR -include(GNUInstallDirs) -add_subdirectory(src) +# INSTALL +######### -# MORE INSTALL -############## +# install rules +install(TARGETS scvpp DESTINATION ${CMAKE_INSTALL_LIBDIR}) +install(FILES ${SCVPP_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/scvpp) find_package(PkgConfig QUIET) #QUIET disables message if not found if(PKG_CONFIG_FOUND) diff --git a/src/scvpp/src/sc_vpp_comm.h b/src/scvpp/inc/scvpp/comm.h index eeeaaf9..9a27517 100644 --- a/src/scvpp/src/sc_vpp_comm.h +++ b/src/scvpp/inc/scvpp/comm.h @@ -23,22 +23,30 @@ #include <vapi/vapi_common.h> #include <vapi/vpe.api.vapi.h> +typedef enum { + SCVPP_OK = 0, /* Success */ + SCVPP_EINVAL, /* Invalid value encountered */ + SCVPP_EAGAIN, /* Operation would block */ + SCVPP_ENOTSUP, /* Operation not supported */ + SCVPP_ENOMEM, /* Out of memory */ + SCVPP_NOT_FOUND, /* Required element can not be found */ +} scvpp_error_e; + // Use VAPI macros to define symbols DEFINE_VAPI_MSG_IDS_VPE_API_JSON; -#define VPP_INTFC_NAME_LEN 64 -#define VPP_TAPV2_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_IP4_PREFIX_STRING_LEN 19 #define VPP_IP4_HOST_PREFIX_LEN 32 -#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 +#define VPP_INTFC_NAME_LEN 64 /* Interface name max length */ +#define VPP_IP4_ADDRESS_LEN 4 /* IPv4 length in VPP format */ +#define VPP_IP6_ADDRESS_LEN 16 /* IPv6 length in VPP format */ +#define VPP_MAC_ADDRESS_LEN 8 /* MAC length in VPP format */ +/* IPv4 and IPv6 length in string format */ +#define VPP_IP4_ADDRESS_STRING_LEN INET_ADDRSTRLEN //16, include '\0' +#define VPP_IP6_ADDRESS_STRING_LEN INET6_ADDRSTRLEN //46, include '\0' +#define VPP_IP4_PREFIX_STRING_LEN \ + INET_ADDRSTRLEN + sizeof('/') + 2 // include '\0' +#define VPP_IP6_PREFIX_STRING_LEN \ + INET6_ADDRSTRLEN + sizeof('/') + 3 // include '\0' /**********************************MACROS**********************************/ #define ARG_CHECK(retval, arg) \ @@ -86,9 +94,10 @@ api_name##_cb (vapi_ctx_t ctx, void *caller_ctx, vapi_error_e rv, bool is_last, vapi_payload_##api_name##_reply * reply) \ { \ UNUSED(ctx); UNUSED(rv); UNUSED(is_last); \ + vapi_payload_##api_name##_reply * passed; \ if (caller_ctx) \ { \ - vapi_payload_##api_name##_reply * passed = (vapi_payload_##api_name##_reply *)caller_ctx; \ + passed = (vapi_payload_##api_name##_reply *)caller_ctx; \ *passed = *reply; \ } \ return VAPI_OK; \ @@ -104,13 +113,81 @@ api_name##_cb (vapi_ctx_t ctx, void *caller_ctx, vapi_error_e rv, bool is_last, else \ { \ while (VAPI_EAGAIN == (rv = call_code)); \ - rv = vapi_dispatch (g_vapi_ctx_instance); \ + if (rv != VAPI_OK) { /* try once more to get reply */ \ + rv = vapi_dispatch (g_vapi_ctx); \ + } \ } \ } \ while (0) #define VAPI_CALL(call_code) VAPI_CALL_MODE(call_code, g_vapi_mode) +struct elt { + void *data; //vapi_payload structure + struct elt *next; + int id; //id of the stack element to count total nb of elements +}; + +static inline int push(struct elt **stack, void *data, int length) +{ + struct elt *el; + + //new stack node + el = malloc(sizeof(struct elt)); + if (!el) + return -ENOMEM; + el->data = malloc(length); + if (!el->data) + return -ENOMEM; + + memcpy(el->data, data, length); + if (*stack) + el->id = (*stack)->id++; + else + el->id = 0; + el->next = *stack; //point to old value of stack + *stack = el; //el is new stack head + + return 0; +} + +static inline void * pop(struct elt **stack) +{ + struct elt *prev; + void *data; + + if (!(*stack)) + return NULL; + + data = (*stack)->data; //get data at stack head + prev = *stack; //save stack to free memory later + *stack = (*stack)->next; //new stack + + free(prev); + prev = NULL; + + return data; +} + +#define VAPI_DUMP_LIST_CB(api_name) \ +static vapi_error_e \ +api_name##_all_cb(vapi_ctx_t ctx, void *caller_ctx, vapi_error_e rv, bool is_last, \ + vapi_payload_##api_name##_details *reply) \ +{ \ + UNUSED(ctx); UNUSED(rv); UNUSED(is_last); \ + struct elt **stackp; \ + ARG_CHECK2(VAPI_EINVAL, caller_ctx, reply); \ + \ + stackp = (struct elt**) caller_ctx; \ + push(stackp, reply, sizeof(*reply)); \ + \ + return VAPI_OK; \ +} + +#define foreach_stack_elt(stack) \ + for(void *data = pop(&stack); data != NULL ; data = pop(&stack)) +//for(void *data = pop(&stack); stack != NULL ; data = pop(&stack)) // No!! + int sc_aton(const char *cp, u8 * buf, size_t length); char * sc_ntoa(const u8 * buf); @@ -126,7 +203,7 @@ uint32_t hardntohlu32(uint8_t host[4]); * VPP */ -extern vapi_ctx_t g_vapi_ctx_instance; +extern vapi_ctx_t g_vapi_ctx; extern vapi_mode_e g_vapi_mode; int sc_connect_vpp(); diff --git a/src/scvpp/inc/scvpp/interface.h b/src/scvpp/inc/scvpp/interface.h new file mode 100644 index 0000000..86cd185 --- /dev/null +++ b/src/scvpp/inc/scvpp/interface.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018 PANTHEON.tech. + * + * 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 __BAPI_INTERFACE_H__ +#define __BAPI_INTERFACE_H__ + +#include <vapi/interface.api.vapi.h> +#include <scvpp/comm.h> + +typedef vapi_payload_sw_interface_details sw_interface_dump_t; + +/** + * @brief Change an interface state + * @param interface_name - name of target interface + * @param enable - true=state up, false=state down + * @return 0 for success, else negative SCVPP error code + */ +int interface_enable(const char *interface_name, const bool enable); + +/** + * @brief Dump details about all existing interfaces + * @return stack structure containing all interfaces or NULL if empty + */ +extern struct elt * interface_dump_all(); + + +/** + * @brief Dump details about a specific interface + * @param details - where answer will be written + * @param interface_name - name of the interface to dump + * @return 0 for success or negative SCVPP error code + */ +extern int interface_dump_iface(sw_interface_dump_t *details, + const char *interface_name); + +/* + * Library internal helper functions. Symbols should not be exported eventually + */ + +/* + * @brief Get VPP internal index for an interface + * @param interface_name - name of the interface to get id from + * @param sw_if_index - pointer to interface index to be returned + * @return 0 upon success or negative SCVPP error code + */ +extern int get_interface_id(const char *interface_name, uint32_t *sw_if_index); + +/* @brief Get interface name from an interface ID. This is a super expensive + * operation !!! Avoid using it. + * @param interface_name - pointer to string holding returned interface name + * @param sw_if_index - interface index provided + * @return 0 upon success or negative SCVPP error code + */ +extern int get_interface_name(char *interface_name, uint32_t sw_if_index); + +#endif /* __BAPI_INTERFACE_H__ */ diff --git a/src/scvpp/inc/scvpp/ip.h b/src/scvpp/inc/scvpp/ip.h new file mode 100644 index 0000000..f8805b3 --- /dev/null +++ b/src/scvpp/inc/scvpp/ip.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2018 PANTHEON.tech. + * + * 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 __BAPI_IP_H__ +#define __BAPI_IP_H__ + +#include <vapi/interface.api.vapi.h> +#include <vapi/ip.api.vapi.h> + +typedef vapi_payload_ip_fib_details fib_dump_t; + +/* + * @brief Dump IPv4/IPv6 address from an interface. + * @param interface_name - name of the interface to get ip from. + * @param ip_addr - where dump will store IP. If IP not found, returns 0.0.0.0 + * @param prefix_len - pointer where dump will store prefix + * @param is_ipv6 - true = IPv6, false = IPv4 + * @return 0 on success, or nergative SCVPP error code + */ +extern int ipv46_address_dump(const char *interface_name, char *ip_addr, + u8 *prefix_len, bool is_ipv6); + +/** + * @brief Add or remove IPv4/IPv6 address to/from an interface. + * @param interface_name - name of interface to configure + * @param addr - address to add + * @param prefix_len - prefix length of interface + * @param is_ipv6 - true if ipv6, false otherwise + * @param add - true to add, false to remove + */ +extern int ipv46_config_add_remove(const char *interface_name, const char *addr, + uint8_t prefix_len, bool is_ipv6, bool add); + +/* + * TODO should add a field is_ipv6 because it only do ipv4 now + * @brief Add or remove an IP route + * @param dst_address - subnet IP you wish to route + * @param dst_address_length - prefix length for subnet you wish to route + * @param next_address - Next hop IP (can use next_hop_interface instead) + * @param is_add - true to add, false to remove + * @param table_id - id of the tab in FIB + * @param next_hop_interface - Next hop interface (can use next_address instead) + */ +extern int +ipv46_config_add_del_route(const char* dst_address, u8 dst_address_length, + const char* next_address, u8 is_add, u32 table_id, + const char *next_hop_interface); + +/** + * @brief Dump all FIB tables entries + * @return stacked answers on success, or NULL on failure + */ +extern struct elt* ipv4_fib_dump_all(); + +/* + * @brief Dump information about a prefix, based on fib_dump_all + * @param prefix_xpath - prefix to look for in FIB + * @param reply - FIB entry dump replied + * @return SCVPP_OK if prefix found or SCVPP_NOT_FOUND + */ +extern int ipv4_fib_dump_prefix(const char *prefix_xpath, fib_dump_t **reply); + +#endif /* __BAPI_IP_H__ */ diff --git a/src/scvpp/src/sc_vpp_nat.h b/src/scvpp/inc/scvpp/nat.h index 40e727e..40e727e 100644 --- a/src/scvpp/src/sc_vpp_nat.h +++ b/src/scvpp/inc/scvpp/nat.h diff --git a/src/scvpp/inc/scvpp/v3po.h b/src/scvpp/inc/scvpp/v3po.h new file mode 100644 index 0000000..f876ab4 --- /dev/null +++ b/src/scvpp/inc/scvpp/v3po.h @@ -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. + */ + +#ifndef _V3PO__INTERFACE_H__ +#define _V3PO__INTERFACE_H__ + +#include <vapi/tapv2.api.vapi.h> +#include <vapi/l2.api.vapi.h> + +/** + * V3PO defines operations for specific interfaces used by VPP like: + * - tapv2 + */ + +/* tapv2 */ + +typedef vapi_payload_tap_create_v2 tapv2_create_t; +typedef vapi_payload_sw_interface_tap_v2_details tapv2_dump_t; + +/** + * TODO problem: vapi_payload_sw_interface_tap_v2_details reply is NULL + * @brief Dump information about a tap interface + * @param dump - where dump information will be stored + * @return 0 on success, or negative SCVPP error code + */ +extern int dump_tapv2(tapv2_dump_t *dump); + +/** + * @brief Create a tapv2 interface + * @param query - required structure for the creation of a VPP tapv2 interface + * @return 0 on success, or negative SCVPP error code + */ +extern int create_tapv2(tapv2_create_t *query); + +/** + * @brief Delete a tapv2 interface + * @param interface_name - name of the interface to delete + * @return 0 on success, or negative SCVPP error code + */ +extern int delete_tapv2(char *interface_name); + +#endif /* __V3PO_INTERFACE_H__ */ diff --git a/src/scvpp/src/CMakeLists.txt b/src/scvpp/src/CMakeLists.txt deleted file mode 100644 index 71a891f..0000000 --- a/src/scvpp/src/CMakeLists.txt +++ /dev/null @@ -1,57 +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. -# - -# scvpp sources -set(SCVPP_SOURCES - sc_vpp_comm.c - sc_vpp_interface.c - sc_vpp_ip.c - sc_vpp_v3po.c - sc_vpp_nat.c -) - -# scvpp public headers -set(SCVPP_HEADERS - sc_vpp_comm.h - sc_vpp_interface.h - sc_vpp_ip.h - sc_vpp_v3po.h - sc_vpp_nat.h -) - -# Generate a compile_commands.json with compile options -set(CMAKE_EXPORT_COMPILE_COMMANDS 1) - -#set compiler and linker flags -set(RIGOROUS_C_FLAGS "-Wlogical-op -Wformat=2") -set(CMAKE_C_FLAGS "-Wall -Wextra -std=gnu99 ${RIGOROUS_C_FLAGS}") -set(CMAKE_C_FLAGS_DEBUG "-Wall -Wextra -std=gnu99 -g -O0 ${RIGOROUS_C_FLAGS}") -#NDEBUG to skip assert checks -set(CMAKE_C_FLAGS_RELEASE "-Wall -Wextra -std=gnu99 -DNDEBUG -O2 ${RIGOROUS_C_FLAGS}") - -# libraries to link with -set(LINK_LIBRARIES 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_comm.c b/src/scvpp/src/comm.c index cd0b035..a065b58 100644 --- a/src/scvpp/src/sc_vpp_comm.c +++ b/src/scvpp/src/comm.c @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "sc_vpp_comm.h" +#include <scvpp/comm.h> #include <assert.h> #include <string.h> @@ -24,21 +24,21 @@ #define MAX_OUTSTANDING_REQUESTS 4 #define RESPONSE_QUEUE_SIZE 2 -vapi_ctx_t g_vapi_ctx_instance = NULL; +vapi_ctx_t g_vapi_ctx = NULL; vapi_mode_e g_vapi_mode = VAPI_MODE_NONBLOCKING; int sc_connect_vpp() { - if (g_vapi_ctx_instance == NULL) + if (g_vapi_ctx == NULL) { - vapi_error_e rv = vapi_ctx_alloc(&g_vapi_ctx_instance); - rv = vapi_connect(g_vapi_ctx_instance, APP_NAME, NULL, + vapi_error_e rv = vapi_ctx_alloc(&g_vapi_ctx); + rv = vapi_connect(g_vapi_ctx, APP_NAME, NULL, MAX_OUTSTANDING_REQUESTS, RESPONSE_QUEUE_SIZE, VAPI_MODE_BLOCKING, true); if (rv != VAPI_OK) { - vapi_ctx_free(g_vapi_ctx_instance); - g_vapi_ctx_instance = NULL; + vapi_ctx_free(g_vapi_ctx); + g_vapi_ctx = NULL; return -1; } } @@ -48,11 +48,11 @@ int sc_connect_vpp() int sc_disconnect_vpp() { - if (NULL != g_vapi_ctx_instance) + if (NULL != g_vapi_ctx) { - vapi_disconnect(g_vapi_ctx_instance); - vapi_ctx_free(g_vapi_ctx_instance); - g_vapi_ctx_instance = NULL; + vapi_disconnect(g_vapi_ctx); + vapi_ctx_free(g_vapi_ctx); + g_vapi_ctx = NULL; } return 0; } diff --git a/src/scvpp/src/interface.c b/src/scvpp/src/interface.c new file mode 100644 index 0000000..53cea1c --- /dev/null +++ b/src/scvpp/src/interface.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2018 PANTHEON.tech. + * + * 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 <assert.h> +#include <stdbool.h> + +#include <scvpp/comm.h> +#include <scvpp/interface.h> + +// Use VAPI macros to define symbols +DEFINE_VAPI_MSG_IDS_INTERFACE_API_JSON + +static vapi_error_e +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) +{ + UNUSED(rv); UNUSED(ctx); UNUSED(is_last); + + vapi_payload_sw_interface_details *passed; + + ARG_CHECK2(VAPI_EINVAL, callback_ctx, reply); + + //copy + passed = (vapi_payload_sw_interface_details *) callback_ctx; + *passed = *reply; + + return VAPI_OK; +} + +static vapi_error_e +bin_api_sw_interface_dump(vapi_payload_sw_interface_details *details, + const char *iface_name) +{ + vapi_msg_sw_interface_dump *mp; + vapi_error_e rv; + + mp = vapi_alloc_sw_interface_dump(g_vapi_ctx); + assert(NULL != mp); + + /* Dump a specific interfaces */ + mp->payload.name_filter_valid = true; + strncpy((char *)mp->payload.name_filter, iface_name, VPP_INTFC_NAME_LEN); + + VAPI_CALL(vapi_sw_interface_dump(g_vapi_ctx, mp, + sw_interface_dump_cb, details)); + if (rv != VAPI_OK) + return -SCVPP_EINVAL; + + return rv; +} + +int get_interface_id(const char *if_name, uint32_t *sw_if_index) +{ + vapi_payload_sw_interface_details details = {0}; + vapi_error_e rv; + + ARG_CHECK2(-SCVPP_EINVAL, if_name, sw_if_index); + + rv = bin_api_sw_interface_dump(&details, if_name); + if (rv != VAPI_OK) + return -SCVPP_EINVAL; + + if (strncmp(if_name, (char*) details.interface_name, VPP_INTFC_NAME_LEN) + != 0) + return -SCVPP_NOT_FOUND; + + *sw_if_index = details.sw_if_index; + + return 0; +} + +/* + * dump only a specific interface + */ +int interface_dump_iface(sw_interface_dump_t *details, const char *iface_name) +{ + vapi_error_e rv; + + rv = bin_api_sw_interface_dump(details, iface_name); + if (rv != VAPI_OK) + return -SCVPP_EINVAL; + + if (strncmp(iface_name, (char*) details->interface_name, VPP_INTFC_NAME_LEN) + != 0) + return -SCVPP_NOT_FOUND; + + return SCVPP_OK; +} + +VAPI_DUMP_LIST_CB(sw_interface) + +struct elt* interface_dump_all() +{ + struct elt* stack = NULL; + vapi_msg_sw_interface_dump *mp; + vapi_error_e rv; + + mp = vapi_alloc_sw_interface_dump(g_vapi_ctx); + + /* Dump all */ + mp->payload.name_filter_valid = false; + memset(mp->payload.name_filter, 0, sizeof(mp->payload.name_filter)); + + VAPI_CALL(vapi_sw_interface_dump(g_vapi_ctx, mp, sw_interface_all_cb, + &stack)); + if (VAPI_OK != rv) + return NULL; + + return stack; +} + +VAPI_RETVAL_CB(sw_interface_set_flags); + +int interface_enable(const char *interface_name, const bool enable) +{ + vapi_msg_sw_interface_set_flags *mp; + uint32_t sw_if_index; + vapi_error_e rv; + int rc; + + ARG_CHECK(-SCVPP_EINVAL, interface_name); + + rc = get_interface_id(interface_name, &sw_if_index); + if (rc != 0) + return -SCVPP_NOT_FOUND; + + mp = vapi_alloc_sw_interface_set_flags(g_vapi_ctx); + assert(NULL != mp); + mp->payload.sw_if_index = sw_if_index; + mp->payload.admin_up_down = enable; + + VAPI_CALL(vapi_sw_interface_set_flags(g_vapi_ctx, mp, + sw_interface_set_flags_cb, NULL)); + if (VAPI_OK != rv) + return -SCVPP_EINVAL; + + return 0; +} + +int get_interface_name(char *interface_name, uint32_t sw_if_index) +{ + struct elt *stack= NULL; + sw_interface_dump_t *dump; + int rc = -SCVPP_NOT_FOUND; + + stack = interface_dump_all(); + if (!stack) + return -SCVPP_NOT_FOUND; + + foreach_stack_elt(stack) { + dump = (sw_interface_dump_t *) data; + + if (dump->sw_if_index == sw_if_index) { + strncpy(interface_name, (char *)dump->interface_name, VPP_INTFC_NAME_LEN); + rc = SCVPP_OK; + } + + free(dump); + } + + return rc; +} diff --git a/src/scvpp/src/sc_vpp_ip.c b/src/scvpp/src/ip.c index 0dfd108..2dc991c 100644 --- a/src/scvpp/src/sc_vpp_ip.c +++ b/src/scvpp/src/ip.c @@ -14,12 +14,12 @@ * limitations under the License. */ -#include "sc_vpp_comm.h" -#include "sc_vpp_ip.h" - -#include "sc_vpp_interface.h" +#include <scvpp/comm.h> +#include <scvpp/ip.h> +#include <scvpp/interface.h> #include <assert.h> +#include <stdio.h> // Use VAPI macros to define symbols DEFINE_VAPI_MSG_IDS_IP_API_JSON @@ -36,7 +36,7 @@ bin_api_sw_interface_add_del_address(u32 sw_if_index, bool is_add, bool is_ipv6, ARG_CHECK(VAPI_EINVAL, ip_address); - mp = vapi_alloc_sw_interface_add_del_address(g_vapi_ctx_instance); + mp = vapi_alloc_sw_interface_add_del_address(g_vapi_ctx); assert(NULL != mp); mp->payload.sw_if_index = sw_if_index; @@ -44,10 +44,10 @@ bin_api_sw_interface_add_del_address(u32 sw_if_index, bool is_add, bool is_ipv6, mp->payload.is_ipv6 = is_ipv6; mp->payload.del_all = del_all; mp->payload.address_length = address_length; - if (sc_aton(ip_address, mp->payload.address, sizeof(mp->payload.address))) + if (sc_aton(ip_address, mp->payload.address, VPP_IP4_ADDRESS_LEN)) return VAPI_EINVAL; - VAPI_CALL(vapi_sw_interface_add_del_address(g_vapi_ctx_instance, mp, + VAPI_CALL(vapi_sw_interface_add_del_address(g_vapi_ctx, mp, sw_interface_add_del_address_cb, NULL)); return rv; @@ -59,38 +59,41 @@ static vapi_error_e bin_api_ip_add_del_route(vapi_payload_ip_add_del_route_reply * reply, const char* dst_address, uint8_t dst_address_length, const char* next_hop, uint8_t is_add, - uint32_t table_id, const char *interface_name) + uint32_t table_id, const char *next_interface) { - sw_interface_details_query_t query = {0}; vapi_msg_ip_add_del_route *mp; + uint32_t sw_if_index; + vapi_error_e rv ; + int rc; - ARG_CHECK4(VAPI_EINVAL, reply, dst_address, next_hop, interface_name); - - sw_interface_details_query_set_name(&query, interface_name); + ARG_CHECK2(VAPI_EINVAL, reply, dst_address); - if (!get_interface_id(&query)) + //Require interface or next hop IP or both + if (!next_interface && !next_hop) return VAPI_EINVAL; - mp = vapi_alloc_ip_add_del_route (g_vapi_ctx_instance, 1); + mp = vapi_alloc_ip_add_del_route(g_vapi_ctx, 1); assert(NULL != mp); - //ip route add 2.2.2.2/24 via 5.5.5.5 - //show ip fib table 0 2.2.2.0/24 detail + if (next_interface) { + rc = get_interface_id(next_interface, &sw_if_index); + if (rc < 0) + return VAPI_EINVAL; + } mp->payload.is_add = is_add; - mp->payload.dst_address_length = dst_address_length; mp->payload.table_id = table_id; - mp->payload.next_hop_sw_if_index = query.sw_interface_details.sw_if_index; - - if (sc_aton(dst_address, mp->payload.dst_address, - sizeof(mp->payload.dst_address))) - return VAPI_EINVAL; - if (sc_aton(next_hop, mp->payload.next_hop_address, - sizeof(mp->payload.next_hop_address))) - return VAPI_EINVAL; + mp->payload.is_ipv6 = false; + mp->payload.is_local = false; + sc_aton(dst_address, mp->payload.dst_address, VPP_IP4_ADDRESS_LEN); + mp->payload.dst_address_length = dst_address_length; + if (next_interface) //interface is not mandatory + mp->payload.next_hop_sw_if_index = sw_if_index; + if (next_hop) //next hop ip is not mandatory + sc_aton(next_hop, mp->payload.next_hop_address, VPP_IP4_ADDRESS_LEN); - vapi_error_e rv ; - VAPI_CALL(vapi_ip_add_del_route(g_vapi_ctx_instance, mp, ip_add_del_route_cb, reply)); + VAPI_CALL(vapi_ip_add_del_route(g_vapi_ctx, mp, + ip_add_del_route_cb, reply)); return rv; } @@ -100,12 +103,13 @@ ip_address_dump_cb (struct vapi_ctx_s *ctx, void *callback_ctx, vapi_error_e rv, bool is_last, vapi_payload_ip_address_details *reply) { UNUSED(rv); + vapi_payload_ip_address_details *passed; + ARG_CHECK3(VAPI_EINVAL, ctx, callback_ctx, reply); //copy dump reply in callback context - if (!is_last && callback_ctx) { - vapi_payload_ip_address_details *passed = - (vapi_payload_ip_address_details *) callback_ctx; + if (!is_last) { + passed = (vapi_payload_ip_address_details *) callback_ctx; *passed = *reply; } @@ -119,11 +123,13 @@ bin_api_ip_address_dump(u32 sw_if_index, bool is_ipv6, vapi_msg_ip_address_dump *mp; vapi_error_e rv; - mp = vapi_alloc_ip_address_dump(g_vapi_ctx_instance); + mp = vapi_alloc_ip_address_dump(g_vapi_ctx); + assert(mp != NULL); + mp->payload.sw_if_index = sw_if_index; mp->payload.is_ipv6 = is_ipv6; - VAPI_CALL(vapi_ip_address_dump(g_vapi_ctx_instance, mp, ip_address_dump_cb, + VAPI_CALL(vapi_ip_address_dump(g_vapi_ctx, mp, ip_address_dump_cb, dctx)); if (rv != VAPI_OK) return rv; @@ -131,64 +137,112 @@ bin_api_ip_address_dump(u32 sw_if_index, bool is_ipv6, return VAPI_OK; } -/* - * @brief Dump IPv4/IPv6 address from an interface. - * @param interface_name Name of the interface to dump. - * @param ip_addr pointer where dump will store IP. - * @param prefix_len pointer where dump will store prefix - */ +///VAPI_DUMP_LIST_CB(ip_fib); can not be used because of path flexible array + +static vapi_error_e +ip_fib_all_cb(vapi_ctx_t ctx, void *caller_ctx, vapi_error_e rv, bool is_last, + vapi_payload_ip_fib_details *reply) +{ + UNUSED(ctx); UNUSED(rv); UNUSED(is_last); + struct elt **stackp; + ARG_CHECK2(VAPI_EINVAL, caller_ctx, reply); + + stackp = (struct elt**) caller_ctx; + push(stackp, reply, sizeof(*reply)+reply->count*sizeof(vapi_type_fib_path)); + + return VAPI_OK; +} + +struct elt* ipv4_fib_dump_all() +{ + struct elt *stack = NULL; + vapi_msg_ip_fib_dump *mp; + vapi_error_e rv; + + mp = vapi_alloc_ip_fib_dump(g_vapi_ctx); + assert(mp != NULL); + + VAPI_CALL(vapi_ip_fib_dump(g_vapi_ctx, mp, ip_fib_all_cb, &stack)); + if(VAPI_OK != rv) + return NULL; + + return stack; +} + +int ipv4_fib_dump_prefix(const char *prefix_xpath, fib_dump_t **reply) +{ + struct elt *stack = NULL; + char prefix[VPP_IP4_PREFIX_STRING_LEN]; + fib_dump_t *dump; + int rc = -SCVPP_NOT_FOUND; + + stack = ipv4_fib_dump_all(); + if (!stack) + return rc; + + foreach_stack_elt(stack) { + dump = (fib_dump_t *) data; + + if (rc == -SCVPP_NOT_FOUND) { + snprintf(prefix, VPP_IP4_PREFIX_STRING_LEN, "%s/%u", + sc_ntoa(dump->address), dump->address_length); + if (!strncmp(prefix_xpath, prefix, VPP_IP4_PREFIX_STRING_LEN)) { + *reply = dump; + rc = SCVPP_OK; + continue; + } + } + + free(dump); + } + + return rc; +} + int ipv46_address_dump(const char *interface_name, char *ip_addr, u8 *prefix_len, bool is_ipv6) { vapi_payload_ip_address_details dctx = {0}; - sw_interface_details_query_t query = {0}; + uint32_t sw_if_index; vapi_error_e rv; + int rc; - sw_interface_details_query_set_name(&query, interface_name); - - if (!get_interface_id(&query)) - return -EINVAL; + rc = get_interface_id(interface_name, &sw_if_index); + if (rc < 0) + return rc; - rv = bin_api_ip_address_dump(query.sw_interface_details.sw_if_index, is_ipv6, &dctx); + rv = bin_api_ip_address_dump(sw_if_index, is_ipv6, &dctx); if (rv != VAPI_OK) - return -EAGAIN; + return -SCVPP_EINVAL; strcpy(ip_addr, sc_ntoa(dctx.ip)); //IP string *prefix_len = dctx.prefix_length; //prefix length - return 0; + return SCVPP_OK; } -/** - * @brief Add or remove IPv4/IPv6 address to/from an interface. - */ int ipv46_config_add_remove(const char *if_name, const char *addr, uint8_t prefix, bool is_ipv6, bool add) { vapi_error_e rv; + uint32_t sw_if_index; int rc; ARG_CHECK2(-1, if_name, addr); - /* get interface index */ - sw_interface_details_query_t query = {0}; - sw_interface_details_query_set_name(&query, if_name); - rc = get_interface_id(&query); - if (!rc) - return -EINVAL; + rc = get_interface_id(if_name, &sw_if_index); + if (rc < 0) + return rc; /* add del addr */ - rv = bin_api_sw_interface_add_del_address(query.sw_interface_details.sw_if_index, - add, is_ipv6, 0, prefix, addr); + rv = bin_api_sw_interface_add_del_address(sw_if_index, add, is_ipv6, 0, + prefix, addr); if (rv != VAPI_OK) - return -EINVAL; + return -SCVPP_EINVAL; - return 0; + return SCVPP_OK; } -/* - * @brief Add or remove an IP route - */ int ipv46_config_add_del_route(const char* dst_address, u8 dst_address_length, const char* next_address, u8 is_add, u32 table_id, const char *interface) @@ -198,9 +252,8 @@ int ipv46_config_add_del_route(const char* dst_address, u8 dst_address_length, rv = bin_api_ip_add_del_route(&reply, dst_address, dst_address_length, next_address, is_add, table_id, interface); - if (VAPI_OK != rv || reply.retval > 0) { - return -EINVAL; - } + if (VAPI_OK != rv || reply.retval > 0) + return -SCVPP_EINVAL; - return 0; + return SCVPP_OK; } diff --git a/src/scvpp/src/sc_vpp_nat.c b/src/scvpp/src/nat.c index e4bf2b7..17ace64 100644 --- a/src/scvpp/src/sc_vpp_nat.c +++ b/src/scvpp/src/nat.c @@ -14,8 +14,8 @@ * limitations under the License. */ -#include "sc_vpp_comm.h" -#include "sc_vpp_nat.h" +#include <scvpp/comm.h> +#include <scvpp/nat.h> #include <assert.h> #include <stdbool.h> @@ -28,8 +28,7 @@ nat44_interface_dump_cb(struct vapi_ctx_s *ctx, void *callback_ctx, vapi_error_e rv, bool is_last, vapi_payload_nat44_interface_details *reply) { - UNUSED(ctx); - UNUSED(rv); + UNUSED(ctx); UNUSED(rv); vapi_payload_nat44_interface_details *dctx = callback_ctx; assert(dctx); @@ -56,10 +55,10 @@ bin_api_nat44_interface_dump(vapi_payload_nat44_interface_details *reply) ARG_CHECK(VAPI_EINVAL, reply); - mp = vapi_alloc_nat44_interface_dump(g_vapi_ctx_instance); + mp = vapi_alloc_nat44_interface_dump(g_vapi_ctx); assert(NULL != mp); - VAPI_CALL(vapi_nat44_interface_dump(g_vapi_ctx_instance, mp, + VAPI_CALL(vapi_nat44_interface_dump(g_vapi_ctx, mp, nat44_interface_dump_cb, reply)); return rv; @@ -76,12 +75,12 @@ bin_api_nat44_add_del_interface_addr( ARG_CHECK(VAPI_EINVAL, msg); - mp = vapi_alloc_nat44_add_del_interface_addr(g_vapi_ctx_instance); + mp = vapi_alloc_nat44_add_del_interface_addr(g_vapi_ctx); assert(NULL != mp); mp->payload = *msg; - VAPI_CALL(vapi_nat44_add_del_interface_addr(g_vapi_ctx_instance, mp, + VAPI_CALL(vapi_nat44_add_del_interface_addr(g_vapi_ctx, mp, nat44_add_del_interface_addr_cb, NULL)); @@ -99,13 +98,13 @@ bin_api_nat44_add_del_addr_range( ARG_CHECK(VAPI_EINVAL, range); - mp = vapi_alloc_nat44_add_del_address_range(g_vapi_ctx_instance); + mp = vapi_alloc_nat44_add_del_address_range(g_vapi_ctx); assert(NULL != mp); mp->payload = *range; - VAPI_CALL(vapi_nat44_add_del_address_range(g_vapi_ctx_instance, mp, + VAPI_CALL(vapi_nat44_add_del_address_range(g_vapi_ctx, mp, nat44_add_del_address_range_cb, NULL)); @@ -123,13 +122,12 @@ bin_api_nat44_add_del_static_mapping( ARG_CHECK(VAPI_EINVAL, msg); - mp = vapi_alloc_nat44_add_del_static_mapping(g_vapi_ctx_instance); - + mp = vapi_alloc_nat44_add_del_static_mapping(g_vapi_ctx); assert(NULL != mp); mp->payload = *msg; - VAPI_CALL(vapi_nat44_add_del_static_mapping(g_vapi_ctx_instance, mp, + VAPI_CALL(vapi_nat44_add_del_static_mapping(g_vapi_ctx, mp, nat44_add_del_static_mapping_cb, NULL)); @@ -140,8 +138,7 @@ static vapi_error_e nat44_static_mapping_dump_cb( struct vapi_ctx_s *ctx, void *callback_ctx, vapi_error_e rv, bool is_last,vapi_payload_nat44_static_mapping_details *reply) { - UNUSED(rv); - UNUSED(ctx); + UNUSED(rv); UNUSED(ctx); vapi_payload_nat44_static_mapping_details *dctx = callback_ctx; assert(dctx); @@ -166,10 +163,10 @@ bin_api_nat44_static_mapping_dump( ARG_CHECK(VAPI_EINVAL, reply); - msg = vapi_alloc_nat44_static_mapping_dump(g_vapi_ctx_instance); + msg = vapi_alloc_nat44_static_mapping_dump(g_vapi_ctx); assert(NULL != msg); - VAPI_CALL(vapi_nat44_static_mapping_dump(g_vapi_ctx_instance, msg, + VAPI_CALL(vapi_nat44_static_mapping_dump(g_vapi_ctx, msg, nat44_static_mapping_dump_cb, reply)); @@ -186,13 +183,13 @@ static vapi_error_e bin_api_nat44_forwarding_enable_disable( ARG_CHECK(VAPI_EINVAL, msg); - mp = vapi_alloc_nat44_forwarding_enable_disable(g_vapi_ctx_instance); + mp = vapi_alloc_nat44_forwarding_enable_disable(g_vapi_ctx); assert(NULL != mp); mp->payload = *msg; VAPI_CALL(vapi_nat44_forwarding_enable_disable( - g_vapi_ctx_instance, mp, nat44_forwarding_enable_disable_cb, NULL)); + g_vapi_ctx, mp, nat44_forwarding_enable_disable_cb, NULL)); return rv; } @@ -207,113 +204,91 @@ bin_api_nat_set_workers(const vapi_payload_nat_set_workers *msg) ARG_CHECK(VAPI_EINVAL, msg); - mp = vapi_alloc_nat_set_workers(g_vapi_ctx_instance); + mp = vapi_alloc_nat_set_workers(g_vapi_ctx); assert(NULL != mp); mp->payload = *msg; - VAPI_CALL(vapi_nat_set_workers(g_vapi_ctx_instance, mp, nat_set_workers_cb, - NULL)); + VAPI_CALL(vapi_nat_set_workers(g_vapi_ctx, mp, nat_set_workers_cb, NULL)); return rv; } int nat44_interface_dump(nat44_interface_details_t *reply) { - vapi_error_e rc; + vapi_error_e rv; - rc = bin_api_nat44_interface_dump(reply); - if (VAPI_OK != rc) { - //TODO: Need implement log function -// ERROR("Error in nat44_interface_dump, error: %u", rc); - return -1; - } + rv = bin_api_nat44_interface_dump(reply); + if (VAPI_OK != rv) + return -SCVPP_EINVAL; - return 0; + return SCVPP_OK; } int nat44_add_del_interface_addr(const nat44_add_del_interface_addr_t *msg) { - vapi_error_e rc; + vapi_error_e rv; - rc = bin_api_nat44_add_del_interface_addr(msg); - if (VAPI_OK != rc) { - //TODO: Need implement log function -// ERROR("Error in nat44_interface_dump, error: %u", rc); - return -1; - } + rv = bin_api_nat44_add_del_interface_addr(msg); + if (VAPI_OK != rv) + return -SCVPP_EINVAL; - return 0; + return SCVPP_OK; } int nat44_add_del_addr_range(const nat44_add_del_address_range_t *range) { - vapi_error_e rc; + vapi_error_e rv; - rc = bin_api_nat44_add_del_addr_range(range); - if (VAPI_OK != rc) { - //TODO: Need implement log function -// ERROR("Error in nat44_interface_dump, error: %u", rc); - return -1; - } + rv = bin_api_nat44_add_del_addr_range(range); + if (VAPI_OK != rv) + return -SCVPP_EINVAL; - return 0; + return SCVPP_OK; } int nat44_add_del_static_mapping(const nat44_add_del_static_mapping_t *msg) { - vapi_error_e rc; + vapi_error_e rv; - rc = bin_api_nat44_add_del_static_mapping(msg); - if (VAPI_OK != rc) { - //TODO: Need implement log function -// ERROR("Error in nat44_interface_dump, error: %u", rc); - return -1; - } + rv = bin_api_nat44_add_del_static_mapping(msg); + if (VAPI_OK != rv) + return -SCVPP_EINVAL; - return 0; + return SCVPP_OK; } int nat44_static_mapping_dump(nat44_static_mapping_details_t *reply) { - vapi_error_e rc; + vapi_error_e rv; - rc = bin_api_nat44_static_mapping_dump(reply); - if (VAPI_OK != rc) { - //TODO: Need implement log function -// ERROR("Error in nat44_interface_dump, error: %u", rc); - return -1; - } + rv = bin_api_nat44_static_mapping_dump(reply); + if (VAPI_OK != rv) + return -SCVPP_EINVAL; - return 0; + return SCVPP_OK; } -int nat44_forwarding_enable_disable( - const nat44_forwarding_enable_disable_t *msg) +int +nat44_forwarding_enable_disable(const nat44_forwarding_enable_disable_t *msg) { - vapi_error_e rc; + vapi_error_e rv; - rc = bin_api_nat44_forwarding_enable_disable(msg); - if (VAPI_OK != rc) { - //TODO: Need implement log function -// ERROR("Error in nat44_interface_dump, error: %u", rc); - return -1; - } + rv = bin_api_nat44_forwarding_enable_disable(msg); + if (VAPI_OK != rv) + return -SCVPP_EINVAL; return 0; } int nat_set_workers(const nat_set_workers_t *msg) { - vapi_error_e rc; + vapi_error_e rv; - rc = bin_api_nat_set_workers(msg); - if (VAPI_OK != rc) { - //TODO: Need implement log function -// ERROR("Error in nat44_interface_dump, error: %u", rc); - return -1; - } + rv = bin_api_nat_set_workers(msg); + if (VAPI_OK != rv) + return -SCVPP_EINVAL; - return 0; + return SCVPP_OK; } diff --git a/src/scvpp/src/sc_vpp_interface.c b/src/scvpp/src/sc_vpp_interface.c deleted file mode 100644 index bc5befc..0000000 --- a/src/scvpp/src/sc_vpp_interface.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (c) 2018 PANTHEON.tech. - * - * 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 <assert.h> -#include <stdbool.h> - -#include <vapi/l2.api.vapi.h> - -#include "sc_vpp_comm.h" -#include "sc_vpp_interface.h" - - -// Use VAPI macros to define symbols -DEFINE_VAPI_MSG_IDS_INTERFACE_API_JSON -DEFINE_VAPI_MSG_IDS_L2_API_JSON; - -void sw_interface_details_query_set_name(sw_interface_details_query_t * query, - const char * interface_name) -{ - assert(query && interface_name); - - memset(query, 0, sizeof(*query)); - - strncpy((char*) query->sw_interface_details.interface_name, interface_name, - sizeof(query->sw_interface_details.interface_name)); -} - -static vapi_error_e -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) -{ - UNUSED(rv); UNUSED(ctx); UNUSED(is_last); - - vapi_payload_sw_interface_details *passed; - - ARG_CHECK(-EINVAL, callback_ctx); - - passed = (vapi_payload_sw_interface_details *) callback_ctx; - - //Interface is found if index of query equals index of reply - if (passed->sw_if_index != reply->sw_if_index) - return -EINVAL; - - //copy - *passed = *reply; - - return VAPI_OK; -} - -static vapi_error_e -bin_api_sw_interface_dump(vapi_payload_sw_interface_details *details) -{ - vapi_msg_sw_interface_dump *mp; - vapi_error_e rv; - - mp = vapi_alloc_sw_interface_dump(g_vapi_ctx_instance); - - mp->payload.name_filter_valid = 0; - memset(mp->payload.name_filter, 0, sizeof(mp->payload.name_filter)); - assert(NULL != mp); - - VAPI_CALL(vapi_sw_interface_dump(g_vapi_ctx_instance, mp, sw_interface_dump_cb, details)); - if (!rv) - return -EINVAL; - - return rv; -} - -static vapi_error_e -interface_dump_all_cb(struct vapi_ctx_s *ctx, void *callback_ctx, - vapi_error_e rv, bool is_last, - vapi_payload_sw_interface_details * reply) -{ - UNUSED(ctx); UNUSED(rv); - dump_all_ctx *dctx = callback_ctx; - - if (is_last) - return VAPI_OK; - - if(dctx->capacity == 0 && dctx->intfcArray == NULL) { - dctx->capacity = 10; - dctx->intfcArray = (vpp_interface_t*)malloc( sizeof(vpp_interface_t)*dctx->capacity ); - } - if(dctx->num_ifs >= dctx->capacity-1) { - dctx->capacity += 10; - dctx->intfcArray = (vpp_interface_t*)realloc(dctx->intfcArray, sizeof(vpp_interface_t)*dctx->capacity ); - } - - vpp_interface_t * iface = &dctx->intfcArray[dctx->num_ifs]; - - iface->sw_if_index = reply->sw_if_index; - strncpy(iface->interface_name, (char*) reply->interface_name, - VPP_INTFC_NAME_LEN); - iface->l2_address_length = reply->l2_address_length; - memcpy(iface->l2_address, reply->l2_address, reply->l2_address_length ); - iface->link_speed = reply->link_speed; - - iface->link_mtu = reply->link_mtu; - iface->admin_up_down = reply->admin_up_down; - iface->link_up_down = reply->link_up_down; - - dctx->num_ifs += 1; - - return VAPI_OK; -} - -int interface_dump_all(dump_all_ctx * dctx) -{ - vapi_msg_sw_interface_dump *dump; - vapi_error_e rv; - - ARG_CHECK(-1, dctx); - - if(dctx == NULL) - return -1; - - dctx->intfcArray = NULL; - dctx->capacity = 0; - dctx->num_ifs = 0; - - 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, interface_dump_all_cb, - dctx))); - - return dctx->num_ifs; -} - -static vapi_error_e -get_interface_id_cb (struct vapi_ctx_s *ctx, void *callback_ctx, - vapi_error_e rv, bool is_last, - vapi_payload_sw_interface_details * reply) -{ - UNUSED(ctx); UNUSED(rv); - - sw_interface_details_query_t *dctx = callback_ctx; - assert(dctx); - - if (!dctx->interface_found) - { - if (is_last) - { - assert(NULL == reply); - } - else - { - assert(NULL != reply); - - if (0 == strcmp((const char*)dctx->sw_interface_details.interface_name, - (const char*)reply->interface_name)) - { - dctx->interface_found = true; - dctx->sw_interface_details = *reply; - } - } - } - - return VAPI_OK; -} - -// return error code instead of boolean -int get_interface_id(sw_interface_details_query_t * sw_interface_details_query) -{ - vapi_error_e rv; - - ARG_CHECK(false, sw_interface_details_query); - - sw_interface_details_query->interface_found = false; - - vapi_msg_sw_interface_dump *mp = vapi_alloc_sw_interface_dump (g_vapi_ctx_instance); - assert(NULL != mp); - - mp->payload.name_filter_valid = true; - memcpy(mp->payload.name_filter, sw_interface_details_query->sw_interface_details.interface_name, - sizeof(mp->payload.name_filter)); - - VAPI_CALL(vapi_sw_interface_dump(g_vapi_ctx_instance, mp, get_interface_id_cb, sw_interface_details_query)); - if (VAPI_OK != rv) - return false; - - return sw_interface_details_query->interface_found; -} - -int get_interface_name(sw_interface_details_query_t *query) -{ - vapi_error_e rv; - - ARG_CHECK(-EINVAL, query); - - query->interface_found = false; - - rv = bin_api_sw_interface_dump(&query->sw_interface_details); - if (rv == VAPI_OK) - query->interface_found = true; - - return query->interface_found; -} - -VAPI_RETVAL_CB(sw_interface_set_flags); - -static vapi_error_e -bin_api_sw_interface_set_flags(uint32_t if_index, uint8_t up) -{ - vapi_msg_sw_interface_set_flags *mp = vapi_alloc_sw_interface_set_flags (g_vapi_ctx_instance); - assert(NULL != mp); - - mp->payload.sw_if_index = if_index; - mp->payload.admin_up_down = up; - - vapi_error_e rv; - VAPI_CALL(vapi_sw_interface_set_flags(g_vapi_ctx_instance, mp, sw_interface_set_flags_cb, NULL)); - - return rv; -} - -int interface_enable(const char *interface_name, const bool enable) -{ - ARG_CHECK(-1, interface_name); - - int rc = 0; - sw_interface_details_query_t query = {0}; - sw_interface_details_query_set_name(&query, interface_name); - - rc = get_interface_id(&query); - if (!rc) - return -1; - - rc = bin_api_sw_interface_set_flags(query.sw_interface_details.sw_if_index, - enable); - if (VAPI_OK != rc) - return -1; - - return 0; -} diff --git a/src/scvpp/src/sc_vpp_interface.h b/src/scvpp/src/sc_vpp_interface.h deleted file mode 100644 index 32b61bc..0000000 --- a/src/scvpp/src/sc_vpp_interface.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2018 PANTHEON.tech. - * - * 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 __BAPI_INTERFACE_H__ -#define __BAPI_INTERFACE_H__ - -#include <vapi/interface.api.vapi.h> - -int interface_enable(const char *interface_name, const bool enable); - -//TODO remove the following structures ASAP -typedef struct { - bool interface_found; - vapi_payload_sw_interface_details sw_interface_details; -} sw_interface_details_query_t; - -typedef struct _vpp_interface_t -{ - 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; -} vpp_interface_t; - -typedef struct _dump_all_ctx -{ - int num_ifs; - int capacity; - vpp_interface_t * intfcArray; -} dump_all_ctx; - -/* return the number of interfaces or a negative error code */ -extern int interface_dump_all(dump_all_ctx * dctx); - -extern void sw_interface_details_query_set_name(sw_interface_details_query_t * query, - const char * interface_name); - -//input - sw_interface_details_query shall contain interface_name -extern int get_interface_id(sw_interface_details_query_t * sw_interface_details_query); - -//input - sw_interface_details_query shall contain sw_if_index -extern int get_interface_name(sw_interface_details_query_t * sw_interface_details_query); - -#endif /* __BAPI_INTERFACE_H__ */ diff --git a/src/scvpp/src/sc_vpp_ip.h b/src/scvpp/src/sc_vpp_ip.h deleted file mode 100644 index a9f19d4..0000000 --- a/src/scvpp/src/sc_vpp_ip.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2018 PANTHEON.tech. - * - * 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 __BAPI_IP_H__ -#define __BAPI_IP_H__ - -#include <vapi/interface.api.vapi.h> -#include <vapi/ip.api.vapi.h> - -/* If no IP has been found ip_addr will be "0.0.0.0" */ -extern int ipv46_address_dump(const char *interface_name, char *ip_addr, - u8 *prefix_len, bool is_ipv6); - -extern int ipv46_config_add_remove(const char *if_name, const char *addr, - uint8_t prefix, bool is_ipv6, bool add); - -extern int -ipv46_config_add_del_route(const char* dst_address, u8 dst_address_length, - const char* next_address, u8 is_add, u32 table_id, - const char *interface); - -#endif /* __BAPI_IP_H__ */ diff --git a/src/scvpp/src/sc_vpp_v3po.h b/src/scvpp/src/sc_vpp_v3po.h deleted file mode 100644 index 9c13569..0000000 --- a/src/scvpp/src/sc_vpp_v3po.h +++ /dev/null @@ -1,26 +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 _V3PO__INTERFACE_H__ -#define _V3PO__INTERFACE_H__ - -#include <vapi/tapv2.api.vapi.h> - -typedef vapi_payload_tap_create_v2 tapv2_create_t; - -int create_tapv2(tapv2_create_t *query); -int delete_tapv2(char *iface_name); - -#endif /* __V3PO_INTERFACE_H__ */ diff --git a/src/scvpp/src/sc_vpp_v3po.c b/src/scvpp/src/v3po.c index d312331..f0a41c5 100644 --- a/src/scvpp/src/sc_vpp_v3po.c +++ b/src/scvpp/src/v3po.c @@ -1,5 +1,7 @@ /* * Copyright (c) 2016 Cisco and/or its affiliates. + * Copyright (c) 2018 PANTHEON.tech. + * * 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: @@ -15,35 +17,18 @@ #include <assert.h> -#include "sc_vpp_comm.h" -#include "sc_vpp_v3po.h" -#include "sc_vpp_interface.h" +#include <scvpp/comm.h> +#include <scvpp/v3po.h> +#include <scvpp/interface.h> + +// Use VAPI macros to define symbols +DEFINE_VAPI_MSG_IDS_L2_API_JSON; +DEFINE_VAPI_MSG_IDS_TAPV2_API_JSON /* * tap-v2 interfaces */ -DEFINE_VAPI_MSG_IDS_TAPV2_API_JSON - -// Dump tapv2 - -//typedef struct __attribute__ ((__packed__)) { -// u32 sw_if_index; -// u32 id; -// u8 dev_name[64]; -// u16 tx_ring_sz; -// u16 rx_ring_sz; -// u8 host_mac_addr[6]; -// u8 host_if_name[64]; -// u8 host_namespace[64]; -// u8 host_bridge[64]; -// u8 host_ip4_addr[4]; -// u8 host_ip4_prefix_len; -// u8 host_ip6_addr[16]; -// u8 host_ip6_prefix_len; -// u32 tap_flags; -//} vapi_payload_sw_interface_tap_v2_details; - // Delete tapv2 VAPI_RETVAL_CB(tap_delete_v2); @@ -53,35 +38,33 @@ static vapi_error_e bin_api_delete_tapv2(u32 sw_if_index) vapi_msg_tap_delete_v2 *mp; vapi_error_e rv; - mp = vapi_alloc_tap_delete_v2(g_vapi_ctx_instance); + mp = vapi_alloc_tap_delete_v2(g_vapi_ctx); assert(NULL != mp); mp->payload.sw_if_index = sw_if_index; - VAPI_CALL(vapi_tap_delete_v2(g_vapi_ctx_instance, mp, tap_delete_v2_cb, - NULL)); + VAPI_CALL(vapi_tap_delete_v2(g_vapi_ctx, mp, tap_delete_v2_cb, NULL)); if (rv != VAPI_OK) - return -EAGAIN; + return -rv; - return rv; + return VAPI_OK; } int delete_tapv2(char *iface_name) { + uint32_t sw_if_index; + vapi_error_e rv; int rc; - sw_interface_details_query_t query = {0}; - sw_interface_details_query_set_name(&query, iface_name); + rc = get_interface_id(iface_name, &sw_if_index); + if (rc < 0) + return rc; - rc = get_interface_id(&query); - if (!rc) - return -1; + rv = bin_api_delete_tapv2(sw_if_index); + if (VAPI_OK != rv) + return -SCVPP_EINVAL; - rc = bin_api_delete_tapv2(query.sw_interface_details.sw_if_index); - if (VAPI_OK != rc) - return -1; - - return 0; + return SCVPP_OK; } // Create tapv2 @@ -93,13 +76,12 @@ int create_tapv2(tapv2_create_t *query) vapi_msg_tap_create_v2 *mp; vapi_error_e rv; - mp = vapi_alloc_tap_create_v2(g_vapi_ctx_instance); + mp = vapi_alloc_tap_create_v2(g_vapi_ctx); assert(NULL != mp); memcpy(&mp->payload, query, sizeof(tapv2_create_t)); - VAPI_CALL(vapi_tap_create_v2(g_vapi_ctx_instance, mp, tap_create_v2_cb, - NULL)); + VAPI_CALL(vapi_tap_create_v2(g_vapi_ctx, mp, tap_create_v2_cb, NULL)); if (rv != VAPI_OK) return -EAGAIN; diff --git a/src/scvpp/tests/CMakeLists.txt b/src/scvpp/tests/CMakeLists.txt index 3153fe0..2b6de4a 100644 --- a/src/scvpp/tests/CMakeLists.txt +++ b/src/scvpp/tests/CMakeLists.txt @@ -18,24 +18,23 @@ 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 - scvpp_nat_test.c - ) - add_executable(${TEST_NAME} ${TEST_SRC}) - target_link_libraries(${TEST_NAME} ${CMOCKA_LIBRARIES} scvpp_a) - add_test(${TEST_NAME} ${TEST_NAME}) +set(TEST_SRC + scvpp_test.h + scvpp_test.c + scvpp_iface_test.c + scvpp_ip_test.c + scvpp_nat_test.c +) - 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_executable(scvpp_test ${TEST_SRC}) +target_link_libraries(scvpp_test ${CMOCKA_LIBRARIES} scvpp_a) +target_include_directories(scvpp_test PRIVATE ../inc) +add_test(scvpp_test scvpp_test) -# add individual unit-tests -ADD_UNIT_TEST(scvpp_test) +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) diff --git a/src/scvpp/tests/scvpp_iface_test.c b/src/scvpp/tests/scvpp_iface_test.c new file mode 100644 index 0000000..6a96694 --- /dev/null +++ b/src/scvpp/tests/scvpp_iface_test.c @@ -0,0 +1,130 @@ +/* + * 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 <unistd.h> +#include <setjmp.h> +#include <stdarg.h> +#include <cmocka.h> + +#include "scvpp_test.h" + +#include <scvpp/interface.h> +#include <scvpp/v3po.h> + +static void test_enable_disable(void **state) +{ + UNUSED(state); + sw_interface_dump_t dump = {0}; + int rc; + + rc = interface_enable("tap0", 1); + assert_int_equal(rc, SCVPP_OK); + + rc = interface_dump_iface(&dump, "tap0"); + assert_int_equal(rc, SCVPP_OK); + + assert_int_equal(dump.admin_up_down, true); + + rc = interface_enable("tap0", 0); + assert_int_equal(rc, SCVPP_OK); +} + +static void test_create_tapv2(void **state) +{ + UNUSED(state); + tapv2_create_t query = {0}; + sw_interface_dump_t dump = {0}; + int rc; + + query.id = 1; + query.use_random_mac = 1; + + rc = create_tapv2(&query); + assert_int_equal(rc, SCVPP_OK); + + rc = interface_dump_iface(&dump, "tap1"); + assert_int_equal(rc, SCVPP_OK); +} + +static int teardown_tapv2(void **state) +{ + UNUSED(state); + return delete_tapv2("tap1"); +} + +static void test_dump_iface_all(void **state) +{ + UNUSED(state); + struct elt *stack = NULL; + sw_interface_dump_t *dump; + bool exist = false; + + stack = interface_dump_all(); + assert_non_null(stack); + foreach_stack_elt(stack) { + dump = (sw_interface_dump_t *) data; + if (!strncmp((char*) dump->interface_name, "tap0", VPP_INTFC_NAME_LEN)) + exist = true; + free(dump); + } + assert_true(exist); +} + +static void test_dump_iface_exist(void **state) +{ + UNUSED(state); + vapi_payload_sw_interface_details details = {0}; + int rc; + + rc = interface_dump_iface(&details, "local0"); + assert_int_equal(rc, SCVPP_OK); + + assert_string_equal(details.interface_name, "local0"); +} + +static void test_dump_iface_unexist(void **state) +{ + UNUSED(state); + vapi_payload_sw_interface_details details = {0}; + int rc; + + rc = interface_dump_iface(&details, "unexisting"); + assert_int_equal(rc, -SCVPP_NOT_FOUND); +} + +static void test_get_interface_name(void **state) +{ + UNUSED(state); + char interface_name[VPP_INTFC_NAME_LEN]; + uint32_t tap0_if_index; + int rc; + + rc = get_interface_id("tap0", &tap0_if_index); + assert_int_equal(rc, SCVPP_OK); + + rc = get_interface_name(interface_name, tap0_if_index); + assert_int_equal(rc, SCVPP_OK); + + assert_string_equal(interface_name, "tap0"); +} + +const struct CMUnitTest iface_tests[IFACE_TEST_SIZE] = { + cmocka_unit_test_teardown(test_create_tapv2, teardown_tapv2), + cmocka_unit_test(test_enable_disable), + cmocka_unit_test(test_dump_iface_all), + cmocka_unit_test(test_dump_iface_exist), + cmocka_unit_test(test_dump_iface_unexist), + cmocka_unit_test(test_get_interface_name), +}; diff --git a/src/scvpp/tests/scvpp_ip_test.c b/src/scvpp/tests/scvpp_ip_test.c new file mode 100644 index 0000000..5e28123 --- /dev/null +++ b/src/scvpp/tests/scvpp_ip_test.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2019 Cisco + * + * 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 <unistd.h> +#include <setjmp.h> +#include <stdarg.h> +#include <cmocka.h> + +#include "scvpp_test.h" + +#include <scvpp/ip.h> +#include <scvpp/interface.h> +#include <scvpp/comm.h> + +static void test_add_remove_ipv4(void **state) +{ + UNUSED(state); + const char ip_q[VPP_IP4_ADDRESS_STRING_LEN] = "192.168.100.144"; + char ip_r[VPP_IP4_ADDRESS_STRING_LEN]; + u8 prefix_q = 24; + u8 prefix_r; + int rc; + + //add ipv4 on tap0 + rc = ipv46_config_add_remove("tap0", ip_q, prefix_q, false, true); + assert_int_equal(rc, SCVPP_OK); + + //dump ipv4 on tap0 and check if it mach + rc = ipv46_address_dump("tap0", ip_r, &prefix_r, false); + assert_int_equal(rc, SCVPP_OK); + assert_string_equal(ip_q, ip_r); + assert_int_equal(prefix_q, prefix_r); + + //remove ipv4 on tap0 + rc = ipv46_config_add_remove("tap0", ip_q, prefix_q, false, false); + assert_int_equal(rc, SCVPP_OK); + + //dump ipv4 after removal and check if equals 0.0.0.0 + rc = ipv46_address_dump("tap0", ip_r, &prefix_r, false); + assert_int_equal(rc, SCVPP_OK); + assert_string_equal(ip_r, "0.0.0.0"); +} + +static void test_ipv4_add_del_route_no_iface(void **state) +{ + UNUSED(state); + int rc; + char dst_address[VPP_IP4_ADDRESS_STRING_LEN] = "192.168.100.0"; + uint8_t prefix_len = 24; + char next_hop[VPP_IP4_ADDRESS_STRING_LEN] = "192.168.100.100"; + uint32_t table_id = 0; + fib_dump_t *dump; + struct elt *stack; + bool route_found = false; + + /* Must fail, can not have both interface and next hop IP null */ + rc = ipv46_config_add_del_route(dst_address, prefix_len, NULL, true, + table_id, NULL); + assert_int_equal(rc, -SCVPP_EINVAL); + + rc = ipv46_config_add_del_route(dst_address, prefix_len, next_hop, true, + table_id, NULL); + assert_int_equal(rc, SCVPP_OK); + + /* Dump all FIB routes and check if we find ours */ + stack = ipv4_fib_dump_all(); + assert_non_null(stack); + foreach_stack_elt(stack) { + dump = (fib_dump_t *) data; + + if (strncmp(sc_ntoa(dump->address), dst_address, + VPP_IP4_ADDRESS_STRING_LEN) == 0 && + dump->address_length == prefix_len) { + route_found = true; + assert_int_equal(dump->table_id, table_id); + assert_int_equal(dump->count, 1); + assert_string_equal(sc_ntoa(dump->path[0].next_hop), next_hop); + } + free(dump); + } + assert_true(route_found); + + /* Delete previously set route */ + rc = ipv46_config_add_del_route(dst_address, prefix_len, next_hop, false, + table_id, NULL); + assert_int_equal(rc, SCVPP_OK); + + /* Check our route has been deleted */ + route_found = false; + stack = ipv4_fib_dump_all(); + assert_non_null(stack); + foreach_stack_elt(stack) { + dump = (fib_dump_t *) data; + if (strncmp(sc_ntoa(dump->address), dst_address, + VPP_IP4_ADDRESS_STRING_LEN) == 0 && + dump->address_length == prefix_len) { + route_found = true; + } + free(dump); + } + assert_false(route_found); +} + +static void test_ipv4_add_del_route_no_next_hop_ip(void **state) +{ + UNUSED(state); + int rc; + char dst_address[VPP_IP4_ADDRESS_STRING_LEN] = "192.168.100.0"; + uint8_t prefix_len = 24; + char interface[VPP_IP4_ADDRESS_STRING_LEN] = "tap0"; + uint32_t table_id = 0; + uint32_t sw_if_index; + fib_dump_t *dump; + struct elt *stack; + bool route_found = false; + + //Add a new route + rc = ipv46_config_add_del_route(dst_address, prefix_len, NULL, true, + table_id, interface); + assert_int_equal(rc, SCVPP_OK); + + //Dump all FIB routes and check we find ours + stack = ipv4_fib_dump_all(); + assert_non_null(stack); + + rc = get_interface_id(interface, &sw_if_index); + assert_int_equal(rc, SCVPP_OK); + + foreach_stack_elt(stack) { + dump = (fib_dump_t *) data; + + if (strncmp(sc_ntoa(dump->address), dst_address, + VPP_IP4_ADDRESS_STRING_LEN) == 0 && + dump->address_length == prefix_len) { + route_found = true; + assert_int_equal(dump->table_id, table_id); + assert_int_equal(dump->count, 1); + assert_int_equal(dump->path[0].sw_if_index, sw_if_index); + } + free(dump); + } + assert_true(route_found); + + //Delete route + rc = ipv46_config_add_del_route(dst_address, prefix_len, NULL, false, + table_id, interface); + assert_int_equal(rc, SCVPP_OK); + + //Check our route has been deleted + route_found = false; + stack = ipv4_fib_dump_all(); + assert_non_null(stack); + + foreach_stack_elt(stack) { + dump = (fib_dump_t *) data; + if (strncmp(sc_ntoa(dump->address), dst_address, + VPP_IP4_ADDRESS_STRING_LEN) == 0 && + dump->address_length == prefix_len) { + route_found = true; + } + free(dump); + } + assert_false(route_found); +} + + +const struct CMUnitTest ip_tests[IP_TEST_SIZE] = { + cmocka_unit_test(test_add_remove_ipv4), + cmocka_unit_test(test_ipv4_add_del_route_no_next_hop_ip), + cmocka_unit_test(test_ipv4_add_del_route_no_iface), +}; diff --git a/src/scvpp/tests/scvpp_nat_test.c b/src/scvpp/tests/scvpp_nat_test.c index fae9615..044102e 100644 --- a/src/scvpp/tests/scvpp_nat_test.c +++ b/src/scvpp/tests/scvpp_nat_test.c @@ -20,36 +20,37 @@ #include <setjmp.h> #include <cmocka.h> -#include "scvpp_nat_test.h" -#include "sc_vpp_comm.h" -#include "sc_vpp_nat.h" +#include "scvpp_test.h" -void test_nat44_static_mapping(__attribute__((unused)) void **state) +#include <scvpp/comm.h> +#include <scvpp/nat.h> + + +void test_nat44_static_mapping(void **state) { + UNUSED(state); nat44_add_del_static_mapping_t map = {0}; nat44_static_mapping_details_t dump = {0}; u8 empty_ip[4] = {0}; + int rc; /*Configure the static mapping Alternative to this CLI command: nat44 add static mapping local 172.168.0.1 external 172.168.8.5 */ - sc_aton("172.168.0.1", map.local_ip_address, sizeof(map.local_ip_address)); - sc_aton("172.168.8.5", map.external_ip_address, sizeof(map.external_ip_address)); - map.addr_only = 1; - map.external_sw_if_index = ~0; - map.is_add = 1; - nat44_add_del_static_mapping(&map); + rc = nat44_add_del_static_mapping(&map); + assert_int_equal(rc, SCVPP_OK); - nat44_static_mapping_dump(&dump); + rc = nat44_static_mapping_dump(&dump); + assert_int_equal(rc, SCVPP_OK); assert_int_equal(dump.addr_only, map.addr_only); @@ -62,11 +63,13 @@ void test_nat44_static_mapping(__attribute__((unused)) void **state) /* Remove previous config*/ map.is_add = 0; - nat44_add_del_static_mapping(&map); + rc = nat44_add_del_static_mapping(&map); + assert_int_equal(rc, SCVPP_OK); memset(&dump, 0, sizeof(dump)); - nat44_static_mapping_dump(&dump); + rc = nat44_static_mapping_dump(&dump); + assert_int_equal(rc, SCVPP_OK); assert_int_equal(dump.addr_only, 0); @@ -77,14 +80,16 @@ void test_nat44_static_mapping(__attribute__((unused)) void **state) sizeof(dump.external_ip_address)); } -void test_nat44_static_mapping_with_ports(__attribute__((unused)) void **state) +void test_nat44_static_mapping_with_ports(void **state) { + UNUSED(state); nat44_add_del_static_mapping_t map = {0}; nat44_static_mapping_details_t dump = {0}; nat44_add_del_address_range_t range = {0}; u8 empty_ip[4] = {0}; const u16 lport = 77; const u16 eport = 88; + int rc; /*Configure address pool Alternative to this CLI: @@ -98,7 +103,8 @@ void test_nat44_static_mapping_with_ports(__attribute__((unused)) void **state) range.is_add = 1; - nat44_add_del_addr_range(&range); + rc = nat44_add_del_addr_range(&range); + assert_int_equal(rc, SCVPP_OK); /*Configure NAT with ports Alternative to this CLI: @@ -122,9 +128,11 @@ void test_nat44_static_mapping_with_ports(__attribute__((unused)) void **state) map.is_add = 1; - nat44_add_del_static_mapping(&map); + rc = nat44_add_del_static_mapping(&map); + assert_int_equal(rc, SCVPP_OK); - nat44_static_mapping_dump(&dump); + rc = nat44_static_mapping_dump(&dump); + assert_int_equal(rc, SCVPP_OK); assert_int_equal(dump.addr_only, map.addr_only); @@ -142,11 +150,13 @@ void test_nat44_static_mapping_with_ports(__attribute__((unused)) void **state) map.is_add = 0; - nat44_add_del_static_mapping(&map); + rc = nat44_add_del_static_mapping(&map); + assert_int_equal(rc, SCVPP_OK); memset(&dump, 0, sizeof(dump)); - nat44_static_mapping_dump(&dump); + rc = nat44_static_mapping_dump(&dump); + assert_int_equal(rc, SCVPP_OK); assert_int_equal(dump.addr_only, 0); @@ -162,7 +172,8 @@ void test_nat44_static_mapping_with_ports(__attribute__((unused)) void **state) range.is_add = 0; - nat44_add_del_addr_range(&range); + rc = nat44_add_del_addr_range(&range); + assert_int_equal(rc, SCVPP_OK); } const struct CMUnitTest nat_tests[] = { diff --git a/src/scvpp/tests/scvpp_test.c b/src/scvpp/tests/scvpp_test.c index cc23e43..f6e99a0 100644 --- a/src/scvpp/tests/scvpp_test.c +++ b/src/scvpp/tests/scvpp_test.c @@ -14,89 +14,19 @@ */ #include <stdlib.h> -#include <stdio.h> #include <unistd.h> +#include <stdio.h> #include <setjmp.h> -#include <cmocka.h> - -#include "sc_vpp_comm.h" -#include "sc_vpp_interface.h" -#include "sc_vpp_ip.h" -#include "sc_vpp_v3po.h" -#include "scvpp_nat_test.h" - -//TODO Check with future function get_interface_state -static void test_enable_disable(void **state) -{ - int rc; - - rc = interface_enable("tap0", 1); - assert_int_equal(rc, 0); - - rc = interface_enable("tap0", 0); - assert_int_equal(rc, 0); -} - -//TODO would need to make sure tap0 is index 1 -//TODO delete eventually because get_interface_id will not be extern -static void test_name2index(void **state) -{ - int rc; - const char iface_name[] = "tap0"; - sw_interface_details_query_t query = {0}; - sw_interface_details_query_set_name(&query, iface_name); - - rc = get_interface_id(&query); - assert_int_equal(rc, 1); - - assert_string_equal(iface_name, query.sw_interface_details.interface_name); - assert_int_equal(query.sw_interface_details.sw_if_index, 1); -} - -static void test_add_ipv4(void **state) -{ - const char ip_q[VPP_IP4_ADDRESS_STRING_LEN] = "192.168.100.144"; - char ip_r[VPP_IP4_ADDRESS_STRING_LEN]; - u8 prefix_q = 24; - u8 prefix_r; - int rc; - - //add ipv4 on tap0 - rc = ipv46_config_add_remove("tap0", ip_q, prefix_q, false, true); - assert_int_equal(rc, 0); - - rc = ipv46_address_dump("tap0", ip_r, &prefix_r, false); - assert_int_equal(rc, 0); - - assert_string_equal(ip_q, ip_r); - assert_int_equal(prefix_q, prefix_r); -} - -static void test_remove_ipv4(void **state) -{ - const char ip_q[VPP_IP4_ADDRESS_STRING_LEN] = "192.168.100.144"; - char ip_r[VPP_IP4_ADDRESS_STRING_LEN]; - u8 prefix_q = 24; - u8 prefix_r; - int rc; - - //add ipv4 on tap0 - rc = ipv46_config_add_remove("tap0", ip_q, prefix_q, false, true); - assert_int_equal(rc, 0); - //remove ipv4 on tap0 - rc = ipv46_config_add_remove("tap0", ip_q, prefix_q, false, false); - assert_int_equal(rc, 0); - - //dump ipv4 - rc = ipv46_address_dump("tap0", ip_r, &prefix_r, false); - assert_int_equal(rc, 0); +#include <scvpp/comm.h> +#include <scvpp/v3po.h> - assert_string_equal(ip_r, "0.0.0.0"); -} +#include "scvpp_test.h" +/* test "AAA.BBB.CCC.DDD" -> {A, B, C, D} */ static void test_sc_ntoa(void **state) { + UNUSED(state); u8 buf[4] = {192, 168, 100, 44}; char *res; @@ -104,52 +34,76 @@ static void test_sc_ntoa(void **state) assert_string_equal(res, "192.168.100.44"); } -static void test_create_tapv2(void **state) +/* test {A, B, C, D} -> "AAA.BBB.CCC.DDD" */ +static void test_sc_aton(void **state) { - tapv2_create_t query = {0}; + UNUSED(state); + char ip[VPP_IP4_ADDRESS_STRING_LEN] = "192.168.100.44"; + uint8_t buf[4]; int rc; - query.id = 1; - query.use_random_mac = 1; - - rc = create_tapv2(&query); + rc = sc_aton(ip, buf, VPP_IP4_ADDRESS_LEN); assert_int_equal(rc, 0); - //TODO dump_tav2 and compare values - - rc = delete_tapv2("tap1"); - assert_int_equal(rc, 0); + assert_int_equal(buf[0], 192); + assert_int_equal(buf[1], 168); + assert_int_equal(buf[2], 100); + assert_int_equal(buf[3], 44); } -int main() +static int setup(void **state) { + UNUSED(state); tapv2_create_t query = {0}; - const struct CMUnitTest tests[] = { - cmocka_unit_test_setup_teardown(test_enable_disable, NULL, NULL), - cmocka_unit_test_setup_teardown(test_name2index, NULL, NULL), - cmocka_unit_test_setup_teardown(test_add_ipv4, NULL, NULL), - cmocka_unit_test_setup_teardown(test_remove_ipv4, NULL, NULL), - cmocka_unit_test_setup_teardown(test_sc_ntoa, NULL, NULL), - cmocka_unit_test_setup_teardown(test_create_tapv2, NULL, NULL), - }; - if (sc_connect_vpp() != 0) + if (sc_connect_vpp() != 0) { fprintf(stderr, "Error connecting to VPP\n"); + return -1; + } /* Create interface tap0 to test several functions */ query.id = 0; query.use_random_mac = 1; - if (create_tapv2(&query) != 0) + if (create_tapv2(&query) != 0) { fprintf(stderr, "Error creating tap0\n"); + return -1; + } - cmocka_run_group_tests(tests, NULL, NULL); - - print_message("\nNAT Tests\n"); - cmocka_run_group_tests(nat_tests, NULL, NULL); + return 0; +} +static int teardown(void **state) +{ + UNUSED(state); /* Delete tap0 */ - if (delete_tapv2("tap0") != 0) + if (delete_tapv2("tap0") != 0) { fprintf(stderr, "Failed deleting tap0\n"); + return -1; + } + + sc_disconnect_vpp(); + + return 0; +} + +/* return code for scvpp-test binary is the number of failed test */ +int main() +{ + int rc = 0; + + const struct CMUnitTest common_tests[] = { + cmocka_unit_test(test_sc_ntoa), + cmocka_unit_test(test_sc_aton), + }; + + print_message("Common tests\n"); + rc |= cmocka_run_group_tests(common_tests, NULL, NULL); + print_message("Interface tests\n"); + rc |= cmocka_run_group_tests(iface_tests, setup, teardown); + print_message("IP tests\n"); + rc |= cmocka_run_group_tests(ip_tests, setup, teardown); + print_message("NAT tests\n"); + rc |= cmocka_run_group_tests(nat_tests, setup, teardown); - return sc_disconnect_vpp(); + return rc; } diff --git a/src/scvpp/tests/scvpp_nat_test.h b/src/scvpp/tests/scvpp_test.h index 8a22f87..28bd514 100644 --- a/src/scvpp/tests/scvpp_nat_test.h +++ b/src/scvpp/tests/scvpp_test.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 PANTHEON.tech. + * Copyright (c) 2019 Cisco * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,11 +14,18 @@ * limitations under the License. */ -/* inclusion guard */ -#ifndef __SCVPP_NAT_TEST_H__ -#define __SCVPP_NAT_TEST_H__ +#ifndef __SCVPP_TEST_H +#define __SCVPP_TEST_H__ + +#include <cmocka.h> + +#define IFACE_TEST_SIZE 6 +extern const struct CMUnitTest iface_tests[IFACE_TEST_SIZE]; + +#define IP_TEST_SIZE 3 +extern const struct CMUnitTest ip_tests[IP_TEST_SIZE]; #define NAT_TEST_SIZE 2 extern const struct CMUnitTest nat_tests[NAT_TEST_SIZE]; -#endif /* __SCVPP_NAT_TEST_H__ */ +#endif /* __SCVPP_TEST_H__ */ |