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