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