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