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