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