| /* |
| * nsh.c - nsh mapping |
| * |
| * 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> |
| #include <vnet/gre/gre.h> |
| #include <vnet/vxlan/vxlan.h> |
| #include <vnet/vxlan-gpe/vxlan_gpe.h> |
| #include <vnet/l2/l2_classify.h> |
| #include <vnet/adj/adj.h> |
| #include <vpp/app/version.h> |
| |
| nsh_main_t nsh_main; |
| |
| /* Uses network order's class and type to register */ |
| int |
| nsh_md2_register_option (u16 class, |
| u8 type, |
| u8 option_size, |
| int add_options (u8 * opt, |
| u8 * opt_size), |
| int options (vlib_buffer_t * b, |
| nsh_tlv_header_t * opt), |
| int swap_options (vlib_buffer_t * b, |
| nsh_tlv_header_t * old_opt, |
| nsh_tlv_header_t * new_opt), |
| int pop_options (vlib_buffer_t * b, |
| nsh_tlv_header_t * opt), |
| u8 * trace (u8 * s, nsh_tlv_header_t * opt)) |
| { |
| nsh_main_t *nm = &nsh_main; |
| nsh_option_map_by_key_t key, *key_copy; |
| uword *p; |
| nsh_option_map_t *nsh_option; |
| |
| key.class = class; |
| key.type = type; |
| key.pad = 0; |
| |
| p = hash_get_mem (nm->nsh_option_map_by_key, &key); |
| /* Already registered */ |
| if (p != 0) |
| { |
| return (-1); |
| } |
| |
| pool_get_aligned (nm->nsh_option_mappings, nsh_option, |
| CLIB_CACHE_LINE_BYTES); |
| clib_memset (nsh_option, 0, sizeof (*nsh_option)); |
| nsh_option->option_id = nsh_option - nm->nsh_option_mappings; |
| |
| key_copy = clib_mem_alloc (sizeof (*key_copy)); |
| clib_memcpy (key_copy, &key, sizeof (*key_copy)); |
| hash_set_mem (nm->nsh_option_map_by_key, key_copy, |
| nsh_option - nm->nsh_option_mappings); |
| |
| if (option_size > (MAX_NSH_OPTION_LEN + sizeof (nsh_tlv_header_t))) |
| { |
| return (-1); |
| } |
| nm->options_size[nsh_option->option_id] = option_size; |
| nm->add_options[nsh_option->option_id] = add_options; |
| nm->options[nsh_option->option_id] = options; |
| nm->swap_options[nsh_option->option_id] = swap_options; |
| nm->pop_options[nsh_option->option_id] = pop_options; |
| nm->trace[nsh_option->option_id] = trace; |
| |
| return (0); |
| } |
| |
| /* Uses network order's class and type to lookup */ |
| nsh_option_map_t * |
| nsh_md2_lookup_option (u16 class, u8 type) |
| { |
| nsh_main_t *nm = &nsh_main; |
| nsh_option_map_by_key_t key; |
| uword *p; |
| |
| key.class = class; |
| key.type = type; |
| key.pad = 0; |
| |
| p = hash_get_mem (nm->nsh_option_map_by_key, &key); |
| /* not registered */ |
| if (p == 0) |
| { |
| return NULL; |
| } |
| |
| return pool_elt_at_index (nm->nsh_option_mappings, p[0]); |
| |
| } |
| |
| /* Uses network order's class and type to unregister */ |
| int |
| nsh_md2_unregister_option (u16 class, |
| u8 type, |
| int options (vlib_buffer_t * b, |
| nsh_tlv_header_t * opt), |
| u8 * trace (u8 * s, nsh_tlv_header_t * opt)) |
| { |
| nsh_main_t *nm = &nsh_main; |
| nsh_option_map_by_key_t key, *key_copy; |
| uword *p; |
| hash_pair_t *hp; |
| nsh_option_map_t *nsh_option; |
| |
| key.class = class; |
| key.type = type; |
| key.pad = 0; |
| |
| p = hash_get_mem (nm->nsh_option_map_by_key, &key); |
| /* not registered */ |
| if (p == 0) |
| { |
| return (-1); |
| } |
| |
| nsh_option = pool_elt_at_index (nm->nsh_option_mappings, p[0]); |
| nm->options[nsh_option->option_id] = NULL; |
| nm->add_options[nsh_option->option_id] = NULL; |
| nm->pop_options[nsh_option->option_id] = NULL; |
| nm->trace[nsh_option->option_id] = NULL; |
| |
| hp = hash_get_pair (nm->nsh_option_map_by_key, &key); |
| key_copy = (void *) (hp->key); |
| hash_unset_mem (nm->nsh_option_map_by_key, &key_copy); |
| clib_mem_free (key_copy); |
| |
| pool_put (nm->nsh_option_mappings, nsh_option); |
| |
| return (0); |
| } |
| |
| /** |
| * @brief Formatting function for tracing VXLAN GPE with length |
| * |
| * @param *s |
| * @param *args |
| * |
| * @return *s |
| * |
| */ |
| static u8 * |
| format_nsh_tunnel_with_length (u8 * s, va_list * args) |
| { |
| u32 dev_instance = va_arg (*args, u32); |
| s = format (s, "unimplemented dev %u", dev_instance); |
| return s; |
| } |
| |
| /* *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, |
| }; |
| /* *INDENT-ON* */ |
| |
| void |
| nsh_md2_set_next_ioam_export_override (uword next) |
| { |
| nsh_main_t *hm = &nsh_main; |
| hm->decap_v4_next_override = 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; |
| uword next_node; |
| |
| /* Init the main structures from VPP */ |
| nm->vlib_main = vm; |
| nm->vnet_main = vnet_get_main (); |
| |
| /* Various state maintenance mappings */ |
| nm->nsh_mapping_by_key = hash_create_mem (0, sizeof (u32), sizeof (uword)); |
| |
| nm->nsh_mapping_by_mapped_key |
| = hash_create_mem (0, sizeof (u32), sizeof (uword)); |
| |
| nm->nsh_entry_by_key = hash_create_mem (0, sizeof (u32), sizeof (uword)); |
| |
| nm->nsh_proxy_session_by_key |
| = |
| hash_create_mem (0, sizeof (nsh_proxy_session_by_key_t), sizeof (uword)); |
| |
| nm->nsh_option_map_by_key |
| = hash_create_mem (0, sizeof (nsh_option_map_by_key_t), sizeof (uword)); |
| |
| error = nsh_api_init (vm, nm); |
| if (error) |
| return error; |
| |
| node = vlib_get_node_by_name (vm, (u8 *) "nsh-input"); |
| nm->nsh_input_node_index = node->index; |
| |
| node = vlib_get_node_by_name (vm, (u8 *) "nsh-proxy"); |
| nm->nsh_proxy_node_index = node->index; |
| |
| 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, |
| 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, |
| 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, 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, 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, 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, |
| 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, |
| nm->nsh_classifier_node_index); |
| |
| /* Add Ethernet+NSH support */ |
| ethernet_register_input_type (vm, ETHERNET_TYPE_NSH, |
| nm->nsh_input_node_index); |
| |
| return error; |
| } |
| |
| VLIB_INIT_FUNCTION (nsh_init); |
| |
| /* *INDENT-OFF* */ |
| VLIB_PLUGIN_REGISTER () = { |
| .version = VPP_BUILD_VER, |
| .description = "Network Service Header", |
| }; |
| /* *INDENT-ON* */ |
| |
| /* |
| * fd.io coding-style-patch-verification: ON |
| * |
| * Local Variables: |
| * eval: (c-set-style "gnu") |
| * End: |
| */ |