ccae5544c851e7aabeade7c4d76a23ad20e352ea
[vpp.git] / src / plugins / nsh / nsh_api.c
1 /*
2  * nsh_api.c - nsh mapping api
3  *
4  * Copyright (c) 2019 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 #include <vnet/vnet.h>
18 #include <vnet/plugin/plugin.h>
19 #include <nsh/nsh.h>
20
21 #include <vlibapi/api.h>
22 #include <vlibmemory/api.h>
23 #include <vpp/app/version.h>
24
25 /* define message IDs */
26 #define vl_msg_id(n,h) n,
27 typedef enum
28 {
29 #include <nsh/nsh.api.h>
30   /* We'll want to know how many messages IDs we need... */
31   VL_MSG_FIRST_AVAILABLE,
32 } vl_msg_id_t;
33 #undef vl_msg_id
34
35 /* define message structures */
36 #define vl_typedefs
37 #include <nsh/nsh.api.h>
38 #undef vl_typedefs
39
40 /* define generated endian-swappers */
41 #define vl_endianfun
42 #include <nsh/nsh.api.h>
43 #undef vl_endianfun
44
45 /* instantiate all the print functions we know about */
46 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
47 #define vl_printfun
48 #include <nsh/nsh.api.h>
49 #undef vl_printfun
50
51 /* Get the API version number */
52 #define vl_api_version(n,v) static u32 api_version=(v);
53 #include <nsh/nsh.api.h>
54 #undef vl_api_version
55
56 #define vl_msg_name_crc_list
57 #include <nsh/nsh.api.h>
58 #undef vl_msg_name_crc_list
59
60 /*
61  * A handy macro to set up a message reply.
62  * Assumes that the following variables are available:
63  * mp - pointer to request message
64  * rmp - pointer to reply message type
65  * rv - return value
66  */
67
68 #define REPLY_MACRO(t)                                          \
69   do {                                                          \
70     unix_shared_memory_queue_t * q =                            \
71       vl_api_client_index_to_input_queue (mp->client_index);    \
72     if (!q)                                                     \
73       return;                                                   \
74                                                                 \
75     rmp = vl_msg_api_alloc (sizeof (*rmp));                     \
76     rmp->_vl_msg_id = ntohs((t)+nm->msg_id_base);               \
77     rmp->context = mp->context;                                 \
78     rmp->retval = ntohl(rv);                                    \
79                                                                 \
80     vl_msg_api_send_shmem (q, (u8 *)&rmp);                      \
81   } while(0);
82
83 #define REPLY_MACRO2(t, body)                                   \
84   do {                                                          \
85     unix_shared_memory_queue_t * q;                             \
86     rv = vl_msg_api_pd_handler (mp, rv);                        \
87     q = vl_api_client_index_to_input_queue (mp->client_index);  \
88     if (!q)                                                     \
89         return;                                                 \
90                                                                 \
91     rmp = vl_msg_api_alloc (sizeof (*rmp));                     \
92     rmp->_vl_msg_id = ntohs((t)+nm->msg_id_base);               \
93     rmp->context = mp->context;                                 \
94     rmp->retval = ntohl(rv);                                    \
95     do {body;} while (0);                                       \
96     vl_msg_api_send_shmem (q, (u8 *)&rmp);                      \
97   } while(0);
98
99 /* List of message types that this plugin understands */
100
101 #define foreach_nsh_plugin_api_msg              \
102   _(NSH_ADD_DEL_ENTRY, nsh_add_del_entry)       \
103   _(NSH_ENTRY_DUMP, nsh_entry_dump)             \
104   _(NSH_ADD_DEL_MAP, nsh_add_del_map)           \
105   _(NSH_MAP_DUMP, nsh_map_dump)
106
107 /**
108  * @brief CLI function for NSH admin up/down
109  *
110  * @param *vnm
111  * @param nsh_hw_if
112  * @param flag
113  *
114  * @return *rc
115  *
116  */
117 static clib_error_t *
118 nsh_interface_admin_up_down (vnet_main_t * vnm, u32 nsh_hw_if, u32 flags)
119 {
120   if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
121     vnet_hw_interface_set_flags (vnm, nsh_hw_if,
122                                  VNET_HW_INTERFACE_FLAG_LINK_UP);
123   else
124     vnet_hw_interface_set_flags (vnm, nsh_hw_if, 0);
125
126   return 0;
127 }
128
129 static uword
130 dummy_interface_tx (vlib_main_t * vm,
131                     vlib_node_runtime_t * node, vlib_frame_t * frame)
132 {
133   clib_warning ("you shouldn't be here, leaking buffers...");
134   return frame->n_vectors;
135 }
136
137 /**
138  * @brief Naming for NSH tunnel
139  *
140  * @param *s formatting string
141  * @param *args
142  *
143  * @return *s formatted string
144  *
145  */
146 static u8 *
147 format_nsh_name (u8 * s, va_list * args)
148 {
149   u32 dev_instance = va_arg (*args, u32);
150   return format (s, "nsh_tunnel%d", dev_instance);
151 }
152
153 /* *INDENT-OFF* */
154 VNET_DEVICE_CLASS (nsh_device_class, static) = {
155   .name = "NSH",
156   .format_device_name = format_nsh_name,
157   .tx_function = dummy_interface_tx,
158   .admin_up_down_function = nsh_interface_admin_up_down,
159 };
160 /* *INDENT-ON* */
161
162 static void send_nsh_entry_details
163   (nsh_entry_t * t, unix_shared_memory_queue_t * q, u32 context)
164 {
165   vl_api_nsh_entry_details_t *rmp;
166   nsh_main_t *nm = &nsh_main;
167
168   rmp = vl_msg_api_alloc (sizeof (*rmp));
169   clib_memset (rmp, 0, sizeof (*rmp));
170
171   rmp->_vl_msg_id = ntohs ((VL_API_NSH_ENTRY_DETAILS) + nm->msg_id_base);
172   rmp->ver_o_c = t->nsh_base.ver_o_c;
173   rmp->ttl = (t->nsh_base.ver_o_c & NSH_TTL_H4_MASK) << 2 |
174     (t->nsh_base.length & NSH_TTL_L2_MASK) >> 6;
175   rmp->length = t->nsh_base.length & NSH_LEN_MASK;
176   rmp->md_type = t->nsh_base.md_type;
177   rmp->next_protocol = t->nsh_base.next_protocol;
178   rmp->nsp_nsi = htonl (t->nsh_base.nsp_nsi);
179
180   if (t->nsh_base.md_type == 1)
181     {
182       rmp->tlv_length = 4;
183       rmp->c1 = htonl (t->md.md1_data.c1);
184       rmp->c2 = htonl (t->md.md1_data.c2);
185       rmp->c3 = htonl (t->md.md1_data.c3);
186       rmp->c4 = htonl (t->md.md1_data.c4);
187     }
188   else if (t->nsh_base.md_type == 2)
189     {
190       rmp->tlv_length = t->tlvs_len;
191       clib_memcpy (rmp->tlv, t->tlvs_data, t->tlvs_len);
192     }
193
194   rmp->context = context;
195
196   vl_msg_api_send_shmem (q, (u8 *) & rmp);
197 }
198
199 static void send_nsh_map_details
200   (nsh_map_t * t, unix_shared_memory_queue_t * q, u32 context)
201 {
202   vl_api_nsh_map_details_t *rmp;
203   nsh_main_t *nm = &nsh_main;
204
205   rmp = vl_msg_api_alloc (sizeof (*rmp));
206   clib_memset (rmp, 0, sizeof (*rmp));
207
208   rmp->_vl_msg_id = ntohs ((VL_API_NSH_MAP_DETAILS) + nm->msg_id_base);
209   rmp->nsp_nsi = htonl (t->nsp_nsi);
210   rmp->mapped_nsp_nsi = htonl (t->mapped_nsp_nsi);
211   rmp->nsh_action = htonl (t->nsh_action);
212   rmp->sw_if_index = htonl (t->sw_if_index);
213   rmp->rx_sw_if_index = htonl (t->rx_sw_if_index);
214   rmp->next_node = htonl (t->next_node);
215
216   rmp->context = context;
217
218   vl_msg_api_send_shmem (q, (u8 *) & rmp);
219 }
220
221 static void
222 vl_api_nsh_map_dump_t_handler (vl_api_nsh_map_dump_t * mp)
223 {
224   unix_shared_memory_queue_t *q;
225   nsh_main_t *nm = &nsh_main;
226   nsh_map_t *t;
227   u32 map_index;
228
229   q = vl_api_client_index_to_input_queue (mp->client_index);
230   if (q == 0)
231     {
232       return;
233     }
234
235   map_index = ntohl (mp->map_index);
236
237   if (~0 == map_index)
238     {
239       pool_foreach (t, nm->nsh_mappings, (
240                                            {
241                                            send_nsh_map_details (t, q,
242                                                                  mp->context);
243                                            }
244                     ));
245     }
246   else
247     {
248       if (map_index >= vec_len (nm->nsh_mappings))
249         {
250           return;
251         }
252       t = &nm->nsh_mappings[map_index];
253       send_nsh_map_details (t, q, mp->context);
254     }
255 }
256
257 /** API message handler */
258 static void
259 vl_api_nsh_add_del_map_t_handler (vl_api_nsh_add_del_map_t * mp)
260 {
261   vl_api_nsh_add_del_map_reply_t *rmp;
262   nsh_main_t *nm = &nsh_main;
263   int rv;
264   nsh_add_del_map_args_t _a, *a = &_a;
265   u32 map_index = ~0;
266
267   a->is_add = mp->is_add;
268   a->map.nsp_nsi = ntohl (mp->nsp_nsi);
269   a->map.mapped_nsp_nsi = ntohl (mp->mapped_nsp_nsi);
270   a->map.nsh_action = ntohl (mp->nsh_action);
271   a->map.sw_if_index = ntohl (mp->sw_if_index);
272   a->map.rx_sw_if_index = ntohl (mp->rx_sw_if_index);
273   a->map.next_node = ntohl (mp->next_node);
274
275   rv = nsh_add_del_map (a, &map_index);
276
277   if ((a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN4)
278       | (a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN6))
279     {
280       rv = nsh_add_del_proxy_session (a);
281     }
282
283   REPLY_MACRO2 (VL_API_NSH_ADD_DEL_MAP_REPLY, (
284                                                 {
285                                                 rmp->map_index =
286                                                 htonl (map_index);
287                                                 }
288                 ));
289 }
290
291 int
292 nsh_header_rewrite (nsh_entry_t * nsh_entry)
293 {
294   u8 *rw = 0;
295   int len = 0;
296   nsh_base_header_t *nsh_base;
297   nsh_md1_data_t *nsh_md1;
298   nsh_main_t *nm = &nsh_main;
299   nsh_md2_data_t *opt0;
300   nsh_md2_data_t *limit0;
301   nsh_md2_data_t *nsh_md2;
302   nsh_option_map_t _nsh_option, *nsh_option = &_nsh_option;
303   u8 old_option_size = 0;
304   u8 new_option_size = 0;
305
306   vec_free (nsh_entry->rewrite);
307   if (nsh_entry->nsh_base.md_type == 1)
308     {
309       len = sizeof (nsh_base_header_t) + sizeof (nsh_md1_data_t);
310     }
311   else if (nsh_entry->nsh_base.md_type == 2)
312     {
313       /* set to maxim, maybe dataplane will add more TLVs */
314       len = MAX_NSH_HEADER_LEN;
315     }
316   vec_validate_aligned (rw, len - 1, CLIB_CACHE_LINE_BYTES);
317   clib_memset (rw, 0, len);
318
319   nsh_base = (nsh_base_header_t *) rw;
320   nsh_base->ver_o_c = nsh_entry->nsh_base.ver_o_c;
321   nsh_base->length = nsh_entry->nsh_base.length;
322   nsh_base->md_type = nsh_entry->nsh_base.md_type;
323   nsh_base->next_protocol = nsh_entry->nsh_base.next_protocol;
324   nsh_base->nsp_nsi = clib_host_to_net_u32 (nsh_entry->nsh_base.nsp_nsi);
325
326   if (nsh_base->md_type == 1)
327     {
328       nsh_md1 = (nsh_md1_data_t *) (rw + sizeof (nsh_base_header_t));
329       nsh_md1->c1 = clib_host_to_net_u32 (nsh_entry->md.md1_data.c1);
330       nsh_md1->c2 = clib_host_to_net_u32 (nsh_entry->md.md1_data.c2);
331       nsh_md1->c3 = clib_host_to_net_u32 (nsh_entry->md.md1_data.c3);
332       nsh_md1->c4 = clib_host_to_net_u32 (nsh_entry->md.md1_data.c4);
333       nsh_entry->rewrite_size = 24;
334     }
335   else if (nsh_base->md_type == 2)
336     {
337       opt0 = (nsh_md2_data_t *) (nsh_entry->tlvs_data);
338       limit0 = (nsh_md2_data_t *) ((u8 *) opt0 + nsh_entry->tlvs_len);
339
340       nsh_md2 = (nsh_md2_data_t *) (rw + sizeof (nsh_base_header_t));
341       nsh_entry->rewrite_size = sizeof (nsh_base_header_t);
342
343       while (opt0 < limit0)
344         {
345           old_option_size = sizeof (nsh_md2_data_t) + opt0->length;
346           /* round to 4-byte */
347           old_option_size = ((old_option_size + 3) >> 2) << 2;
348
349           nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type);
350           if (nsh_option == NULL)
351             {
352               goto next_tlv_md2;
353             }
354
355           if (nm->add_options[nsh_option->option_id] != NULL)
356             {
357               if (0 != nm->add_options[nsh_option->option_id] ((u8 *) nsh_md2,
358                                                                &new_option_size))
359                 {
360                   goto next_tlv_md2;
361                 }
362
363               /* round to 4-byte */
364               new_option_size = ((new_option_size + 3) >> 2) << 2;
365
366               nsh_entry->rewrite_size += new_option_size;
367               nsh_md2 =
368                 (nsh_md2_data_t *) (((u8 *) nsh_md2) + new_option_size);
369               opt0 = (nsh_md2_data_t *) (((u8 *) opt0) + old_option_size);
370             }
371           else
372             {
373             next_tlv_md2:
374               opt0 = (nsh_md2_data_t *) (((u8 *) opt0) + old_option_size);
375             }
376
377         }
378     }
379
380   nsh_entry->rewrite = rw;
381   nsh_base->length = (nsh_base->length & NSH_TTL_L2_MASK) |
382     ((nsh_entry->rewrite_size >> 2) & NSH_LEN_MASK);
383
384   return 0;
385 }
386
387 extern vnet_hw_interface_class_t nsh_hw_class;
388
389 /**
390  * Action function to add or del an nsh map.
391  * Shared by both CLI and binary API
392  **/
393 int
394 nsh_add_del_map (nsh_add_del_map_args_t * a, u32 * map_indexp)
395 {
396   nsh_main_t *nm = &nsh_main;
397   vnet_main_t *vnm = nm->vnet_main;
398   nsh_map_t *map = 0;
399   u32 key, *key_copy;
400   uword *entry;
401   hash_pair_t *hp;
402   u32 map_index = ~0;
403   vnet_hw_interface_t *hi;
404   u32 nsh_hw_if = ~0;
405   u32 nsh_sw_if = ~0;
406
407   /* net order, so data plane could use nsh header to lookup directly */
408   key = clib_host_to_net_u32 (a->map.nsp_nsi);
409
410   entry = hash_get_mem (nm->nsh_mapping_by_key, &key);
411
412   if (a->is_add)
413     {
414       /* adding an entry, must not already exist */
415       if (entry)
416         return -1;              //TODO API_ERROR_INVALID_VALUE;
417
418       pool_get_aligned (nm->nsh_mappings, map, CLIB_CACHE_LINE_BYTES);
419       clib_memset (map, 0, sizeof (*map));
420
421       /* copy from arg structure */
422       map->nsp_nsi = a->map.nsp_nsi;
423       map->mapped_nsp_nsi = a->map.mapped_nsp_nsi;
424       map->nsh_action = a->map.nsh_action;
425       map->sw_if_index = a->map.sw_if_index;
426       map->rx_sw_if_index = a->map.rx_sw_if_index;
427       map->next_node = a->map.next_node;
428       map->adj_index = a->map.adj_index;
429
430
431       key_copy = clib_mem_alloc (sizeof (*key_copy));
432       clib_memcpy (key_copy, &key, sizeof (*key_copy));
433
434       hash_set_mem (nm->nsh_mapping_by_key, key_copy, map - nm->nsh_mappings);
435       map_index = map - nm->nsh_mappings;
436
437       if (vec_len (nm->free_nsh_tunnel_hw_if_indices) > 0)
438         {
439           nsh_hw_if = nm->free_nsh_tunnel_hw_if_indices
440             [vec_len (nm->free_nsh_tunnel_hw_if_indices) - 1];
441           _vec_len (nm->free_nsh_tunnel_hw_if_indices) -= 1;
442
443           hi = vnet_get_hw_interface (vnm, nsh_hw_if);
444           hi->dev_instance = map_index;
445           hi->hw_instance = hi->dev_instance;
446         }
447       else
448         {
449           nsh_hw_if = vnet_register_interface
450             (vnm, nsh_device_class.index, map_index, nsh_hw_class.index,
451              map_index);
452           hi = vnet_get_hw_interface (vnm, nsh_hw_if);
453           hi->output_node_index = nsh_aware_vnf_proxy_node.index;
454         }
455
456       map->nsh_hw_if = nsh_hw_if;
457       map->nsh_sw_if = nsh_sw_if = hi->sw_if_index;
458       vec_validate_init_empty (nm->tunnel_index_by_sw_if_index, nsh_sw_if,
459                                ~0);
460       nm->tunnel_index_by_sw_if_index[nsh_sw_if] = key;
461
462       vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
463                                    VNET_SW_INTERFACE_FLAG_ADMIN_UP);
464     }
465   else
466     {
467       if (!entry)
468         return -2;              //TODO API_ERROR_NO_SUCH_ENTRY;
469
470       map = pool_elt_at_index (nm->nsh_mappings, entry[0]);
471
472       vnet_sw_interface_set_flags (vnm, map->nsh_sw_if,
473                                    VNET_SW_INTERFACE_FLAG_ADMIN_DOWN);
474       vec_add1 (nm->free_nsh_tunnel_hw_if_indices, map->nsh_sw_if);
475       nm->tunnel_index_by_sw_if_index[map->nsh_sw_if] = ~0;
476
477       hp = hash_get_pair (nm->nsh_mapping_by_key, &key);
478       key_copy = (void *) (hp->key);
479       hash_unset_mem (nm->nsh_mapping_by_key, &key);
480       clib_mem_free (key_copy);
481
482       pool_put (nm->nsh_mappings, map);
483     }
484
485   if (map_indexp)
486     *map_indexp = map_index;
487
488   return 0;
489 }
490
491 /**
492  * Action function to add or del an nsh-proxy-session.
493  * Shared by both CLI and binary API
494  **/
495 int
496 nsh_add_del_proxy_session (nsh_add_del_map_args_t * a)
497 {
498   nsh_main_t *nm = &nsh_main;
499   nsh_proxy_session_t *proxy = 0;
500   nsh_proxy_session_by_key_t key, *key_copy;
501   uword *entry;
502   hash_pair_t *hp;
503   u32 nsp = 0, nsi = 0;
504
505   clib_memset (&key, 0, sizeof (key));
506   key.transport_type = a->map.next_node;
507   key.transport_index = a->map.sw_if_index;
508
509   entry = hash_get_mem (nm->nsh_proxy_session_by_key, &key);
510
511   if (a->is_add)
512     {
513       /* adding an entry, must not already exist */
514       if (entry)
515         return -1;              //TODO API_ERROR_INVALID_VALUE;
516
517       pool_get_aligned (nm->nsh_proxy_sessions, proxy, CLIB_CACHE_LINE_BYTES);
518       clib_memset (proxy, 0, sizeof (*proxy));
519
520       /* Nsi needs to minus 1 within NSH-Proxy */
521       nsp = (a->map.nsp_nsi >> NSH_NSP_SHIFT) & NSH_NSP_MASK;
522       nsi = a->map.nsp_nsi & NSH_NSI_MASK;
523       if (nsi == 0)
524         return -1;
525
526       nsi = nsi - 1;
527       /* net order, so could use it to lookup nsh map table directly */
528       proxy->nsp_nsi = clib_host_to_net_u32 ((nsp << NSH_NSP_SHIFT) | nsi);
529
530       key_copy = clib_mem_alloc (sizeof (*key_copy));
531       clib_memcpy (key_copy, &key, sizeof (*key_copy));
532
533       hash_set_mem (nm->nsh_proxy_session_by_key, key_copy,
534                     proxy - nm->nsh_proxy_sessions);
535     }
536   else
537     {
538       if (!entry)
539         return -2;              //TODO API_ERROR_NO_SUCH_ENTRY;
540
541       proxy = pool_elt_at_index (nm->nsh_proxy_sessions, entry[0]);
542       hp = hash_get_pair (nm->nsh_proxy_session_by_key, &key);
543       key_copy = (void *) (hp->key);
544       hash_unset_mem (nm->nsh_proxy_session_by_key, &key);
545       clib_mem_free (key_copy);
546
547       pool_put (nm->nsh_proxy_sessions, proxy);
548     }
549
550   return 0;
551 }
552
553 /**
554  * Action function for adding an NSH entry
555  * nsh_add_del_entry_args_t *a: host order
556  */
557 int
558 nsh_add_del_entry (nsh_add_del_entry_args_t * a, u32 * entry_indexp)
559 {
560   nsh_main_t *nm = &nsh_main;
561   nsh_entry_t *nsh_entry = 0;
562   u32 key, *key_copy;
563   uword *entry_id;
564   hash_pair_t *hp;
565   u32 entry_index = ~0;
566   u8 tlvs_len = 0;
567   u8 *data = 0;
568
569   /* host order, because nsh map table stores nsp_nsi in host order */
570   key = a->nsh_entry.nsh_base.nsp_nsi;
571
572   entry_id = hash_get_mem (nm->nsh_entry_by_key, &key);
573
574   if (a->is_add)
575     {
576       /* adding an entry, must not already exist */
577       if (entry_id)
578         return -1;              // TODO VNET_API_ERROR_INVALID_VALUE;
579
580       pool_get_aligned (nm->nsh_entries, nsh_entry, CLIB_CACHE_LINE_BYTES);
581       clib_memset (nsh_entry, 0, sizeof (*nsh_entry));
582
583       /* copy from arg structure */
584 #define _(x) nsh_entry->nsh_base.x = a->nsh_entry.nsh_base.x;
585       foreach_copy_nsh_base_hdr_field;
586 #undef _
587
588       if (a->nsh_entry.nsh_base.md_type == 1)
589         {
590           nsh_entry->md.md1_data.c1 = a->nsh_entry.md.md1_data.c1;
591           nsh_entry->md.md1_data.c2 = a->nsh_entry.md.md1_data.c2;
592           nsh_entry->md.md1_data.c3 = a->nsh_entry.md.md1_data.c3;
593           nsh_entry->md.md1_data.c4 = a->nsh_entry.md.md1_data.c4;
594         }
595       else if (a->nsh_entry.nsh_base.md_type == 2)
596         {
597           vec_free (nsh_entry->tlvs_data);
598           tlvs_len = a->nsh_entry.tlvs_len;
599           vec_validate_aligned (data, tlvs_len - 1, CLIB_CACHE_LINE_BYTES);
600
601           clib_memcpy (data, a->nsh_entry.tlvs_data, tlvs_len);
602           nsh_entry->tlvs_data = data;
603           nsh_entry->tlvs_len = tlvs_len;
604           vec_free (a->nsh_entry.tlvs_data);
605         }
606
607       nsh_header_rewrite (nsh_entry);
608
609       key_copy = clib_mem_alloc (sizeof (*key_copy));
610       clib_memcpy (key_copy, &key, sizeof (*key_copy));
611
612       hash_set_mem (nm->nsh_entry_by_key, key_copy,
613                     nsh_entry - nm->nsh_entries);
614       entry_index = nsh_entry - nm->nsh_entries;
615     }
616   else
617     {
618       if (!entry_id)
619         return -2;              //TODO API_ERROR_NO_SUCH_ENTRY;
620
621       nsh_entry = pool_elt_at_index (nm->nsh_entries, entry_id[0]);
622       hp = hash_get_pair (nm->nsh_entry_by_key, &key);
623       key_copy = (void *) (hp->key);
624       hash_unset_mem (nm->nsh_entry_by_key, &key);
625       clib_mem_free (key_copy);
626
627       vec_free (nsh_entry->tlvs_data);
628       vec_free (nsh_entry->rewrite);
629       pool_put (nm->nsh_entries, nsh_entry);
630     }
631
632   if (entry_indexp)
633     *entry_indexp = entry_index;
634
635   return 0;
636 }
637
638
639 /** API message handler */
640 static void vl_api_nsh_add_del_entry_t_handler
641   (vl_api_nsh_add_del_entry_t * mp)
642 {
643   vl_api_nsh_add_del_entry_reply_t *rmp;
644   nsh_main_t *nm = &nsh_main;
645   int rv;
646   nsh_add_del_entry_args_t _a, *a = &_a;
647   u32 entry_index = ~0;
648   u8 tlvs_len = 0;
649   u8 *data = 0;
650
651   a->is_add = mp->is_add;
652   a->nsh_entry.nsh_base.ver_o_c =
653     (mp->ver_o_c & 0xF0) | ((mp->ttl & NSH_LEN_MASK) >> 2);
654   a->nsh_entry.nsh_base.length =
655     (mp->length & NSH_LEN_MASK) | ((mp->ttl & 0x3) << 6);
656   a->nsh_entry.nsh_base.md_type = mp->md_type;
657   a->nsh_entry.nsh_base.next_protocol = mp->next_protocol;
658   a->nsh_entry.nsh_base.nsp_nsi = ntohl (mp->nsp_nsi);
659   if (mp->md_type == 1)
660     {
661       a->nsh_entry.md.md1_data.c1 = ntohl (mp->c1);
662       a->nsh_entry.md.md1_data.c2 = ntohl (mp->c2);
663       a->nsh_entry.md.md1_data.c3 = ntohl (mp->c3);
664       a->nsh_entry.md.md1_data.c4 = ntohl (mp->c4);
665     }
666   else if (mp->md_type == 2)
667     {
668       tlvs_len = mp->tlv_length;
669       vec_validate_aligned (data, tlvs_len - 1, CLIB_CACHE_LINE_BYTES);
670
671       clib_memcpy (data, mp->tlv, tlvs_len);
672       a->nsh_entry.tlvs_data = data;
673       a->nsh_entry.tlvs_len = tlvs_len;
674     }
675
676   rv = nsh_add_del_entry (a, &entry_index);
677
678   REPLY_MACRO2 (VL_API_NSH_ADD_DEL_ENTRY_REPLY, (
679                                                   {
680                                                   rmp->entry_index =
681                                                   htonl (entry_index);
682                                                   }
683                 ));
684 }
685
686 static void
687 vl_api_nsh_entry_dump_t_handler (vl_api_nsh_entry_dump_t * mp)
688 {
689   unix_shared_memory_queue_t *q;
690   nsh_main_t *nm = &nsh_main;
691   nsh_entry_t *t;
692   u32 entry_index;
693
694   q = vl_api_client_index_to_input_queue (mp->client_index);
695   if (q == 0)
696     {
697       return;
698     }
699
700   entry_index = ntohl (mp->entry_index);
701
702   if (~0 == entry_index)
703     {
704       pool_foreach (t, nm->nsh_entries, (
705                                           {
706                                           send_nsh_entry_details (t, q,
707                                                                   mp->context);
708                                           }
709                     ));
710     }
711   else
712     {
713       if (entry_index >= vec_len (nm->nsh_entries))
714         {
715           return;
716         }
717       t = &nm->nsh_entries[entry_index];
718       send_nsh_entry_details (t, q, mp->context);
719     }
720 }
721
722 static void
723 setup_message_id_table (nsh_main_t * nm, api_main_t * am)
724 {
725 #define _(id,n,crc) \
726   vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + nm->msg_id_base);
727   foreach_vl_msg_name_crc_nsh;
728 #undef _
729 }
730
731 /* Set up the API message handling tables */
732 static clib_error_t *
733 nsh_plugin_api_hookup (vlib_main_t * vm)
734 {
735   nsh_main_t *nm __attribute__ ((unused)) = &nsh_main;
736 #define _(N,n)                                                  \
737   vl_msg_api_set_handlers((VL_API_##N + nm->msg_id_base),       \
738                           #n,                                   \
739                           vl_api_##n##_t_handler,               \
740                           vl_noop_handler,                      \
741                           vl_api_##n##_t_endian,                \
742                           vl_api_##n##_t_print,                 \
743                           sizeof(vl_api_##n##_t), 1);
744   foreach_nsh_plugin_api_msg;
745 #undef _
746
747   return 0;
748 }
749
750 clib_error_t *
751 nsh_api_init (vlib_main_t * vm, nsh_main_t * nm)
752 {
753   clib_error_t *error;
754   u8 *name;
755
756   name = format (0, "nsh_%08x%c", api_version, 0);
757
758   /* Set up the API */
759   nm->msg_id_base = vl_msg_api_get_msg_ids
760     ((char *) name, VL_MSG_FIRST_AVAILABLE);
761
762   error = nsh_plugin_api_hookup (vm);
763
764   /* Add our API messages to the global name_crc hash table */
765   setup_message_id_table (nm, &api_main);
766
767   vec_free (name);
768
769   return error;
770 }
771
772 /*
773  * fd.io coding-style-patch-verification: ON
774  *
775  * Local Variables:
776  * eval: (c-set-style "gnu")
777  * End:
778  */