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