
Type: refactor Change-Id: I5235bf3e9aff58af6ba2c14e8c6529c4fc9ec86c Signed-off-by: Damjan Marion <damarion@cisco.com>
297 lines
8.4 KiB
C
297 lines
8.4 KiB
C
/*
|
|
* 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 <gre/gre.h>
|
|
#include <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;
|
|
}
|
|
|
|
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,
|
|
};
|
|
|
|
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, *gre4_input, *gre6_input;
|
|
nsh_main_t *nm = &nsh_main;
|
|
clib_error_t *error = 0;
|
|
uword next_node;
|
|
vlib_node_registration_t *vxlan4_input, *vxlan6_input;
|
|
|
|
/* 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);
|
|
|
|
gre4_input = vlib_get_node_by_name (vm, (u8 *) "gre4-input");
|
|
gre6_input = vlib_get_node_by_name (vm, (u8 *) "gre6-input");
|
|
if (gre4_input == 0 || gre6_input == 0)
|
|
{
|
|
error = clib_error_return (0, "gre_plugin.so is not loaded");
|
|
return error;
|
|
}
|
|
vlib_node_add_next (vm, gre4_input->index, nm->nsh_input_node_index);
|
|
vlib_node_add_next (vm, gre4_input->index, nm->nsh_proxy_node_index);
|
|
vlib_node_add_next (vm, gre4_input->index, nsh_aware_vnf_proxy_node.index);
|
|
vlib_node_add_next (vm, gre6_input->index, nm->nsh_input_node_index);
|
|
vlib_node_add_next (vm, gre6_input->index, nm->nsh_proxy_node_index);
|
|
vlib_node_add_next (vm, gre6_input->index, nsh_aware_vnf_proxy_node.index);
|
|
|
|
/* Add NSH-Proxy support */
|
|
vxlan4_input =
|
|
vlib_get_plugin_symbol ("vxlan_plugin.so", "vxlan4_input_node");
|
|
vxlan6_input =
|
|
vlib_get_plugin_symbol ("vxlan_plugin.so", "vxlan6_input_node");
|
|
if (vxlan4_input == 0 || vxlan6_input == 0)
|
|
{
|
|
error = clib_error_return (0, "vxlan_plugin.so is not loaded");
|
|
return error;
|
|
}
|
|
vlib_node_add_next (vm, vxlan4_input->index, nm->nsh_proxy_node_index);
|
|
vlib_node_add_next (vm, vxlan6_input->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);
|
|
|
|
VLIB_PLUGIN_REGISTER () = {
|
|
.version = VPP_BUILD_VER,
|
|
.description = "Network Service Header (NSH)",
|
|
};
|
|
|
|
/*
|
|
* fd.io coding-style-patch-verification: ON
|
|
*
|
|
* Local Variables:
|
|
* eval: (c-set-style "gnu")
|
|
* End:
|
|
*/
|