diff options
Diffstat (limited to 'src/plugins/nsh')
-rw-r--r-- | src/plugins/nsh/CMakeLists.txt | 8 | ||||
-rw-r--r-- | src/plugins/nsh/nsh.c | 2299 | ||||
-rw-r--r-- | src/plugins/nsh/nsh.h | 28 | ||||
-rw-r--r-- | src/plugins/nsh/nsh_api.c | 724 | ||||
-rw-r--r-- | src/plugins/nsh/nsh_cli.c | 645 | ||||
-rw-r--r-- | src/plugins/nsh/nsh_node.c | 982 | ||||
-rw-r--r-- | src/plugins/nsh/nsh_output.c | 18 | ||||
-rw-r--r-- | src/plugins/nsh/nsh_pop.c | 23 |
8 files changed, 2438 insertions, 2289 deletions
diff --git a/src/plugins/nsh/CMakeLists.txt b/src/plugins/nsh/CMakeLists.txt index 1200754c7e5..b5cbcf0cb0c 100644 --- a/src/plugins/nsh/CMakeLists.txt +++ b/src/plugins/nsh/CMakeLists.txt @@ -14,8 +14,11 @@ add_vpp_plugin(nsh SOURCES nsh.c + nsh_node.c nsh_output.c nsh_pop.c + nsh_cli.c + nsh_api.c nsh-md2-ioam/nsh_md2_ioam.c nsh-md2-ioam/nsh_md2_ioam_api.c nsh-md2-ioam/md2_ioam_transit.c @@ -24,6 +27,11 @@ add_vpp_plugin(nsh nsh-md2-ioam/export-nsh-md2-ioam/nsh_md2_ioam_export_thread.c nsh-md2-ioam/export-nsh-md2-ioam/nsh_md2_ioam_node.c + MULTIARCH_SOURCES + nsh_node.c + nsh_output.c + nsh_pop.c + API_FILES nsh.api diff --git a/src/plugins/nsh/nsh.c b/src/plugins/nsh/nsh.c index b293b85db8a..446314c839f 100644 --- a/src/plugins/nsh/nsh.c +++ b/src/plugins/nsh/nsh.c @@ -23,104 +23,11 @@ #include <vnet/vxlan-gpe/vxlan_gpe.h> #include <vnet/l2/l2_classify.h> #include <vnet/adj/adj.h> - -#include <vlibapi/api.h> -#include <vlibmemory/api.h> #include <vpp/app/version.h> -/* define message IDs */ -#define vl_msg_id(n,h) n, -typedef enum -{ -#include <nsh/nsh.api.h> - /* We'll want to know how many messages IDs we need... */ - VL_MSG_FIRST_AVAILABLE, -} vl_msg_id_t; -#undef vl_msg_id - -/* define message structures */ -#define vl_typedefs -#include <nsh/nsh.api.h> -#undef vl_typedefs - -/* define generated endian-swappers */ -#define vl_endianfun -#include <nsh/nsh.api.h> -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) -#define vl_printfun -#include <nsh/nsh.api.h> -#undef vl_printfun - -/* Get the API version number */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include <nsh/nsh.api.h> -#undef vl_api_version - -#define vl_msg_name_crc_list -#include <nsh/nsh.api.h> -#undef vl_msg_name_crc_list - -/* Dummy Eth header */ -const char dummy_dst_address[6] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 }; -const char dummy_src_address[6] = { 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc }; - -/* - * A handy macro to set up a message reply. - * Assumes that the following variables are available: - * mp - pointer to request message - * rmp - pointer to reply message type - * rv - return value - */ - -#define REPLY_MACRO(t) \ - do { \ - unix_shared_memory_queue_t * q = \ - vl_api_client_index_to_input_queue (mp->client_index); \ - if (!q) \ - return; \ - \ - rmp = vl_msg_api_alloc (sizeof (*rmp)); \ - rmp->_vl_msg_id = ntohs((t)+nm->msg_id_base); \ - rmp->context = mp->context; \ - rmp->retval = ntohl(rv); \ - \ - vl_msg_api_send_shmem (q, (u8 *)&rmp); \ - } while(0); - -#define REPLY_MACRO2(t, body) \ - do { \ - unix_shared_memory_queue_t * q; \ - rv = vl_msg_api_pd_handler (mp, rv); \ - q = vl_api_client_index_to_input_queue (mp->client_index); \ - if (!q) \ - return; \ - \ - rmp = vl_msg_api_alloc (sizeof (*rmp)); \ - rmp->_vl_msg_id = ntohs((t)+nm->msg_id_base); \ - rmp->context = mp->context; \ - rmp->retval = ntohl(rv); \ - do {body;} while (0); \ - vl_msg_api_send_shmem (q, (u8 *)&rmp); \ - } while(0); - -#define FINISH \ - vec_add1 (s, 0); \ - vl_print (handle, (char *)s); \ - vec_free (s); \ - return handle; +nsh_main_t nsh_main; -/* List of message types that this plugin understands */ - -#define foreach_nsh_plugin_api_msg \ - _(NSH_ADD_DEL_ENTRY, nsh_add_del_entry) \ - _(NSH_ENTRY_DUMP, nsh_entry_dump) \ - _(NSH_ADD_DEL_MAP, nsh_add_del_map) \ - _(NSH_MAP_DUMP, nsh_map_dump) - - /* Uses network order's class and type to register */ +/* Uses network order's class and type to register */ int nsh_md2_register_option (u16 class, u8 type, @@ -240,186 +147,6 @@ nsh_md2_unregister_option (u16 class, return (0); } -/* format from network order */ -u8 * -format_nsh_header (u8 * s, va_list * args) -{ - nsh_main_t *nm = &nsh_main; - nsh_md2_data_t *opt0; - nsh_md2_data_t *limit0; - nsh_option_map_t *nsh_option; - u8 option_len = 0; - - u8 *header = va_arg (*args, u8 *); - nsh_base_header_t *nsh_base = (nsh_base_header_t *) header; - nsh_md1_data_t *nsh_md1 = (nsh_md1_data_t *) (nsh_base + 1); - nsh_md2_data_t *nsh_md2 = (nsh_md2_data_t *) (nsh_base + 1); - opt0 = (nsh_md2_data_t *) nsh_md2; - limit0 = (nsh_md2_data_t *) ((u8 *) nsh_md2 + - ((nsh_base->length & NSH_LEN_MASK) * 4 - - sizeof (nsh_base_header_t))); - - s = format (s, "nsh ver %d ", (nsh_base->ver_o_c >> 6)); - if (nsh_base->ver_o_c & NSH_O_BIT) - s = format (s, "O-set "); - - if (nsh_base->ver_o_c & NSH_C_BIT) - s = format (s, "C-set "); - - s = format (s, "ttl %d ", (nsh_base->ver_o_c & NSH_TTL_H4_MASK) << 2 | - (nsh_base->length & NSH_TTL_L2_MASK) >> 6); - - s = format (s, "len %d (%d bytes) md_type %d next_protocol %d\n", - (nsh_base->length & NSH_LEN_MASK), - (nsh_base->length & NSH_LEN_MASK) * 4, - nsh_base->md_type, nsh_base->next_protocol); - - s = format (s, " service path %d service index %d\n", - (clib_net_to_host_u32 (nsh_base->nsp_nsi) >> NSH_NSP_SHIFT) & - NSH_NSP_MASK, - clib_net_to_host_u32 (nsh_base->nsp_nsi) & NSH_NSI_MASK); - - if (nsh_base->md_type == 1) - { - s = format (s, " c1 %d c2 %d c3 %d c4 %d\n", - clib_net_to_host_u32 (nsh_md1->c1), - clib_net_to_host_u32 (nsh_md1->c2), - clib_net_to_host_u32 (nsh_md1->c3), - clib_net_to_host_u32 (nsh_md1->c4)); - } - else if (nsh_base->md_type == 2) - { - s = format (s, " Supported TLVs: \n"); - - /* Scan the set of variable metadata, network order */ - while (opt0 < limit0) - { - nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type); - if (nsh_option != NULL) - { - if (nm->trace[nsh_option->option_id] != NULL) - { - s = (*nm->trace[nsh_option->option_id]) (s, opt0); - } - else - { - s = - format (s, "\n untraced option %d length %d", - opt0->type, opt0->length); - } - } - else - { - s = - format (s, "\n unrecognized option %d length %d", - opt0->type, opt0->length); - } - - /* round to 4-byte */ - option_len = ((opt0->length + 3) >> 2) << 2; - opt0 = - (nsh_md2_data_t *) (((u8 *) opt0) + sizeof (nsh_md2_data_t) + - option_len); - } - } - - return s; -} - -static u8 * -format_nsh_action (u8 * s, va_list * args) -{ - u32 nsh_action = va_arg (*args, u32); - - switch (nsh_action) - { - case NSH_ACTION_SWAP: - return format (s, "swap"); - case NSH_ACTION_PUSH: - return format (s, "push"); - case NSH_ACTION_POP: - return format (s, "pop"); - default: - return format (s, "unknown %d", nsh_action); - } - return s; -} - -u8 * -format_nsh_map (u8 * s, va_list * args) -{ - nsh_map_t *map = va_arg (*args, nsh_map_t *); - - s = format (s, "nsh entry nsp: %d nsi: %d ", - (map->nsp_nsi >> NSH_NSP_SHIFT) & NSH_NSP_MASK, - map->nsp_nsi & NSH_NSI_MASK); - s = format (s, "maps to nsp: %d nsi: %d ", - (map->mapped_nsp_nsi >> NSH_NSP_SHIFT) & NSH_NSP_MASK, - map->mapped_nsp_nsi & NSH_NSI_MASK); - - s = format (s, " nsh_action %U\n", format_nsh_action, map->nsh_action); - - switch (map->next_node) - { - case NSH_NODE_NEXT_ENCAP_GRE4: - { - s = format (s, "encapped by GRE4 intf: %d", map->sw_if_index); - break; - } - case NSH_NODE_NEXT_ENCAP_GRE6: - { - s = format (s, "encapped by GRE6 intf: %d", map->sw_if_index); - break; - } - case NSH_NODE_NEXT_ENCAP_VXLANGPE: - { - s = format (s, "encapped by VXLAN GPE intf: %d", map->sw_if_index); - break; - } - case NSH_NODE_NEXT_ENCAP_VXLAN4: - { - s = format (s, "encapped by VXLAN4 intf: %d", map->sw_if_index); - break; - } - case NSH_NODE_NEXT_ENCAP_VXLAN6: - { - s = format (s, "encapped by VXLAN6 intf: %d", map->sw_if_index); - break; - } - case NSH_NODE_NEXT_DECAP_ETH_INPUT: - { - s = format (s, "encap-none"); - break; - } - case NSH_NODE_NEXT_ENCAP_LISP_GPE: - { - s = format (s, "encapped by LISP GPE intf: %d", map->sw_if_index); - break; - } - case NSH_NODE_NEXT_ENCAP_ETHERNET: - { - s = format (s, "encapped by Ethernet intf: %d", map->sw_if_index); - break; - } - default: - s = format (s, "only GRE and VXLANGPE support in this rev"); - } - - return s; -} - -u8 * -format_nsh_node_map_trace (u8 * s, va_list * args) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - nsh_input_trace_t *t = va_arg (*args, nsh_input_trace_t *); - - s = format (s, "\n %U", format_nsh_header, &(t->trace_data)); - - return s; -} - /** * @brief Naming for NSH tunnel * @@ -466,11 +193,14 @@ dummy_interface_tx (vlib_main_t * vm, return frame->n_vectors; } -VNET_DEVICE_CLASS (nsh_device_class, static) = -{ -.name = "NSH",.format_device_name = format_nsh_name,.tx_function = - dummy_interface_tx,.admin_up_down_function = - nsh_interface_admin_up_down,}; +/* *INDENT-OFF* */ +VNET_DEVICE_CLASS (nsh_device_class, static) = { + .name = "NSH", + .format_device_name = format_nsh_name, + .tx_function = dummy_interface_tx, + .admin_up_down_function = nsh_interface_admin_up_down, +}; +/* *INDENT-ON* */ /** * @brief Formatting function for tracing VXLAN GPE with length @@ -489,1954 +219,14 @@ format_nsh_tunnel_with_length (u8 * s, va_list * args) return s; } -VNET_HW_INTERFACE_CLASS (nsh_hw_class) = -{ -.name = "NSH",.format_header = - format_nsh_tunnel_with_length,.build_rewrite = - default_build_rewrite,.flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,}; - - -/** - * Action function to add or del an nsh map. - * Shared by both CLI and binary API - **/ - -int -nsh_add_del_map (nsh_add_del_map_args_t * a, u32 * map_indexp) -{ - nsh_main_t *nm = &nsh_main; - vnet_main_t *vnm = nm->vnet_main; - nsh_map_t *map = 0; - u32 key, *key_copy; - uword *entry; - hash_pair_t *hp; - u32 map_index = ~0; - vnet_hw_interface_t *hi; - u32 nsh_hw_if = ~0; - u32 nsh_sw_if = ~0; - - /* net order, so data plane could use nsh header to lookup directly */ - key = clib_host_to_net_u32 (a->map.nsp_nsi); - - entry = hash_get_mem (nm->nsh_mapping_by_key, &key); - - if (a->is_add) - { - /* adding an entry, must not already exist */ - if (entry) - return -1; //TODO API_ERROR_INVALID_VALUE; - - pool_get_aligned (nm->nsh_mappings, map, CLIB_CACHE_LINE_BYTES); - clib_memset (map, 0, sizeof (*map)); - - /* copy from arg structure */ - map->nsp_nsi = a->map.nsp_nsi; - map->mapped_nsp_nsi = a->map.mapped_nsp_nsi; - map->nsh_action = a->map.nsh_action; - map->sw_if_index = a->map.sw_if_index; - map->rx_sw_if_index = a->map.rx_sw_if_index; - map->next_node = a->map.next_node; - map->adj_index = a->map.adj_index; - - - key_copy = clib_mem_alloc (sizeof (*key_copy)); - clib_memcpy (key_copy, &key, sizeof (*key_copy)); - - hash_set_mem (nm->nsh_mapping_by_key, key_copy, map - nm->nsh_mappings); - map_index = map - nm->nsh_mappings; - - if (vec_len (nm->free_nsh_tunnel_hw_if_indices) > 0) - { - nsh_hw_if = nm->free_nsh_tunnel_hw_if_indices - [vec_len (nm->free_nsh_tunnel_hw_if_indices) - 1]; - _vec_len (nm->free_nsh_tunnel_hw_if_indices) -= 1; - - hi = vnet_get_hw_interface (vnm, nsh_hw_if); - hi->dev_instance = map_index; - hi->hw_instance = hi->dev_instance; - } - else - { - nsh_hw_if = vnet_register_interface - (vnm, nsh_device_class.index, map_index, nsh_hw_class.index, - map_index); - hi = vnet_get_hw_interface (vnm, nsh_hw_if); - hi->output_node_index = nsh_aware_vnf_proxy_node.index; - } - - map->nsh_hw_if = nsh_hw_if; - map->nsh_sw_if = nsh_sw_if = hi->sw_if_index; - vec_validate_init_empty (nm->tunnel_index_by_sw_if_index, nsh_sw_if, - ~0); - nm->tunnel_index_by_sw_if_index[nsh_sw_if] = key; - - vnet_sw_interface_set_flags (vnm, hi->sw_if_index, - VNET_SW_INTERFACE_FLAG_ADMIN_UP); - } - else - { - if (!entry) - return -2; //TODO API_ERROR_NO_SUCH_ENTRY; - - map = pool_elt_at_index (nm->nsh_mappings, entry[0]); - - vnet_sw_interface_set_flags (vnm, map->nsh_sw_if, - VNET_SW_INTERFACE_FLAG_ADMIN_DOWN); - vec_add1 (nm->free_nsh_tunnel_hw_if_indices, map->nsh_sw_if); - nm->tunnel_index_by_sw_if_index[map->nsh_sw_if] = ~0; - - hp = hash_get_pair (nm->nsh_mapping_by_key, &key); - key_copy = (void *) (hp->key); - hash_unset_mem (nm->nsh_mapping_by_key, &key); - clib_mem_free (key_copy); - - pool_put (nm->nsh_mappings, map); - } - - if (map_indexp) - *map_indexp = map_index; - - return 0; -} - -/** - * Action function to add or del an nsh-proxy-session. - * Shared by both CLI and binary API - **/ - -int -nsh_add_del_proxy_session (nsh_add_del_map_args_t * a) -{ - nsh_main_t *nm = &nsh_main; - nsh_proxy_session_t *proxy = 0; - nsh_proxy_session_by_key_t key, *key_copy; - uword *entry; - hash_pair_t *hp; - u32 nsp = 0, nsi = 0; - - clib_memset (&key, 0, sizeof (key)); - key.transport_type = a->map.next_node; - key.transport_index = a->map.sw_if_index; - - entry = hash_get_mem (nm->nsh_proxy_session_by_key, &key); - - if (a->is_add) - { - /* adding an entry, must not already exist */ - if (entry) - return -1; //TODO API_ERROR_INVALID_VALUE; - - pool_get_aligned (nm->nsh_proxy_sessions, proxy, CLIB_CACHE_LINE_BYTES); - clib_memset (proxy, 0, sizeof (*proxy)); - - /* Nsi needs to minus 1 within NSH-Proxy */ - nsp = (a->map.nsp_nsi >> NSH_NSP_SHIFT) & NSH_NSP_MASK; - nsi = a->map.nsp_nsi & NSH_NSI_MASK; - if (nsi == 0) - return -1; - - nsi = nsi - 1; - /* net order, so could use it to lookup nsh map table directly */ - proxy->nsp_nsi = clib_host_to_net_u32 ((nsp << NSH_NSP_SHIFT) | nsi); - - key_copy = clib_mem_alloc (sizeof (*key_copy)); - clib_memcpy (key_copy, &key, sizeof (*key_copy)); - - hash_set_mem (nm->nsh_proxy_session_by_key, key_copy, - proxy - nm->nsh_proxy_sessions); - } - else - { - if (!entry) - return -2; //TODO API_ERROR_NO_SUCH_ENTRY; - - proxy = pool_elt_at_index (nm->nsh_proxy_sessions, entry[0]); - hp = hash_get_pair (nm->nsh_proxy_session_by_key, &key); - key_copy = (void *) (hp->key); - hash_unset_mem (nm->nsh_proxy_session_by_key, &key); - clib_mem_free (key_copy); - - pool_put (nm->nsh_proxy_sessions, proxy); - } - - return 0; -} - -/** - * CLI command for NSH map - */ - -static uword -unformat_nsh_action (unformat_input_t * input, va_list * args) -{ - u32 *result = va_arg (*args, u32 *); - u32 tmp; - - if (unformat (input, "swap")) - *result = NSH_ACTION_SWAP; - else if (unformat (input, "push")) - *result = NSH_ACTION_PUSH; - else if (unformat (input, "pop")) - *result = NSH_ACTION_POP; - else if (unformat (input, "%d", &tmp)) - *result = tmp; - else - return 0; - - return 1; -} - -static adj_index_t -nsh_get_adj_by_sw_if_index (u32 sw_if_index) -{ - adj_index_t ai = ~0; - - /* *INDENT-OFF* */ - pool_foreach_index(ai, adj_pool, - ({ - if (sw_if_index == adj_get_sw_if_index(ai)) - { - return ai; - } - })); - /* *INDENT-ON* */ - - return ~0; -} - -static clib_error_t * -nsh_add_del_map_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - u8 is_add = 1; - u32 nsp, nsi, mapped_nsp, mapped_nsi, nsh_action; - int nsp_set = 0, nsi_set = 0, mapped_nsp_set = 0, mapped_nsi_set = 0; - int nsh_action_set = 0; - u32 next_node = ~0; - u32 adj_index = ~0; - u32 sw_if_index = ~0; // temporary requirement to get this moved over to NSHSFC - u32 rx_sw_if_index = ~0; // temporary requirement to get this moved over to NSHSFC - nsh_add_del_map_args_t _a, *a = &_a; - u32 map_index; - int rv; - - /* Get a line of input. */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "del")) - is_add = 0; - else if (unformat (line_input, "nsp %d", &nsp)) - nsp_set = 1; - else if (unformat (line_input, "nsi %d", &nsi)) - nsi_set = 1; - else if (unformat (line_input, "mapped-nsp %d", &mapped_nsp)) - mapped_nsp_set = 1; - else if (unformat (line_input, "mapped-nsi %d", &mapped_nsi)) - mapped_nsi_set = 1; - else if (unformat (line_input, "nsh_action %U", unformat_nsh_action, - &nsh_action)) - nsh_action_set = 1; - else if (unformat (line_input, "encap-gre4-intf %d", &sw_if_index)) - next_node = NSH_NODE_NEXT_ENCAP_GRE4; - else if (unformat (line_input, "encap-gre6-intf %d", &sw_if_index)) - next_node = NSH_NODE_NEXT_ENCAP_GRE6; - else if (unformat (line_input, "encap-vxlan-gpe-intf %d", &sw_if_index)) - next_node = NSH_NODE_NEXT_ENCAP_VXLANGPE; - else if (unformat (line_input, "encap-lisp-gpe-intf %d", &sw_if_index)) - next_node = NSH_NODE_NEXT_ENCAP_LISP_GPE; - else if (unformat (line_input, "encap-vxlan4-intf %d", &sw_if_index)) - next_node = NSH_NODE_NEXT_ENCAP_VXLAN4; - else if (unformat (line_input, "encap-vxlan6-intf %d", &sw_if_index)) - next_node = NSH_NODE_NEXT_ENCAP_VXLAN6; - else if (unformat (line_input, "encap-eth-intf %d", &sw_if_index)) - { - next_node = NSH_NODE_NEXT_ENCAP_ETHERNET; - adj_index = nsh_get_adj_by_sw_if_index (sw_if_index); - } - else - if (unformat - (line_input, "encap-none %d %d", &sw_if_index, &rx_sw_if_index)) - next_node = NSH_NODE_NEXT_DECAP_ETH_INPUT; - else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); - } - - unformat_free (line_input); - - if (nsp_set == 0 || nsi_set == 0) - return clib_error_return (0, "nsp nsi pair required. Key: for NSH entry"); - - if (mapped_nsp_set == 0 || mapped_nsi_set == 0) - return clib_error_return (0, - "mapped-nsp mapped-nsi pair required. Key: for NSH entry"); - - if (nsh_action_set == 0) - return clib_error_return (0, "nsh_action required: swap|push|pop."); - - if (next_node == ~0) - return clib_error_return (0, - "must specific action: [encap-gre-intf <nn> | encap-vxlan-gpe-intf <nn> | encap-lisp-gpe-intf <nn> | encap-none <tx_sw_if_index> <rx_sw_if_index>]"); - - clib_memset (a, 0, sizeof (*a)); - - /* set args structure */ - a->is_add = is_add; - a->map.nsp_nsi = (nsp << NSH_NSP_SHIFT) | nsi; - a->map.mapped_nsp_nsi = (mapped_nsp << NSH_NSP_SHIFT) | mapped_nsi; - a->map.nsh_action = nsh_action; - a->map.sw_if_index = sw_if_index; - a->map.rx_sw_if_index = rx_sw_if_index; - a->map.next_node = next_node; - a->map.adj_index = adj_index; - - rv = nsh_add_del_map (a, &map_index); - - switch (rv) - { - case 0: - break; - case -1: //TODO API_ERROR_INVALID_VALUE: - return clib_error_return (0, - "mapping already exists. Remove it first."); - - case -2: // TODO API_ERROR_NO_SUCH_ENTRY: - return clib_error_return (0, "mapping does not exist."); - - default: - return clib_error_return (0, "nsh_add_del_map returned %d", rv); - } - - if ((a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN4) - | (a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN6)) - { - rv = nsh_add_del_proxy_session (a); - - switch (rv) - { - case 0: - break; - case -1: //TODO API_ERROR_INVALID_VALUE: - return clib_error_return (0, - "nsh-proxy-session already exists. Remove it first."); - - case -2: // TODO API_ERROR_NO_SUCH_ENTRY: - return clib_error_return (0, "nsh-proxy-session does not exist."); - - default: - return clib_error_return - (0, "nsh_add_del_proxy_session() returned %d", rv); - } - } - - return 0; -} - -VLIB_CLI_COMMAND (create_nsh_map_command, static) = -{ -.path = "create nsh map",.short_help = - "create nsh map nsp <nn> nsi <nn> [del] mapped-nsp <nn> mapped-nsi <nn> nsh_action [swap|push|pop] " - "[encap-gre4-intf <nn> | encap-gre4-intf <nn> | encap-vxlan-gpe-intf <nn> | encap-lisp-gpe-intf <nn> " - " encap-vxlan4-intf <nn> | encap-vxlan6-intf <nn>| encap-eth-intf <nn> | encap-none]\n",.function - = nsh_add_del_map_command_fn,}; - -/** API message handler */ -static void -vl_api_nsh_add_del_map_t_handler (vl_api_nsh_add_del_map_t * mp) -{ - vl_api_nsh_add_del_map_reply_t *rmp; - nsh_main_t *nm = &nsh_main; - int rv; - nsh_add_del_map_args_t _a, *a = &_a; - u32 map_index = ~0; - - a->is_add = mp->is_add; - a->map.nsp_nsi = ntohl (mp->nsp_nsi); - a->map.mapped_nsp_nsi = ntohl (mp->mapped_nsp_nsi); - a->map.nsh_action = ntohl (mp->nsh_action); - a->map.sw_if_index = ntohl (mp->sw_if_index); - a->map.rx_sw_if_index = ntohl (mp->rx_sw_if_index); - a->map.next_node = ntohl (mp->next_node); - - rv = nsh_add_del_map (a, &map_index); - - if ((a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN4) - | (a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN6)) - { - rv = nsh_add_del_proxy_session (a); - } - - REPLY_MACRO2 (VL_API_NSH_ADD_DEL_MAP_REPLY, ( - { - rmp->map_index = - htonl (map_index); - } - )); -} - -/** - * CLI command for showing the mapping between NSH entries - */ -static clib_error_t * -show_nsh_map_command_fn (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - nsh_main_t *nm = &nsh_main; - nsh_map_t *map; - - if (pool_elts (nm->nsh_mappings) == 0) - vlib_cli_output (vm, "No nsh maps configured."); - - pool_foreach (map, nm->nsh_mappings, ( - { - vlib_cli_output (vm, "%U", - format_nsh_map, - map); - } - )); - - return 0; -} - -VLIB_CLI_COMMAND (show_nsh_map_command, static) = -{ -.path = "show nsh map",.function = show_nsh_map_command_fn,}; - -int -nsh_header_rewrite (nsh_entry_t * nsh_entry) -{ - u8 *rw = 0; - int len = 0; - nsh_base_header_t *nsh_base; - nsh_md1_data_t *nsh_md1; - nsh_main_t *nm = &nsh_main; - nsh_md2_data_t *opt0; - nsh_md2_data_t *limit0; - nsh_md2_data_t *nsh_md2; - nsh_option_map_t _nsh_option, *nsh_option = &_nsh_option; - u8 old_option_size = 0; - u8 new_option_size = 0; - - vec_free (nsh_entry->rewrite); - if (nsh_entry->nsh_base.md_type == 1) - { - len = sizeof (nsh_base_header_t) + sizeof (nsh_md1_data_t); - } - else if (nsh_entry->nsh_base.md_type == 2) - { - /* set to maxim, maybe dataplane will add more TLVs */ - len = MAX_NSH_HEADER_LEN; - } - vec_validate_aligned (rw, len - 1, CLIB_CACHE_LINE_BYTES); - clib_memset (rw, 0, len); - - nsh_base = (nsh_base_header_t *) rw; - nsh_base->ver_o_c = nsh_entry->nsh_base.ver_o_c; - nsh_base->length = nsh_entry->nsh_base.length; - nsh_base->md_type = nsh_entry->nsh_base.md_type; - nsh_base->next_protocol = nsh_entry->nsh_base.next_protocol; - nsh_base->nsp_nsi = clib_host_to_net_u32 (nsh_entry->nsh_base.nsp_nsi); - - if (nsh_base->md_type == 1) - { - nsh_md1 = (nsh_md1_data_t *) (rw + sizeof (nsh_base_header_t)); - nsh_md1->c1 = clib_host_to_net_u32 (nsh_entry->md.md1_data.c1); - nsh_md1->c2 = clib_host_to_net_u32 (nsh_entry->md.md1_data.c2); - nsh_md1->c3 = clib_host_to_net_u32 (nsh_entry->md.md1_data.c3); - nsh_md1->c4 = clib_host_to_net_u32 (nsh_entry->md.md1_data.c4); - nsh_entry->rewrite_size = 24; - } - else if (nsh_base->md_type == 2) - { - opt0 = (nsh_md2_data_t *) (nsh_entry->tlvs_data); - limit0 = (nsh_md2_data_t *) ((u8 *) opt0 + nsh_entry->tlvs_len); - - nsh_md2 = (nsh_md2_data_t *) (rw + sizeof (nsh_base_header_t)); - nsh_entry->rewrite_size = sizeof (nsh_base_header_t); - - while (opt0 < limit0) - { - old_option_size = sizeof (nsh_md2_data_t) + opt0->length; - /* round to 4-byte */ - old_option_size = ((old_option_size + 3) >> 2) << 2; - - nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type); - if (nsh_option == NULL) - { - goto next_tlv_md2; - } - - if (nm->add_options[nsh_option->option_id] != NULL) - { - if (0 != nm->add_options[nsh_option->option_id] ((u8 *) nsh_md2, - &new_option_size)) - { - goto next_tlv_md2; - } - - /* round to 4-byte */ - new_option_size = ((new_option_size + 3) >> 2) << 2; - - nsh_entry->rewrite_size += new_option_size; - nsh_md2 = - (nsh_md2_data_t *) (((u8 *) nsh_md2) + new_option_size); - opt0 = (nsh_md2_data_t *) (((u8 *) opt0) + old_option_size); - } - else - { - next_tlv_md2: - opt0 = (nsh_md2_data_t *) (((u8 *) opt0) + old_option_size); - } - - } - } - - nsh_entry->rewrite = rw; - nsh_base->length = (nsh_base->length & NSH_TTL_L2_MASK) | - ((nsh_entry->rewrite_size >> 2) & NSH_LEN_MASK); - - return 0; -} - - -/** - * Action function for adding an NSH entry - * nsh_add_del_entry_args_t *a: host order - */ - -int -nsh_add_del_entry (nsh_add_del_entry_args_t * a, u32 * entry_indexp) -{ - nsh_main_t *nm = &nsh_main; - nsh_entry_t *nsh_entry = 0; - u32 key, *key_copy; - uword *entry_id; - hash_pair_t *hp; - u32 entry_index = ~0; - u8 tlvs_len = 0; - u8 *data = 0; - - /* host order, because nsh map table stores nsp_nsi in host order */ - key = a->nsh_entry.nsh_base.nsp_nsi; - - entry_id = hash_get_mem (nm->nsh_entry_by_key, &key); - - if (a->is_add) - { - /* adding an entry, must not already exist */ - if (entry_id) - return -1; // TODO VNET_API_ERROR_INVALID_VALUE; - - pool_get_aligned (nm->nsh_entries, nsh_entry, CLIB_CACHE_LINE_BYTES); - clib_memset (nsh_entry, 0, sizeof (*nsh_entry)); - - /* copy from arg structure */ -#define _(x) nsh_entry->nsh_base.x = a->nsh_entry.nsh_base.x; - foreach_copy_nsh_base_hdr_field; -#undef _ - - if (a->nsh_entry.nsh_base.md_type == 1) - { - nsh_entry->md.md1_data.c1 = a->nsh_entry.md.md1_data.c1; - nsh_entry->md.md1_data.c2 = a->nsh_entry.md.md1_data.c2; - nsh_entry->md.md1_data.c3 = a->nsh_entry.md.md1_data.c3; - nsh_entry->md.md1_data.c4 = a->nsh_entry.md.md1_data.c4; - } - else if (a->nsh_entry.nsh_base.md_type == 2) - { - vec_free (nsh_entry->tlvs_data); - tlvs_len = a->nsh_entry.tlvs_len; - vec_validate_aligned (data, tlvs_len - 1, CLIB_CACHE_LINE_BYTES); - - clib_memcpy (data, a->nsh_entry.tlvs_data, tlvs_len); - nsh_entry->tlvs_data = data; - nsh_entry->tlvs_len = tlvs_len; - vec_free (a->nsh_entry.tlvs_data); - } - - nsh_header_rewrite (nsh_entry); - - key_copy = clib_mem_alloc (sizeof (*key_copy)); - clib_memcpy (key_copy, &key, sizeof (*key_copy)); - - hash_set_mem (nm->nsh_entry_by_key, key_copy, - nsh_entry - nm->nsh_entries); - entry_index = nsh_entry - nm->nsh_entries; - } - else - { - if (!entry_id) - return -2; //TODO API_ERROR_NO_SUCH_ENTRY; - - nsh_entry = pool_elt_at_index (nm->nsh_entries, entry_id[0]); - hp = hash_get_pair (nm->nsh_entry_by_key, &key); - key_copy = (void *) (hp->key); - hash_unset_mem (nm->nsh_entry_by_key, &key); - clib_mem_free (key_copy); - - vec_free (nsh_entry->tlvs_data); - vec_free (nsh_entry->rewrite); - pool_put (nm->nsh_entries, nsh_entry); - } - - if (entry_indexp) - *entry_indexp = entry_index; - - return 0; -} - - -/** - * CLI command for adding NSH entry - */ - -static clib_error_t * -nsh_add_del_entry_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - u8 is_add = 1; - u8 ver_o_c = 0; - u8 ttl = 63; - u8 length = 0; - u8 md_type = 0; - u8 next_protocol = 1; /* default: ip4 */ - u32 nsp; - u8 nsp_set = 0; - u32 nsi; - u8 nsi_set = 0; - u32 nsp_nsi; - u32 c1 = 0; - u32 c2 = 0; - u32 c3 = 0; - u32 c4 = 0; - u8 *data = 0; - nsh_tlv_header_t tlv_header; - u8 cur_len = 0, tlvs_len = 0; - u8 *current; - nsh_main_t *nm = &nsh_main; - nsh_option_map_t _nsh_option, *nsh_option = &_nsh_option; - u8 option_size = 0; - u32 tmp; - int rv; - u32 entry_index; - nsh_add_del_entry_args_t _a, *a = &_a; - u8 has_ioam_trace_option = 0; - - /* Get a line of input. */ - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "del")) - is_add = 0; - else if (unformat (line_input, "version %d", &tmp)) - ver_o_c |= (tmp & 3) << 6; - else if (unformat (line_input, "o-bit %d", &tmp)) - ver_o_c |= (tmp & 1) << 5; - else if (unformat (line_input, "c-bit %d", &tmp)) - ver_o_c |= (tmp & 1) << 4; - else if (unformat (line_input, "ttl %d", &ttl)) - ver_o_c |= (ttl & NSH_LEN_MASK) >> 2; - else if (unformat (line_input, "md-type %d", &tmp)) - md_type = tmp; - else if (unformat (line_input, "next-ip4")) - next_protocol = 1; - else if (unformat (line_input, "next-ip6")) - next_protocol = 2; - else if (unformat (line_input, "next-ethernet")) - next_protocol = 3; - else if (unformat (line_input, "c1 %d", &c1)) - ; - else if (unformat (line_input, "c2 %d", &c2)) - ; - else if (unformat (line_input, "c3 %d", &c3)) - ; - else if (unformat (line_input, "c4 %d", &c4)) - ; - else if (unformat (line_input, "nsp %d", &nsp)) - nsp_set = 1; - else if (unformat (line_input, "nsi %d", &nsi)) - nsi_set = 1; - else if (unformat (line_input, "tlv-ioam-trace")) - has_ioam_trace_option = 1; - else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); - } - - unformat_free (line_input); - - if (nsp_set == 0) - return clib_error_return (0, "nsp not specified"); - - if (nsi_set == 0) - return clib_error_return (0, "nsi not specified"); - - if (md_type == 1 && has_ioam_trace_option == 1) - return clib_error_return (0, "Invalid MD Type"); - - nsp_nsi = (nsp << 8) | nsi; - - clib_memset (a, 0, sizeof (*a)); - a->is_add = is_add; - - if (md_type == 1) - { - a->nsh_entry.md.md1_data.c1 = c1; - a->nsh_entry.md.md1_data.c2 = c2; - a->nsh_entry.md.md1_data.c3 = c3; - a->nsh_entry.md.md1_data.c4 = c4; - length = (sizeof (nsh_base_header_t) + sizeof (nsh_md1_data_t)) >> 2; - } - else if (md_type == 2) - { - length = sizeof (nsh_base_header_t) >> 2; - - vec_free (a->nsh_entry.tlvs_data); - tlvs_len = (MAX_METADATA_LEN << 2); - vec_validate_aligned (data, tlvs_len - 1, CLIB_CACHE_LINE_BYTES); - a->nsh_entry.tlvs_data = data; - current = data; - - if (has_ioam_trace_option) - { - tlv_header.class = clib_host_to_net_u16 (NSH_MD2_IOAM_CLASS); - tlv_header.type = NSH_MD2_IOAM_OPTION_TYPE_TRACE; - /* Uses network order's class and type to lookup */ - nsh_option = - nsh_md2_lookup_option (tlv_header.class, tlv_header.type); - if (nsh_option == NULL) - return clib_error_return (0, "iOAM Trace not registered"); - - if (nm->add_options[nsh_option->option_id] != NULL) - { - if (0 != nm->add_options[nsh_option->option_id] ((u8 *) current, - &option_size)) - { - return clib_error_return (0, "Invalid MD Type"); - } - } - - nm->options_size[nsh_option->option_id] = option_size; - /* round to 4-byte */ - option_size = (((option_size + 3) >> 2) << 2); - - cur_len += option_size; - current = data + option_size; - } - - /* Add more options' parsing */ - - a->nsh_entry.tlvs_len = cur_len; - length += (cur_len >> 2); - } - length = (length & NSH_LEN_MASK) | ((ttl & 0x3) << 6); - -#define _(x) a->nsh_entry.nsh_base.x = x; - foreach_copy_nsh_base_hdr_field; -#undef _ - - rv = nsh_add_del_entry (a, &entry_index); - - switch (rv) - { - case 0: - break; - default: - return clib_error_return (0, "nsh_add_del_entry returned %d", rv); - } - - return 0; -} - -VLIB_CLI_COMMAND (create_nsh_entry_command, static) = -{ -.path = "create nsh entry",.short_help = - "create nsh entry {nsp <nn> nsi <nn>} [ttl <nn>] [md-type <nn>]" - " [c1 <nn> c2 <nn> c3 <nn> c4 <nn>] [tlv-ioam-trace] [del]\n",.function - = nsh_add_del_entry_command_fn,}; - -/** API message handler */ -static void vl_api_nsh_add_del_entry_t_handler - (vl_api_nsh_add_del_entry_t * mp) -{ - vl_api_nsh_add_del_entry_reply_t *rmp; - nsh_main_t *nm = &nsh_main; - int rv; - nsh_add_del_entry_args_t _a, *a = &_a; - u32 entry_index = ~0; - u8 tlvs_len = 0; - u8 *data = 0; - - a->is_add = mp->is_add; - a->nsh_entry.nsh_base.ver_o_c = - (mp->ver_o_c & 0xF0) | ((mp->ttl & NSH_LEN_MASK) >> 2); - a->nsh_entry.nsh_base.length = - (mp->length & NSH_LEN_MASK) | ((mp->ttl & 0x3) << 6); - a->nsh_entry.nsh_base.md_type = mp->md_type; - a->nsh_entry.nsh_base.next_protocol = mp->next_protocol; - a->nsh_entry.nsh_base.nsp_nsi = ntohl (mp->nsp_nsi); - if (mp->md_type == 1) - { - a->nsh_entry.md.md1_data.c1 = ntohl (mp->c1); - a->nsh_entry.md.md1_data.c2 = ntohl (mp->c2); - a->nsh_entry.md.md1_data.c3 = ntohl (mp->c3); - a->nsh_entry.md.md1_data.c4 = ntohl (mp->c4); - } - else if (mp->md_type == 2) - { - tlvs_len = mp->tlv_length; - vec_validate_aligned (data, tlvs_len - 1, CLIB_CACHE_LINE_BYTES); - - clib_memcpy (data, mp->tlv, tlvs_len); - a->nsh_entry.tlvs_data = data; - a->nsh_entry.tlvs_len = tlvs_len; - } - - rv = nsh_add_del_entry (a, &entry_index); - - REPLY_MACRO2 (VL_API_NSH_ADD_DEL_ENTRY_REPLY, ( - { - rmp->entry_index = - htonl (entry_index); - } - )); -} - -static void send_nsh_entry_details - (nsh_entry_t * t, unix_shared_memory_queue_t * q, u32 context) -{ - vl_api_nsh_entry_details_t *rmp; - nsh_main_t *nm = &nsh_main; - - rmp = vl_msg_api_alloc (sizeof (*rmp)); - clib_memset (rmp, 0, sizeof (*rmp)); - - rmp->_vl_msg_id = ntohs ((VL_API_NSH_ENTRY_DETAILS) + nm->msg_id_base); - rmp->ver_o_c = t->nsh_base.ver_o_c; - rmp->ttl = (t->nsh_base.ver_o_c & NSH_TTL_H4_MASK) << 2 | - (t->nsh_base.length & NSH_TTL_L2_MASK) >> 6; - rmp->length = t->nsh_base.length & NSH_LEN_MASK; - rmp->md_type = t->nsh_base.md_type; - rmp->next_protocol = t->nsh_base.next_protocol; - rmp->nsp_nsi = htonl (t->nsh_base.nsp_nsi); - - if (t->nsh_base.md_type == 1) - { - rmp->tlv_length = 4; - rmp->c1 = htonl (t->md.md1_data.c1); - rmp->c2 = htonl (t->md.md1_data.c2); - rmp->c3 = htonl (t->md.md1_data.c3); - rmp->c4 = htonl (t->md.md1_data.c4); - } - else if (t->nsh_base.md_type == 2) - { - rmp->tlv_length = t->tlvs_len; - clib_memcpy (rmp->tlv, t->tlvs_data, t->tlvs_len); - } - - rmp->context = context; - - vl_msg_api_send_shmem (q, (u8 *) & rmp); -} - -static void -vl_api_nsh_entry_dump_t_handler (vl_api_nsh_entry_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - nsh_main_t *nm = &nsh_main; - nsh_entry_t *t; - u32 entry_index; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - { - return; - } - - entry_index = ntohl (mp->entry_index); - - if (~0 == entry_index) - { - pool_foreach (t, nm->nsh_entries, ( - { - send_nsh_entry_details (t, q, - mp->context); - } - )); - } - else - { - if (entry_index >= vec_len (nm->nsh_entries)) - { - return; - } - t = &nm->nsh_entries[entry_index]; - send_nsh_entry_details (t, q, mp->context); - } -} - -static void send_nsh_map_details - (nsh_map_t * t, unix_shared_memory_queue_t * q, u32 context) -{ - vl_api_nsh_map_details_t *rmp; - nsh_main_t *nm = &nsh_main; - - rmp = vl_msg_api_alloc (sizeof (*rmp)); - clib_memset (rmp, 0, sizeof (*rmp)); - - rmp->_vl_msg_id = ntohs ((VL_API_NSH_MAP_DETAILS) + nm->msg_id_base); - rmp->nsp_nsi = htonl (t->nsp_nsi); - rmp->mapped_nsp_nsi = htonl (t->mapped_nsp_nsi); - rmp->nsh_action = htonl (t->nsh_action); - rmp->sw_if_index = htonl (t->sw_if_index); - rmp->rx_sw_if_index = htonl (t->rx_sw_if_index); - rmp->next_node = htonl (t->next_node); - - rmp->context = context; - - vl_msg_api_send_shmem (q, (u8 *) & rmp); -} - -static void -vl_api_nsh_map_dump_t_handler (vl_api_nsh_map_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - nsh_main_t *nm = &nsh_main; - nsh_map_t *t; - u32 map_index; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - { - return; - } - - map_index = ntohl (mp->map_index); - - if (~0 == map_index) - { - pool_foreach (t, nm->nsh_mappings, ( - { - send_nsh_map_details (t, q, - mp->context); - } - )); - } - else - { - if (map_index >= vec_len (nm->nsh_mappings)) - { - return; - } - t = &nm->nsh_mappings[map_index]; - send_nsh_map_details (t, q, mp->context); - } -} - -static clib_error_t * -show_nsh_entry_command_fn (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - nsh_main_t *nm = &nsh_main; - nsh_entry_t *nsh_entry; - - if (pool_elts (nm->nsh_entries) == 0) - vlib_cli_output (vm, "No nsh entries configured."); - - pool_foreach (nsh_entry, nm->nsh_entries, ( - { - vlib_cli_output (vm, "%U", - format_nsh_header, - nsh_entry->rewrite); - vlib_cli_output (vm, - " rewrite_size: %d bytes", - nsh_entry->rewrite_size); - } - )); - - return 0; -} - -VLIB_CLI_COMMAND (show_nsh_entry_command, static) = -{ -.path = "show nsh entry",.function = show_nsh_entry_command_fn,}; - - -/* Set up the API message handling tables */ -static clib_error_t * -nsh_plugin_api_hookup (vlib_main_t * vm) -{ - nsh_main_t *nm __attribute__ ((unused)) = &nsh_main; -#define _(N,n) \ - vl_msg_api_set_handlers((VL_API_##N + nm->msg_id_base), \ - #n, \ - vl_api_##n##_t_handler, \ - vl_noop_handler, \ - vl_api_##n##_t_endian, \ - vl_api_##n##_t_print, \ - sizeof(vl_api_##n##_t), 1); - foreach_nsh_plugin_api_msg; -#undef _ - - return 0; -} - -static void -setup_message_id_table (nsh_main_t * nm, api_main_t * am) -{ -#define _(id,n,crc) \ - vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + nm->msg_id_base); - foreach_vl_msg_name_crc_nsh; -#undef _ -} - -always_inline void -nsh_md2_encap (vlib_buffer_t * b, nsh_base_header_t * hdr, - nsh_entry_t * nsh_entry) -{ - nsh_main_t *nm = &nsh_main; - nsh_base_header_t *nsh_base; - nsh_tlv_header_t *opt0; - nsh_tlv_header_t *limit0; - nsh_tlv_header_t *nsh_md2; - nsh_option_map_t *nsh_option; - u8 old_option_size = 0; - u8 new_option_size = 0; - - /* Populate the NSH Header */ - opt0 = (nsh_tlv_header_t *) (nsh_entry->tlvs_data); - limit0 = (nsh_tlv_header_t *) (nsh_entry->tlvs_data + nsh_entry->tlvs_len); - - nsh_md2 = (nsh_tlv_header_t *) ((u8 *) hdr /*nsh_entry->rewrite */ + - sizeof (nsh_base_header_t)); - nsh_entry->rewrite_size = sizeof (nsh_base_header_t); - - /* Scan the set of variable metadata, process ones that we understand */ - while (opt0 < limit0) - { - old_option_size = sizeof (nsh_tlv_header_t) + opt0->length; - /* round to 4-byte */ - old_option_size = ((old_option_size + 3) >> 2) << 2; - - nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type); - if (nsh_option == NULL) - { - goto next_tlv_md2; - } - - if (nm->options[nsh_option->option_id]) - { - if ((*nm->options[nsh_option->option_id]) (b, nsh_md2)) - { - goto next_tlv_md2; - } - - /* option length may be varied */ - new_option_size = sizeof (nsh_tlv_header_t) + nsh_md2->length; - /* round to 4-byte */ - new_option_size = ((new_option_size + 3) >> 2) << 2; - nsh_entry->rewrite_size += new_option_size; - - nsh_md2 = (nsh_tlv_header_t *) (((u8 *) nsh_md2) + new_option_size); - opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size); - - } - else - { - next_tlv_md2: - opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size); - } - } - - /* update nsh header's length */ - nsh_base = (nsh_base_header_t *) nsh_entry->rewrite; - nsh_base->length = (nsh_base->length & NSH_TTL_L2_MASK) | - ((nsh_entry->rewrite_size >> 2) & NSH_LEN_MASK); - return; -} - -always_inline void -nsh_md2_swap (vlib_buffer_t * b, - nsh_base_header_t * hdr, - u32 header_len, - nsh_entry_t * nsh_entry, u32 * next, u32 drop_node_val) -{ - nsh_main_t *nm = &nsh_main; - nsh_base_header_t *nsh_base; - nsh_tlv_header_t *opt0; - nsh_tlv_header_t *limit0; - nsh_tlv_header_t *nsh_md2; - nsh_option_map_t *nsh_option; - u8 old_option_size = 0; - u8 new_option_size = 0; - - /* Populate the NSH Header */ - opt0 = (nsh_md2_data_t *) (hdr + 1); - limit0 = (nsh_md2_data_t *) ((u8 *) hdr + header_len); - - nsh_md2 = - (nsh_tlv_header_t *) (nsh_entry->rewrite + sizeof (nsh_base_header_t)); - nsh_entry->rewrite_size = sizeof (nsh_base_header_t); - - /* Scan the set of variable metadata, process ones that we understand */ - while (opt0 < limit0) - { - old_option_size = sizeof (nsh_tlv_header_t) + opt0->length; - /* round to 4-byte */ - old_option_size = ((old_option_size + 3) >> 2) << 2; - - nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type); - if (nsh_option == NULL) - { - goto next_tlv_md2; - } - - if (nm->swap_options[nsh_option->option_id]) - { - if ((*nm->swap_options[nsh_option->option_id]) (b, opt0, nsh_md2)) - { - goto next_tlv_md2; - } - - /* option length may be varied */ - new_option_size = sizeof (nsh_tlv_header_t) + nsh_md2->length; - /* round to 4-byte */ - new_option_size = ((new_option_size + 3) >> 2) << 2; - nsh_entry->rewrite_size += new_option_size; - nsh_md2 = (nsh_tlv_header_t *) (((u8 *) nsh_md2) + new_option_size); - - opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size); - - } - else - { - next_tlv_md2: - opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size); - } - } - - /* update nsh header's length */ - nsh_base = (nsh_base_header_t *) nsh_entry->rewrite; - nsh_base->length = (nsh_base->length & NSH_TTL_L2_MASK) | - ((nsh_entry->rewrite_size >> 2) & NSH_LEN_MASK); - return; -} - -always_inline void -nsh_md2_decap (vlib_buffer_t * b, - nsh_base_header_t * hdr, - u32 * header_len, u32 * next, u32 drop_node_val) -{ - nsh_main_t *nm = &nsh_main; - nsh_md2_data_t *opt0; - nsh_md2_data_t *limit0; - nsh_option_map_t *nsh_option; - u8 option_len = 0; - - /* Populate the NSH Header */ - opt0 = (nsh_md2_data_t *) (hdr + 1); - limit0 = (nsh_md2_data_t *) ((u8 *) hdr + *header_len); - - /* Scan the set of variable metadata, process ones that we understand */ - while (opt0 < limit0) - { - nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type); - if (nsh_option == NULL) - { - *next = drop_node_val; - return; - } - - if (nm->pop_options[nsh_option->option_id]) - { - if ((*nm->pop_options[nsh_option->option_id]) (b, opt0)) - { - *next = drop_node_val; - return; - } - } - /* round to 4-byte */ - option_len = ((opt0->length + 3) >> 2) << 2; - opt0 = - (nsh_md2_data_t *) (((u8 *) opt0) + sizeof (nsh_md2_data_t) + - option_len); - *next = - (nm->decap_v4_next_override) ? (nm->decap_v4_next_override) : (*next); - *header_len = (nm->decap_v4_next_override) ? 0 : (*header_len); - } - - return; -} - -static uword -nsh_input_map (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * from_frame, u32 node_type) -{ - u32 n_left_from, next_index, *from, *to_next; - nsh_main_t *nm = &nsh_main; - - from = vlib_frame_vector_args (from_frame); - n_left_from = from_frame->n_vectors; - - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); - - while (n_left_from >= 4 && n_left_to_next >= 2) - { - u32 bi0, bi1; - vlib_buffer_t *b0, *b1; - u32 next0 = NSH_NODE_NEXT_DROP, next1 = NSH_NODE_NEXT_DROP; - uword *entry0, *entry1; - nsh_base_header_t *hdr0 = 0, *hdr1 = 0; - u32 header_len0 = 0, header_len1 = 0; - u32 nsp_nsi0, nsp_nsi1; - u32 ttl0, ttl1; - u32 error0, error1; - nsh_map_t *map0 = 0, *map1 = 0; - nsh_entry_t *nsh_entry0 = 0, *nsh_entry1 = 0; - nsh_base_header_t *encap_hdr0 = 0, *encap_hdr1 = 0; - u32 encap_hdr_len0 = 0, encap_hdr_len1 = 0; - nsh_proxy_session_by_key_t key0, key1; - uword *p0, *p1; - nsh_proxy_session_t *proxy0, *proxy1; - u32 sw_if_index0 = 0, sw_if_index1 = 0; - ethernet_header_t dummy_eth0, dummy_eth1; - - /* Prefetch next iteration. */ - { - vlib_buffer_t *p2, *p3; - - p2 = vlib_get_buffer (vm, from[2]); - p3 = vlib_get_buffer (vm, from[3]); - - vlib_prefetch_buffer_header (p2, LOAD); - vlib_prefetch_buffer_header (p3, LOAD); - - CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD); - CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD); - } - - bi0 = from[0]; - bi1 = from[1]; - to_next[0] = bi0; - to_next[1] = bi1; - from += 2; - to_next += 2; - n_left_from -= 2; - n_left_to_next -= 2; - - error0 = 0; - error1 = 0; - - b0 = vlib_get_buffer (vm, bi0); - b1 = vlib_get_buffer (vm, bi1); - hdr0 = vlib_buffer_get_current (b0); - hdr1 = vlib_buffer_get_current (b1); - - /* Process packet 0 */ - if (node_type == NSH_INPUT_TYPE) - { - nsp_nsi0 = hdr0->nsp_nsi; - header_len0 = (hdr0->length & NSH_LEN_MASK) * 4; - ttl0 = (hdr0->ver_o_c & NSH_TTL_H4_MASK) << 2 | - (hdr0->length & NSH_TTL_L2_MASK) >> 6; - ttl0 = ttl0 - 1; - if (PREDICT_FALSE (ttl0 == 0)) - { - error0 = NSH_NODE_ERROR_INVALID_TTL; - goto trace0; - } - } - else if (node_type == NSH_CLASSIFIER_TYPE) - { - nsp_nsi0 = - clib_host_to_net_u32 (vnet_buffer (b0)-> - l2_classify.opaque_index); - } - else if (node_type == NSH_AWARE_VNF_PROXY_TYPE) - { - /* Push dummy Eth header */ - clib_memcpy_fast (dummy_eth0.dst_address, dummy_dst_address, 6); - clib_memcpy_fast (dummy_eth0.src_address, dummy_src_address, 6); - dummy_eth0.type = 0x0800; - vlib_buffer_advance (b0, -(word) sizeof (ethernet_header_t)); - hdr0 = vlib_buffer_get_current (b0); - clib_memcpy_fast (hdr0, &dummy_eth0, - (word) sizeof (ethernet_header_t)); - - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - nsp_nsi0 = nm->tunnel_index_by_sw_if_index[sw_if_index0]; - } - else - { - clib_memset (&key0, 0, sizeof (key0)); - key0.transport_type = NSH_NODE_NEXT_ENCAP_VXLAN4; - key0.transport_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - - p0 = hash_get_mem (nm->nsh_proxy_session_by_key, &key0); - if (PREDICT_FALSE (p0 == 0)) - { - error0 = NSH_NODE_ERROR_NO_PROXY; - goto trace0; - } - - proxy0 = pool_elt_at_index (nm->nsh_proxy_sessions, p0[0]); - if (PREDICT_FALSE (proxy0 == 0)) - { - error0 = NSH_NODE_ERROR_NO_PROXY; - goto trace0; - } - nsp_nsi0 = proxy0->nsp_nsi; - } - - entry0 = hash_get_mem (nm->nsh_mapping_by_key, &nsp_nsi0); - if (PREDICT_FALSE (entry0 == 0)) - { - error0 = NSH_NODE_ERROR_NO_MAPPING; - goto trace0; - } - - /* Entry should point to a mapping ... */ - map0 = pool_elt_at_index (nm->nsh_mappings, entry0[0]); - if (PREDICT_FALSE (map0 == 0)) - { - error0 = NSH_NODE_ERROR_NO_MAPPING; - goto trace0; - } - - /* set up things for next node to transmit ie which node to handle it and where */ - next0 = map0->next_node; - vnet_buffer (b0)->sw_if_index[VLIB_TX] = map0->sw_if_index; - vnet_buffer (b0)->ip.adj_index[VLIB_TX] = map0->adj_index; - - if (PREDICT_FALSE (map0->nsh_action == NSH_ACTION_POP)) - { - /* Manipulate MD2 */ - if (PREDICT_FALSE (hdr0->md_type == 2)) - { - nsh_md2_decap (b0, hdr0, &header_len0, &next0, - NSH_NODE_NEXT_DROP); - if (PREDICT_FALSE (next0 == NSH_NODE_NEXT_DROP)) - { - error0 = NSH_NODE_ERROR_INVALID_OPTIONS; - goto trace0; - } - vnet_buffer (b0)->sw_if_index[VLIB_RX] = - map0->rx_sw_if_index; - } - - /* Pop NSH header */ - vlib_buffer_advance (b0, (word) header_len0); - goto trace0; - } - - entry0 = hash_get_mem (nm->nsh_entry_by_key, &map0->mapped_nsp_nsi); - if (PREDICT_FALSE (entry0 == 0)) - { - error0 = NSH_NODE_ERROR_NO_ENTRY; - goto trace0; - } - - nsh_entry0 = - (nsh_entry_t *) pool_elt_at_index (nm->nsh_entries, entry0[0]); - encap_hdr0 = (nsh_base_header_t *) (nsh_entry0->rewrite); - /* rewrite_size should equal to (encap_hdr0->length * 4) */ - encap_hdr_len0 = nsh_entry0->rewrite_size; - - if (PREDICT_TRUE (map0->nsh_action == NSH_ACTION_SWAP)) - { - /* Manipulate MD2 */ - if (PREDICT_FALSE (hdr0->md_type == 2)) - { - nsh_md2_swap (b0, hdr0, header_len0, nsh_entry0, - &next0, NSH_NODE_NEXT_DROP); - if (PREDICT_FALSE (next0 == NSH_NODE_NEXT_DROP)) - { - error0 = NSH_NODE_ERROR_INVALID_OPTIONS; - goto trace0; - } - } - - /* Pop old NSH header */ - vlib_buffer_advance (b0, (word) header_len0); - - /* After processing, md2's length may be varied */ - encap_hdr_len0 = nsh_entry0->rewrite_size; - /* Push new NSH header */ - vlib_buffer_advance (b0, -(word) encap_hdr_len0); - hdr0 = vlib_buffer_get_current (b0); - clib_memcpy_fast (hdr0, encap_hdr0, (word) encap_hdr_len0); - - goto trace0; - } - - if (PREDICT_TRUE (map0->nsh_action == NSH_ACTION_PUSH)) - { - /* After processing, md2's length may be varied */ - encap_hdr_len0 = nsh_entry0->rewrite_size; - /* Push new NSH header */ - vlib_buffer_advance (b0, -(word) encap_hdr_len0); - hdr0 = vlib_buffer_get_current (b0); - clib_memcpy_fast (hdr0, encap_hdr0, (word) encap_hdr_len0); - - /* Manipulate MD2 */ - if (PREDICT_FALSE (nsh_entry0->nsh_base.md_type == 2)) - { - nsh_md2_encap (b0, hdr0, nsh_entry0); - } - - } - - trace0: - b0->error = error0 ? node->errors[error0] : 0; - - if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) - { - nsh_input_trace_t *tr = - vlib_add_trace (vm, node, b0, sizeof (*tr)); - clib_memcpy_fast (&(tr->trace_data), hdr0, - ((hdr0->length & NSH_LEN_MASK) * 4)); - } - - /* Process packet 1 */ - if (node_type == NSH_INPUT_TYPE) - { - nsp_nsi1 = hdr1->nsp_nsi; - header_len1 = (hdr1->length & NSH_LEN_MASK) * 4; - ttl1 = (hdr1->ver_o_c & NSH_TTL_H4_MASK) << 2 | - (hdr1->length & NSH_TTL_L2_MASK) >> 6; - ttl1 = ttl1 - 1; - if (PREDICT_FALSE (ttl1 == 0)) - { - error1 = NSH_NODE_ERROR_INVALID_TTL; - goto trace1; - } - } - else if (node_type == NSH_CLASSIFIER_TYPE) - { - nsp_nsi1 = - clib_host_to_net_u32 (vnet_buffer (b1)-> - l2_classify.opaque_index); - } - else if (node_type == NSH_AWARE_VNF_PROXY_TYPE) - { - /* Push dummy Eth header */ - clib_memcpy_fast (dummy_eth1.dst_address, dummy_dst_address, 6); - clib_memcpy_fast (dummy_eth1.src_address, dummy_src_address, 6); - dummy_eth1.type = 0x0800; - vlib_buffer_advance (b1, -(word) sizeof (ethernet_header_t)); - hdr1 = vlib_buffer_get_current (b1); - clib_memcpy_fast (hdr1, &dummy_eth1, - (word) sizeof (ethernet_header_t)); - - sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_TX]; - nsp_nsi1 = nm->tunnel_index_by_sw_if_index[sw_if_index1]; - } - else - { - clib_memset (&key1, 0, sizeof (key1)); - key1.transport_type = NSH_NODE_NEXT_ENCAP_VXLAN4; - key1.transport_index = vnet_buffer (b1)->sw_if_index[VLIB_RX]; - - p1 = hash_get_mem (nm->nsh_proxy_session_by_key, &key1); - if (PREDICT_FALSE (p1 == 0)) - { - error1 = NSH_NODE_ERROR_NO_PROXY; - goto trace1; - } - - proxy1 = pool_elt_at_index (nm->nsh_proxy_sessions, p1[0]); - if (PREDICT_FALSE (proxy1 == 0)) - { - error1 = NSH_NODE_ERROR_NO_PROXY; - goto trace1; - } - nsp_nsi1 = proxy1->nsp_nsi; - } - - entry1 = hash_get_mem (nm->nsh_mapping_by_key, &nsp_nsi1); - if (PREDICT_FALSE (entry1 == 0)) - { - error1 = NSH_NODE_ERROR_NO_MAPPING; - goto trace1; - } - - /* Entry should point to a mapping ... */ - map1 = pool_elt_at_index (nm->nsh_mappings, entry1[0]); - if (PREDICT_FALSE (map1 == 0)) - { - error1 = NSH_NODE_ERROR_NO_MAPPING; - goto trace1; - } - - /* set up things for next node to transmit ie which node to handle it and where */ - next1 = map1->next_node; - vnet_buffer (b1)->sw_if_index[VLIB_TX] = map1->sw_if_index; - vnet_buffer (b1)->ip.adj_index[VLIB_TX] = map1->adj_index; - - if (PREDICT_FALSE (map1->nsh_action == NSH_ACTION_POP)) - { - /* Manipulate MD2 */ - if (PREDICT_FALSE (hdr1->md_type == 2)) - { - nsh_md2_decap (b1, hdr1, &header_len1, &next1, - NSH_NODE_NEXT_DROP); - if (PREDICT_FALSE (next1 == NSH_NODE_NEXT_DROP)) - { - error1 = NSH_NODE_ERROR_INVALID_OPTIONS; - goto trace1; - } - vnet_buffer (b1)->sw_if_index[VLIB_RX] = - map1->rx_sw_if_index; - } - - /* Pop NSH header */ - vlib_buffer_advance (b1, (word) header_len1); - goto trace1; - } - - entry1 = hash_get_mem (nm->nsh_entry_by_key, &map1->mapped_nsp_nsi); - if (PREDICT_FALSE (entry1 == 0)) - { - error1 = NSH_NODE_ERROR_NO_ENTRY; - goto trace1; - } - - nsh_entry1 = - (nsh_entry_t *) pool_elt_at_index (nm->nsh_entries, entry1[0]); - encap_hdr1 = (nsh_base_header_t *) (nsh_entry1->rewrite); - /* rewrite_size should equal to (encap_hdr0->length * 4) */ - encap_hdr_len1 = nsh_entry1->rewrite_size; - - if (PREDICT_TRUE (map1->nsh_action == NSH_ACTION_SWAP)) - { - /* Manipulate MD2 */ - if (PREDICT_FALSE (hdr1->md_type == 2)) - { - nsh_md2_swap (b1, hdr1, header_len1, nsh_entry1, - &next1, NSH_NODE_NEXT_DROP); - if (PREDICT_FALSE (next1 == NSH_NODE_NEXT_DROP)) - { - error1 = NSH_NODE_ERROR_INVALID_OPTIONS; - goto trace1; - } - } - - /* Pop old NSH header */ - vlib_buffer_advance (b1, (word) header_len1); - - /* After processing, md2's length may be varied */ - encap_hdr_len1 = nsh_entry1->rewrite_size; - /* Push new NSH header */ - vlib_buffer_advance (b1, -(word) encap_hdr_len1); - hdr1 = vlib_buffer_get_current (b1); - clib_memcpy_fast (hdr1, encap_hdr1, (word) encap_hdr_len1); - - goto trace1; - } - - if (PREDICT_FALSE (map1->nsh_action == NSH_ACTION_PUSH)) - { - /* After processing, md2's length may be varied */ - encap_hdr_len1 = nsh_entry1->rewrite_size; - /* Push new NSH header */ - vlib_buffer_advance (b1, -(word) encap_hdr_len1); - hdr1 = vlib_buffer_get_current (b1); - clib_memcpy_fast (hdr1, encap_hdr1, (word) encap_hdr_len1); - - /* Manipulate MD2 */ - if (PREDICT_FALSE (nsh_entry1->nsh_base.md_type == 2)) - { - nsh_md2_encap (b1, hdr1, nsh_entry1); - } - - } - - trace1: - b1->error = error1 ? node->errors[error1] : 0; - - if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED)) - { - nsh_input_trace_t *tr = - vlib_add_trace (vm, node, b1, sizeof (*tr)); - clib_memcpy_fast (&(tr->trace_data), hdr1, - ((hdr1->length & NSH_LEN_MASK) * 4)); - } - - vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, - n_left_to_next, bi0, bi1, next0, - next1); - - } - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0 = 0; - vlib_buffer_t *b0 = NULL; - u32 next0 = NSH_NODE_NEXT_DROP; - uword *entry0; - nsh_base_header_t *hdr0 = 0; - u32 header_len0 = 0; - u32 nsp_nsi0; - u32 ttl0; - u32 error0; - nsh_map_t *map0 = 0; - nsh_entry_t *nsh_entry0 = 0; - nsh_base_header_t *encap_hdr0 = 0; - u32 encap_hdr_len0 = 0; - nsh_proxy_session_by_key_t key0; - uword *p0; - nsh_proxy_session_t *proxy0 = 0; - u32 sw_if_index0 = 0; - ethernet_header_t dummy_eth0; - - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - error0 = 0; - - b0 = vlib_get_buffer (vm, bi0); - hdr0 = vlib_buffer_get_current (b0); - - if (node_type == NSH_INPUT_TYPE) - { - nsp_nsi0 = hdr0->nsp_nsi; - header_len0 = (hdr0->length & NSH_LEN_MASK) * 4; - ttl0 = (hdr0->ver_o_c & NSH_TTL_H4_MASK) << 2 | - (hdr0->length & NSH_TTL_L2_MASK) >> 6; - ttl0 = ttl0 - 1; - if (PREDICT_FALSE (ttl0 == 0)) - { - error0 = NSH_NODE_ERROR_INVALID_TTL; - goto trace00; - } - } - else if (node_type == NSH_CLASSIFIER_TYPE) - { - nsp_nsi0 = - clib_host_to_net_u32 (vnet_buffer (b0)-> - l2_classify.opaque_index); - } - else if (node_type == NSH_AWARE_VNF_PROXY_TYPE) - { - /* Push dummy Eth header */ - clib_memcpy_fast (dummy_eth0.dst_address, dummy_dst_address, 6); - clib_memcpy_fast (dummy_eth0.src_address, dummy_src_address, 6); - dummy_eth0.type = 0x0800; - vlib_buffer_advance (b0, -(word) sizeof (ethernet_header_t)); - hdr0 = vlib_buffer_get_current (b0); - clib_memcpy_fast (hdr0, &dummy_eth0, - (word) sizeof (ethernet_header_t)); - - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - nsp_nsi0 = nm->tunnel_index_by_sw_if_index[sw_if_index0]; - } - else - { - clib_memset (&key0, 0, sizeof (key0)); - key0.transport_type = NSH_NODE_NEXT_ENCAP_VXLAN4; - key0.transport_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - - p0 = hash_get_mem (nm->nsh_proxy_session_by_key, &key0); - if (PREDICT_FALSE (p0 == 0)) - { - error0 = NSH_NODE_ERROR_NO_PROXY; - goto trace00; - } - - proxy0 = pool_elt_at_index (nm->nsh_proxy_sessions, p0[0]); - if (PREDICT_FALSE (proxy0 == 0)) - { - error0 = NSH_NODE_ERROR_NO_PROXY; - goto trace00; - } - nsp_nsi0 = proxy0->nsp_nsi; - } - - entry0 = hash_get_mem (nm->nsh_mapping_by_key, &nsp_nsi0); - - if (PREDICT_FALSE (entry0 == 0)) - { - error0 = NSH_NODE_ERROR_NO_MAPPING; - goto trace00; - } - - /* Entry should point to a mapping ... */ - map0 = pool_elt_at_index (nm->nsh_mappings, entry0[0]); - - if (PREDICT_FALSE (map0 == 0)) - { - error0 = NSH_NODE_ERROR_NO_MAPPING; - goto trace00; - } - - /* set up things for next node to transmit ie which node to handle it and where */ - next0 = map0->next_node; - vnet_buffer (b0)->sw_if_index[VLIB_TX] = map0->sw_if_index; - vnet_buffer (b0)->ip.adj_index[VLIB_TX] = map0->adj_index; - vnet_buffer (b0)->sw_if_index[VLIB_RX] = map0->nsh_sw_if; - - if (PREDICT_FALSE (map0->nsh_action == NSH_ACTION_POP)) - { - /* Manipulate MD2 */ - if (PREDICT_FALSE (hdr0->md_type == 2)) - { - nsh_md2_decap (b0, hdr0, &header_len0, &next0, - NSH_NODE_NEXT_DROP); - if (PREDICT_FALSE (next0 == NSH_NODE_NEXT_DROP)) - { - error0 = NSH_NODE_ERROR_INVALID_OPTIONS; - goto trace00; - } - vnet_buffer (b0)->sw_if_index[VLIB_RX] = - map0->rx_sw_if_index; - } - - /* Pop NSH header */ - vlib_buffer_advance (b0, (word) header_len0); - goto trace00; - } - - entry0 = hash_get_mem (nm->nsh_entry_by_key, &map0->mapped_nsp_nsi); - if (PREDICT_FALSE (entry0 == 0)) - { - error0 = NSH_NODE_ERROR_NO_ENTRY; - goto trace00; - } - - nsh_entry0 = - (nsh_entry_t *) pool_elt_at_index (nm->nsh_entries, entry0[0]); - encap_hdr0 = (nsh_base_header_t *) (nsh_entry0->rewrite); - /* rewrite_size should equal to (encap_hdr0->length * 4) */ - encap_hdr_len0 = nsh_entry0->rewrite_size; - - if (PREDICT_TRUE (map0->nsh_action == NSH_ACTION_SWAP)) - { - /* Manipulate MD2 */ - if (PREDICT_FALSE (hdr0->md_type == 2)) - { - nsh_md2_swap (b0, hdr0, header_len0, nsh_entry0, - &next0, NSH_NODE_NEXT_DROP); - if (PREDICT_FALSE (next0 == NSH_NODE_NEXT_DROP)) - { - error0 = NSH_NODE_ERROR_INVALID_OPTIONS; - goto trace00; - } - } - - /* Pop old NSH header */ - vlib_buffer_advance (b0, (word) header_len0); - - /* After processing, md2's length may be varied */ - encap_hdr_len0 = nsh_entry0->rewrite_size; - /* Push new NSH header */ - vlib_buffer_advance (b0, -(word) encap_hdr_len0); - hdr0 = vlib_buffer_get_current (b0); - clib_memcpy_fast (hdr0, encap_hdr0, (word) encap_hdr_len0); - - goto trace00; - } - - if (PREDICT_TRUE (map0->nsh_action == NSH_ACTION_PUSH)) - { - /* After processing, md2's length may be varied */ - encap_hdr_len0 = nsh_entry0->rewrite_size; - /* Push new NSH header */ - vlib_buffer_advance (b0, -(word) encap_hdr_len0); - hdr0 = vlib_buffer_get_current (b0); - clib_memcpy_fast (hdr0, encap_hdr0, (word) encap_hdr_len0); - /* Manipulate MD2 */ - if (PREDICT_FALSE (nsh_entry0->nsh_base.md_type == 2)) - { - nsh_md2_encap (b0, hdr0, nsh_entry0); - } - - } - - trace00:b0->error = error0 ? node->errors[error0] : 0; - - if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) - { - nsh_input_trace_t *tr = - vlib_add_trace (vm, node, b0, sizeof (*tr)); - clib_memcpy_fast (&(tr->trace_data[0]), hdr0, - ((hdr0->length & NSH_LEN_MASK) * 4)); - } - - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, - n_left_to_next, bi0, next0); - } - - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - - } - - return from_frame->n_vectors; -} - -/** - * @brief Graph processing dispatch function for NSH Input - * - * @node nsh_input - * @param *vm - * @param *node - * @param *from_frame - * - * @return from_frame->n_vectors - * - */ -static uword -nsh_input (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * from_frame) -{ - return nsh_input_map (vm, node, from_frame, NSH_INPUT_TYPE); -} - -/** - * @brief Graph processing dispatch function for NSH-Proxy - * - * @node nsh_proxy - * @param *vm - * @param *node - * @param *from_frame - * - * @return from_frame->n_vectors - * - */ -static uword -nsh_proxy (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * from_frame) -{ - return nsh_input_map (vm, node, from_frame, NSH_PROXY_TYPE); -} - -/** - * @brief Graph processing dispatch function for NSH Classifier - * - * @node nsh_classifier - * @param *vm - * @param *node - * @param *from_frame - * - * @return from_frame->n_vectors - * - */ -static uword -nsh_classifier (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * from_frame) -{ - return nsh_input_map (vm, node, from_frame, NSH_CLASSIFIER_TYPE); -} - -/** - * @brief Graph processing dispatch function for NSH-AWARE-VNF-PROXY - * - * @node nsh_aware_vnf_proxy - * @param *vm - * @param *node - * @param *from_frame - * - * @return from_frame->n_vectors - * - */ -static uword -nsh_aware_vnf_proxy (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * from_frame) -{ - return nsh_input_map (vm, node, from_frame, NSH_AWARE_VNF_PROXY_TYPE); -} - -static char *nsh_node_error_strings[] = { -#define _(sym,string) string, - foreach_nsh_node_error -#undef _ +/* *INDENT-OFF* */ +VNET_HW_INTERFACE_CLASS (nsh_hw_class) = { + .name = "NSH", + .format_header = format_nsh_tunnel_with_length, + .build_rewrite = default_build_rewrite, + .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P, }; - -/* register nsh-input node */ -VLIB_REGISTER_NODE (nsh_input_node) = -{ - .function = nsh_input,.name = "nsh-input",.vector_size = - sizeof (u32),.format_trace = format_nsh_node_map_trace,.format_buffer = - format_nsh_header,.type = VLIB_NODE_TYPE_INTERNAL,.n_errors = - ARRAY_LEN (nsh_node_error_strings),.error_strings = - nsh_node_error_strings,.n_next_nodes = NSH_NODE_N_NEXT,.next_nodes = - { -#define _(s,n) [NSH_NODE_NEXT_##s] = n, - foreach_nsh_node_next -#undef _ - } -,}; - -VLIB_NODE_FUNCTION_MULTIARCH (nsh_input_node, nsh_input); - -/* register nsh-proxy node */ -VLIB_REGISTER_NODE (nsh_proxy_node) = -{ - .function = nsh_proxy,.name = "nsh-proxy",.vector_size = - sizeof (u32),.format_trace = format_nsh_node_map_trace,.format_buffer = - format_nsh_header,.type = VLIB_NODE_TYPE_INTERNAL,.n_errors = - ARRAY_LEN (nsh_node_error_strings),.error_strings = - nsh_node_error_strings,.n_next_nodes = NSH_NODE_N_NEXT,.next_nodes = - { -#define _(s,n) [NSH_NODE_NEXT_##s] = n, - foreach_nsh_node_next -#undef _ - } -,}; - -VLIB_NODE_FUNCTION_MULTIARCH (nsh_proxy_node, nsh_proxy); - -/* register nsh-classifier node */ -VLIB_REGISTER_NODE (nsh_classifier_node) = -{ - .function = nsh_classifier,.name = "nsh-classifier",.vector_size = - sizeof (u32),.format_trace = format_nsh_node_map_trace,.format_buffer = - format_nsh_header,.type = VLIB_NODE_TYPE_INTERNAL,.n_errors = - ARRAY_LEN (nsh_node_error_strings),.error_strings = - nsh_node_error_strings,.n_next_nodes = NSH_NODE_N_NEXT,.next_nodes = - { -#define _(s,n) [NSH_NODE_NEXT_##s] = n, - foreach_nsh_node_next -#undef _ - } -,}; - -VLIB_NODE_FUNCTION_MULTIARCH (nsh_classifier_node, nsh_classifier); - -/* register nsh-aware-vnf-proxy node */ -VLIB_REGISTER_NODE (nsh_aware_vnf_proxy_node) = -{ - .function = nsh_aware_vnf_proxy,.name = "nsh-aware-vnf-proxy",.vector_size = - sizeof (u32),.format_trace = format_nsh_node_map_trace,.format_buffer = - format_nsh_header,.type = VLIB_NODE_TYPE_INTERNAL,.n_errors = - ARRAY_LEN (nsh_node_error_strings),.error_strings = - nsh_node_error_strings,.n_next_nodes = NSH_NODE_N_NEXT,.next_nodes = - { -#define _(s,n) [NSH_NODE_NEXT_##s] = n, - foreach_nsh_node_next -#undef _ - } -,}; - -VLIB_NODE_FUNCTION_MULTIARCH (nsh_aware_vnf_proxy_node, nsh_aware_vnf_proxy); +/* *INDENT-ON* */ void nsh_md2_set_next_ioam_export_override (uword next) @@ -2446,13 +236,12 @@ nsh_md2_set_next_ioam_export_override (uword next) return; } - clib_error_t * nsh_init (vlib_main_t * vm) { + vlib_node_t *node; nsh_main_t *nm = &nsh_main; clib_error_t *error = 0; - u8 *name; uword next_node; /* Init the main structures from VPP */ @@ -2474,56 +263,62 @@ nsh_init (vlib_main_t * vm) nm->nsh_option_map_by_key = hash_create_mem (0, sizeof (nsh_option_map_by_key_t), sizeof (uword)); - name = format (0, "nsh_%08x%c", api_version, 0); + error = nsh_api_init (vm, nm); + if (error) + return error; - /* Set up the API */ - nm->msg_id_base = vl_msg_api_get_msg_ids - ((char *) name, VL_MSG_FIRST_AVAILABLE); + node = vlib_get_node_by_name (vm, (u8 *) "nsh-input"); + nm->nsh_input_node_index = node->index; - error = nsh_plugin_api_hookup (vm); + node = vlib_get_node_by_name (vm, (u8 *) "nsh-proxy"); + nm->nsh_proxy_node_index = node->index; - /* Add our API messages to the global name_crc hash table */ - setup_message_id_table (nm, &api_main); + node = vlib_get_node_by_name (vm, (u8 *) "nsh-classifier"); + nm->nsh_classifier_node_index = node->index; /* Add dispositions to nodes that feed nsh-input */ //alagalah - validate we don't really need to use the node value next_node = vlib_node_add_next (vm, vxlan4_gpe_input_node.index, - nsh_input_node.index); - vlib_node_add_next (vm, vxlan4_gpe_input_node.index, nsh_proxy_node.index); + nm->nsh_input_node_index); + vlib_node_add_next (vm, vxlan4_gpe_input_node.index, + nm->nsh_proxy_node_index); vlib_node_add_next (vm, vxlan4_gpe_input_node.index, nsh_aware_vnf_proxy_node.index); vxlan_gpe_register_decap_protocol (VXLAN_GPE_PROTOCOL_NSH, next_node); - vlib_node_add_next (vm, vxlan6_gpe_input_node.index, nsh_input_node.index); - vlib_node_add_next (vm, vxlan6_gpe_input_node.index, nsh_proxy_node.index); + vlib_node_add_next (vm, vxlan6_gpe_input_node.index, + nm->nsh_input_node_index); + vlib_node_add_next (vm, vxlan6_gpe_input_node.index, + nm->nsh_proxy_node_index); vlib_node_add_next (vm, vxlan6_gpe_input_node.index, nsh_aware_vnf_proxy_node.index); - vlib_node_add_next (vm, gre4_input_node.index, nsh_input_node.index); - vlib_node_add_next (vm, gre4_input_node.index, nsh_proxy_node.index); + vlib_node_add_next (vm, gre4_input_node.index, nm->nsh_input_node_index); + vlib_node_add_next (vm, gre4_input_node.index, nm->nsh_proxy_node_index); vlib_node_add_next (vm, gre4_input_node.index, nsh_aware_vnf_proxy_node.index); - vlib_node_add_next (vm, gre6_input_node.index, nsh_input_node.index); - vlib_node_add_next (vm, gre6_input_node.index, nsh_proxy_node.index); + vlib_node_add_next (vm, gre6_input_node.index, nm->nsh_input_node_index); + vlib_node_add_next (vm, gre6_input_node.index, nm->nsh_proxy_node_index); vlib_node_add_next (vm, gre6_input_node.index, nsh_aware_vnf_proxy_node.index); /* Add NSH-Proxy support */ - vlib_node_add_next (vm, vxlan4_input_node.index, nsh_proxy_node.index); - vlib_node_add_next (vm, vxlan6_input_node.index, nsh_proxy_node.index); + vlib_node_add_next (vm, vxlan4_input_node.index, nm->nsh_proxy_node_index); + vlib_node_add_next (vm, vxlan6_input_node.index, nm->nsh_proxy_node_index); /* Add NSH-Classifier support */ - vlib_node_add_next (vm, ip4_classify_node.index, nsh_classifier_node.index); - vlib_node_add_next (vm, ip6_classify_node.index, nsh_classifier_node.index); + vlib_node_add_next (vm, ip4_classify_node.index, + nm->nsh_classifier_node_index); + vlib_node_add_next (vm, ip6_classify_node.index, + nm->nsh_classifier_node_index); vlib_node_add_next (vm, l2_input_classify_node.index, - nsh_classifier_node.index); + nm->nsh_classifier_node_index); /* Add Ethernet+NSH support */ - ethernet_register_input_type (vm, ETHERNET_TYPE_NSH, nsh_input_node.index); - - vec_free (name); + ethernet_register_input_type (vm, ETHERNET_TYPE_NSH, + nm->nsh_input_node_index); return error; } diff --git a/src/plugins/nsh/nsh.h b/src/plugins/nsh/nsh.h index 1b14567078b..46dd879dce1 100644 --- a/src/plugins/nsh/nsh.h +++ b/src/plugins/nsh/nsh.h @@ -159,13 +159,16 @@ typedef struct { u8 input_feature_arc_index; u8 output_feature_arc_index; + u32 nsh_input_node_index; + u32 nsh_proxy_node_index; + u32 nsh_classifier_node_index; + /* convenience */ vlib_main_t * vlib_main; vnet_main_t * vnet_main; } nsh_main_t; -nsh_main_t nsh_main; - +extern nsh_main_t nsh_main; extern vlib_node_registration_t nsh_aware_vnf_proxy_node; extern vlib_node_registration_t nsh_eth_output_node; @@ -268,4 +271,25 @@ typedef struct _nsh_main_dummy u8 output_feature_arc_index; } nsh_main_dummy_t; +int +nsh_add_del_map (nsh_add_del_map_args_t * a, u32 * map_indexp); + +int +nsh_add_del_proxy_session (nsh_add_del_map_args_t * a); + +nsh_option_map_t * +nsh_md2_lookup_option (u16 class, u8 type); + +int +nsh_add_del_entry (nsh_add_del_entry_args_t * a, u32 * entry_indexp); + +u8 * +format_nsh_node_map_trace (u8 * s, va_list * args); + +u8 * +format_nsh_header (u8 * s, va_list * args); + +clib_error_t * +nsh_api_init (vlib_main_t * vm, nsh_main_t * nm); + #endif /* included_nsh_h */ diff --git a/src/plugins/nsh/nsh_api.c b/src/plugins/nsh/nsh_api.c new file mode 100644 index 00000000000..72ca2d28671 --- /dev/null +++ b/src/plugins/nsh/nsh_api.c @@ -0,0 +1,724 @@ +/* + * nsh_api.c - nsh mapping api + * + * Copyright (c) 2019 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 <vnet/vnet.h> +#include <vnet/plugin/plugin.h> +#include <nsh/nsh.h> + +#include <vlibapi/api.h> +#include <vlibmemory/api.h> +#include <vpp/app/version.h> + +/* define message IDs */ +#define vl_msg_id(n,h) n, +typedef enum +{ +#include <nsh/nsh.api.h> + /* We'll want to know how many messages IDs we need... */ + VL_MSG_FIRST_AVAILABLE, +} vl_msg_id_t; +#undef vl_msg_id + +/* define message structures */ +#define vl_typedefs +#include <nsh/nsh.api.h> +#undef vl_typedefs + +/* define generated endian-swappers */ +#define vl_endianfun +#include <nsh/nsh.api.h> +#undef vl_endianfun + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) +#define vl_printfun +#include <nsh/nsh.api.h> +#undef vl_printfun + +/* Get the API version number */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include <nsh/nsh.api.h> +#undef vl_api_version + +#define vl_msg_name_crc_list +#include <nsh/nsh.api.h> +#undef vl_msg_name_crc_list + +/* + * A handy macro to set up a message reply. + * Assumes that the following variables are available: + * mp - pointer to request message + * rmp - pointer to reply message type + * rv - return value + */ + +#define REPLY_MACRO(t) \ + do { \ + unix_shared_memory_queue_t * q = \ + vl_api_client_index_to_input_queue (mp->client_index); \ + if (!q) \ + return; \ + \ + rmp = vl_msg_api_alloc (sizeof (*rmp)); \ + rmp->_vl_msg_id = ntohs((t)+nm->msg_id_base); \ + rmp->context = mp->context; \ + rmp->retval = ntohl(rv); \ + \ + vl_msg_api_send_shmem (q, (u8 *)&rmp); \ + } while(0); + +#define REPLY_MACRO2(t, body) \ + do { \ + unix_shared_memory_queue_t * q; \ + rv = vl_msg_api_pd_handler (mp, rv); \ + q = vl_api_client_index_to_input_queue (mp->client_index); \ + if (!q) \ + return; \ + \ + rmp = vl_msg_api_alloc (sizeof (*rmp)); \ + rmp->_vl_msg_id = ntohs((t)+nm->msg_id_base); \ + rmp->context = mp->context; \ + rmp->retval = ntohl(rv); \ + do {body;} while (0); \ + vl_msg_api_send_shmem (q, (u8 *)&rmp); \ + } while(0); + +/* List of message types that this plugin understands */ + +#define foreach_nsh_plugin_api_msg \ + _(NSH_ADD_DEL_ENTRY, nsh_add_del_entry) \ + _(NSH_ENTRY_DUMP, nsh_entry_dump) \ + _(NSH_ADD_DEL_MAP, nsh_add_del_map) \ + _(NSH_MAP_DUMP, nsh_map_dump) + +static void send_nsh_entry_details + (nsh_entry_t * t, unix_shared_memory_queue_t * q, u32 context) +{ + vl_api_nsh_entry_details_t *rmp; + nsh_main_t *nm = &nsh_main; + + rmp = vl_msg_api_alloc (sizeof (*rmp)); + clib_memset (rmp, 0, sizeof (*rmp)); + + rmp->_vl_msg_id = ntohs ((VL_API_NSH_ENTRY_DETAILS) + nm->msg_id_base); + rmp->ver_o_c = t->nsh_base.ver_o_c; + rmp->ttl = (t->nsh_base.ver_o_c & NSH_TTL_H4_MASK) << 2 | + (t->nsh_base.length & NSH_TTL_L2_MASK) >> 6; + rmp->length = t->nsh_base.length & NSH_LEN_MASK; + rmp->md_type = t->nsh_base.md_type; + rmp->next_protocol = t->nsh_base.next_protocol; + rmp->nsp_nsi = htonl (t->nsh_base.nsp_nsi); + + if (t->nsh_base.md_type == 1) + { + rmp->tlv_length = 4; + rmp->c1 = htonl (t->md.md1_data.c1); + rmp->c2 = htonl (t->md.md1_data.c2); + rmp->c3 = htonl (t->md.md1_data.c3); + rmp->c4 = htonl (t->md.md1_data.c4); + } + else if (t->nsh_base.md_type == 2) + { + rmp->tlv_length = t->tlvs_len; + clib_memcpy (rmp->tlv, t->tlvs_data, t->tlvs_len); + } + + rmp->context = context; + + vl_msg_api_send_shmem (q, (u8 *) & rmp); +} + +static void send_nsh_map_details + (nsh_map_t * t, unix_shared_memory_queue_t * q, u32 context) +{ + vl_api_nsh_map_details_t *rmp; + nsh_main_t *nm = &nsh_main; + + rmp = vl_msg_api_alloc (sizeof (*rmp)); + clib_memset (rmp, 0, sizeof (*rmp)); + + rmp->_vl_msg_id = ntohs ((VL_API_NSH_MAP_DETAILS) + nm->msg_id_base); + rmp->nsp_nsi = htonl (t->nsp_nsi); + rmp->mapped_nsp_nsi = htonl (t->mapped_nsp_nsi); + rmp->nsh_action = htonl (t->nsh_action); + rmp->sw_if_index = htonl (t->sw_if_index); + rmp->rx_sw_if_index = htonl (t->rx_sw_if_index); + rmp->next_node = htonl (t->next_node); + + rmp->context = context; + + vl_msg_api_send_shmem (q, (u8 *) & rmp); +} + +static void +vl_api_nsh_map_dump_t_handler (vl_api_nsh_map_dump_t * mp) +{ + unix_shared_memory_queue_t *q; + nsh_main_t *nm = &nsh_main; + nsh_map_t *t; + u32 map_index; + + q = vl_api_client_index_to_input_queue (mp->client_index); + if (q == 0) + { + return; + } + + map_index = ntohl (mp->map_index); + + if (~0 == map_index) + { + pool_foreach (t, nm->nsh_mappings, ( + { + send_nsh_map_details (t, q, + mp->context); + } + )); + } + else + { + if (map_index >= vec_len (nm->nsh_mappings)) + { + return; + } + t = &nm->nsh_mappings[map_index]; + send_nsh_map_details (t, q, mp->context); + } +} + +/** API message handler */ +static void +vl_api_nsh_add_del_map_t_handler (vl_api_nsh_add_del_map_t * mp) +{ + vl_api_nsh_add_del_map_reply_t *rmp; + nsh_main_t *nm = &nsh_main; + int rv; + nsh_add_del_map_args_t _a, *a = &_a; + u32 map_index = ~0; + + a->is_add = mp->is_add; + a->map.nsp_nsi = ntohl (mp->nsp_nsi); + a->map.mapped_nsp_nsi = ntohl (mp->mapped_nsp_nsi); + a->map.nsh_action = ntohl (mp->nsh_action); + a->map.sw_if_index = ntohl (mp->sw_if_index); + a->map.rx_sw_if_index = ntohl (mp->rx_sw_if_index); + a->map.next_node = ntohl (mp->next_node); + + rv = nsh_add_del_map (a, &map_index); + + if ((a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN4) + | (a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN6)) + { + rv = nsh_add_del_proxy_session (a); + } + + REPLY_MACRO2 (VL_API_NSH_ADD_DEL_MAP_REPLY, ( + { + rmp->map_index = + htonl (map_index); + } + )); +} + +int +nsh_header_rewrite (nsh_entry_t * nsh_entry) +{ + u8 *rw = 0; + int len = 0; + nsh_base_header_t *nsh_base; + nsh_md1_data_t *nsh_md1; + nsh_main_t *nm = &nsh_main; + nsh_md2_data_t *opt0; + nsh_md2_data_t *limit0; + nsh_md2_data_t *nsh_md2; + nsh_option_map_t _nsh_option, *nsh_option = &_nsh_option; + u8 old_option_size = 0; + u8 new_option_size = 0; + + vec_free (nsh_entry->rewrite); + if (nsh_entry->nsh_base.md_type == 1) + { + len = sizeof (nsh_base_header_t) + sizeof (nsh_md1_data_t); + } + else if (nsh_entry->nsh_base.md_type == 2) + { + /* set to maxim, maybe dataplane will add more TLVs */ + len = MAX_NSH_HEADER_LEN; + } + vec_validate_aligned (rw, len - 1, CLIB_CACHE_LINE_BYTES); + clib_memset (rw, 0, len); + + nsh_base = (nsh_base_header_t *) rw; + nsh_base->ver_o_c = nsh_entry->nsh_base.ver_o_c; + nsh_base->length = nsh_entry->nsh_base.length; + nsh_base->md_type = nsh_entry->nsh_base.md_type; + nsh_base->next_protocol = nsh_entry->nsh_base.next_protocol; + nsh_base->nsp_nsi = clib_host_to_net_u32 (nsh_entry->nsh_base.nsp_nsi); + + if (nsh_base->md_type == 1) + { + nsh_md1 = (nsh_md1_data_t *) (rw + sizeof (nsh_base_header_t)); + nsh_md1->c1 = clib_host_to_net_u32 (nsh_entry->md.md1_data.c1); + nsh_md1->c2 = clib_host_to_net_u32 (nsh_entry->md.md1_data.c2); + nsh_md1->c3 = clib_host_to_net_u32 (nsh_entry->md.md1_data.c3); + nsh_md1->c4 = clib_host_to_net_u32 (nsh_entry->md.md1_data.c4); + nsh_entry->rewrite_size = 24; + } + else if (nsh_base->md_type == 2) + { + opt0 = (nsh_md2_data_t *) (nsh_entry->tlvs_data); + limit0 = (nsh_md2_data_t *) ((u8 *) opt0 + nsh_entry->tlvs_len); + + nsh_md2 = (nsh_md2_data_t *) (rw + sizeof (nsh_base_header_t)); + nsh_entry->rewrite_size = sizeof (nsh_base_header_t); + + while (opt0 < limit0) + { + old_option_size = sizeof (nsh_md2_data_t) + opt0->length; + /* round to 4-byte */ + old_option_size = ((old_option_size + 3) >> 2) << 2; + + nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type); + if (nsh_option == NULL) + { + goto next_tlv_md2; + } + + if (nm->add_options[nsh_option->option_id] != NULL) + { + if (0 != nm->add_options[nsh_option->option_id] ((u8 *) nsh_md2, + &new_option_size)) + { + goto next_tlv_md2; + } + + /* round to 4-byte */ + new_option_size = ((new_option_size + 3) >> 2) << 2; + + nsh_entry->rewrite_size += new_option_size; + nsh_md2 = + (nsh_md2_data_t *) (((u8 *) nsh_md2) + new_option_size); + opt0 = (nsh_md2_data_t *) (((u8 *) opt0) + old_option_size); + } + else + { + next_tlv_md2: + opt0 = (nsh_md2_data_t *) (((u8 *) opt0) + old_option_size); + } + + } + } + + nsh_entry->rewrite = rw; + nsh_base->length = (nsh_base->length & NSH_TTL_L2_MASK) | + ((nsh_entry->rewrite_size >> 2) & NSH_LEN_MASK); + + return 0; +} + +extern vnet_device_class_t nsh_device_class; +extern vnet_hw_interface_class_t nsh_hw_class; + +/** + * Action function to add or del an nsh map. + * Shared by both CLI and binary API + **/ +int +nsh_add_del_map (nsh_add_del_map_args_t * a, u32 * map_indexp) +{ + nsh_main_t *nm = &nsh_main; + vnet_main_t *vnm = nm->vnet_main; + nsh_map_t *map = 0; + u32 key, *key_copy; + uword *entry; + hash_pair_t *hp; + u32 map_index = ~0; + vnet_hw_interface_t *hi; + u32 nsh_hw_if = ~0; + u32 nsh_sw_if = ~0; + + /* net order, so data plane could use nsh header to lookup directly */ + key = clib_host_to_net_u32 (a->map.nsp_nsi); + + entry = hash_get_mem (nm->nsh_mapping_by_key, &key); + + if (a->is_add) + { + /* adding an entry, must not already exist */ + if (entry) + return -1; //TODO API_ERROR_INVALID_VALUE; + + pool_get_aligned (nm->nsh_mappings, map, CLIB_CACHE_LINE_BYTES); + clib_memset (map, 0, sizeof (*map)); + + /* copy from arg structure */ + map->nsp_nsi = a->map.nsp_nsi; + map->mapped_nsp_nsi = a->map.mapped_nsp_nsi; + map->nsh_action = a->map.nsh_action; + map->sw_if_index = a->map.sw_if_index; + map->rx_sw_if_index = a->map.rx_sw_if_index; + map->next_node = a->map.next_node; + map->adj_index = a->map.adj_index; + + + key_copy = clib_mem_alloc (sizeof (*key_copy)); + clib_memcpy (key_copy, &key, sizeof (*key_copy)); + + hash_set_mem (nm->nsh_mapping_by_key, key_copy, map - nm->nsh_mappings); + map_index = map - nm->nsh_mappings; + + if (vec_len (nm->free_nsh_tunnel_hw_if_indices) > 0) + { + nsh_hw_if = nm->free_nsh_tunnel_hw_if_indices + [vec_len (nm->free_nsh_tunnel_hw_if_indices) - 1]; + _vec_len (nm->free_nsh_tunnel_hw_if_indices) -= 1; + + hi = vnet_get_hw_interface (vnm, nsh_hw_if); + hi->dev_instance = map_index; + hi->hw_instance = hi->dev_instance; + } + else + { + nsh_hw_if = vnet_register_interface + (vnm, nsh_device_class.index, map_index, nsh_hw_class.index, + map_index); + hi = vnet_get_hw_interface (vnm, nsh_hw_if); + hi->output_node_index = nsh_aware_vnf_proxy_node.index; + } + + map->nsh_hw_if = nsh_hw_if; + map->nsh_sw_if = nsh_sw_if = hi->sw_if_index; + vec_validate_init_empty (nm->tunnel_index_by_sw_if_index, nsh_sw_if, + ~0); + nm->tunnel_index_by_sw_if_index[nsh_sw_if] = key; + + vnet_sw_interface_set_flags (vnm, hi->sw_if_index, + VNET_SW_INTERFACE_FLAG_ADMIN_UP); + } + else + { + if (!entry) + return -2; //TODO API_ERROR_NO_SUCH_ENTRY; + + map = pool_elt_at_index (nm->nsh_mappings, entry[0]); + + vnet_sw_interface_set_flags (vnm, map->nsh_sw_if, + VNET_SW_INTERFACE_FLAG_ADMIN_DOWN); + vec_add1 (nm->free_nsh_tunnel_hw_if_indices, map->nsh_sw_if); + nm->tunnel_index_by_sw_if_index[map->nsh_sw_if] = ~0; + + hp = hash_get_pair (nm->nsh_mapping_by_key, &key); + key_copy = (void *) (hp->key); + hash_unset_mem (nm->nsh_mapping_by_key, &key); + clib_mem_free (key_copy); + + pool_put (nm->nsh_mappings, map); + } + + if (map_indexp) + *map_indexp = map_index; + + return 0; +} + +/** + * Action function to add or del an nsh-proxy-session. + * Shared by both CLI and binary API + **/ +int +nsh_add_del_proxy_session (nsh_add_del_map_args_t * a) +{ + nsh_main_t *nm = &nsh_main; + nsh_proxy_session_t *proxy = 0; + nsh_proxy_session_by_key_t key, *key_copy; + uword *entry; + hash_pair_t *hp; + u32 nsp = 0, nsi = 0; + + clib_memset (&key, 0, sizeof (key)); + key.transport_type = a->map.next_node; + key.transport_index = a->map.sw_if_index; + + entry = hash_get_mem (nm->nsh_proxy_session_by_key, &key); + + if (a->is_add) + { + /* adding an entry, must not already exist */ + if (entry) + return -1; //TODO API_ERROR_INVALID_VALUE; + + pool_get_aligned (nm->nsh_proxy_sessions, proxy, CLIB_CACHE_LINE_BYTES); + clib_memset (proxy, 0, sizeof (*proxy)); + + /* Nsi needs to minus 1 within NSH-Proxy */ + nsp = (a->map.nsp_nsi >> NSH_NSP_SHIFT) & NSH_NSP_MASK; + nsi = a->map.nsp_nsi & NSH_NSI_MASK; + if (nsi == 0) + return -1; + + nsi = nsi - 1; + /* net order, so could use it to lookup nsh map table directly */ + proxy->nsp_nsi = clib_host_to_net_u32 ((nsp << NSH_NSP_SHIFT) | nsi); + + key_copy = clib_mem_alloc (sizeof (*key_copy)); + clib_memcpy (key_copy, &key, sizeof (*key_copy)); + + hash_set_mem (nm->nsh_proxy_session_by_key, key_copy, + proxy - nm->nsh_proxy_sessions); + } + else + { + if (!entry) + return -2; //TODO API_ERROR_NO_SUCH_ENTRY; + + proxy = pool_elt_at_index (nm->nsh_proxy_sessions, entry[0]); + hp = hash_get_pair (nm->nsh_proxy_session_by_key, &key); + key_copy = (void *) (hp->key); + hash_unset_mem (nm->nsh_proxy_session_by_key, &key); + clib_mem_free (key_copy); + + pool_put (nm->nsh_proxy_sessions, proxy); + } + + return 0; +} + +/** + * Action function for adding an NSH entry + * nsh_add_del_entry_args_t *a: host order + */ +int +nsh_add_del_entry (nsh_add_del_entry_args_t * a, u32 * entry_indexp) +{ + nsh_main_t *nm = &nsh_main; + nsh_entry_t *nsh_entry = 0; + u32 key, *key_copy; + uword *entry_id; + hash_pair_t *hp; + u32 entry_index = ~0; + u8 tlvs_len = 0; + u8 *data = 0; + + /* host order, because nsh map table stores nsp_nsi in host order */ + key = a->nsh_entry.nsh_base.nsp_nsi; + + entry_id = hash_get_mem (nm->nsh_entry_by_key, &key); + + if (a->is_add) + { + /* adding an entry, must not already exist */ + if (entry_id) + return -1; // TODO VNET_API_ERROR_INVALID_VALUE; + + pool_get_aligned (nm->nsh_entries, nsh_entry, CLIB_CACHE_LINE_BYTES); + clib_memset (nsh_entry, 0, sizeof (*nsh_entry)); + + /* copy from arg structure */ +#define _(x) nsh_entry->nsh_base.x = a->nsh_entry.nsh_base.x; + foreach_copy_nsh_base_hdr_field; +#undef _ + + if (a->nsh_entry.nsh_base.md_type == 1) + { + nsh_entry->md.md1_data.c1 = a->nsh_entry.md.md1_data.c1; + nsh_entry->md.md1_data.c2 = a->nsh_entry.md.md1_data.c2; + nsh_entry->md.md1_data.c3 = a->nsh_entry.md.md1_data.c3; + nsh_entry->md.md1_data.c4 = a->nsh_entry.md.md1_data.c4; + } + else if (a->nsh_entry.nsh_base.md_type == 2) + { + vec_free (nsh_entry->tlvs_data); + tlvs_len = a->nsh_entry.tlvs_len; + vec_validate_aligned (data, tlvs_len - 1, CLIB_CACHE_LINE_BYTES); + + clib_memcpy (data, a->nsh_entry.tlvs_data, tlvs_len); + nsh_entry->tlvs_data = data; + nsh_entry->tlvs_len = tlvs_len; + vec_free (a->nsh_entry.tlvs_data); + } + + nsh_header_rewrite (nsh_entry); + + key_copy = clib_mem_alloc (sizeof (*key_copy)); + clib_memcpy (key_copy, &key, sizeof (*key_copy)); + + hash_set_mem (nm->nsh_entry_by_key, key_copy, + nsh_entry - nm->nsh_entries); + entry_index = nsh_entry - nm->nsh_entries; + } + else + { + if (!entry_id) + return -2; //TODO API_ERROR_NO_SUCH_ENTRY; + + nsh_entry = pool_elt_at_index (nm->nsh_entries, entry_id[0]); + hp = hash_get_pair (nm->nsh_entry_by_key, &key); + key_copy = (void *) (hp->key); + hash_unset_mem (nm->nsh_entry_by_key, &key); + clib_mem_free (key_copy); + + vec_free (nsh_entry->tlvs_data); + vec_free (nsh_entry->rewrite); + pool_put (nm->nsh_entries, nsh_entry); + } + + if (entry_indexp) + *entry_indexp = entry_index; + + return 0; +} + + +/** API message handler */ +static void vl_api_nsh_add_del_entry_t_handler + (vl_api_nsh_add_del_entry_t * mp) +{ + vl_api_nsh_add_del_entry_reply_t *rmp; + nsh_main_t *nm = &nsh_main; + int rv; + nsh_add_del_entry_args_t _a, *a = &_a; + u32 entry_index = ~0; + u8 tlvs_len = 0; + u8 *data = 0; + + a->is_add = mp->is_add; + a->nsh_entry.nsh_base.ver_o_c = + (mp->ver_o_c & 0xF0) | ((mp->ttl & NSH_LEN_MASK) >> 2); + a->nsh_entry.nsh_base.length = + (mp->length & NSH_LEN_MASK) | ((mp->ttl & 0x3) << 6); + a->nsh_entry.nsh_base.md_type = mp->md_type; + a->nsh_entry.nsh_base.next_protocol = mp->next_protocol; + a->nsh_entry.nsh_base.nsp_nsi = ntohl (mp->nsp_nsi); + if (mp->md_type == 1) + { + a->nsh_entry.md.md1_data.c1 = ntohl (mp->c1); + a->nsh_entry.md.md1_data.c2 = ntohl (mp->c2); + a->nsh_entry.md.md1_data.c3 = ntohl (mp->c3); + a->nsh_entry.md.md1_data.c4 = ntohl (mp->c4); + } + else if (mp->md_type == 2) + { + tlvs_len = mp->tlv_length; + vec_validate_aligned (data, tlvs_len - 1, CLIB_CACHE_LINE_BYTES); + + clib_memcpy (data, mp->tlv, tlvs_len); + a->nsh_entry.tlvs_data = data; + a->nsh_entry.tlvs_len = tlvs_len; + } + + rv = nsh_add_del_entry (a, &entry_index); + + REPLY_MACRO2 (VL_API_NSH_ADD_DEL_ENTRY_REPLY, ( + { + rmp->entry_index = + htonl (entry_index); + } + )); +} + +static void +vl_api_nsh_entry_dump_t_handler (vl_api_nsh_entry_dump_t * mp) +{ + unix_shared_memory_queue_t *q; + nsh_main_t *nm = &nsh_main; + nsh_entry_t *t; + u32 entry_index; + + q = vl_api_client_index_to_input_queue (mp->client_index); + if (q == 0) + { + return; + } + + entry_index = ntohl (mp->entry_index); + + if (~0 == entry_index) + { + pool_foreach (t, nm->nsh_entries, ( + { + send_nsh_entry_details (t, q, + mp->context); + } + )); + } + else + { + if (entry_index >= vec_len (nm->nsh_entries)) + { + return; + } + t = &nm->nsh_entries[entry_index]; + send_nsh_entry_details (t, q, mp->context); + } +} + +static void +setup_message_id_table (nsh_main_t * nm, api_main_t * am) +{ +#define _(id,n,crc) \ + vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + nm->msg_id_base); + foreach_vl_msg_name_crc_nsh; +#undef _ +} + +/* Set up the API message handling tables */ +static clib_error_t * +nsh_plugin_api_hookup (vlib_main_t * vm) +{ + nsh_main_t *nm __attribute__ ((unused)) = &nsh_main; +#define _(N,n) \ + vl_msg_api_set_handlers((VL_API_##N + nm->msg_id_base), \ + #n, \ + vl_api_##n##_t_handler, \ + vl_noop_handler, \ + vl_api_##n##_t_endian, \ + vl_api_##n##_t_print, \ + sizeof(vl_api_##n##_t), 1); + foreach_nsh_plugin_api_msg; +#undef _ + + return 0; +} + +clib_error_t * +nsh_api_init (vlib_main_t * vm, nsh_main_t * nm) +{ + clib_error_t *error; + u8 *name; + + name = format (0, "nsh_%08x%c", api_version, 0); + + /* Set up the API */ + nm->msg_id_base = vl_msg_api_get_msg_ids + ((char *) name, VL_MSG_FIRST_AVAILABLE); + + error = nsh_plugin_api_hookup (vm); + + /* Add our API messages to the global name_crc hash table */ + setup_message_id_table (nm, &api_main); + + vec_free (name); + + return error; +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/nsh/nsh_cli.c b/src/plugins/nsh/nsh_cli.c new file mode 100644 index 00000000000..8bebb7220c4 --- /dev/null +++ b/src/plugins/nsh/nsh_cli.c @@ -0,0 +1,645 @@ +/* + * nsh_cli.c - nsh cli functions + * + * Copyright (c) 2019 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 <vnet/vnet.h> +#include <vnet/plugin/plugin.h> +#include <nsh/nsh.h> +#include <vnet/adj/adj.h> + +/* format from network order */ +u8 * +format_nsh_pop_header (u8 * s, va_list * args) +{ + return format_nsh_header (s, args); +} + +u8 * +format_nsh_pop_node_map_trace (u8 * s, va_list * args) +{ + return format_nsh_node_map_trace (s, args); +} + +static uword +unformat_nsh_action (unformat_input_t * input, va_list * args) +{ + u32 *result = va_arg (*args, u32 *); + u32 tmp; + + if (unformat (input, "swap")) + *result = NSH_ACTION_SWAP; + else if (unformat (input, "push")) + *result = NSH_ACTION_PUSH; + else if (unformat (input, "pop")) + *result = NSH_ACTION_POP; + else if (unformat (input, "%d", &tmp)) + *result = tmp; + else + return 0; + + return 1; +} + +static u8 * +format_nsh_action (u8 * s, va_list * args) +{ + u32 nsh_action = va_arg (*args, u32); + + switch (nsh_action) + { + case NSH_ACTION_SWAP: + return format (s, "swap"); + case NSH_ACTION_PUSH: + return format (s, "push"); + case NSH_ACTION_POP: + return format (s, "pop"); + default: + return format (s, "unknown %d", nsh_action); + } + return s; +} + +u8 * +format_nsh_map (u8 * s, va_list * args) +{ + nsh_map_t *map = va_arg (*args, nsh_map_t *); + + s = format (s, "nsh entry nsp: %d nsi: %d ", + (map->nsp_nsi >> NSH_NSP_SHIFT) & NSH_NSP_MASK, + map->nsp_nsi & NSH_NSI_MASK); + s = format (s, "maps to nsp: %d nsi: %d ", + (map->mapped_nsp_nsi >> NSH_NSP_SHIFT) & NSH_NSP_MASK, + map->mapped_nsp_nsi & NSH_NSI_MASK); + + s = format (s, " nsh_action %U\n", format_nsh_action, map->nsh_action); + + switch (map->next_node) + { + case NSH_NODE_NEXT_ENCAP_GRE4: + { + s = format (s, "encapped by GRE4 intf: %d", map->sw_if_index); + break; + } + case NSH_NODE_NEXT_ENCAP_GRE6: + { + s = format (s, "encapped by GRE6 intf: %d", map->sw_if_index); + break; + } + case NSH_NODE_NEXT_ENCAP_VXLANGPE: + { + s = format (s, "encapped by VXLAN GPE intf: %d", map->sw_if_index); + break; + } + case NSH_NODE_NEXT_ENCAP_VXLAN4: + { + s = format (s, "encapped by VXLAN4 intf: %d", map->sw_if_index); + break; + } + case NSH_NODE_NEXT_ENCAP_VXLAN6: + { + s = format (s, "encapped by VXLAN6 intf: %d", map->sw_if_index); + break; + } + case NSH_NODE_NEXT_DECAP_ETH_INPUT: + { + s = format (s, "encap-none"); + break; + } + case NSH_NODE_NEXT_ENCAP_LISP_GPE: + { + s = format (s, "encapped by LISP GPE intf: %d", map->sw_if_index); + break; + } + case NSH_NODE_NEXT_ENCAP_ETHERNET: + { + s = format (s, "encapped by Ethernet intf: %d", map->sw_if_index); + break; + } + default: + s = format (s, "only GRE and VXLANGPE support in this rev"); + } + + return s; +} + +static adj_index_t +nsh_get_adj_by_sw_if_index (u32 sw_if_index) +{ + adj_index_t ai = ~0; + + /* *INDENT-OFF* */ + pool_foreach_index(ai, adj_pool, + ({ + if (sw_if_index == adj_get_sw_if_index(ai)) + { + return ai; + } + })); + /* *INDENT-ON* */ + + return ~0; +} + + +/** + * CLI command for NSH map + */ +static clib_error_t * +nsh_add_del_map_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + u8 is_add = 1; + u32 nsp, nsi, mapped_nsp, mapped_nsi, nsh_action; + int nsp_set = 0, nsi_set = 0, mapped_nsp_set = 0, mapped_nsi_set = 0; + int nsh_action_set = 0; + u32 next_node = ~0; + u32 adj_index = ~0; + u32 sw_if_index = ~0; // temporary requirement to get this moved over to NSHSFC + u32 rx_sw_if_index = ~0; // temporary requirement to get this moved over to NSHSFC + nsh_add_del_map_args_t _a, *a = &_a; + u32 map_index; + int rv; + + /* Get a line of input. */ + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "del")) + is_add = 0; + else if (unformat (line_input, "nsp %d", &nsp)) + nsp_set = 1; + else if (unformat (line_input, "nsi %d", &nsi)) + nsi_set = 1; + else if (unformat (line_input, "mapped-nsp %d", &mapped_nsp)) + mapped_nsp_set = 1; + else if (unformat (line_input, "mapped-nsi %d", &mapped_nsi)) + mapped_nsi_set = 1; + else if (unformat (line_input, "nsh_action %U", unformat_nsh_action, + &nsh_action)) + nsh_action_set = 1; + else if (unformat (line_input, "encap-gre4-intf %d", &sw_if_index)) + next_node = NSH_NODE_NEXT_ENCAP_GRE4; + else if (unformat (line_input, "encap-gre6-intf %d", &sw_if_index)) + next_node = NSH_NODE_NEXT_ENCAP_GRE6; + else if (unformat (line_input, "encap-vxlan-gpe-intf %d", &sw_if_index)) + next_node = NSH_NODE_NEXT_ENCAP_VXLANGPE; + else if (unformat (line_input, "encap-lisp-gpe-intf %d", &sw_if_index)) + next_node = NSH_NODE_NEXT_ENCAP_LISP_GPE; + else if (unformat (line_input, "encap-vxlan4-intf %d", &sw_if_index)) + next_node = NSH_NODE_NEXT_ENCAP_VXLAN4; + else if (unformat (line_input, "encap-vxlan6-intf %d", &sw_if_index)) + next_node = NSH_NODE_NEXT_ENCAP_VXLAN6; + else if (unformat (line_input, "encap-eth-intf %d", &sw_if_index)) + { + next_node = NSH_NODE_NEXT_ENCAP_ETHERNET; + adj_index = nsh_get_adj_by_sw_if_index (sw_if_index); + } + else + if (unformat + (line_input, "encap-none %d %d", &sw_if_index, &rx_sw_if_index)) + next_node = NSH_NODE_NEXT_DECAP_ETH_INPUT; + else + return clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + } + + unformat_free (line_input); + + if (nsp_set == 0 || nsi_set == 0) + return clib_error_return (0, "nsp nsi pair required. Key: for NSH entry"); + + if (mapped_nsp_set == 0 || mapped_nsi_set == 0) + return clib_error_return (0, + "mapped-nsp mapped-nsi pair required. Key: for NSH entry"); + + if (nsh_action_set == 0) + return clib_error_return (0, "nsh_action required: swap|push|pop."); + + if (next_node == ~0) + return clib_error_return (0, + "must specific action: [encap-gre-intf <nn> | encap-vxlan-gpe-intf <nn> | encap-lisp-gpe-intf <nn> | encap-none <tx_sw_if_index> <rx_sw_if_index>]"); + + clib_memset (a, 0, sizeof (*a)); + + /* set args structure */ + a->is_add = is_add; + a->map.nsp_nsi = (nsp << NSH_NSP_SHIFT) | nsi; + a->map.mapped_nsp_nsi = (mapped_nsp << NSH_NSP_SHIFT) | mapped_nsi; + a->map.nsh_action = nsh_action; + a->map.sw_if_index = sw_if_index; + a->map.rx_sw_if_index = rx_sw_if_index; + a->map.next_node = next_node; + a->map.adj_index = adj_index; + + rv = nsh_add_del_map (a, &map_index); + + switch (rv) + { + case 0: + break; + case -1: //TODO API_ERROR_INVALID_VALUE: + return clib_error_return (0, + "mapping already exists. Remove it first."); + + case -2: // TODO API_ERROR_NO_SUCH_ENTRY: + return clib_error_return (0, "mapping does not exist."); + + default: + return clib_error_return (0, "nsh_add_del_map returned %d", rv); + } + + if ((a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN4) + | (a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN6)) + { + rv = nsh_add_del_proxy_session (a); + + switch (rv) + { + case 0: + break; + case -1: //TODO API_ERROR_INVALID_VALUE: + return clib_error_return (0, + "nsh-proxy-session already exists. Remove it first."); + + case -2: // TODO API_ERROR_NO_SUCH_ENTRY: + return clib_error_return (0, "nsh-proxy-session does not exist."); + + default: + return clib_error_return + (0, "nsh_add_del_proxy_session() returned %d", rv); + } + } + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (create_nsh_map_command, static) = { + .path = "create nsh map", + .short_help = + "create nsh map nsp <nn> nsi <nn> [del] mapped-nsp <nn> mapped-nsi <nn> nsh_action [swap|push|pop] " + "[encap-gre4-intf <nn> | encap-gre4-intf <nn> | encap-vxlan-gpe-intf <nn> | encap-lisp-gpe-intf <nn> " + " encap-vxlan4-intf <nn> | encap-vxlan6-intf <nn>| encap-eth-intf <nn> | encap-none]\n", + .function = nsh_add_del_map_command_fn, +}; +/* *INDENT-ON* */ + +/** + * CLI command for showing the mapping between NSH entries + */ +static clib_error_t * +show_nsh_map_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + nsh_main_t *nm = &nsh_main; + nsh_map_t *map; + + if (pool_elts (nm->nsh_mappings) == 0) + vlib_cli_output (vm, "No nsh maps configured."); + + pool_foreach (map, nm->nsh_mappings, ( + { + vlib_cli_output (vm, "%U", + format_nsh_map, + map); + } + )); + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (show_nsh_map_command, static) = { + .path = "show nsh map", + .function = show_nsh_map_command_fn, +}; +/* *INDENT-ON* */ + +/** + * CLI command for adding NSH entry + */ +static clib_error_t * +nsh_add_del_entry_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + u8 is_add = 1; + u8 ver_o_c = 0; + u8 ttl = 63; + u8 length = 0; + u8 md_type = 0; + u8 next_protocol = 1; /* default: ip4 */ + u32 nsp; + u8 nsp_set = 0; + u32 nsi; + u8 nsi_set = 0; + u32 nsp_nsi; + u32 c1 = 0; + u32 c2 = 0; + u32 c3 = 0; + u32 c4 = 0; + u8 *data = 0; + nsh_tlv_header_t tlv_header; + u8 cur_len = 0, tlvs_len = 0; + u8 *current; + nsh_main_t *nm = &nsh_main; + nsh_option_map_t _nsh_option, *nsh_option = &_nsh_option; + u8 option_size = 0; + u32 tmp; + int rv; + u32 entry_index; + nsh_add_del_entry_args_t _a, *a = &_a; + u8 has_ioam_trace_option = 0; + + /* Get a line of input. */ + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "del")) + is_add = 0; + else if (unformat (line_input, "version %d", &tmp)) + ver_o_c |= (tmp & 3) << 6; + else if (unformat (line_input, "o-bit %d", &tmp)) + ver_o_c |= (tmp & 1) << 5; + else if (unformat (line_input, "c-bit %d", &tmp)) + ver_o_c |= (tmp & 1) << 4; + else if (unformat (line_input, "ttl %d", &ttl)) + ver_o_c |= (ttl & NSH_LEN_MASK) >> 2; + else if (unformat (line_input, "md-type %d", &tmp)) + md_type = tmp; + else if (unformat (line_input, "next-ip4")) + next_protocol = 1; + else if (unformat (line_input, "next-ip6")) + next_protocol = 2; + else if (unformat (line_input, "next-ethernet")) + next_protocol = 3; + else if (unformat (line_input, "c1 %d", &c1)) + ; + else if (unformat (line_input, "c2 %d", &c2)) + ; + else if (unformat (line_input, "c3 %d", &c3)) + ; + else if (unformat (line_input, "c4 %d", &c4)) + ; + else if (unformat (line_input, "nsp %d", &nsp)) + nsp_set = 1; + else if (unformat (line_input, "nsi %d", &nsi)) + nsi_set = 1; + else if (unformat (line_input, "tlv-ioam-trace")) + has_ioam_trace_option = 1; + else + return clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + } + + unformat_free (line_input); + + if (nsp_set == 0) + return clib_error_return (0, "nsp not specified"); + + if (nsi_set == 0) + return clib_error_return (0, "nsi not specified"); + + if (md_type == 1 && has_ioam_trace_option == 1) + return clib_error_return (0, "Invalid MD Type"); + + nsp_nsi = (nsp << 8) | nsi; + + clib_memset (a, 0, sizeof (*a)); + a->is_add = is_add; + + if (md_type == 1) + { + a->nsh_entry.md.md1_data.c1 = c1; + a->nsh_entry.md.md1_data.c2 = c2; + a->nsh_entry.md.md1_data.c3 = c3; + a->nsh_entry.md.md1_data.c4 = c4; + length = (sizeof (nsh_base_header_t) + sizeof (nsh_md1_data_t)) >> 2; + } + else if (md_type == 2) + { + length = sizeof (nsh_base_header_t) >> 2; + + vec_free (a->nsh_entry.tlvs_data); + tlvs_len = (MAX_METADATA_LEN << 2); + vec_validate_aligned (data, tlvs_len - 1, CLIB_CACHE_LINE_BYTES); + a->nsh_entry.tlvs_data = data; + current = data; + + if (has_ioam_trace_option) + { + tlv_header.class = clib_host_to_net_u16 (NSH_MD2_IOAM_CLASS); + tlv_header.type = NSH_MD2_IOAM_OPTION_TYPE_TRACE; + /* Uses network order's class and type to lookup */ + nsh_option = + nsh_md2_lookup_option (tlv_header.class, tlv_header.type); + if (nsh_option == NULL) + return clib_error_return (0, "iOAM Trace not registered"); + + if (nm->add_options[nsh_option->option_id] != NULL) + { + if (0 != nm->add_options[nsh_option->option_id] ((u8 *) current, + &option_size)) + { + return clib_error_return (0, "Invalid MD Type"); + } + } + + nm->options_size[nsh_option->option_id] = option_size; + /* round to 4-byte */ + option_size = (((option_size + 3) >> 2) << 2); + + cur_len += option_size; + current = data + option_size; + } + + /* Add more options' parsing */ + + a->nsh_entry.tlvs_len = cur_len; + length += (cur_len >> 2); + } + length = (length & NSH_LEN_MASK) | ((ttl & 0x3) << 6); + +#define _(x) a->nsh_entry.nsh_base.x = x; + foreach_copy_nsh_base_hdr_field; +#undef _ + + rv = nsh_add_del_entry (a, &entry_index); + + switch (rv) + { + case 0: + break; + default: + return clib_error_return (0, "nsh_add_del_entry returned %d", rv); + } + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (create_nsh_entry_command, static) = { + .path = "create nsh entry", + .short_help = + "create nsh entry {nsp <nn> nsi <nn>} [ttl <nn>] [md-type <nn>]" + " [c1 <nn> c2 <nn> c3 <nn> c4 <nn>] [tlv-ioam-trace] [del]\n", + .function = nsh_add_del_entry_command_fn, +}; +/* *INDENT-ON* */ + +/* format from network order */ +u8 * +format_nsh_header (u8 * s, va_list * args) +{ + nsh_main_t *nm = &nsh_main; + nsh_md2_data_t *opt0; + nsh_md2_data_t *limit0; + nsh_option_map_t *nsh_option; + u8 option_len = 0; + + u8 *header = va_arg (*args, u8 *); + nsh_base_header_t *nsh_base = (nsh_base_header_t *) header; + nsh_md1_data_t *nsh_md1 = (nsh_md1_data_t *) (nsh_base + 1); + nsh_md2_data_t *nsh_md2 = (nsh_md2_data_t *) (nsh_base + 1); + opt0 = (nsh_md2_data_t *) nsh_md2; + limit0 = (nsh_md2_data_t *) ((u8 *) nsh_md2 + + ((nsh_base->length & NSH_LEN_MASK) * 4 + - sizeof (nsh_base_header_t))); + + s = format (s, "nsh ver %d ", (nsh_base->ver_o_c >> 6)); + if (nsh_base->ver_o_c & NSH_O_BIT) + s = format (s, "O-set "); + + if (nsh_base->ver_o_c & NSH_C_BIT) + s = format (s, "C-set "); + + s = format (s, "ttl %d ", (nsh_base->ver_o_c & NSH_TTL_H4_MASK) << 2 | + (nsh_base->length & NSH_TTL_L2_MASK) >> 6); + + s = format (s, "len %d (%d bytes) md_type %d next_protocol %d\n", + (nsh_base->length & NSH_LEN_MASK), + (nsh_base->length & NSH_LEN_MASK) * 4, + nsh_base->md_type, nsh_base->next_protocol); + + s = format (s, " service path %d service index %d\n", + (clib_net_to_host_u32 (nsh_base->nsp_nsi) >> NSH_NSP_SHIFT) & + NSH_NSP_MASK, + clib_net_to_host_u32 (nsh_base->nsp_nsi) & NSH_NSI_MASK); + + if (nsh_base->md_type == 1) + { + s = format (s, " c1 %d c2 %d c3 %d c4 %d\n", + clib_net_to_host_u32 (nsh_md1->c1), + clib_net_to_host_u32 (nsh_md1->c2), + clib_net_to_host_u32 (nsh_md1->c3), + clib_net_to_host_u32 (nsh_md1->c4)); + } + else if (nsh_base->md_type == 2) + { + s = format (s, " Supported TLVs: \n"); + + /* Scan the set of variable metadata, network order */ + while (opt0 < limit0) + { + nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type); + if (nsh_option != NULL) + { + if (nm->trace[nsh_option->option_id] != NULL) + { + s = (*nm->trace[nsh_option->option_id]) (s, opt0); + } + else + { + s = + format (s, "\n untraced option %d length %d", + opt0->type, opt0->length); + } + } + else + { + s = + format (s, "\n unrecognized option %d length %d", + opt0->type, opt0->length); + } + + /* round to 4-byte */ + option_len = ((opt0->length + 3) >> 2) << 2; + opt0 = + (nsh_md2_data_t *) (((u8 *) opt0) + sizeof (nsh_md2_data_t) + + option_len); + } + } + + return s; +} + +u8 * +format_nsh_node_map_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + nsh_input_trace_t *t = va_arg (*args, nsh_input_trace_t *); + + s = format (s, "\n %U", format_nsh_header, &(t->trace_data)); + + return s; +} + +static clib_error_t * +show_nsh_entry_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + nsh_main_t *nm = &nsh_main; + nsh_entry_t *nsh_entry; + + if (pool_elts (nm->nsh_entries) == 0) + vlib_cli_output (vm, "No nsh entries configured."); + + pool_foreach (nsh_entry, nm->nsh_entries, ( + { + vlib_cli_output (vm, "%U", + format_nsh_header, + nsh_entry->rewrite); + vlib_cli_output (vm, + " rewrite_size: %d bytes", + nsh_entry->rewrite_size); + } + )); + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (show_nsh_entry_command, static) = { + .path = "show nsh entry", + .function = show_nsh_entry_command_fn, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/nsh/nsh_node.c b/src/plugins/nsh/nsh_node.c new file mode 100644 index 00000000000..5e2af68e417 --- /dev/null +++ b/src/plugins/nsh/nsh_node.c @@ -0,0 +1,982 @@ +/* + * nsh_node.c - nsh nodes + * + * Copyright (c) 2013 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 <vnet/vnet.h> +#include <vnet/plugin/plugin.h> +#include <nsh/nsh.h> + +always_inline void +nsh_md2_encap (vlib_buffer_t * b, nsh_base_header_t * hdr, + nsh_entry_t * nsh_entry) +{ + nsh_main_t *nm = &nsh_main; + nsh_base_header_t *nsh_base; + nsh_tlv_header_t *opt0; + nsh_tlv_header_t *limit0; + nsh_tlv_header_t *nsh_md2; + nsh_option_map_t *nsh_option; + u8 old_option_size = 0; + u8 new_option_size = 0; + + /* Populate the NSH Header */ + opt0 = (nsh_tlv_header_t *) (nsh_entry->tlvs_data); + limit0 = (nsh_tlv_header_t *) (nsh_entry->tlvs_data + nsh_entry->tlvs_len); + + nsh_md2 = (nsh_tlv_header_t *) ((u8 *) hdr /*nsh_entry->rewrite */ + + sizeof (nsh_base_header_t)); + nsh_entry->rewrite_size = sizeof (nsh_base_header_t); + + /* Scan the set of variable metadata, process ones that we understand */ + while (opt0 < limit0) + { + old_option_size = sizeof (nsh_tlv_header_t) + opt0->length; + /* round to 4-byte */ + old_option_size = ((old_option_size + 3) >> 2) << 2; + + nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type); + if (nsh_option == NULL) + { + goto next_tlv_md2; + } + + if (nm->options[nsh_option->option_id]) + { + if ((*nm->options[nsh_option->option_id]) (b, nsh_md2)) + { + goto next_tlv_md2; + } + + /* option length may be varied */ + new_option_size = sizeof (nsh_tlv_header_t) + nsh_md2->length; + /* round to 4-byte */ + new_option_size = ((new_option_size + 3) >> 2) << 2; + nsh_entry->rewrite_size += new_option_size; + + nsh_md2 = (nsh_tlv_header_t *) (((u8 *) nsh_md2) + new_option_size); + opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size); + + } + else + { + next_tlv_md2: + opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size); + } + } + + /* update nsh header's length */ + nsh_base = (nsh_base_header_t *) nsh_entry->rewrite; + nsh_base->length = (nsh_base->length & NSH_TTL_L2_MASK) | + ((nsh_entry->rewrite_size >> 2) & NSH_LEN_MASK); + return; +} + +always_inline void +nsh_md2_swap (vlib_buffer_t * b, + nsh_base_header_t * hdr, + u32 header_len, + nsh_entry_t * nsh_entry, u32 * next, u32 drop_node_val) +{ + nsh_main_t *nm = &nsh_main; + nsh_base_header_t *nsh_base; + nsh_tlv_header_t *opt0; + nsh_tlv_header_t *limit0; + nsh_tlv_header_t *nsh_md2; + nsh_option_map_t *nsh_option; + u8 old_option_size = 0; + u8 new_option_size = 0; + + /* Populate the NSH Header */ + opt0 = (nsh_md2_data_t *) (hdr + 1); + limit0 = (nsh_md2_data_t *) ((u8 *) hdr + header_len); + + nsh_md2 = + (nsh_tlv_header_t *) (nsh_entry->rewrite + sizeof (nsh_base_header_t)); + nsh_entry->rewrite_size = sizeof (nsh_base_header_t); + + /* Scan the set of variable metadata, process ones that we understand */ + while (opt0 < limit0) + { + old_option_size = sizeof (nsh_tlv_header_t) + opt0->length; + /* round to 4-byte */ + old_option_size = ((old_option_size + 3) >> 2) << 2; + + nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type); + if (nsh_option == NULL) + { + goto next_tlv_md2; + } + + if (nm->swap_options[nsh_option->option_id]) + { + if ((*nm->swap_options[nsh_option->option_id]) (b, opt0, nsh_md2)) + { + goto next_tlv_md2; + } + + /* option length may be varied */ + new_option_size = sizeof (nsh_tlv_header_t) + nsh_md2->length; + /* round to 4-byte */ + new_option_size = ((new_option_size + 3) >> 2) << 2; + nsh_entry->rewrite_size += new_option_size; + nsh_md2 = (nsh_tlv_header_t *) (((u8 *) nsh_md2) + new_option_size); + + opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size); + + } + else + { + next_tlv_md2: + opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size); + } + } + + /* update nsh header's length */ + nsh_base = (nsh_base_header_t *) nsh_entry->rewrite; + nsh_base->length = (nsh_base->length & NSH_TTL_L2_MASK) | + ((nsh_entry->rewrite_size >> 2) & NSH_LEN_MASK); + return; +} + +always_inline void +nsh_md2_decap (vlib_buffer_t * b, + nsh_base_header_t * hdr, + u32 * header_len, u32 * next, u32 drop_node_val) +{ + nsh_main_t *nm = &nsh_main; + nsh_md2_data_t *opt0; + nsh_md2_data_t *limit0; + nsh_option_map_t *nsh_option; + u8 option_len = 0; + + /* Populate the NSH Header */ + opt0 = (nsh_md2_data_t *) (hdr + 1); + limit0 = (nsh_md2_data_t *) ((u8 *) hdr + *header_len); + + /* Scan the set of variable metadata, process ones that we understand */ + while (opt0 < limit0) + { + nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type); + if (nsh_option == NULL) + { + *next = drop_node_val; + return; + } + + if (nm->pop_options[nsh_option->option_id]) + { + if ((*nm->pop_options[nsh_option->option_id]) (b, opt0)) + { + *next = drop_node_val; + return; + } + } + /* round to 4-byte */ + option_len = ((opt0->length + 3) >> 2) << 2; + opt0 = + (nsh_md2_data_t *) (((u8 *) opt0) + sizeof (nsh_md2_data_t) + + option_len); + *next = + (nm->decap_v4_next_override) ? (nm->decap_v4_next_override) : (*next); + *header_len = (nm->decap_v4_next_override) ? 0 : (*header_len); + } + + return; +} + +static uword +nsh_input_map (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * from_frame, u32 node_type) +{ + u32 n_left_from, next_index, *from, *to_next; + nsh_main_t *nm = &nsh_main; + + from = vlib_frame_vector_args (from_frame); + n_left_from = from_frame->n_vectors; + + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from >= 4 && n_left_to_next >= 2) + { + u32 bi0, bi1; + vlib_buffer_t *b0, *b1; + u32 next0 = NSH_NODE_NEXT_DROP, next1 = NSH_NODE_NEXT_DROP; + uword *entry0, *entry1; + nsh_base_header_t *hdr0 = 0, *hdr1 = 0; + u32 header_len0 = 0, header_len1 = 0; + u32 nsp_nsi0, nsp_nsi1; + u32 ttl0, ttl1; + u32 error0, error1; + nsh_map_t *map0 = 0, *map1 = 0; + nsh_entry_t *nsh_entry0 = 0, *nsh_entry1 = 0; + nsh_base_header_t *encap_hdr0 = 0, *encap_hdr1 = 0; + u32 encap_hdr_len0 = 0, encap_hdr_len1 = 0; + nsh_proxy_session_by_key_t key0, key1; + uword *p0, *p1; + nsh_proxy_session_t *proxy0, *proxy1; + u32 sw_if_index0 = 0, sw_if_index1 = 0; + ethernet_header_t dummy_eth0, dummy_eth1; + + /* Prefetch next iteration. */ + { + vlib_buffer_t *p2, *p3; + + p2 = vlib_get_buffer (vm, from[2]); + p3 = vlib_get_buffer (vm, from[3]); + + vlib_prefetch_buffer_header (p2, LOAD); + vlib_prefetch_buffer_header (p3, LOAD); + + CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD); + CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD); + } + + bi0 = from[0]; + bi1 = from[1]; + to_next[0] = bi0; + to_next[1] = bi1; + from += 2; + to_next += 2; + n_left_from -= 2; + n_left_to_next -= 2; + + error0 = 0; + error1 = 0; + + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + hdr0 = vlib_buffer_get_current (b0); + hdr1 = vlib_buffer_get_current (b1); + + /* Process packet 0 */ + if (node_type == NSH_INPUT_TYPE) + { + nsp_nsi0 = hdr0->nsp_nsi; + header_len0 = (hdr0->length & NSH_LEN_MASK) * 4; + ttl0 = (hdr0->ver_o_c & NSH_TTL_H4_MASK) << 2 | + (hdr0->length & NSH_TTL_L2_MASK) >> 6; + ttl0 = ttl0 - 1; + if (PREDICT_FALSE (ttl0 == 0)) + { + error0 = NSH_NODE_ERROR_INVALID_TTL; + goto trace0; + } + } + else if (node_type == NSH_CLASSIFIER_TYPE) + { + nsp_nsi0 = + clib_host_to_net_u32 (vnet_buffer (b0)-> + l2_classify.opaque_index); + } + else if (node_type == NSH_AWARE_VNF_PROXY_TYPE) + { + /* Push dummy Eth header */ + char dummy_dst_address[6] = + { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 }; + char dummy_src_address[6] = + { 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc }; + clib_memcpy_fast (dummy_eth0.dst_address, dummy_dst_address, 6); + clib_memcpy_fast (dummy_eth0.src_address, dummy_src_address, 6); + dummy_eth0.type = 0x0800; + vlib_buffer_advance (b0, -(word) sizeof (ethernet_header_t)); + hdr0 = vlib_buffer_get_current (b0); + clib_memcpy_fast (hdr0, &dummy_eth0, + (word) sizeof (ethernet_header_t)); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + nsp_nsi0 = nm->tunnel_index_by_sw_if_index[sw_if_index0]; + } + else + { + clib_memset (&key0, 0, sizeof (key0)); + key0.transport_type = NSH_NODE_NEXT_ENCAP_VXLAN4; + key0.transport_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + + p0 = hash_get_mem (nm->nsh_proxy_session_by_key, &key0); + if (PREDICT_FALSE (p0 == 0)) + { + error0 = NSH_NODE_ERROR_NO_PROXY; + goto trace0; + } + + proxy0 = pool_elt_at_index (nm->nsh_proxy_sessions, p0[0]); + if (PREDICT_FALSE (proxy0 == 0)) + { + error0 = NSH_NODE_ERROR_NO_PROXY; + goto trace0; + } + nsp_nsi0 = proxy0->nsp_nsi; + } + + entry0 = hash_get_mem (nm->nsh_mapping_by_key, &nsp_nsi0); + if (PREDICT_FALSE (entry0 == 0)) + { + error0 = NSH_NODE_ERROR_NO_MAPPING; + goto trace0; + } + + /* Entry should point to a mapping ... */ + map0 = pool_elt_at_index (nm->nsh_mappings, entry0[0]); + if (PREDICT_FALSE (map0 == 0)) + { + error0 = NSH_NODE_ERROR_NO_MAPPING; + goto trace0; + } + + /* set up things for next node to transmit ie which node to handle it and where */ + next0 = map0->next_node; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = map0->sw_if_index; + vnet_buffer (b0)->ip.adj_index[VLIB_TX] = map0->adj_index; + + if (PREDICT_FALSE (map0->nsh_action == NSH_ACTION_POP)) + { + /* Manipulate MD2 */ + if (PREDICT_FALSE (hdr0->md_type == 2)) + { + nsh_md2_decap (b0, hdr0, &header_len0, &next0, + NSH_NODE_NEXT_DROP); + if (PREDICT_FALSE (next0 == NSH_NODE_NEXT_DROP)) + { + error0 = NSH_NODE_ERROR_INVALID_OPTIONS; + goto trace0; + } + vnet_buffer (b0)->sw_if_index[VLIB_RX] = + map0->rx_sw_if_index; + } + + /* Pop NSH header */ + vlib_buffer_advance (b0, (word) header_len0); + goto trace0; + } + + entry0 = hash_get_mem (nm->nsh_entry_by_key, &map0->mapped_nsp_nsi); + if (PREDICT_FALSE (entry0 == 0)) + { + error0 = NSH_NODE_ERROR_NO_ENTRY; + goto trace0; + } + + nsh_entry0 = + (nsh_entry_t *) pool_elt_at_index (nm->nsh_entries, entry0[0]); + encap_hdr0 = (nsh_base_header_t *) (nsh_entry0->rewrite); + /* rewrite_size should equal to (encap_hdr0->length * 4) */ + encap_hdr_len0 = nsh_entry0->rewrite_size; + + if (PREDICT_TRUE (map0->nsh_action == NSH_ACTION_SWAP)) + { + /* Manipulate MD2 */ + if (PREDICT_FALSE (hdr0->md_type == 2)) + { + nsh_md2_swap (b0, hdr0, header_len0, nsh_entry0, + &next0, NSH_NODE_NEXT_DROP); + if (PREDICT_FALSE (next0 == NSH_NODE_NEXT_DROP)) + { + error0 = NSH_NODE_ERROR_INVALID_OPTIONS; + goto trace0; + } + } + + /* Pop old NSH header */ + vlib_buffer_advance (b0, (word) header_len0); + + /* After processing, md2's length may be varied */ + encap_hdr_len0 = nsh_entry0->rewrite_size; + /* Push new NSH header */ + vlib_buffer_advance (b0, -(word) encap_hdr_len0); + hdr0 = vlib_buffer_get_current (b0); + clib_memcpy_fast (hdr0, encap_hdr0, (word) encap_hdr_len0); + + goto trace0; + } + + if (PREDICT_TRUE (map0->nsh_action == NSH_ACTION_PUSH)) + { + /* After processing, md2's length may be varied */ + encap_hdr_len0 = nsh_entry0->rewrite_size; + /* Push new NSH header */ + vlib_buffer_advance (b0, -(word) encap_hdr_len0); + hdr0 = vlib_buffer_get_current (b0); + clib_memcpy_fast (hdr0, encap_hdr0, (word) encap_hdr_len0); + + /* Manipulate MD2 */ + if (PREDICT_FALSE (nsh_entry0->nsh_base.md_type == 2)) + { + nsh_md2_encap (b0, hdr0, nsh_entry0); + } + + } + + trace0: + b0->error = error0 ? node->errors[error0] : 0; + + if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) + { + nsh_input_trace_t *tr = + vlib_add_trace (vm, node, b0, sizeof (*tr)); + clib_memcpy_fast (&(tr->trace_data), hdr0, + ((hdr0->length & NSH_LEN_MASK) * 4)); + } + + /* Process packet 1 */ + if (node_type == NSH_INPUT_TYPE) + { + nsp_nsi1 = hdr1->nsp_nsi; + header_len1 = (hdr1->length & NSH_LEN_MASK) * 4; + ttl1 = (hdr1->ver_o_c & NSH_TTL_H4_MASK) << 2 | + (hdr1->length & NSH_TTL_L2_MASK) >> 6; + ttl1 = ttl1 - 1; + if (PREDICT_FALSE (ttl1 == 0)) + { + error1 = NSH_NODE_ERROR_INVALID_TTL; + goto trace1; + } + } + else if (node_type == NSH_CLASSIFIER_TYPE) + { + nsp_nsi1 = + clib_host_to_net_u32 (vnet_buffer (b1)-> + l2_classify.opaque_index); + } + else if (node_type == NSH_AWARE_VNF_PROXY_TYPE) + { + /* Push dummy Eth header */ + char dummy_dst_address[6] = + { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 }; + char dummy_src_address[6] = + { 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc }; + clib_memcpy_fast (dummy_eth1.dst_address, dummy_dst_address, 6); + clib_memcpy_fast (dummy_eth1.src_address, dummy_src_address, 6); + dummy_eth1.type = 0x0800; + vlib_buffer_advance (b1, -(word) sizeof (ethernet_header_t)); + hdr1 = vlib_buffer_get_current (b1); + clib_memcpy_fast (hdr1, &dummy_eth1, + (word) sizeof (ethernet_header_t)); + + sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_TX]; + nsp_nsi1 = nm->tunnel_index_by_sw_if_index[sw_if_index1]; + } + else + { + clib_memset (&key1, 0, sizeof (key1)); + key1.transport_type = NSH_NODE_NEXT_ENCAP_VXLAN4; + key1.transport_index = vnet_buffer (b1)->sw_if_index[VLIB_RX]; + + p1 = hash_get_mem (nm->nsh_proxy_session_by_key, &key1); + if (PREDICT_FALSE (p1 == 0)) + { + error1 = NSH_NODE_ERROR_NO_PROXY; + goto trace1; + } + + proxy1 = pool_elt_at_index (nm->nsh_proxy_sessions, p1[0]); + if (PREDICT_FALSE (proxy1 == 0)) + { + error1 = NSH_NODE_ERROR_NO_PROXY; + goto trace1; + } + nsp_nsi1 = proxy1->nsp_nsi; + } + + entry1 = hash_get_mem (nm->nsh_mapping_by_key, &nsp_nsi1); + if (PREDICT_FALSE (entry1 == 0)) + { + error1 = NSH_NODE_ERROR_NO_MAPPING; + goto trace1; + } + + /* Entry should point to a mapping ... */ + map1 = pool_elt_at_index (nm->nsh_mappings, entry1[0]); + if (PREDICT_FALSE (map1 == 0)) + { + error1 = NSH_NODE_ERROR_NO_MAPPING; + goto trace1; + } + + /* set up things for next node to transmit ie which node to handle it and where */ + next1 = map1->next_node; + vnet_buffer (b1)->sw_if_index[VLIB_TX] = map1->sw_if_index; + vnet_buffer (b1)->ip.adj_index[VLIB_TX] = map1->adj_index; + + if (PREDICT_FALSE (map1->nsh_action == NSH_ACTION_POP)) + { + /* Manipulate MD2 */ + if (PREDICT_FALSE (hdr1->md_type == 2)) + { + nsh_md2_decap (b1, hdr1, &header_len1, &next1, + NSH_NODE_NEXT_DROP); + if (PREDICT_FALSE (next1 == NSH_NODE_NEXT_DROP)) + { + error1 = NSH_NODE_ERROR_INVALID_OPTIONS; + goto trace1; + } + vnet_buffer (b1)->sw_if_index[VLIB_RX] = + map1->rx_sw_if_index; + } + + /* Pop NSH header */ + vlib_buffer_advance (b1, (word) header_len1); + goto trace1; + } + + entry1 = hash_get_mem (nm->nsh_entry_by_key, &map1->mapped_nsp_nsi); + if (PREDICT_FALSE (entry1 == 0)) + { + error1 = NSH_NODE_ERROR_NO_ENTRY; + goto trace1; + } + + nsh_entry1 = + (nsh_entry_t *) pool_elt_at_index (nm->nsh_entries, entry1[0]); + encap_hdr1 = (nsh_base_header_t *) (nsh_entry1->rewrite); + /* rewrite_size should equal to (encap_hdr0->length * 4) */ + encap_hdr_len1 = nsh_entry1->rewrite_size; + + if (PREDICT_TRUE (map1->nsh_action == NSH_ACTION_SWAP)) + { + /* Manipulate MD2 */ + if (PREDICT_FALSE (hdr1->md_type == 2)) + { + nsh_md2_swap (b1, hdr1, header_len1, nsh_entry1, + &next1, NSH_NODE_NEXT_DROP); + if (PREDICT_FALSE (next1 == NSH_NODE_NEXT_DROP)) + { + error1 = NSH_NODE_ERROR_INVALID_OPTIONS; + goto trace1; + } + } + + /* Pop old NSH header */ + vlib_buffer_advance (b1, (word) header_len1); + + /* After processing, md2's length may be varied */ + encap_hdr_len1 = nsh_entry1->rewrite_size; + /* Push new NSH header */ + vlib_buffer_advance (b1, -(word) encap_hdr_len1); + hdr1 = vlib_buffer_get_current (b1); + clib_memcpy_fast (hdr1, encap_hdr1, (word) encap_hdr_len1); + + goto trace1; + } + + if (PREDICT_FALSE (map1->nsh_action == NSH_ACTION_PUSH)) + { + /* After processing, md2's length may be varied */ + encap_hdr_len1 = nsh_entry1->rewrite_size; + /* Push new NSH header */ + vlib_buffer_advance (b1, -(word) encap_hdr_len1); + hdr1 = vlib_buffer_get_current (b1); + clib_memcpy_fast (hdr1, encap_hdr1, (word) encap_hdr_len1); + + /* Manipulate MD2 */ + if (PREDICT_FALSE (nsh_entry1->nsh_base.md_type == 2)) + { + nsh_md2_encap (b1, hdr1, nsh_entry1); + } + + } + + trace1: + b1->error = error1 ? node->errors[error1] : 0; + + if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED)) + { + nsh_input_trace_t *tr = + vlib_add_trace (vm, node, b1, sizeof (*tr)); + clib_memcpy_fast (&(tr->trace_data), hdr1, + ((hdr1->length & NSH_LEN_MASK) * 4)); + } + + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, + n_left_to_next, bi0, bi1, next0, + next1); + + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0 = 0; + vlib_buffer_t *b0 = NULL; + u32 next0 = NSH_NODE_NEXT_DROP; + uword *entry0; + nsh_base_header_t *hdr0 = 0; + u32 header_len0 = 0; + u32 nsp_nsi0; + u32 ttl0; + u32 error0; + nsh_map_t *map0 = 0; + nsh_entry_t *nsh_entry0 = 0; + nsh_base_header_t *encap_hdr0 = 0; + u32 encap_hdr_len0 = 0; + nsh_proxy_session_by_key_t key0; + uword *p0; + nsh_proxy_session_t *proxy0 = 0; + u32 sw_if_index0 = 0; + ethernet_header_t dummy_eth0; + + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + error0 = 0; + + b0 = vlib_get_buffer (vm, bi0); + hdr0 = vlib_buffer_get_current (b0); + + if (node_type == NSH_INPUT_TYPE) + { + nsp_nsi0 = hdr0->nsp_nsi; + header_len0 = (hdr0->length & NSH_LEN_MASK) * 4; + ttl0 = (hdr0->ver_o_c & NSH_TTL_H4_MASK) << 2 | + (hdr0->length & NSH_TTL_L2_MASK) >> 6; + ttl0 = ttl0 - 1; + if (PREDICT_FALSE (ttl0 == 0)) + { + error0 = NSH_NODE_ERROR_INVALID_TTL; + goto trace00; + } + } + else if (node_type == NSH_CLASSIFIER_TYPE) + { + nsp_nsi0 = + clib_host_to_net_u32 (vnet_buffer (b0)-> + l2_classify.opaque_index); + } + else if (node_type == NSH_AWARE_VNF_PROXY_TYPE) + { + /* Push dummy Eth header */ + char dummy_dst_address[6] = + { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 }; + char dummy_src_address[6] = + { 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc }; + clib_memcpy_fast (dummy_eth0.dst_address, dummy_dst_address, 6); + clib_memcpy_fast (dummy_eth0.src_address, dummy_src_address, 6); + dummy_eth0.type = 0x0800; + vlib_buffer_advance (b0, -(word) sizeof (ethernet_header_t)); + hdr0 = vlib_buffer_get_current (b0); + clib_memcpy_fast (hdr0, &dummy_eth0, + (word) sizeof (ethernet_header_t)); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + nsp_nsi0 = nm->tunnel_index_by_sw_if_index[sw_if_index0]; + } + else + { + clib_memset (&key0, 0, sizeof (key0)); + key0.transport_type = NSH_NODE_NEXT_ENCAP_VXLAN4; + key0.transport_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + + p0 = hash_get_mem (nm->nsh_proxy_session_by_key, &key0); + if (PREDICT_FALSE (p0 == 0)) + { + error0 = NSH_NODE_ERROR_NO_PROXY; + goto trace00; + } + + proxy0 = pool_elt_at_index (nm->nsh_proxy_sessions, p0[0]); + if (PREDICT_FALSE (proxy0 == 0)) + { + error0 = NSH_NODE_ERROR_NO_PROXY; + goto trace00; + } + nsp_nsi0 = proxy0->nsp_nsi; + } + + entry0 = hash_get_mem (nm->nsh_mapping_by_key, &nsp_nsi0); + + if (PREDICT_FALSE (entry0 == 0)) + { + error0 = NSH_NODE_ERROR_NO_MAPPING; + goto trace00; + } + + /* Entry should point to a mapping ... */ + map0 = pool_elt_at_index (nm->nsh_mappings, entry0[0]); + + if (PREDICT_FALSE (map0 == 0)) + { + error0 = NSH_NODE_ERROR_NO_MAPPING; + goto trace00; + } + + /* set up things for next node to transmit ie which node to handle it and where */ + next0 = map0->next_node; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = map0->sw_if_index; + vnet_buffer (b0)->ip.adj_index[VLIB_TX] = map0->adj_index; + vnet_buffer (b0)->sw_if_index[VLIB_RX] = map0->nsh_sw_if; + + if (PREDICT_FALSE (map0->nsh_action == NSH_ACTION_POP)) + { + /* Manipulate MD2 */ + if (PREDICT_FALSE (hdr0->md_type == 2)) + { + nsh_md2_decap (b0, hdr0, &header_len0, &next0, + NSH_NODE_NEXT_DROP); + if (PREDICT_FALSE (next0 == NSH_NODE_NEXT_DROP)) + { + error0 = NSH_NODE_ERROR_INVALID_OPTIONS; + goto trace00; + } + vnet_buffer (b0)->sw_if_index[VLIB_RX] = + map0->rx_sw_if_index; + } + + /* Pop NSH header */ + vlib_buffer_advance (b0, (word) header_len0); + goto trace00; + } + + entry0 = hash_get_mem (nm->nsh_entry_by_key, &map0->mapped_nsp_nsi); + if (PREDICT_FALSE (entry0 == 0)) + { + error0 = NSH_NODE_ERROR_NO_ENTRY; + goto trace00; + } + + nsh_entry0 = + (nsh_entry_t *) pool_elt_at_index (nm->nsh_entries, entry0[0]); + encap_hdr0 = (nsh_base_header_t *) (nsh_entry0->rewrite); + /* rewrite_size should equal to (encap_hdr0->length * 4) */ + encap_hdr_len0 = nsh_entry0->rewrite_size; + + if (PREDICT_TRUE (map0->nsh_action == NSH_ACTION_SWAP)) + { + /* Manipulate MD2 */ + if (PREDICT_FALSE (hdr0->md_type == 2)) + { + nsh_md2_swap (b0, hdr0, header_len0, nsh_entry0, + &next0, NSH_NODE_NEXT_DROP); + if (PREDICT_FALSE (next0 == NSH_NODE_NEXT_DROP)) + { + error0 = NSH_NODE_ERROR_INVALID_OPTIONS; + goto trace00; + } + } + + /* Pop old NSH header */ + vlib_buffer_advance (b0, (word) header_len0); + + /* After processing, md2's length may be varied */ + encap_hdr_len0 = nsh_entry0->rewrite_size; + /* Push new NSH header */ + vlib_buffer_advance (b0, -(word) encap_hdr_len0); + hdr0 = vlib_buffer_get_current (b0); + clib_memcpy_fast (hdr0, encap_hdr0, (word) encap_hdr_len0); + + goto trace00; + } + + if (PREDICT_TRUE (map0->nsh_action == NSH_ACTION_PUSH)) + { + /* After processing, md2's length may be varied */ + encap_hdr_len0 = nsh_entry0->rewrite_size; + /* Push new NSH header */ + vlib_buffer_advance (b0, -(word) encap_hdr_len0); + hdr0 = vlib_buffer_get_current (b0); + clib_memcpy_fast (hdr0, encap_hdr0, (word) encap_hdr_len0); + /* Manipulate MD2 */ + if (PREDICT_FALSE (nsh_entry0->nsh_base.md_type == 2)) + { + nsh_md2_encap (b0, hdr0, nsh_entry0); + } + + } + + trace00:b0->error = error0 ? node->errors[error0] : 0; + + if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) + { + nsh_input_trace_t *tr = + vlib_add_trace (vm, node, b0, sizeof (*tr)); + clib_memcpy_fast (&(tr->trace_data[0]), hdr0, + ((hdr0->length & NSH_LEN_MASK) * 4)); + } + + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, + n_left_to_next, bi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + + } + + return from_frame->n_vectors; +} + +/** + * @brief Graph processing dispatch function for NSH Input + * + * @node nsh_input + * @param *vm + * @param *node + * @param *from_frame + * + * @return from_frame->n_vectors + * + */ +VLIB_NODE_FN (nsh_input) (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + return nsh_input_map (vm, node, from_frame, NSH_INPUT_TYPE); +} + +/** + * @brief Graph processing dispatch function for NSH-Proxy + * + * @node nsh_proxy + * @param *vm + * @param *node + * @param *from_frame + * + * @return from_frame->n_vectors + * + */ +VLIB_NODE_FN (nsh_proxy) (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + return nsh_input_map (vm, node, from_frame, NSH_PROXY_TYPE); +} + +/** + * @brief Graph processing dispatch function for NSH Classifier + * + * @node nsh_classifier + * @param *vm + * @param *node + * @param *from_frame + * + * @return from_frame->n_vectors + * + */ +VLIB_NODE_FN (nsh_classifier) (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + return nsh_input_map (vm, node, from_frame, NSH_CLASSIFIER_TYPE); +} + +/** + * @brief Graph processing dispatch function for NSH-AWARE-VNF-PROXY + * + * @node nsh_aware_vnf_proxy + * @param *vm + * @param *node + * @param *from_frame + * + * @return from_frame->n_vectors + * + */ +VLIB_NODE_FN (nsh_aware_vnf_proxy) (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * from_frame) +{ + return nsh_input_map (vm, node, from_frame, NSH_AWARE_VNF_PROXY_TYPE); +} + +static char *nsh_node_error_strings[] = { +#define _(sym,string) string, + foreach_nsh_node_error +#undef _ +}; + +/* *INDENT-OFF* */ + +/* register nsh-input node */ +VLIB_REGISTER_NODE (nsh_input_node) = { + .name = "nsh-input", + .vector_size = sizeof (u32), + .format_trace = format_nsh_node_map_trace, + .format_buffer = format_nsh_header, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (nsh_node_error_strings), + .error_strings = nsh_node_error_strings, + .n_next_nodes = NSH_NODE_N_NEXT, + .next_nodes = { +#define _(s,n) [NSH_NODE_NEXT_##s] = n, + foreach_nsh_node_next +#undef _ + }, +}; + +/* register nsh-proxy node */ +VLIB_REGISTER_NODE (nsh_proxy_node) = +{ + .name = "nsh-proxy", + .vector_size = sizeof (u32), + .format_trace = format_nsh_node_map_trace, + .format_buffer = format_nsh_header, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (nsh_node_error_strings), + .error_strings = nsh_node_error_strings, + .n_next_nodes = NSH_NODE_N_NEXT, + .next_nodes = { +#define _(s,n) [NSH_NODE_NEXT_##s] = n, + foreach_nsh_node_next +#undef _ + }, +}; + +/* register nsh-classifier node */ +VLIB_REGISTER_NODE (nsh_classifier_node) = +{ + .name = "nsh-classifier", + .vector_size = sizeof (u32), + .format_trace = format_nsh_node_map_trace, + .format_buffer = format_nsh_header, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (nsh_node_error_strings), + .error_strings = nsh_node_error_strings, + .n_next_nodes = NSH_NODE_N_NEXT, + .next_nodes = { +#define _(s,n) [NSH_NODE_NEXT_##s] = n, + foreach_nsh_node_next +#undef _ + }, +}; + +/* register nsh-aware-vnf-proxy node */ +VLIB_REGISTER_NODE (nsh_aware_vnf_proxy_node) = +{ + .name = "nsh-aware-vnf-proxy", + .vector_size = sizeof (u32), + .format_trace = format_nsh_node_map_trace, + .format_buffer = format_nsh_header, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (nsh_node_error_strings), + .error_strings = nsh_node_error_strings, + .n_next_nodes = NSH_NODE_N_NEXT, + .next_nodes = { +#define _(s,n) [NSH_NODE_NEXT_##s] = n, + foreach_nsh_node_next +#undef _ + }, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/nsh/nsh_output.c b/src/plugins/nsh/nsh_output.c index f0ac673cf61..047fe8ae3b2 100644 --- a/src/plugins/nsh/nsh_output.c +++ b/src/plugins/nsh/nsh_output.c @@ -323,8 +323,7 @@ typedef enum nsh_midchain_next_t_ NSH_MIDCHAIN_NEXT_DROP, } nsh_midchain_next_t; -static inline uword -nsh_eth_output (vlib_main_t * vm, +VLIB_NODE_FN (nsh_eth_output) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame) { @@ -332,7 +331,6 @@ nsh_eth_output (vlib_main_t * vm, } VLIB_REGISTER_NODE (nsh_eth_output_node) = { - .function = nsh_eth_output, .name = "nsh-eth-output", /* Takes a vector of packets. */ .vector_size = sizeof (u32), @@ -346,10 +344,7 @@ VLIB_REGISTER_NODE (nsh_eth_output_node) = { .format_trace = format_nsh_output_trace, }; -VLIB_NODE_FUNCTION_MULTIARCH (nsh_eth_output_node, nsh_eth_output) - -static inline uword -nsh_midchain (vlib_main_t * vm, +VLIB_NODE_FN (nsh_midchain) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame) { @@ -357,7 +352,6 @@ nsh_midchain (vlib_main_t * vm, } VLIB_REGISTER_NODE (nsh_midchain_node) = { - .function = nsh_midchain, .name = "nsh-midchain", .vector_size = sizeof (u32), .format_trace = format_nsh_output_trace, @@ -367,8 +361,6 @@ VLIB_REGISTER_NODE (nsh_midchain_node) = { }, }; -VLIB_NODE_FUNCTION_MULTIARCH (nsh_midchain_node, nsh_midchain) - /* Built-in nsh tx feature path definition */ VNET_FEATURE_INIT (nsh_interface_output, static) = { .arc_name = "nsh-eth-output", @@ -423,8 +415,7 @@ typedef struct nsh_adj_incomplete_trace_t_ * We pay a cost for this 'routing' node, but an incomplete adj is the * exception case. */ -static inline uword -nsh_adj_incomplete (vlib_main_t * vm, +VLIB_NODE_FN (nsh_adj_incomplete) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame) { @@ -503,7 +494,6 @@ format_nsh_adj_incomplete_trace (u8 * s, va_list * args) } VLIB_REGISTER_NODE (nsh_adj_incomplete_node) = { - .function = nsh_adj_incomplete, .name = "nsh-adj-incomplete", .format_trace = format_nsh_adj_incomplete_trace, /* Takes a vector of packets. */ @@ -516,5 +506,3 @@ VLIB_REGISTER_NODE (nsh_adj_incomplete_node) = { }, }; -VLIB_NODE_FUNCTION_MULTIARCH (nsh_adj_incomplete_node, - nsh_adj_incomplete) diff --git a/src/plugins/nsh/nsh_pop.c b/src/plugins/nsh/nsh_pop.c index 682a92d178a..15d50fdfeea 100644 --- a/src/plugins/nsh/nsh_pop.c +++ b/src/plugins/nsh/nsh_pop.c @@ -30,20 +30,8 @@ extern nsh_option_map_t * nsh_md2_lookup_option (u16 class, u8 type); extern u8 * format_nsh_header (u8 * s, va_list * args); extern u8 * format_nsh_node_map_trace (u8 * s, va_list * args); - -/* format from network order */ -u8 * format_nsh_pop_header (u8 * s, va_list * args) -{ - return format_nsh_header(s, args); -} - - - -u8 * format_nsh_pop_node_map_trace (u8 * s, va_list * args) -{ - return format_nsh_node_map_trace(s, args); -} - +extern u8 * format_nsh_pop_header (u8 * s, va_list * args); +extern u8 * format_nsh_pop_node_map_trace (u8 * s, va_list * args); static uword nsh_pop_inline (vlib_main_t * vm, @@ -326,8 +314,7 @@ nsh_pop_inline (vlib_main_t * vm, * @return from_frame->n_vectors * */ -static uword -nsh_pop (vlib_main_t * vm, vlib_node_runtime_t * node, +VLIB_NODE_FN (nsh_pop) (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame) { return nsh_pop_inline (vm, node, from_frame); @@ -341,7 +328,6 @@ static char * nsh_pop_node_error_strings[] = { /* register nsh-input node */ VLIB_REGISTER_NODE (nsh_pop_node) = { - .function = nsh_pop, .name = "nsh-pop", .vector_size = sizeof (u32), .format_trace = format_nsh_pop_node_map_trace, @@ -360,6 +346,3 @@ VLIB_REGISTER_NODE (nsh_pop_node) = { }, }; -VLIB_NODE_FUNCTION_MULTIARCH (nsh_pop_node, nsh_pop); - - |