summaryrefslogtreecommitdiffstats
path: root/src/plugins/nsh/nsh_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/nsh/nsh_api.c')
-rw-r--r--src/plugins/nsh/nsh_api.c724
1 files changed, 724 insertions, 0 deletions
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:
+ */