nsh.c revision 7cf94623
1/*
2 * nsh.c - nsh mapping
3 *
4 * Copyright (c) 2013 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
18#include <vnet/vnet.h>
19#include <vnet/plugin/plugin.h>
20#include <nsh/nsh.h>
21#include <vnet/gre/gre.h>
22#include <vnet/vxlan/vxlan.h>
23#include <vnet/vxlan-gpe/vxlan_gpe.h>
24#include <vnet/l2/l2_classify.h>
25#include <vnet/adj/adj.h>
26
27#include <vlibapi/api.h>
28#include <vlibmemory/api.h>
29#include <vlibsocket/api.h>
30
31/* define message IDs */
32#include <vpp-api/nsh_msg_enum.h>
33
34/* define message structures */
35#define vl_typedefs
36#include <vpp-api/nsh_all_api_h.h>
37#undef vl_typedefs
38
39/* define generated endian-swappers */
40#define vl_endianfun
41#include <vpp-api/nsh_all_api_h.h>
42#undef vl_endianfun
43
44/* instantiate all the print functions we know about */
45#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
46#define vl_printfun
47#include <vpp-api/nsh_all_api_h.h>
48#undef vl_printfun
49
50/* Get the API version number */
51#define vl_api_version(n,v) static u32 api_version=(v);
52#include <vpp-api/nsh_all_api_h.h>
53#undef vl_api_version
54
55#define vl_msg_name_crc_list
56#include <vpp-api/nsh_all_api_h.h>
57#undef vl_msg_name_crc_list
58
59/*
60 * A handy macro to set up a message reply.
61 * Assumes that the following variables are available:
62 * mp - pointer to request message
63 * rmp - pointer to reply message type
64 * rv - return value
65 */
66
67#define REPLY_MACRO(t)                                          \
68  do {								\
69    unix_shared_memory_queue_t * q =                            \
70      vl_api_client_index_to_input_queue (mp->client_index);	\
71    if (!q)                                                     \
72      return;							\
73                                                                \
74    rmp = vl_msg_api_alloc (sizeof (*rmp));                     \
75    rmp->_vl_msg_id = ntohs((t)+nm->msg_id_base);               \
76    rmp->context = mp->context;                                 \
77    rmp->retval = ntohl(rv);                                    \
78                                                                \
79    vl_msg_api_send_shmem (q, (u8 *)&rmp);                      \
80  } while(0);
81
82#define REPLY_MACRO2(t, body)                                   \
83  do {                                                          \
84    unix_shared_memory_queue_t * q;                             \
85    rv = vl_msg_api_pd_handler (mp, rv);                        \
86    q = vl_api_client_index_to_input_queue (mp->client_index);  \
87    if (!q)                                                     \
88        return;                                                 \
89                                                                \
90    rmp = vl_msg_api_alloc (sizeof (*rmp));                     \
91    rmp->_vl_msg_id = ntohs((t)+nm->msg_id_base);               \
92    rmp->context = mp->context;                                 \
93    rmp->retval = ntohl(rv);                                    \
94    do {body;} while (0);                                       \
95    vl_msg_api_send_shmem (q, (u8 *)&rmp);                      \
96  } while(0);
97
98#define FINISH                                  \
99    vec_add1 (s, 0);                            \
100    vl_print (handle, (char *)s);               \
101    vec_free (s);                               \
102    return handle;
103
104/* List of message types that this plugin understands */
105
106#define foreach_nsh_plugin_api_msg		\
107  _(NSH_ADD_DEL_ENTRY, nsh_add_del_entry)	\
108  _(NSH_ENTRY_DUMP, nsh_entry_dump)             \
109  _(NSH_ADD_DEL_MAP, nsh_add_del_map)           \
110  _(NSH_MAP_DUMP, nsh_map_dump)
111
112/* *INDENT-OFF* */
113VLIB_PLUGIN_REGISTER () = {
114};
115/* *INDENT-ON* */
116
117 /* Uses network order's class and type to register */
118int
119nsh_md2_register_option (u16 class,
120                      u8 type,
121                      u8 option_size,
122                      int add_options (u8 * opt,
123                                       u8 * opt_size),
124                      int options(vlib_buffer_t * b,
125                                  nsh_tlv_header_t * opt),
126                      int swap_options (vlib_buffer_t * b,
127				        nsh_tlv_header_t * old_opt,
128		                        nsh_tlv_header_t * new_opt),
129                      int pop_options (vlib_buffer_t * b,
130                                       nsh_tlv_header_t * opt),
131                      u8 * trace (u8 * s,
132                                  nsh_tlv_header_t * opt))
133{
134  nsh_main_t *nm = &nsh_main;
135  nsh_option_map_by_key_t key, *key_copy;
136  uword *p;
137  nsh_option_map_t *nsh_option;
138
139  key.class = class;
140  key.type = type;
141  key.pad = 0;
142
143  p = hash_get_mem(nm->nsh_option_map_by_key, &key);
144  /* Already registered */
145  if (p != 0)
146    {
147      return (-1);
148    }
149
150  pool_get_aligned (nm->nsh_option_mappings, nsh_option, CLIB_CACHE_LINE_BYTES);
151  memset (nsh_option, 0, sizeof (*nsh_option));
152  nsh_option->option_id = nsh_option - nm->nsh_option_mappings;
153
154  key_copy = clib_mem_alloc (sizeof (*key_copy));
155  clib_memcpy (key_copy, &key, sizeof (*key_copy));
156  hash_set_mem (nm->nsh_option_map_by_key, key_copy,
157	        nsh_option - nm->nsh_option_mappings);
158
159  if(option_size > (MAX_NSH_OPTION_LEN + sizeof(nsh_tlv_header_t)) )
160    {
161      return (-1);
162    }
163  nm->options_size[nsh_option->option_id] = option_size;
164  nm->add_options[nsh_option->option_id] = add_options;
165  nm->options[nsh_option->option_id] = options;
166  nm->swap_options[nsh_option->option_id] = swap_options;
167  nm->pop_options[nsh_option->option_id] = pop_options;
168  nm->trace[nsh_option->option_id] = trace;
169
170  return (0);
171}
172
173/* Uses network order's class and type to lookup */
174nsh_option_map_t *
175nsh_md2_lookup_option (u16 class, u8 type)
176{
177  nsh_main_t *nm = &nsh_main;
178  nsh_option_map_by_key_t key;
179  uword *p;
180
181  key.class = class;
182  key.type = type;
183  key.pad = 0;
184
185  p = hash_get_mem(nm->nsh_option_map_by_key, &key);
186  /* not registered */
187  if (p == 0)
188    {
189      return NULL;
190    }
191
192  return pool_elt_at_index(nm->nsh_option_mappings, p[0]);
193
194}
195
196/* Uses network order's class and type to unregister */
197int
198nsh_md2_unregister_option (u16 class,
199			u8 type,
200			int options(vlib_buffer_t * b,
201				   nsh_tlv_header_t * opt),
202			u8 * trace (u8 * s,
203				   nsh_tlv_header_t * opt))
204{
205  nsh_main_t *nm = &nsh_main;
206  nsh_option_map_by_key_t key, *key_copy;
207  uword *p;
208  hash_pair_t *hp;
209  nsh_option_map_t *nsh_option;
210
211  key.class = class;
212  key.type = type;
213  key.pad = 0;
214
215  p = hash_get_mem(nm->nsh_option_map_by_key, &key);
216  /* not registered */
217  if (p == 0)
218    {
219      return (-1);
220    }
221
222  nsh_option = pool_elt_at_index(nm->nsh_option_mappings, p[0]);
223  nm->options[nsh_option->option_id] = NULL;
224  nm->add_options[nsh_option->option_id] = NULL;
225  nm->pop_options[nsh_option->option_id] = NULL;
226  nm->trace[nsh_option->option_id] = NULL;
227
228  hp = hash_get_pair (nm->nsh_option_map_by_key, &key);
229  key_copy = (void *)(hp->key);
230  hash_unset_mem (nm->nsh_option_map_by_key, &key_copy);
231  clib_mem_free (key_copy);
232
233  pool_put (nm->nsh_option_mappings, nsh_option);
234
235  return (0);
236}
237
238/* format from network order */
239u8 * format_nsh_header (u8 * s, va_list * args)
240{
241  nsh_main_t *nm = &nsh_main;
242  nsh_md2_data_t *opt0;
243  nsh_md2_data_t *limit0;
244  nsh_option_map_t *nsh_option;
245  u8 option_len = 0;
246
247  u8 * header = va_arg (*args, u8 *);
248  nsh_base_header_t * nsh_base = (nsh_base_header_t *) header ;
249  nsh_md1_data_t * nsh_md1 = (nsh_md1_data_t *)(nsh_base + 1);
250  nsh_md2_data_t * nsh_md2 = (nsh_md2_data_t *)(nsh_base + 1);
251  opt0 = (nsh_md2_data_t *)nsh_md2;
252  limit0 = (nsh_md2_data_t *) ((u8 *) nsh_md2 +
253                              (nsh_base->length*4-sizeof(nsh_base_header_t)) );
254
255  s = format (s, "nsh ver %d ", (nsh_base->ver_o_c>>6));
256  if (nsh_base->ver_o_c & NSH_O_BIT)
257    s = format (s, "O-set ");
258
259  if (nsh_base->ver_o_c & NSH_C_BIT)
260    s = format (s, "C-set ");
261
262  s = format (s, "len %d (%d bytes) md_type %d next_protocol %d\n",
263	      nsh_base->length, nsh_base->length * 4,
264	      nsh_base->md_type, nsh_base->next_protocol);
265
266  s = format (s, "  service path %d service index %d\n",
267        (clib_net_to_host_u32(nsh_base->nsp_nsi)>>NSH_NSP_SHIFT) & NSH_NSP_MASK,
268	 clib_net_to_host_u32(nsh_base->nsp_nsi) & NSH_NSI_MASK);
269
270  if (nsh_base->md_type == 1 )
271    {
272      s = format (s, "  c1 %d c2 %d c3 %d c4 %d\n",
273		  clib_net_to_host_u32(nsh_md1->c1),
274		  clib_net_to_host_u32(nsh_md1->c2),
275		  clib_net_to_host_u32(nsh_md1->c3),
276		  clib_net_to_host_u32(nsh_md1->c4) );
277    }
278  else if (nsh_base->md_type == 2 )
279    {
280      s = format (s, "  Supported TLVs: \n");
281
282      /* Scan the set of variable metadata, network order */
283      while (opt0 < limit0)
284        {
285          nsh_option = nsh_md2_lookup_option(opt0->class, opt0->type);
286          if( nsh_option != NULL)
287    	    {
288    	      if (nm->trace[nsh_option->option_id] != NULL)
289    	        {
290    	          s = (*nm->trace[nsh_option->option_id]) (s, opt0);
291    	        }
292    	      else
293    	        {
294    	          s = format (s, "\n    untraced option %d length %d", opt0->type,
295    			  opt0->length);
296    	        }
297    	    }
298          else
299            {
300              s = format (s, "\n    unrecognized option %d length %d", opt0->type,
301                          opt0->length);
302            }
303
304          /* round to 4-byte */
305          option_len = ( (opt0->length+3)>>2 ) << 2;
306          opt0 = (nsh_md2_data_t *) (((u8 *) opt0) + sizeof (nsh_md2_data_t) + option_len);
307        }
308    }
309
310  return s;
311}
312
313static u8 * format_nsh_action (u8 * s, va_list * args)
314{
315  u32 nsh_action = va_arg (*args, u32);
316
317  switch (nsh_action)
318    {
319    case NSH_ACTION_SWAP:
320      return format (s, "swap");
321    case NSH_ACTION_PUSH:
322      return format (s, "push");
323    case NSH_ACTION_POP:
324      return format (s, "pop");
325    default:
326      return format (s, "unknown %d", nsh_action);
327    }
328  return s;
329}
330
331u8 * format_nsh_map (u8 * s, va_list * args)
332{
333  nsh_map_t * map = va_arg (*args, nsh_map_t *);
334
335  s = format (s, "nsh entry nsp: %d nsi: %d ",
336              (map->nsp_nsi>>NSH_NSP_SHIFT) & NSH_NSP_MASK,
337              map->nsp_nsi & NSH_NSI_MASK);
338  s = format (s, "maps to nsp: %d nsi: %d ",
339              (map->mapped_nsp_nsi>>NSH_NSP_SHIFT) & NSH_NSP_MASK,
340              map->mapped_nsp_nsi & NSH_NSI_MASK);
341
342  s = format (s, " nsh_action %U\n", format_nsh_action, map->nsh_action);
343
344  switch (map->next_node)
345    {
346    case NSH_NODE_NEXT_ENCAP_GRE4:
347      {
348	s = format (s, "encapped by GRE4 intf: %d", map->sw_if_index);
349	break;
350      }
351    case NSH_NODE_NEXT_ENCAP_GRE6:
352      {
353	s = format (s, "encapped by GRE6 intf: %d", map->sw_if_index);
354	break;
355      }
356    case NSH_NODE_NEXT_ENCAP_VXLANGPE:
357      {
358	s = format (s, "encapped by VXLAN GPE intf: %d", map->sw_if_index);
359	break;
360      }
361    case NSH_NODE_NEXT_ENCAP_VXLAN4:
362      {
363	s = format (s, "encapped by VXLAN4 intf: %d", map->sw_if_index);
364	break;
365      }
366    case NSH_NODE_NEXT_ENCAP_VXLAN6:
367      {
368	s = format (s, "encapped by VXLAN6 intf: %d", map->sw_if_index);
369	break;
370      }
371    case NSH_NODE_NEXT_DECAP_ETH_INPUT:
372      {
373	s = format (s, "encap-none");
374	break;
375      }
376    case NSH_NODE_NEXT_ENCAP_LISP_GPE:
377      {
378       s = format (s, "encapped by LISP GPE intf: %d", map->sw_if_index);
379       break;
380      }
381    case NSH_NODE_NEXT_ENCAP_ETHERNET:
382      {
383       s = format (s, "encapped by Ethernet intf: %d", map->sw_if_index);
384       break;
385      }
386    default:
387      s = format (s, "only GRE and VXLANGPE support in this rev");
388    }
389
390  return s;
391}
392
393u8 * format_nsh_node_map_trace (u8 * s, va_list * args)
394{
395  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
396  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
397  nsh_input_trace_t * t
398    = va_arg (*args, nsh_input_trace_t *);
399
400  s = format (s, "\n  %U", format_nsh_header, &(t->trace_data) );
401
402  return s;
403}
404
405/**
406 * @brief Naming for NSH tunnel
407 *
408 * @param *s formatting string
409 * @param *args
410 *
411 * @return *s formatted string
412 *
413 */
414static u8 * format_nsh_name (u8 * s, va_list * args)
415{
416  u32 dev_instance = va_arg (*args, u32);
417  return format (s, "nsh_tunnel%d", dev_instance);
418}
419
420/**
421 * @brief CLI function for NSH admin up/down
422 *
423 * @param *vnm
424 * @param nsh_hw_if
425 * @param flag
426 *
427 * @return *rc
428 *
429 */
430static clib_error_t *
431nsh_interface_admin_up_down (vnet_main_t * vnm, u32 nsh_hw_if, u32 flags)
432{
433  if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
434    vnet_hw_interface_set_flags (vnm, nsh_hw_if, VNET_HW_INTERFACE_FLAG_LINK_UP);
435  else
436    vnet_hw_interface_set_flags (vnm, nsh_hw_if, 0);
437
438  return 0;
439}
440
441static uword dummy_interface_tx (vlib_main_t * vm,
442                                 vlib_node_runtime_t * node,
443                                 vlib_frame_t * frame)
444{
445  clib_warning ("you shouldn't be here, leaking buffers...");
446  return frame->n_vectors;
447}
448
449VNET_DEVICE_CLASS (nsh_device_class,static) = {
450  .name = "NSH",
451  .format_device_name = format_nsh_name,
452  .tx_function = dummy_interface_tx,
453  .admin_up_down_function = nsh_interface_admin_up_down,
454};
455
456/**
457 * @brief Formatting function for tracing VXLAN GPE with length
458 *
459 * @param *s
460 * @param *args
461 *
462 * @return *s
463 *
464 */
465static u8 * format_nsh_tunnel_with_length (u8 * s, va_list * args)
466{
467  u32 dev_instance = va_arg (*args, u32);
468  s = format (s, "unimplemented dev %u", dev_instance);
469  return s;
470}
471
472VNET_HW_INTERFACE_CLASS (nsh_hw_class) = {
473  .name = "NSH",
474  .format_header = format_nsh_tunnel_with_length,
475  .build_rewrite = default_build_rewrite,
476  .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
477};
478
479
480/**
481 * Action function to add or del an nsh map.
482 * Shared by both CLI and binary API
483 **/
484
485int nsh_add_del_map (nsh_add_del_map_args_t *a, u32 * map_indexp)
486{
487  nsh_main_t * nm = &nsh_main;
488  vnet_main_t * vnm = nm->vnet_main;
489  nsh_map_t *map = 0;
490  u32 key, *key_copy;
491  uword * entry;
492  hash_pair_t *hp;
493  u32 map_index = ~0;
494  vnet_hw_interface_t * hi;
495  u32 nsh_hw_if = ~0;
496  u32 nsh_sw_if = ~0;
497
498  /* net order, so data plane could use nsh header to lookup directly */
499  key = clib_host_to_net_u32(a->map.nsp_nsi);
500
501  entry = hash_get_mem (nm->nsh_mapping_by_key, &key);
502
503  if (a->is_add)
504    {
505      /* adding an entry, must not already exist */
506      if (entry)
507        return -1; //TODO API_ERROR_INVALID_VALUE;
508
509      pool_get_aligned (nm->nsh_mappings, map, CLIB_CACHE_LINE_BYTES);
510      memset (map, 0, sizeof (*map));
511
512      /* copy from arg structure */
513      map->nsp_nsi = a->map.nsp_nsi;
514      map->mapped_nsp_nsi = a->map.mapped_nsp_nsi;
515      map->nsh_action = a->map.nsh_action;
516      map->sw_if_index = a->map.sw_if_index;
517      map->rx_sw_if_index = a->map.rx_sw_if_index;
518      map->next_node = a->map.next_node;
519      map->adj_index = a->map.adj_index;
520
521
522      key_copy = clib_mem_alloc (sizeof (*key_copy));
523      clib_memcpy (key_copy, &key, sizeof (*key_copy));
524
525      hash_set_mem (nm->nsh_mapping_by_key, key_copy,
526                    map - nm->nsh_mappings);
527      map_index = map - nm->nsh_mappings;
528
529      if (vec_len (nm->free_nsh_tunnel_hw_if_indices) > 0)
530        {
531          nsh_hw_if = nm->free_nsh_tunnel_hw_if_indices
532            [vec_len (nm->free_nsh_tunnel_hw_if_indices)-1];
533          _vec_len (nm->free_nsh_tunnel_hw_if_indices) -= 1;
534
535          hi = vnet_get_hw_interface (vnm, nsh_hw_if);
536          hi->dev_instance = map_index;
537          hi->hw_instance = hi->dev_instance;
538        }
539      else
540        {
541          nsh_hw_if = vnet_register_interface
542            (vnm, nsh_device_class.index, map_index, nsh_hw_class.index, map_index);
543          hi = vnet_get_hw_interface (vnm, nsh_hw_if);
544          hi->output_node_index = nsh_aware_vnf_proxy_node.index;
545        }
546
547      map->nsh_hw_if = nsh_hw_if;
548      map->nsh_sw_if = nsh_sw_if = hi->sw_if_index;
549      vec_validate_init_empty (nm->tunnel_index_by_sw_if_index, nsh_sw_if, ~0);
550      nm->tunnel_index_by_sw_if_index[nsh_sw_if] = key;
551
552      vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
553                                   VNET_SW_INTERFACE_FLAG_ADMIN_UP);
554    }
555  else
556    {
557      if (!entry)
558	return -2 ; //TODO API_ERROR_NO_SUCH_ENTRY;
559
560      map = pool_elt_at_index (nm->nsh_mappings, entry[0]);
561
562      vnet_sw_interface_set_flags (vnm, map->nsh_sw_if,
563				   VNET_SW_INTERFACE_FLAG_ADMIN_DOWN);
564      vec_add1 (nm->free_nsh_tunnel_hw_if_indices, map->nsh_sw_if);
565      nm->tunnel_index_by_sw_if_index[map->nsh_sw_if] = ~0;
566
567      hp = hash_get_pair (nm->nsh_mapping_by_key, &key);
568      key_copy = (void *)(hp->key);
569      hash_unset_mem (nm->nsh_mapping_by_key, &key);
570      clib_mem_free (key_copy);
571
572      pool_put (nm->nsh_mappings, map);
573    }
574
575  if (map_indexp)
576      *map_indexp = map_index;
577
578  return 0;
579}
580
581/**
582 * Action function to add or del an nsh-proxy-session.
583 * Shared by both CLI and binary API
584 **/
585
586int nsh_add_del_proxy_session (nsh_add_del_map_args_t *a)
587{
588  nsh_main_t * nm = &nsh_main;
589  nsh_proxy_session_t *proxy = 0;
590  nsh_proxy_session_by_key_t key, *key_copy;
591  uword * entry;
592  hash_pair_t *hp;
593  u32 nsp = 0, nsi = 0;
594
595  memset (&key, 0, sizeof (key));
596  key.transport_type = a->map.next_node;
597  key.transport_index = a->map.sw_if_index;
598
599  entry = hash_get_mem (nm->nsh_proxy_session_by_key, &key);
600
601  if (a->is_add)
602    {
603      /* adding an entry, must not already exist */
604      if (entry)
605        return -1; //TODO API_ERROR_INVALID_VALUE;
606
607      pool_get_aligned (nm->nsh_proxy_sessions, proxy, CLIB_CACHE_LINE_BYTES);
608      memset (proxy, 0, sizeof (*proxy));
609
610      /* Nsi needs to minus 1 within NSH-Proxy */
611      nsp = (a->map.nsp_nsi>>NSH_NSP_SHIFT) & NSH_NSP_MASK;
612      nsi = a->map.nsp_nsi & NSH_NSI_MASK;
613      if (nsi == 0 )
614	return -1;
615
616      nsi = nsi -1;
617      /* net order, so could use it to lookup nsh map table directly */
618      proxy->nsp_nsi = clib_host_to_net_u32((nsp<< NSH_NSP_SHIFT) | nsi);
619
620      key_copy = clib_mem_alloc (sizeof (*key_copy));
621      clib_memcpy (key_copy, &key, sizeof (*key_copy));
622
623      hash_set_mem (nm->nsh_proxy_session_by_key, key_copy,
624		    proxy - nm->nsh_proxy_sessions);
625    }
626  else
627    {
628      if (!entry)
629	return -2 ; //TODO API_ERROR_NO_SUCH_ENTRY;
630
631      proxy = pool_elt_at_index (nm->nsh_proxy_sessions, entry[0]);
632      hp = hash_get_pair (nm->nsh_proxy_session_by_key, &key);
633      key_copy = (void *)(hp->key);
634      hash_unset_mem (nm->nsh_proxy_session_by_key, &key);
635      clib_mem_free (key_copy);
636
637      pool_put (nm->nsh_proxy_sessions, proxy);
638    }
639
640  return 0;
641}
642
643/**
644 * CLI command for NSH map
645 */
646
647static uword unformat_nsh_action (unformat_input_t * input, va_list * args)
648{
649  u32 * result = va_arg (*args, u32 *);
650  u32 tmp;
651
652  if (unformat (input, "swap"))
653    *result = NSH_ACTION_SWAP;
654  else if (unformat (input, "push"))
655    *result = NSH_ACTION_PUSH;
656  else if (unformat (input, "pop"))
657    *result = NSH_ACTION_POP;
658  else if (unformat (input, "%d", &tmp))
659    *result = tmp;
660  else
661    return 0;
662
663  return 1;
664}
665
666static adj_index_t
667nsh_get_adj_by_sw_if_index(u32 sw_if_index)
668{
669  adj_index_t ai = ~0;
670
671  /* *INDENT-OFF* */
672  pool_foreach_index(ai, adj_pool,
673  ({
674      if (sw_if_index == adj_get_sw_if_index(ai))
675      {
676        return ai;
677      }
678  }));
679  /* *INDENT-ON* */
680
681  return ~0;
682}
683
684static clib_error_t *
685nsh_add_del_map_command_fn (vlib_main_t * vm,
686			    unformat_input_t * input,
687			    vlib_cli_command_t * cmd)
688{
689  unformat_input_t _line_input, * line_input = &_line_input;
690  u8 is_add = 1;
691  u32 nsp, nsi, mapped_nsp, mapped_nsi, nsh_action;
692  int nsp_set = 0, nsi_set = 0, mapped_nsp_set = 0, mapped_nsi_set = 0;
693  int nsh_action_set = 0;
694  u32 next_node = ~0;
695  u32 adj_index = ~0;
696  u32 sw_if_index = ~0; // temporary requirement to get this moved over to NSHSFC
697  u32 rx_sw_if_index = ~0; // temporary requirement to get this moved over to NSHSFC
698  nsh_add_del_map_args_t _a, * a = &_a;
699  u32 map_index;
700  int rv;
701
702  /* Get a line of input. */
703  if (! unformat_user (input, unformat_line_input, line_input))
704    return 0;
705
706  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
707    if (unformat (line_input, "del"))
708      is_add = 0;
709    else if (unformat (line_input, "nsp %d", &nsp))
710      nsp_set = 1;
711    else if (unformat (line_input, "nsi %d", &nsi))
712      nsi_set = 1;
713    else if (unformat (line_input, "mapped-nsp %d", &mapped_nsp))
714      mapped_nsp_set = 1;
715    else if (unformat (line_input, "mapped-nsi %d", &mapped_nsi))
716      mapped_nsi_set = 1;
717    else if (unformat (line_input, "nsh_action %U", unformat_nsh_action,
718                       &nsh_action))
719      nsh_action_set = 1;
720    else if (unformat (line_input, "encap-gre4-intf %d", &sw_if_index))
721      next_node = NSH_NODE_NEXT_ENCAP_GRE4;
722    else if (unformat (line_input, "encap-gre6-intf %d", &sw_if_index))
723      next_node = NSH_NODE_NEXT_ENCAP_GRE6;
724    else if (unformat (line_input, "encap-vxlan-gpe-intf %d", &sw_if_index))
725      next_node = NSH_NODE_NEXT_ENCAP_VXLANGPE;
726    else if (unformat (line_input, "encap-lisp-gpe-intf %d", &sw_if_index))
727      next_node = NSH_NODE_NEXT_ENCAP_LISP_GPE;
728    else if (unformat (line_input, "encap-vxlan4-intf %d", &sw_if_index))
729      next_node = NSH_NODE_NEXT_ENCAP_VXLAN4;
730    else if (unformat (line_input, "encap-vxlan6-intf %d", &sw_if_index))
731      next_node = NSH_NODE_NEXT_ENCAP_VXLAN6;
732    else if (unformat (line_input, "encap-eth-intf %d", &sw_if_index))
733      {
734        next_node = NSH_NODE_NEXT_ENCAP_ETHERNET;
735        adj_index = nsh_get_adj_by_sw_if_index(sw_if_index);
736      }
737    else if (unformat (line_input, "encap-none %d %d", &sw_if_index, &rx_sw_if_index))
738      next_node = NSH_NODE_NEXT_DECAP_ETH_INPUT;
739    else
740      return clib_error_return (0, "parse error: '%U'",
741                                format_unformat_error, line_input);
742  }
743
744  unformat_free (line_input);
745
746  if (nsp_set == 0 || nsi_set == 0)
747    return clib_error_return (0, "nsp nsi pair required. Key: for NSH entry");
748
749  if (mapped_nsp_set == 0 || mapped_nsi_set == 0)
750    return clib_error_return (0, "mapped-nsp mapped-nsi pair required. Key: for NSH entry");
751
752  if (nsh_action_set == 0 )
753    return clib_error_return (0, "nsh_action required: swap|push|pop.");
754
755  if (next_node == ~0)
756    return clib_error_return (0, "must specific action: [encap-gre-intf <nn> | encap-vxlan-gpe-intf <nn> | encap-lisp-gpe-intf <nn> | encap-none <tx_sw_if_index> <rx_sw_if_index>]");
757
758  memset (a, 0, sizeof (*a));
759
760  /* set args structure */
761  a->is_add = is_add;
762  a->map.nsp_nsi = (nsp<< NSH_NSP_SHIFT) | nsi;
763  a->map.mapped_nsp_nsi = (mapped_nsp<< NSH_NSP_SHIFT) | mapped_nsi;
764  a->map.nsh_action = nsh_action;
765  a->map.sw_if_index = sw_if_index;
766  a->map.rx_sw_if_index = rx_sw_if_index;
767  a->map.next_node = next_node;
768  a->map.adj_index = adj_index;
769
770  rv = nsh_add_del_map(a, &map_index);
771
772  switch(rv)
773    {
774    case 0:
775      break;
776    case -1: //TODO API_ERROR_INVALID_VALUE:
777      return clib_error_return (0, "mapping already exists. Remove it first.");
778
779    case -2: // TODO API_ERROR_NO_SUCH_ENTRY:
780      return clib_error_return (0, "mapping does not exist.");
781
782    default:
783      return clib_error_return
784        (0, "nsh_add_del_map returned %d", rv);
785    }
786
787  if((a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN4)
788      | (a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN6))
789    {
790      rv = nsh_add_del_proxy_session(a);
791
792      switch(rv)
793        {
794        case 0:
795          break;
796        case -1: //TODO API_ERROR_INVALID_VALUE:
797          return clib_error_return (0, "nsh-proxy-session already exists. Remove it first.");
798
799        case -2: // TODO API_ERROR_NO_SUCH_ENTRY:
800          return clib_error_return (0, "nsh-proxy-session does not exist.");
801
802        default:
803          return clib_error_return
804            (0, "nsh_add_del_proxy_session() returned %d", rv);
805        }
806    }
807
808  return 0;
809}
810
811VLIB_CLI_COMMAND (create_nsh_map_command, static) = {
812  .path = "create nsh map",
813  .short_help =
814  "create nsh map nsp <nn> nsi <nn> [del] mapped-nsp <nn> mapped-nsi <nn> nsh_action [swap|push|pop] "
815  "[encap-gre4-intf <nn> | encap-gre4-intf <nn> | encap-vxlan-gpe-intf <nn> | encap-lisp-gpe-intf <nn> "
816  " encap-vxlan4-intf <nn> | encap-vxlan6-intf <nn>| encap-eth-intf <nn> | encap-none]\n",
817  .function = nsh_add_del_map_command_fn,
818};
819
820/** API message handler */
821static void vl_api_nsh_add_del_map_t_handler
822(vl_api_nsh_add_del_map_t * mp)
823{
824  vl_api_nsh_add_del_map_reply_t * rmp;
825  nsh_main_t * nm = &nsh_main;
826  int rv;
827  nsh_add_del_map_args_t _a, *a = &_a;
828  u32 map_index = ~0;
829
830  a->is_add = mp->is_add;
831  a->map.nsp_nsi = ntohl(mp->nsp_nsi);
832  a->map.mapped_nsp_nsi = ntohl(mp->mapped_nsp_nsi);
833  a->map.nsh_action = ntohl(mp->nsh_action);
834  a->map.sw_if_index = ntohl(mp->sw_if_index);
835  a->map.rx_sw_if_index = ntohl(mp->rx_sw_if_index);
836  a->map.next_node = ntohl(mp->next_node);
837
838  rv = nsh_add_del_map (a, &map_index);
839
840  if((a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN4)
841      | (a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN6))
842    {
843      rv = nsh_add_del_proxy_session(a);
844    }
845
846  REPLY_MACRO2(VL_API_NSH_ADD_DEL_MAP_REPLY,
847  ({
848    rmp->map_index = htonl (map_index);
849  }));
850}
851
852/**
853 * CLI command for showing the mapping between NSH entries
854 */
855static clib_error_t *
856show_nsh_map_command_fn (vlib_main_t * vm,
857			 unformat_input_t * input,
858			 vlib_cli_command_t * cmd)
859{
860  nsh_main_t * nm = &nsh_main;
861  nsh_map_t * map;
862
863  if (pool_elts (nm->nsh_mappings) == 0)
864    vlib_cli_output (vm, "No nsh maps configured.");
865
866  pool_foreach (map, nm->nsh_mappings,
867		({
868		  vlib_cli_output (vm, "%U", format_nsh_map, map);
869		}));
870
871  return 0;
872}
873
874VLIB_CLI_COMMAND (show_nsh_map_command, static) = {
875  .path = "show nsh map",
876  .function = show_nsh_map_command_fn,
877};
878
879int nsh_header_rewrite(nsh_entry_t *nsh_entry)
880{
881  u8 *rw = 0;
882  int len = 0;
883  nsh_base_header_t * nsh_base;
884  nsh_md1_data_t * nsh_md1;
885  nsh_main_t *nm = &nsh_main;
886  nsh_md2_data_t *opt0;
887  nsh_md2_data_t *limit0;
888  nsh_md2_data_t *nsh_md2;
889  nsh_option_map_t _nsh_option, *nsh_option=&_nsh_option;
890  u8 old_option_size = 0;
891  u8 new_option_size = 0;
892
893  vec_free(nsh_entry->rewrite);
894  if (nsh_entry->nsh_base.md_type == 1)
895    {
896      len = sizeof(nsh_base_header_t) + sizeof(nsh_md1_data_t);
897    }
898  else if (nsh_entry->nsh_base.md_type == 2)
899    {
900      /* set to maxim, maybe dataplane will add more TLVs */
901      len = MAX_NSH_HEADER_LEN;
902    }
903  vec_validate_aligned (rw, len-1, CLIB_CACHE_LINE_BYTES);
904  memset (rw, 0, len);
905
906  nsh_base = (nsh_base_header_t *) rw;
907  nsh_base->ver_o_c = nsh_entry->nsh_base.ver_o_c;
908  nsh_base->md_type = nsh_entry->nsh_base.md_type;
909  nsh_base->next_protocol = nsh_entry->nsh_base.next_protocol;
910  nsh_base->nsp_nsi = clib_host_to_net_u32(nsh_entry->nsh_base.nsp_nsi);
911
912  if (nsh_base->md_type == 1)
913    {
914      nsh_md1 =(nsh_md1_data_t *)(rw + sizeof(nsh_base_header_t));
915      nsh_md1->c1 = clib_host_to_net_u32(nsh_entry->md.md1_data.c1);
916      nsh_md1->c2 = clib_host_to_net_u32(nsh_entry->md.md1_data.c2);
917      nsh_md1->c3 = clib_host_to_net_u32(nsh_entry->md.md1_data.c3);
918      nsh_md1->c4 = clib_host_to_net_u32(nsh_entry->md.md1_data.c4);
919      nsh_entry->rewrite_size = 24;
920    }
921  else if (nsh_base->md_type == 2)
922    {
923      opt0 = (nsh_md2_data_t *)(nsh_entry->tlvs_data);
924      limit0 = (nsh_md2_data_t *) ((u8 *) opt0 + nsh_entry->tlvs_len);
925
926      nsh_md2 = (nsh_md2_data_t *)(rw + sizeof(nsh_base_header_t));
927      nsh_entry->rewrite_size = sizeof(nsh_base_header_t);
928
929      while(opt0 < limit0)
930	{
931          old_option_size = sizeof (nsh_md2_data_t) + opt0->length;
932          /* round to 4-byte */
933          old_option_size = ( (old_option_size+3)>>2 ) << 2;
934
935          nsh_option = nsh_md2_lookup_option(opt0->class, opt0->type);
936          if( nsh_option == NULL)
937            {
938              goto next_tlv_md2;
939            }
940
941          if(nm->add_options[nsh_option->option_id] != NULL)
942            {
943              if (0 != nm->add_options[nsh_option->option_id] (
944        	  (u8 *)nsh_md2, &new_option_size ))
945                {
946                  goto next_tlv_md2;
947                }
948
949              /* round to 4-byte */
950              new_option_size = ( (new_option_size+3)>>2 ) << 2;
951
952              nsh_entry->rewrite_size += new_option_size;
953              nsh_md2 = (nsh_md2_data_t *) (((u8 *) nsh_md2) + new_option_size);
954              opt0 = (nsh_md2_data_t *) (((u8 *) opt0) + old_option_size);
955            }
956          else
957            {
958next_tlv_md2:
959              opt0 = (nsh_md2_data_t *) (((u8 *) opt0) + old_option_size);
960            }
961
962	}
963    }
964
965  nsh_entry->rewrite = rw;
966  nsh_base->length = nsh_entry->rewrite_size >> 2;
967
968  return 0;
969}
970
971
972/**
973 * Action function for adding an NSH entry
974 * nsh_add_del_entry_args_t *a: host order
975 */
976
977int nsh_add_del_entry (nsh_add_del_entry_args_t *a, u32 * entry_indexp)
978{
979  nsh_main_t * nm = &nsh_main;
980  nsh_entry_t *nsh_entry = 0;
981  u32 key, *key_copy;
982  uword * entry_id;
983  hash_pair_t *hp;
984  u32 entry_index = ~0;
985  u8 tlvs_len = 0;
986  u8 * data = 0;
987
988  /* host order, because nsh map table stores nsp_nsi in host order */
989  key = a->nsh_entry.nsh_base.nsp_nsi;
990
991  entry_id = hash_get_mem (nm->nsh_entry_by_key, &key);
992
993  if (a->is_add)
994    {
995      /* adding an entry, must not already exist */
996      if (entry_id)
997        return -1; // TODO VNET_API_ERROR_INVALID_VALUE;
998
999      pool_get_aligned (nm->nsh_entries, nsh_entry, CLIB_CACHE_LINE_BYTES);
1000      memset (nsh_entry, 0, sizeof (*nsh_entry));
1001
1002      /* copy from arg structure */
1003#define _(x) nsh_entry->nsh_base.x = a->nsh_entry.nsh_base.x;
1004      foreach_copy_nsh_base_hdr_field;
1005#undef _
1006
1007      if (a->nsh_entry.nsh_base.md_type == 1)
1008        {
1009          nsh_entry->md.md1_data.c1 = a->nsh_entry.md.md1_data.c1;
1010          nsh_entry->md.md1_data.c2 = a->nsh_entry.md.md1_data.c2;
1011          nsh_entry->md.md1_data.c3 = a->nsh_entry.md.md1_data.c3;
1012          nsh_entry->md.md1_data.c4 = a->nsh_entry.md.md1_data.c4;
1013        }
1014      else if (a->nsh_entry.nsh_base.md_type == 2)
1015        {
1016	  vec_free(nsh_entry->tlvs_data);
1017	  tlvs_len = a->nsh_entry.tlvs_len;
1018          vec_validate_aligned(data, tlvs_len-1, CLIB_CACHE_LINE_BYTES);
1019
1020          clib_memcpy(data, a->nsh_entry.tlvs_data, tlvs_len);
1021	  nsh_entry->tlvs_data = data;
1022	  nsh_entry->tlvs_len = tlvs_len;
1023	  vec_free(a->nsh_entry.tlvs_data);
1024        }
1025
1026      nsh_header_rewrite(nsh_entry);
1027
1028      key_copy = clib_mem_alloc (sizeof (*key_copy));
1029      clib_memcpy (key_copy, &key, sizeof (*key_copy));
1030
1031      hash_set_mem (nm->nsh_entry_by_key, key_copy,
1032                    nsh_entry - nm->nsh_entries);
1033      entry_index = nsh_entry - nm->nsh_entries;
1034    }
1035  else
1036    {
1037      if (!entry_id)
1038	return -2; //TODO API_ERROR_NO_SUCH_ENTRY;
1039
1040      nsh_entry = pool_elt_at_index (nm->nsh_entries, entry_id[0]);
1041      hp = hash_get_pair (nm->nsh_entry_by_key, &key);
1042      key_copy = (void *)(hp->key);
1043      hash_unset_mem (nm->nsh_entry_by_key, &key);
1044      clib_mem_free (key_copy);
1045
1046      vec_free (nsh_entry->tlvs_data);
1047      vec_free (nsh_entry->rewrite);
1048      pool_put (nm->nsh_entries, nsh_entry);
1049    }
1050
1051  if (entry_indexp)
1052      *entry_indexp = entry_index;
1053
1054  return 0;
1055}
1056
1057
1058/**
1059 * CLI command for adding NSH entry
1060 */
1061
1062static clib_error_t *
1063nsh_add_del_entry_command_fn (vlib_main_t * vm,
1064			      unformat_input_t * input,
1065			      vlib_cli_command_t * cmd)
1066{
1067  unformat_input_t _line_input, * line_input = &_line_input;
1068  u8 is_add = 1;
1069  u8 ver_o_c = 0;
1070  u8 length = 0;
1071  u8 md_type = 0;
1072  u8 next_protocol = 1; /* default: ip4 */
1073  u32 nsp;
1074  u8 nsp_set = 0;
1075  u32 nsi;
1076  u8 nsi_set = 0;
1077  u32 nsp_nsi;
1078  u32 c1 = 0;
1079  u32 c2 = 0;
1080  u32 c3 = 0;
1081  u32 c4 = 0;
1082  u8 * data = 0;
1083  nsh_tlv_header_t tlv_header;
1084  u8 cur_len = 0, tlvs_len = 0;
1085  u8 * current;
1086  nsh_main_t *nm = &nsh_main;
1087  nsh_option_map_t _nsh_option, *nsh_option=&_nsh_option;
1088  u8 option_size = 0;
1089  u32 tmp;
1090  int rv;
1091  u32 entry_index;
1092  nsh_add_del_entry_args_t _a, * a = &_a;
1093  u8 has_ioam_trace_option = 0;
1094
1095  /* Get a line of input. */
1096  if (! unformat_user (input, unformat_line_input, line_input))
1097    return 0;
1098
1099  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
1100    if (unformat (line_input, "del"))
1101      is_add = 0;
1102    else if (unformat (line_input, "version %d", &tmp))
1103      ver_o_c |= (tmp & 3) << 6;
1104    else if (unformat (line_input, "o-bit %d", &tmp))
1105      ver_o_c |= (tmp & 1) << 5;
1106    else if (unformat (line_input, "c-bit %d", &tmp))
1107      ver_o_c |= (tmp & 1) << 4;
1108    else if (unformat (line_input, "md-type %d", &tmp))
1109      md_type = tmp;
1110    else if (unformat(line_input, "next-ip4"))
1111      next_protocol = 1;
1112    else if (unformat(line_input, "next-ip6"))
1113      next_protocol = 2;
1114    else if (unformat(line_input, "next-ethernet"))
1115      next_protocol = 3;
1116    else if (unformat (line_input, "c1 %d", &c1))
1117      ;
1118    else if (unformat (line_input, "c2 %d", &c2))
1119      ;
1120    else if (unformat (line_input, "c3 %d", &c3))
1121      ;
1122    else if (unformat (line_input, "c4 %d", &c4))
1123      ;
1124    else if (unformat (line_input, "nsp %d", &nsp))
1125      nsp_set = 1;
1126    else if (unformat (line_input, "nsi %d", &nsi))
1127      nsi_set = 1;
1128    else if (unformat (line_input, "tlv-ioam-trace"))
1129      has_ioam_trace_option = 1;
1130    else
1131      return clib_error_return (0, "parse error: '%U'",
1132                                format_unformat_error, line_input);
1133  }
1134
1135  unformat_free (line_input);
1136
1137  if (nsp_set == 0)
1138    return clib_error_return (0, "nsp not specified");
1139
1140  if (nsi_set == 0)
1141    return clib_error_return (0, "nsi not specified");
1142
1143  if (md_type == 1 && has_ioam_trace_option == 1)
1144    return clib_error_return (0, "Invalid MD Type");
1145
1146  nsp_nsi = (nsp<<8) | nsi;
1147
1148  memset (a, 0, sizeof (*a));
1149  a->is_add = is_add;
1150
1151  if (md_type == 1)
1152    {
1153      a->nsh_entry.md.md1_data.c1 = c1;
1154      a->nsh_entry.md.md1_data.c2 = c2;
1155      a->nsh_entry.md.md1_data.c3 = c3;
1156      a->nsh_entry.md.md1_data.c4 = c4;
1157      length = (sizeof(nsh_base_header_t)+sizeof(nsh_md1_data_t)) >> 2;
1158    }
1159  else if (md_type == 2)
1160    {
1161      length = sizeof(nsh_base_header_t) >> 2;
1162
1163      vec_free(a->nsh_entry.tlvs_data);
1164      tlvs_len = (MAX_METADATA_LEN << 2);
1165      vec_validate_aligned (data, tlvs_len-1, CLIB_CACHE_LINE_BYTES);
1166      a->nsh_entry.tlvs_data = data;
1167      current = data;
1168
1169      if(has_ioam_trace_option)
1170	{
1171	  tlv_header.class = clib_host_to_net_u16(NSH_MD2_IOAM_CLASS);
1172          tlv_header.type = NSH_MD2_IOAM_OPTION_TYPE_TRACE;
1173          /* Uses network order's class and type to lookup */
1174          nsh_option = nsh_md2_lookup_option(tlv_header.class, tlv_header.type);
1175          if( nsh_option == NULL)
1176              return clib_error_return (0, "iOAM Trace not registered");
1177
1178          if(nm->add_options[nsh_option->option_id] != NULL)
1179            {
1180              if (0 != nm->add_options[nsh_option->option_id] (
1181        	  (u8 *)current, &option_size ))
1182                {
1183        	  return clib_error_return (0, "Invalid MD Type");
1184                }
1185            }
1186
1187          nm->options_size[nsh_option->option_id]=  option_size;
1188          /* round to 4-byte */
1189          option_size = ( ((option_size+3)>>2) << 2 );
1190
1191          cur_len += option_size;
1192          current = data + option_size;
1193	}
1194
1195      /* Add more options' parsing */
1196
1197      a->nsh_entry.tlvs_len = cur_len;
1198      length += (cur_len >> 2);
1199    }
1200
1201#define _(x) a->nsh_entry.nsh_base.x = x;
1202  foreach_copy_nsh_base_hdr_field;
1203#undef _
1204
1205  rv = nsh_add_del_entry (a, &entry_index);
1206
1207  switch(rv)
1208    {
1209    case 0:
1210      break;
1211    default:
1212      return clib_error_return
1213        (0, "nsh_add_del_entry returned %d", rv);
1214    }
1215
1216  return 0;
1217}
1218
1219VLIB_CLI_COMMAND (create_nsh_entry_command, static) = {
1220  .path = "create nsh entry",
1221  .short_help =
1222  "create nsh entry {nsp <nn> nsi <nn>} [md-type <nn>]"
1223  "  [c1 <nn> c2 <nn> c3 <nn> c4 <nn>] [tlv-ioam-trace] [del]\n",
1224  .function = nsh_add_del_entry_command_fn,
1225};
1226
1227/** API message handler */
1228static void vl_api_nsh_add_del_entry_t_handler
1229(vl_api_nsh_add_del_entry_t * mp)
1230{
1231  vl_api_nsh_add_del_entry_reply_t * rmp;
1232  nsh_main_t * nm = &nsh_main;
1233  int rv;
1234  nsh_add_del_entry_args_t _a, *a = &_a;
1235  u32 entry_index = ~0;
1236  u8 tlvs_len = 0;
1237  u8 * data = 0;
1238
1239  a->is_add = mp->is_add;
1240  a->nsh_entry.nsh_base.ver_o_c = mp->ver_o_c;
1241  a->nsh_entry.nsh_base.length = mp->length;
1242  a->nsh_entry.nsh_base.md_type = mp->md_type;
1243  a->nsh_entry.nsh_base.next_protocol = mp->next_protocol;
1244  a->nsh_entry.nsh_base.nsp_nsi = ntohl(mp->nsp_nsi);
1245  if (mp->md_type == 1)
1246    {
1247      a->nsh_entry.md.md1_data.c1 = ntohl(mp->c1);
1248      a->nsh_entry.md.md1_data.c2 = ntohl(mp->c2);
1249      a->nsh_entry.md.md1_data.c3 = ntohl(mp->c3);
1250      a->nsh_entry.md.md1_data.c4 = ntohl(mp->c4);
1251    }
1252  else if (mp->md_type == 2)
1253    {
1254      tlvs_len = mp->tlv_length;
1255      vec_validate_aligned (data, tlvs_len-1, CLIB_CACHE_LINE_BYTES);
1256
1257      clib_memcpy(data, mp->tlv, tlvs_len);
1258      a->nsh_entry.tlvs_data = data;
1259      a->nsh_entry.tlvs_len = tlvs_len;
1260    }
1261
1262  rv = nsh_add_del_entry (a, &entry_index);
1263
1264  REPLY_MACRO2(VL_API_NSH_ADD_DEL_ENTRY_REPLY,
1265  ({
1266    rmp->entry_index = htonl (entry_index);
1267  }));
1268}
1269
1270static void send_nsh_entry_details
1271(nsh_entry_t * t, unix_shared_memory_queue_t * q, u32 context)
1272{
1273    vl_api_nsh_entry_details_t * rmp;
1274    nsh_main_t * nm = &nsh_main;
1275
1276    rmp = vl_msg_api_alloc (sizeof (*rmp));
1277    memset (rmp, 0, sizeof (*rmp));
1278
1279    rmp->_vl_msg_id = ntohs((VL_API_NSH_ENTRY_DETAILS)+nm->msg_id_base);
1280    rmp->ver_o_c = t->nsh_base.ver_o_c;
1281    rmp->length = t->nsh_base.length;
1282    rmp->md_type = t->nsh_base.md_type;
1283    rmp->next_protocol = t->nsh_base.next_protocol;
1284    rmp->nsp_nsi = htonl(t->nsh_base.nsp_nsi);
1285
1286    if (t->nsh_base.md_type == 1)
1287      {
1288	rmp->tlv_length = 4;
1289        rmp->c1 = htonl(t->md.md1_data.c1);
1290        rmp->c2 = htonl(t->md.md1_data.c2);
1291        rmp->c3 = htonl(t->md.md1_data.c3);
1292        rmp->c4 = htonl(t->md.md1_data.c4);
1293      }
1294    else if (t->nsh_base.md_type == 2)
1295      {
1296	rmp->tlv_length = t->tlvs_len;
1297	clib_memcpy(rmp->tlv, t->tlvs_data, t->tlvs_len);
1298      }
1299
1300    rmp->context = context;
1301
1302    vl_msg_api_send_shmem (q, (u8 *)&rmp);
1303}
1304
1305static void vl_api_nsh_entry_dump_t_handler
1306(vl_api_nsh_entry_dump_t * mp)
1307{
1308    unix_shared_memory_queue_t * q;
1309    nsh_main_t * nm = &nsh_main;
1310    nsh_entry_t * t;
1311    u32 entry_index;
1312
1313    q = vl_api_client_index_to_input_queue (mp->client_index);
1314    if (q == 0) {
1315        return;
1316    }
1317
1318    entry_index = ntohl (mp->entry_index);
1319
1320    if (~0 == entry_index)
1321      {
1322	pool_foreach (t, nm->nsh_entries,
1323	({
1324	    send_nsh_entry_details(t, q, mp->context);
1325	}));
1326      }
1327    else
1328      {
1329        if (entry_index >= vec_len (nm->nsh_entries))
1330  	{
1331  	  return;
1332  	}
1333        t = &nm->nsh_entries[entry_index];
1334        send_nsh_entry_details(t, q, mp->context);
1335      }
1336}
1337
1338static void send_nsh_map_details
1339(nsh_map_t * t, unix_shared_memory_queue_t * q, u32 context)
1340{
1341    vl_api_nsh_map_details_t * rmp;
1342    nsh_main_t * nm = &nsh_main;
1343
1344    rmp = vl_msg_api_alloc (sizeof (*rmp));
1345    memset (rmp, 0, sizeof (*rmp));
1346
1347    rmp->_vl_msg_id = ntohs((VL_API_NSH_MAP_DETAILS)+nm->msg_id_base);
1348    rmp->nsp_nsi = htonl(t->nsp_nsi);
1349    rmp->mapped_nsp_nsi = htonl(t->mapped_nsp_nsi);
1350    rmp->nsh_action = htonl(t->nsh_action);
1351    rmp->sw_if_index = htonl(t->sw_if_index);
1352    rmp->rx_sw_if_index = htonl(t->rx_sw_if_index);
1353    rmp->next_node = htonl(t->next_node);
1354
1355    rmp->context = context;
1356
1357    vl_msg_api_send_shmem (q, (u8 *)&rmp);
1358}
1359
1360static void vl_api_nsh_map_dump_t_handler
1361(vl_api_nsh_map_dump_t * mp)
1362{
1363    unix_shared_memory_queue_t * q;
1364    nsh_main_t * nm = &nsh_main;
1365    nsh_map_t * t;
1366    u32 map_index;
1367
1368    q = vl_api_client_index_to_input_queue (mp->client_index);
1369    if (q == 0) {
1370        return;
1371    }
1372
1373    map_index = ntohl (mp->map_index);
1374
1375    if (~0 == map_index)
1376      {
1377	pool_foreach (t, nm->nsh_mappings,
1378	({
1379	    send_nsh_map_details(t, q, mp->context);
1380	}));
1381      }
1382    else
1383      {
1384        if (map_index >= vec_len (nm->nsh_mappings))
1385  	{
1386  	  return;
1387  	}
1388        t = &nm->nsh_mappings[map_index];
1389        send_nsh_map_details(t, q, mp->context);
1390      }
1391}
1392
1393static clib_error_t *
1394show_nsh_entry_command_fn (vlib_main_t * vm,
1395			   unformat_input_t * input,
1396			   vlib_cli_command_t * cmd)
1397{
1398  nsh_main_t * nm = &nsh_main;
1399  nsh_entry_t * nsh_entry;
1400
1401  if (pool_elts (nm->nsh_entries) == 0)
1402    vlib_cli_output (vm, "No nsh entries configured.");
1403
1404  pool_foreach (nsh_entry, nm->nsh_entries,
1405		({
1406		  vlib_cli_output (vm, "%U", format_nsh_header,
1407				   nsh_entry->rewrite );
1408
1409		  vlib_cli_output (vm, "  rewrite_size: %d bytes",
1410				   nsh_entry->rewrite_size);
1411		}));
1412
1413  return 0;
1414}
1415
1416VLIB_CLI_COMMAND (show_nsh_entry_command, static) = {
1417  .path = "show nsh entry",
1418  .function = show_nsh_entry_command_fn,
1419};
1420
1421
1422/* Set up the API message handling tables */
1423static clib_error_t *
1424nsh_plugin_api_hookup (vlib_main_t *vm)
1425{
1426  nsh_main_t * nm __attribute__ ((unused)) = &nsh_main;
1427#define _(N,n)                                                  \
1428  vl_msg_api_set_handlers((VL_API_##N + nm->msg_id_base),	\
1429			  #n,					\
1430			  vl_api_##n##_t_handler,		\
1431			  vl_noop_handler,			\
1432			  vl_api_##n##_t_endian,		\
1433			  vl_api_##n##_t_print,			\
1434			  sizeof(vl_api_##n##_t), 1);
1435  foreach_nsh_plugin_api_msg;
1436#undef _
1437
1438  return 0;
1439}
1440
1441static void
1442setup_message_id_table (nsh_main_t * nm, api_main_t * am)
1443{
1444#define _(id,n,crc) \
1445  vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + nm->msg_id_base);
1446  foreach_vl_msg_name_crc_nsh;
1447#undef _
1448}
1449
1450always_inline void
1451nsh_md2_encap (vlib_buffer_t * b, nsh_base_header_t *hdr,
1452	       nsh_entry_t * nsh_entry)
1453{
1454  nsh_main_t *nm = &nsh_main;
1455  nsh_base_header_t * nsh_base;
1456  nsh_tlv_header_t * opt0;
1457  nsh_tlv_header_t * limit0;
1458  nsh_tlv_header_t * nsh_md2;
1459  nsh_option_map_t * nsh_option;
1460  u8 old_option_size = 0;
1461  u8 new_option_size = 0;
1462
1463  /* Populate the NSH Header */
1464  opt0 = (nsh_tlv_header_t *)(nsh_entry->tlvs_data);
1465  limit0 = (nsh_tlv_header_t *) (nsh_entry->tlvs_data + nsh_entry->tlvs_len);
1466
1467  nsh_md2 = (nsh_tlv_header_t *)((u8 *)hdr /*nsh_entry->rewrite*/ + sizeof(nsh_base_header_t));
1468  nsh_entry->rewrite_size = sizeof(nsh_base_header_t);
1469
1470  /* Scan the set of variable metadata, process ones that we understand */
1471  while (opt0 < limit0)
1472    {
1473      old_option_size = sizeof (nsh_tlv_header_t) + opt0->length;
1474      /* round to 4-byte */
1475      old_option_size = ( (old_option_size+3)>>2 ) << 2;
1476
1477      nsh_option = nsh_md2_lookup_option(opt0->class, opt0->type);
1478      if( nsh_option == NULL)
1479	{
1480	  goto next_tlv_md2;
1481	}
1482
1483      if (nm->options[nsh_option->option_id])
1484	{
1485	  if ( (*nm->options[nsh_option->option_id]) (b, nsh_md2) )
1486	    {
1487	      goto next_tlv_md2;
1488	    }
1489
1490	  /* option length may be varied */
1491	  new_option_size = sizeof (nsh_tlv_header_t) + nsh_md2->length;
1492	  /* round to 4-byte */
1493	  new_option_size = ( (new_option_size+3)>>2 ) << 2;
1494	  nsh_entry->rewrite_size += new_option_size;
1495
1496	  nsh_md2 = (nsh_tlv_header_t *) (((u8 *) nsh_md2) + new_option_size);
1497	  opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size);
1498
1499	}
1500      else
1501	{
1502next_tlv_md2:
1503	  opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size);
1504	}
1505    }
1506
1507  /* update nsh header's length */
1508  nsh_base = (nsh_base_header_t *)nsh_entry->rewrite;
1509  nsh_base->length = (nsh_entry->rewrite_size >> 2);
1510
1511  return;
1512}
1513
1514always_inline void
1515nsh_md2_swap (vlib_buffer_t * b,
1516              nsh_base_header_t * hdr,
1517	      u32 header_len,
1518	      nsh_entry_t * nsh_entry,
1519	      u32 * next,
1520	      u32 drop_node_val)
1521{
1522  nsh_main_t *nm = &nsh_main;
1523  nsh_base_header_t * nsh_base;
1524  nsh_tlv_header_t * opt0;
1525  nsh_tlv_header_t * limit0;
1526  nsh_tlv_header_t * nsh_md2;
1527  nsh_option_map_t * nsh_option;
1528  u8 old_option_size = 0;
1529  u8 new_option_size = 0;
1530
1531  /* Populate the NSH Header */
1532  opt0 = (nsh_md2_data_t *)(hdr + 1);
1533  limit0 = (nsh_md2_data_t *) ((u8 *) hdr + header_len);
1534
1535  nsh_md2 = (nsh_tlv_header_t *)(nsh_entry->rewrite + sizeof(nsh_base_header_t));
1536  nsh_entry->rewrite_size = sizeof(nsh_base_header_t);
1537
1538  /* Scan the set of variable metadata, process ones that we understand */
1539  while (opt0 < limit0)
1540    {
1541      old_option_size = sizeof (nsh_tlv_header_t) + opt0->length;
1542      /* round to 4-byte */
1543      old_option_size = ( (old_option_size+3)>>2 ) << 2;
1544
1545      nsh_option = nsh_md2_lookup_option(opt0->class, opt0->type);
1546      if( nsh_option == NULL)
1547	{
1548	  goto next_tlv_md2;
1549	}
1550
1551      if (nm->swap_options[nsh_option->option_id])
1552	{
1553	  if ( (*nm->swap_options[nsh_option->option_id]) (b, opt0, nsh_md2) )
1554	    {
1555	      goto next_tlv_md2;
1556	    }
1557
1558	  /* option length may be varied */
1559	  new_option_size = sizeof (nsh_tlv_header_t) + nsh_md2->length;
1560	  /* round to 4-byte */
1561	  new_option_size = ( (new_option_size+3)>>2 ) << 2;
1562	  nsh_entry->rewrite_size += new_option_size;
1563	  nsh_md2 = (nsh_tlv_header_t *) (((u8 *) nsh_md2) + new_option_size);
1564
1565	  opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size);
1566
1567	}
1568      else
1569	{
1570next_tlv_md2:
1571	  opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size);
1572	}
1573    }
1574
1575  /* update nsh header's length */
1576  nsh_base = (nsh_base_header_t *)nsh_entry->rewrite;
1577  nsh_base->length = (nsh_entry->rewrite_size >> 2);
1578  return;
1579}
1580
1581always_inline void
1582nsh_md2_decap (vlib_buffer_t * b,
1583               nsh_base_header_t * hdr,
1584	       u32 *header_len,
1585	       u32 * next,
1586	       u32 drop_node_val)
1587{
1588  nsh_main_t *nm = &nsh_main;
1589  nsh_md2_data_t *opt0;
1590  nsh_md2_data_t *limit0;
1591  nsh_option_map_t *nsh_option;
1592  u8 option_len = 0;
1593
1594  /* Populate the NSH Header */
1595  opt0 = (nsh_md2_data_t *)(hdr + 1);
1596  limit0 = (nsh_md2_data_t *) ((u8 *) hdr + *header_len);
1597
1598  /* Scan the set of variable metadata, process ones that we understand */
1599  while (opt0 < limit0)
1600    {
1601      nsh_option = nsh_md2_lookup_option(opt0->class, opt0->type);
1602      if( nsh_option == NULL)
1603	{
1604	  *next = drop_node_val;
1605	  return;
1606	}
1607
1608	  if (nm->pop_options[nsh_option->option_id])
1609	    {
1610	      if ( (*nm->pop_options[nsh_option->option_id]) (b, opt0) )
1611		{
1612		  *next = drop_node_val;
1613		  return;
1614		}
1615	    }
1616      /* round to 4-byte */
1617      option_len = ( (opt0->length+3)>>2 ) << 2;
1618      opt0 = (nsh_md2_data_t *) (((u8 *) opt0) + sizeof (nsh_md2_data_t) + option_len);
1619      *next = (nm->decap_v4_next_override) ? (nm->decap_v4_next_override) : (*next);
1620      *header_len = (nm->decap_v4_next_override) ? 0 : (*header_len);
1621    }
1622
1623  return;
1624}
1625
1626static uword
1627nsh_input_map (vlib_main_t * vm,
1628               vlib_node_runtime_t * node,
1629               vlib_frame_t * from_frame,
1630	       u32 node_type)
1631{
1632  u32 n_left_from, next_index, *from, *to_next;
1633  nsh_main_t * nm = &nsh_main;
1634
1635  from = vlib_frame_vector_args(from_frame);
1636  n_left_from = from_frame->n_vectors;
1637
1638  next_index = node->cached_next_index;
1639
1640  while (n_left_from > 0)
1641    {
1642      u32 n_left_to_next;
1643
1644      vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
1645
1646      while (n_left_from >= 4 && n_left_to_next >= 2)
1647	{
1648	  u32 bi0, bi1;
1649	  vlib_buffer_t * b0, *b1;
1650	  u32 next0 = NSH_NODE_NEXT_DROP, next1 = NSH_NODE_NEXT_DROP;
1651	  uword * entry0, *entry1;
1652	  nsh_base_header_t * hdr0 = 0, *hdr1 = 0;
1653	  u32 header_len0 = 0, header_len1 = 0;
1654	  u32 nsp_nsi0, nsp_nsi1;
1655	  u32 error0, error1;
1656	  nsh_map_t * map0 = 0, *map1 = 0;
1657	  nsh_entry_t * nsh_entry0 = 0, *nsh_entry1 = 0;
1658	  nsh_base_header_t *encap_hdr0 = 0, *encap_hdr1 = 0;
1659	  u32 encap_hdr_len0 = 0, encap_hdr_len1 = 0;
1660	  nsh_proxy_session_by_key_t key0, key1;
1661	  uword *p0, *p1;
1662	  nsh_proxy_session_t *proxy0, *proxy1;
1663	  u32 sw_if_index0 = 0, sw_if_index1 = 0;
1664	  ethernet_header_t dummy_eth0, dummy_eth1;
1665
1666	  /* Prefetch next iteration. */
1667	  {
1668	    vlib_buffer_t * p2, *p3;
1669
1670	    p2 = vlib_get_buffer(vm, from[2]);
1671	    p3 = vlib_get_buffer(vm, from[3]);
1672
1673	    vlib_prefetch_buffer_header(p2, LOAD);
1674	    vlib_prefetch_buffer_header(p3, LOAD);
1675
1676	    CLIB_PREFETCH(p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
1677	    CLIB_PREFETCH(p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
1678	  }
1679
1680	  bi0 = from[0];
1681	  bi1 = from[1];
1682	  to_next[0] = bi0;
1683	  to_next[1] = bi1;
1684	  from += 2;
1685	  to_next += 2;
1686	  n_left_from -= 2;
1687	  n_left_to_next -= 2;
1688
1689	  error0 = 0;
1690	  error1 = 0;
1691
1692	  b0 = vlib_get_buffer(vm, bi0);
1693	  b1 = vlib_get_buffer(vm, bi1);
1694	  hdr0 = vlib_buffer_get_current(b0);
1695          if(node_type == NSH_INPUT_TYPE)
1696            {
1697              nsp_nsi0 = hdr0->nsp_nsi;
1698              header_len0 = hdr0->length * 4;
1699            }
1700          else if(node_type == NSH_CLASSIFIER_TYPE)
1701            {
1702              nsp_nsi0 = clib_host_to_net_u32(vnet_buffer(b0)->l2_classify.opaque_index);
1703            }
1704          else if(node_type == NSH_AWARE_VNF_PROXY_TYPE)
1705            {
1706	      /* Push dummy Eth header */
1707              memset(&dummy_eth0.dst_address[0], 0x11223344, 4);
1708              memset(&dummy_eth0.dst_address[4], 0x5566, 2);
1709              memset(&dummy_eth0.src_address[0], 0x778899aa, 4);
1710              memset(&dummy_eth0.src_address[4], 0xbbcc, 2);
1711              dummy_eth0.type = 0x0800;
1712	      vlib_buffer_advance(b0, -(word)sizeof(ethernet_header_t));
1713	      hdr0 = vlib_buffer_get_current(b0);
1714	      clib_memcpy(hdr0, &dummy_eth0, (word)sizeof(ethernet_header_t));
1715
1716              sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_TX];
1717              nsp_nsi0 = nm->tunnel_index_by_sw_if_index[sw_if_index0];
1718            }
1719          else
1720	    {
1721	      memset (&key0, 0, sizeof(key0));
1722	      key0.transport_type = NSH_NODE_NEXT_ENCAP_VXLAN4;
1723              key0.transport_index = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1724
1725              p0 = hash_get_mem(nm->nsh_proxy_session_by_key, &key0);
1726	      if (PREDICT_FALSE(p0 == 0))
1727		{
1728		  error0 = NSH_NODE_ERROR_NO_PROXY;
1729		  goto trace0;
1730		}
1731
1732	      proxy0 = pool_elt_at_index(nm->nsh_proxy_sessions, p0[0]);
1733              if (PREDICT_FALSE(proxy0 == 0))
1734                {
1735                  error0 = NSH_NODE_ERROR_NO_PROXY;
1736                  goto trace0;
1737                }
1738              nsp_nsi0 = proxy0->nsp_nsi;
1739	    }
1740
1741          hdr1 = vlib_buffer_get_current(b1);
1742          if(node_type == NSH_INPUT_TYPE)
1743	    {
1744	      nsp_nsi1 = hdr1->nsp_nsi;
1745	      header_len1 = hdr1->length * 4;
1746	    }
1747          else if(node_type == NSH_CLASSIFIER_TYPE)
1748            {
1749              nsp_nsi1 = clib_host_to_net_u32(vnet_buffer(b1)->l2_classify.opaque_index);
1750            }
1751          else if(node_type == NSH_AWARE_VNF_PROXY_TYPE)
1752            {
1753	      /* Push dummy Eth header */
1754              memset(&dummy_eth1.dst_address[0], 0x11223344, 4);
1755              memset(&dummy_eth1.dst_address[4], 0x5566, 2);
1756              memset(&dummy_eth1.src_address[0], 0x778899aa, 4);
1757              memset(&dummy_eth1.src_address[4], 0xbbcc, 2);
1758              dummy_eth1.type = 0x0800;
1759	      vlib_buffer_advance(b1, -(word)sizeof(ethernet_header_t));
1760	      hdr1 = vlib_buffer_get_current(b1);
1761	      clib_memcpy(hdr1, &dummy_eth1, (word)sizeof(ethernet_header_t));
1762
1763              sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_TX];
1764              nsp_nsi1 = nm->tunnel_index_by_sw_if_index[sw_if_index1];
1765            }
1766          else
1767	    {
1768	      memset (&key1, 0, sizeof(key1));
1769	      key1.transport_type = NSH_NODE_NEXT_ENCAP_VXLAN4;
1770              key1.transport_index = vnet_buffer(b1)->sw_if_index[VLIB_RX];
1771
1772              p1 = hash_get_mem(nm->nsh_proxy_session_by_key, &key1);
1773	      if (PREDICT_FALSE(p1 == 0))
1774		{
1775		  error1 = NSH_NODE_ERROR_NO_PROXY;
1776		  goto trace1;
1777		}
1778
1779	      proxy1 = pool_elt_at_index(nm->nsh_proxy_sessions, p1[0]);
1780              if (PREDICT_FALSE(proxy1 == 0))
1781                {
1782                  error1 = NSH_NODE_ERROR_NO_PROXY;
1783                  goto trace1;
1784                }
1785              nsp_nsi1 = proxy1->nsp_nsi;
1786	    }
1787
1788	  /* Process packet 0 */
1789	  entry0 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi0);
1790	  if (PREDICT_FALSE(entry0 == 0))
1791	    {
1792	      error0 = NSH_NODE_ERROR_NO_MAPPING;
1793	      goto trace0;
1794	    }
1795
1796	  /* Entry should point to a mapping ...*/
1797	  map0 = pool_elt_at_index(nm->nsh_mappings, entry0[0]);
1798	  if (PREDICT_FALSE(map0 == 0))
1799	    {
1800	      error0 = NSH_NODE_ERROR_NO_MAPPING;
1801	      goto trace0;
1802	    }
1803
1804	  /* set up things for next node to transmit ie which node to handle it and where */
1805	  next0 = map0->next_node;
1806	  vnet_buffer(b0)->sw_if_index[VLIB_TX] = map0->sw_if_index;
1807	  vnet_buffer(b0)->ip.adj_index[VLIB_TX] = map0->adj_index;
1808
1809	  if(PREDICT_FALSE(map0->nsh_action == NSH_ACTION_POP))
1810	    {
1811	      /* Manipulate MD2 */
1812              if(PREDICT_FALSE(hdr0->md_type == 2))
1813        	{
1814        	  nsh_md2_decap(b0, hdr0, &header_len0, &next0, NSH_NODE_NEXT_DROP);
1815        	  if (PREDICT_FALSE(next0 == NSH_NODE_NEXT_DROP))
1816        	    {
1817        	      error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
1818        	      goto trace0;
1819        	    }
1820	          vnet_buffer(b0)->sw_if_index[VLIB_RX] = map0->rx_sw_if_index;
1821        	}
1822
1823              /* Pop NSH header */
1824	      vlib_buffer_advance(b0, (word)header_len0);
1825	      goto trace0;
1826	    }
1827
1828	  entry0 = hash_get_mem(nm->nsh_entry_by_key, &map0->mapped_nsp_nsi);
1829	  if (PREDICT_FALSE(entry0 == 0))
1830	    {
1831	      error0 = NSH_NODE_ERROR_NO_ENTRY;
1832	      goto trace0;
1833	    }
1834
1835	  nsh_entry0 = (nsh_entry_t *)pool_elt_at_index(nm->nsh_entries, entry0[0]);
1836	  encap_hdr0 = (nsh_base_header_t *)(nsh_entry0->rewrite);
1837	  /* rewrite_size should equal to (encap_hdr0->length * 4) */
1838	  encap_hdr_len0 = nsh_entry0->rewrite_size;
1839
1840	  if(PREDICT_TRUE(map0->nsh_action == NSH_ACTION_SWAP))
1841	    {
1842	      /* Manipulate MD2 */
1843              if(PREDICT_FALSE(hdr0->md_type == 2))
1844        	{
1845        	  nsh_md2_swap(b0, hdr0, header_len0, nsh_entry0,
1846        	               &next0, NSH_NODE_NEXT_DROP);
1847        	  if (PREDICT_FALSE(next0 == NSH_NODE_NEXT_DROP))
1848        	    {
1849        	      error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
1850        	      goto trace0;
1851        	    }
1852        	}
1853
1854              /* Pop old NSH header */
1855	      vlib_buffer_advance(b0, (word)header_len0);
1856
1857              /* After processing, md2's length may be varied */
1858              encap_hdr_len0 = nsh_entry0->rewrite_size;
1859	      /* Push new NSH header */
1860	      vlib_buffer_advance(b0, -(word)encap_hdr_len0);
1861	      hdr0 = vlib_buffer_get_current(b0);
1862	      clib_memcpy(hdr0, encap_hdr0, (word)encap_hdr_len0);
1863
1864	      goto trace0;
1865	    }
1866
1867	  if(PREDICT_TRUE(map0->nsh_action == NSH_ACTION_PUSH))
1868	    {
1869              /* After processing, md2's length may be varied */
1870              encap_hdr_len0 = nsh_entry0->rewrite_size;
1871	      /* Push new NSH header */
1872	      vlib_buffer_advance(b0, -(word)encap_hdr_len0);
1873	      hdr0 = vlib_buffer_get_current(b0);
1874	      clib_memcpy(hdr0, encap_hdr0, (word)encap_hdr_len0);
1875
1876	      /* Manipulate MD2 */
1877              if(PREDICT_FALSE(nsh_entry0->nsh_base.md_type == 2))
1878        	{
1879        	  nsh_md2_encap(b0, hdr0, nsh_entry0);
1880        	}
1881
1882	    }
1883
1884        trace0: b0->error = error0 ? node->errors[error0] : 0;
1885
1886          if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
1887            {
1888              nsh_input_trace_t *tr = vlib_add_trace(vm, node, b0, sizeof(*tr));
1889              clib_memcpy ( &(tr->trace_data), hdr0, (hdr0->length*4) );
1890            }
1891
1892	  /* Process packet 1 */
1893	  entry1 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi1);
1894	  if (PREDICT_FALSE(entry1 == 0))
1895	    {
1896	      error1 = NSH_NODE_ERROR_NO_MAPPING;
1897	      goto trace1;
1898	    }
1899
1900	  /* Entry should point to a mapping ...*/
1901	  map1 = pool_elt_at_index(nm->nsh_mappings, entry1[0]);
1902	  if (PREDICT_FALSE(map1 == 0))
1903	    {
1904	      error1 = NSH_NODE_ERROR_NO_MAPPING;
1905	      goto trace1;
1906	    }
1907
1908	  /* set up things for next node to transmit ie which node to handle it and where */
1909	  next1 = map1->next_node;
1910	  vnet_buffer(b1)->sw_if_index[VLIB_TX] = map1->sw_if_index;
1911	  vnet_buffer(b1)->ip.adj_index[VLIB_TX] = map1->adj_index;
1912
1913	  if(PREDICT_FALSE(map1->nsh_action == NSH_ACTION_POP))
1914	    {
1915	      /* Manipulate MD2 */
1916              if(PREDICT_FALSE(hdr1->md_type == 2))
1917        	{
1918        	  nsh_md2_decap(b1, hdr1, &header_len1, &next1, NSH_NODE_NEXT_DROP);
1919        	  if (PREDICT_FALSE(next1 == NSH_NODE_NEXT_DROP))
1920        	    {
1921        	      error1 = NSH_NODE_ERROR_INVALID_OPTIONS;
1922        	      goto trace1;
1923        	    }
1924	          vnet_buffer(b1)->sw_if_index[VLIB_RX] = map0->rx_sw_if_index;
1925        	}
1926
1927              /* Pop NSH header */
1928	      vlib_buffer_advance(b1, (word)header_len1);
1929	      goto trace1;
1930	    }
1931
1932	  entry1 = hash_get_mem(nm->nsh_entry_by_key, &map1->mapped_nsp_nsi);
1933	  if (PREDICT_FALSE(entry1 == 0))
1934	    {
1935	      error1 = NSH_NODE_ERROR_NO_ENTRY;
1936	      goto trace1;
1937	    }
1938
1939	  nsh_entry1 = (nsh_entry_t *)pool_elt_at_index(nm->nsh_entries, entry1[0]);
1940	  encap_hdr1 = (nsh_base_header_t *)(nsh_entry1->rewrite);
1941	  /* rewrite_size should equal to (encap_hdr0->length * 4) */
1942	  encap_hdr_len1 = nsh_entry1->rewrite_size;
1943
1944          if(PREDICT_TRUE(map1->nsh_action == NSH_ACTION_SWAP))
1945            {
1946	      /* Manipulate MD2 */
1947              if(PREDICT_FALSE(hdr1->md_type == 2))
1948        	{
1949        	  nsh_md2_swap(b1, hdr1, header_len1, nsh_entry1,
1950        	               &next1, NSH_NODE_NEXT_DROP);
1951        	  if (PREDICT_FALSE(next1 == NSH_NODE_NEXT_DROP))
1952        	    {
1953        	      error1 = NSH_NODE_ERROR_INVALID_OPTIONS;
1954        	      goto trace1;
1955        	    }
1956        	}
1957
1958              /* Pop old NSH header */
1959	      vlib_buffer_advance(b1, (word)header_len1);
1960
1961              /* After processing, md2's length may be varied */
1962              encap_hdr_len1 = nsh_entry1->rewrite_size;
1963	      /* Push new NSH header */
1964	      vlib_buffer_advance(b1, -(word)encap_hdr_len1);
1965	      hdr1 = vlib_buffer_get_current(b1);
1966	      clib_memcpy(hdr1, encap_hdr1, (word)encap_hdr_len1);
1967
1968	      goto trace1;
1969	    }
1970
1971          if(PREDICT_FALSE(map1->nsh_action == NSH_ACTION_PUSH))
1972            {
1973              /* After processing, md2's length may be varied */
1974              encap_hdr_len1 = nsh_entry1->rewrite_size;
1975	      /* Push new NSH header */
1976	      vlib_buffer_advance(b1, -(word)encap_hdr_len1);
1977	      hdr1 = vlib_buffer_get_current(b1);
1978	      clib_memcpy(hdr1, encap_hdr1, (word)encap_hdr_len1);
1979
1980	      /* Manipulate MD2 */
1981              if(PREDICT_FALSE(nsh_entry1->nsh_base.md_type == 2))
1982        	{
1983        	  nsh_md2_encap(b1, hdr1, nsh_entry1);
1984        	}
1985
1986	    }
1987
1988	trace1: b1->error = error1 ? node->errors[error1] : 0;
1989
1990	  if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
1991	    {
1992	      nsh_input_trace_t *tr = vlib_add_trace(vm, node, b1, sizeof(*tr));
1993	      clib_memcpy ( &(tr->trace_data), hdr1, (hdr1->length*4) );
1994	    }
1995
1996	  vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
1997					  n_left_to_next, bi0, bi1, next0, next1);
1998
1999	}
2000
2001      while (n_left_from > 0 && n_left_to_next > 0)
2002	{
2003	  u32 bi0 = 0;
2004	  vlib_buffer_t * b0 = NULL;
2005	  u32 next0 = NSH_NODE_NEXT_DROP;
2006	  uword * entry0;
2007	  nsh_base_header_t * hdr0 = 0;
2008	  u32 header_len0 = 0;
2009	  u32 nsp_nsi0;
2010	  u32 error0;
2011	  nsh_map_t * map0 = 0;
2012	  nsh_entry_t * nsh_entry0 = 0;
2013	  nsh_base_header_t * encap_hdr0 = 0;
2014	  u32 encap_hdr_len0 = 0;
2015	  nsh_proxy_session_by_key_t key0;
2016	  uword *p0;
2017	  nsh_proxy_session_t *proxy0 = 0;
2018	  u32 sw_if_index0 = 0;
2019	  ethernet_header_t dummy_eth0;
2020
2021	  bi0 = from[0];
2022	  to_next[0] = bi0;
2023	  from += 1;
2024	  to_next += 1;
2025	  n_left_from -= 1;
2026	  n_left_to_next -= 1;
2027	  error0 = 0;
2028
2029	  b0 = vlib_get_buffer(vm, bi0);
2030	  hdr0 = vlib_buffer_get_current(b0);
2031
2032          if(node_type == NSH_INPUT_TYPE)
2033            {
2034              nsp_nsi0 = hdr0->nsp_nsi;
2035              header_len0 = hdr0->length * 4;
2036            }
2037          else if(node_type == NSH_CLASSIFIER_TYPE)
2038            {
2039              nsp_nsi0 = clib_host_to_net_u32(vnet_buffer(b0)->l2_classify.opaque_index);
2040            }
2041          else if(node_type == NSH_AWARE_VNF_PROXY_TYPE)
2042            {
2043	      /* Push dummy Eth header */
2044              memset(&dummy_eth0.dst_address[0], 0x11223344, 4);
2045              memset(&dummy_eth0.dst_address[4], 0x5566, 2);
2046              memset(&dummy_eth0.src_address[0], 0x778899aa, 4);
2047              memset(&dummy_eth0.src_address[4], 0xbbcc, 2);
2048              dummy_eth0.type = 0x0800;
2049	      vlib_buffer_advance(b0, -(word)sizeof(ethernet_header_t));
2050	      hdr0 = vlib_buffer_get_current(b0);
2051	      clib_memcpy(hdr0, &dummy_eth0, (word)sizeof(ethernet_header_t));
2052
2053              sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_TX];
2054              nsp_nsi0 = nm->tunnel_index_by_sw_if_index[sw_if_index0];
2055            }
2056          else
2057	    {
2058	      memset (&key0, 0, sizeof(key0));
2059	      key0.transport_type = NSH_NODE_NEXT_ENCAP_VXLAN4;
2060	      key0.transport_index = vnet_buffer(b0)->sw_if_index[VLIB_RX];
2061
2062	      p0 = hash_get_mem(nm->nsh_proxy_session_by_key, &key0);
2063	      if (PREDICT_FALSE(p0 == 0))
2064		{
2065		  error0 = NSH_NODE_ERROR_NO_PROXY;
2066		  goto trace00;
2067		}
2068
2069	      proxy0 = pool_elt_at_index(nm->nsh_proxy_sessions, p0[0]);
2070	      if (PREDICT_FALSE(proxy0 == 0))
2071		{
2072		  error0 = NSH_NODE_ERROR_NO_PROXY;
2073		  goto trace00;
2074		}
2075	      nsp_nsi0 = proxy0->nsp_nsi;
2076	    }
2077
2078	  entry0 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi0);
2079
2080	  if (PREDICT_FALSE(entry0 == 0))
2081	    {
2082	      error0 = NSH_NODE_ERROR_NO_MAPPING;
2083	      goto trace00;
2084	    }
2085
2086	  /* Entry should point to a mapping ...*/
2087	  map0 = pool_elt_at_index(nm->nsh_mappings, entry0[0]);
2088
2089	  if (PREDICT_FALSE(map0 == 0))
2090	    {
2091	      error0 = NSH_NODE_ERROR_NO_MAPPING;
2092	      goto trace00;
2093	    }
2094
2095	  /* set up things for next node to transmit ie which node to handle it and where */
2096	  next0 = map0->next_node;
2097	  vnet_buffer(b0)->sw_if_index[VLIB_TX] = map0->sw_if_index;
2098	  vnet_buffer(b0)->ip.adj_index[VLIB_TX] = map0->adj_index;
2099	  vnet_buffer(b0)->sw_if_index[VLIB_RX] = map0->nsh_sw_if;
2100
2101	  if(PREDICT_FALSE(map0->nsh_action == NSH_ACTION_POP))
2102	    {
2103	      /* Manipulate MD2 */
2104              if(PREDICT_FALSE(hdr0->md_type == 2))
2105        	{
2106        	  nsh_md2_decap(b0, hdr0, &header_len0, &next0, NSH_NODE_NEXT_DROP);
2107        	  if (PREDICT_FALSE(next0 == NSH_NODE_NEXT_DROP))
2108        	    {
2109        	      error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
2110        	      goto trace00;
2111        	    }
2112	          vnet_buffer(b0)->sw_if_index[VLIB_RX] = map0->rx_sw_if_index;
2113        	}
2114
2115              /* Pop NSH header */
2116	      vlib_buffer_advance(b0, (word)header_len0);
2117	      goto trace00;
2118	    }
2119
2120	  entry0 = hash_get_mem(nm->nsh_entry_by_key, &map0->mapped_nsp_nsi);
2121	  if (PREDICT_FALSE(entry0 == 0))
2122	    {
2123	      error0 = NSH_NODE_ERROR_NO_ENTRY;
2124	      goto trace00;
2125	    }
2126
2127	  nsh_entry0 = (nsh_entry_t *)pool_elt_at_index(nm->nsh_entries, entry0[0]);
2128	  encap_hdr0 = (nsh_base_header_t *)(nsh_entry0->rewrite);
2129	  /* rewrite_size should equal to (encap_hdr0->length * 4) */
2130	  encap_hdr_len0 = nsh_entry0->rewrite_size;
2131
2132	  if(PREDICT_TRUE(map0->nsh_action == NSH_ACTION_SWAP))
2133	    {
2134	      /* Manipulate MD2 */
2135              if(PREDICT_FALSE(hdr0->md_type == 2))
2136        	{
2137        	  nsh_md2_swap(b0, hdr0, header_len0, nsh_entry0,
2138        	               &next0, NSH_NODE_NEXT_DROP);
2139        	  if (PREDICT_FALSE(next0 == NSH_NODE_NEXT_DROP))
2140        	    {
2141        	      error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
2142        	      goto trace00;
2143        	    }
2144        	}
2145
2146              /* Pop old NSH header */
2147	      vlib_buffer_advance(b0, (word)header_len0);
2148
2149              /* After processing, md2's length may be varied */
2150              encap_hdr_len0 = nsh_entry0->rewrite_size;
2151	      /* Push new NSH header */
2152	      vlib_buffer_advance(b0, -(word)encap_hdr_len0);
2153	      hdr0 = vlib_buffer_get_current(b0);
2154	      clib_memcpy(hdr0, encap_hdr0, (word)encap_hdr_len0);
2155
2156	      goto trace00;
2157	    }
2158
2159	  if(PREDICT_TRUE(map0->nsh_action == NSH_ACTION_PUSH))
2160	    {
2161              /* After processing, md2's length may be varied */
2162              encap_hdr_len0 = nsh_entry0->rewrite_size;
2163	      /* Push new NSH header */
2164	      vlib_buffer_advance(b0, -(word)encap_hdr_len0);
2165	      hdr0 = vlib_buffer_get_current(b0);
2166	      clib_memcpy(hdr0, encap_hdr0, (word)encap_hdr_len0);
2167	      /* Manipulate MD2 */
2168              if(PREDICT_FALSE(nsh_entry0->nsh_base.md_type == 2))
2169        	{
2170        	  nsh_md2_encap(b0, hdr0, nsh_entry0);
2171        	}
2172
2173	    }
2174
2175	  trace00: b0->error = error0 ? node->errors[error0] : 0;
2176
2177	  if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
2178	    {
2179	      nsh_input_trace_t *tr = vlib_add_trace(vm, node, b0, sizeof(*tr));
2180	      clib_memcpy ( &(tr->trace_data[0]), hdr0, (hdr0->length*4) );
2181	    }
2182
2183	  vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
2184					  n_left_to_next, bi0, next0);
2185	}
2186
2187      vlib_put_next_frame(vm, node, next_index, n_left_to_next);
2188
2189    }
2190
2191  return from_frame->n_vectors;
2192}
2193
2194/**
2195 * @brief Graph processing dispatch function for NSH Input
2196 *
2197 * @node nsh_input
2198 * @param *vm
2199 * @param *node
2200 * @param *from_frame
2201 *
2202 * @return from_frame->n_vectors
2203 *
2204 */
2205static uword
2206nsh_input (vlib_main_t * vm, vlib_node_runtime_t * node,
2207                  vlib_frame_t * from_frame)
2208{
2209  return nsh_input_map (vm, node, from_frame, NSH_INPUT_TYPE);
2210}
2211
2212/**
2213 * @brief Graph processing dispatch function for NSH-Proxy
2214 *
2215 * @node nsh_proxy
2216 * @param *vm
2217 * @param *node
2218 * @param *from_frame
2219 *
2220 * @return from_frame->n_vectors
2221 *
2222 */
2223static uword
2224nsh_proxy (vlib_main_t * vm, vlib_node_runtime_t * node,
2225                  vlib_frame_t * from_frame)
2226{
2227  return nsh_input_map (vm, node, from_frame, NSH_PROXY_TYPE);
2228}
2229
2230/**
2231 * @brief Graph processing dispatch function for NSH Classifier
2232 *
2233 * @node nsh_classifier
2234 * @param *vm
2235 * @param *node
2236 * @param *from_frame
2237 *
2238 * @return from_frame->n_vectors
2239 *
2240 */
2241static uword
2242nsh_classifier (vlib_main_t * vm, vlib_node_runtime_t * node,
2243                  vlib_frame_t * from_frame)
2244{
2245  return nsh_input_map (vm, node, from_frame, NSH_CLASSIFIER_TYPE);
2246}
2247
2248/**
2249 * @brief Graph processing dispatch function for NSH-AWARE-VNF-PROXY
2250 *
2251 * @node nsh_aware_vnf_proxy
2252 * @param *vm
2253 * @param *node
2254 * @param *from_frame
2255 *
2256 * @return from_frame->n_vectors
2257 *
2258 */
2259static uword
2260nsh_aware_vnf_proxy (vlib_main_t * vm, vlib_node_runtime_t * node,
2261                     vlib_frame_t * from_frame)
2262{
2263  return nsh_input_map (vm, node, from_frame, NSH_AWARE_VNF_PROXY_TYPE);
2264}
2265
2266static char * nsh_node_error_strings[] = {
2267#define _(sym,string) string,
2268  foreach_nsh_node_error
2269#undef _
2270};
2271
2272/* register nsh-input node */
2273VLIB_REGISTER_NODE (nsh_input_node) = {
2274  .function = nsh_input,
2275  .name = "nsh-input",
2276  .vector_size = sizeof (u32),
2277  .format_trace = format_nsh_node_map_trace,
2278  .format_buffer = format_nsh_header,
2279  .type = VLIB_NODE_TYPE_INTERNAL,
2280
2281  .n_errors = ARRAY_LEN(nsh_node_error_strings),
2282  .error_strings = nsh_node_error_strings,
2283
2284  .n_next_nodes = NSH_NODE_N_NEXT,
2285
2286  .next_nodes = {
2287#define _(s,n) [NSH_NODE_NEXT_##s] = n,
2288    foreach_nsh_node_next
2289#undef _
2290  },
2291};
2292
2293VLIB_NODE_FUNCTION_MULTIARCH (nsh_input_node, nsh_input);
2294
2295/* register nsh-proxy node */
2296VLIB_REGISTER_NODE (nsh_proxy_node) = {
2297  .function = nsh_proxy,
2298  .name = "nsh-proxy",
2299  .vector_size = sizeof (u32),
2300  .format_trace = format_nsh_node_map_trace,
2301  .format_buffer = format_nsh_header,
2302  .type = VLIB_NODE_TYPE_INTERNAL,
2303
2304  .n_errors = ARRAY_LEN(nsh_node_error_strings),
2305  .error_strings = nsh_node_error_strings,
2306
2307  .n_next_nodes = NSH_NODE_N_NEXT,
2308
2309  .next_nodes = {
2310#define _(s,n) [NSH_NODE_NEXT_##s] = n,
2311    foreach_nsh_node_next
2312#undef _
2313  },
2314};
2315
2316VLIB_NODE_FUNCTION_MULTIARCH (nsh_proxy_node, nsh_proxy);
2317
2318/* register nsh-classifier node */
2319VLIB_REGISTER_NODE (nsh_classifier_node) = {
2320  .function = nsh_classifier,
2321  .name = "nsh-classifier",
2322  .vector_size = sizeof (u32),
2323  .format_trace = format_nsh_node_map_trace,
2324  .format_buffer = format_nsh_header,
2325  .type = VLIB_NODE_TYPE_INTERNAL,
2326
2327  .n_errors = ARRAY_LEN(nsh_node_error_strings),
2328  .error_strings = nsh_node_error_strings,
2329
2330  .n_next_nodes = NSH_NODE_N_NEXT,
2331
2332  .next_nodes = {
2333#define _(s,n) [NSH_NODE_NEXT_##s] = n,
2334    foreach_nsh_node_next
2335#undef _
2336  },
2337};
2338
2339VLIB_NODE_FUNCTION_MULTIARCH (nsh_classifier_node, nsh_classifier);
2340
2341/* register nsh-aware-vnf-proxy node */
2342VLIB_REGISTER_NODE (nsh_aware_vnf_proxy_node) = {
2343  .function = nsh_aware_vnf_proxy,
2344  .name = "nsh-aware-vnf-proxy",
2345  .vector_size = sizeof (u32),
2346  .format_trace = format_nsh_node_map_trace,
2347  .format_buffer = format_nsh_header,
2348  .type = VLIB_NODE_TYPE_INTERNAL,
2349
2350  .n_errors = ARRAY_LEN(nsh_node_error_strings),
2351  .error_strings = nsh_node_error_strings,
2352
2353  .n_next_nodes = NSH_NODE_N_NEXT,
2354
2355  .next_nodes = {
2356#define _(s,n) [NSH_NODE_NEXT_##s] = n,
2357    foreach_nsh_node_next
2358#undef _
2359  },
2360};
2361
2362VLIB_NODE_FUNCTION_MULTIARCH (nsh_aware_vnf_proxy_node, nsh_aware_vnf_proxy);
2363
2364void
2365nsh_md2_set_next_ioam_export_override (uword next)
2366{
2367  nsh_main_t *hm = &nsh_main;
2368  hm->decap_v4_next_override = next;
2369  return;
2370}
2371
2372
2373clib_error_t *nsh_init (vlib_main_t *vm)
2374{
2375  nsh_main_t *nm = &nsh_main;
2376  clib_error_t * error = 0;
2377  u8 * name;
2378  uword next_node;
2379
2380  /* Init the main structures from VPP */
2381  nm->vlib_main = vm;
2382  nm->vnet_main = vnet_get_main();
2383
2384  /* Various state maintenance mappings */
2385  nm->nsh_mapping_by_key
2386    = hash_create_mem (0, sizeof(u32), sizeof (uword));
2387
2388  nm->nsh_mapping_by_mapped_key
2389    = hash_create_mem (0, sizeof(u32), sizeof (uword));
2390
2391  nm->nsh_entry_by_key
2392    = hash_create_mem (0, sizeof(u32), sizeof (uword));
2393
2394  nm->nsh_proxy_session_by_key
2395    = hash_create_mem (0, sizeof(nsh_proxy_session_by_key_t), sizeof (uword));
2396
2397  nm->nsh_option_map_by_key
2398    = hash_create_mem (0, sizeof(nsh_option_map_by_key_t), sizeof (uword));
2399
2400  name = format (0, "nsh_%08x%c", api_version, 0);
2401
2402  /* Set up the API */
2403  nm->msg_id_base = vl_msg_api_get_msg_ids
2404    ((char *) name, VL_MSG_FIRST_AVAILABLE);
2405
2406  error = nsh_plugin_api_hookup (vm);
2407
2408  /* Add our API messages to the global name_crc hash table */
2409  setup_message_id_table (nm, &api_main);
2410
2411  /* Add dispositions to nodes that feed nsh-input */
2412  //alagalah - validate we don't really need to use the node value
2413  next_node = vlib_node_add_next (vm, vxlan4_gpe_input_node.index, nsh_input_node.index);
2414  vlib_node_add_next (vm, vxlan4_gpe_input_node.index, nsh_proxy_node.index);
2415  vlib_node_add_next (vm, vxlan4_gpe_input_node.index, nsh_aware_vnf_proxy_node.index);
2416  vxlan_gpe_register_decap_protocol (VXLAN_GPE_PROTOCOL_NSH, next_node);
2417
2418  vlib_node_add_next (vm, vxlan6_gpe_input_node.index, nsh_input_node.index);
2419  vlib_node_add_next (vm, vxlan6_gpe_input_node.index, nsh_proxy_node.index);
2420  vlib_node_add_next (vm, vxlan6_gpe_input_node.index, nsh_aware_vnf_proxy_node.index);
2421
2422  vlib_node_add_next (vm, gre4_input_node.index, nsh_input_node.index);
2423  vlib_node_add_next (vm, gre4_input_node.index, nsh_proxy_node.index);
2424  vlib_node_add_next (vm, gre4_input_node.index, nsh_aware_vnf_proxy_node.index);
2425
2426  vlib_node_add_next (vm, gre6_input_node.index, nsh_input_node.index);
2427  vlib_node_add_next (vm, gre6_input_node.index, nsh_proxy_node.index);
2428  vlib_node_add_next (vm, gre6_input_node.index, nsh_aware_vnf_proxy_node.index);
2429
2430  /* Add NSH-Proxy support */
2431  vlib_node_add_next (vm, vxlan4_input_node.index, nsh_proxy_node.index);
2432  vlib_node_add_next (vm, vxlan6_input_node.index, nsh_proxy_node.index);
2433
2434  /* Add NSH-Classifier support */
2435  vlib_node_add_next (vm, ip4_classify_node.index, nsh_classifier_node.index);
2436  vlib_node_add_next (vm, ip6_classify_node.index, nsh_classifier_node.index);
2437  vlib_node_add_next (vm, l2_input_classify_node.index, nsh_classifier_node.index);
2438
2439  /* Add Ethernet+NSH support */
2440  ethernet_register_input_type (vm, ETHERNET_TYPE_NSH, nsh_input_node.index);
2441
2442  vec_free(name);
2443
2444  return error;
2445}
2446
2447VLIB_INIT_FUNCTION(nsh_init);
2448