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