nsh_api.c revision 39d69112
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,
27typedef 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 */
81static clib_error_t *
82nsh_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 */
102static u8 *
103format_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* */
110VNET_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
117static 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
154static 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
176static void
177vl_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 */
211static void
212vl_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
244int
245nsh_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
340extern 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 **/
346int
347nsh_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 **/
448int
449nsh_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 */
510int
511nsh_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 */
593static 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
639static void
640vl_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
673static void
674setup_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 */
683static clib_error_t *
684nsh_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
701clib_error_t *
702nsh_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 */
730