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