VPP43 - NSH refactoring: Added nsh-map nodes
[vpp.git] / vnet / vnet / 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 <vlib/vlib.h>
19 #include <vnet/pg/pg.h>
20 #include <vnet/nsh/nsh.h>
21
22
23 typedef struct {
24   nsh_header_t nsh_header;
25 } nsh_input_trace_t;
26
27 u8 * format_nsh_header (u8 * s, va_list * args)
28 {
29   nsh_header_t * nsh = va_arg (*args, nsh_header_t *);
30
31   s = format (s, "nsh ver %d ", (nsh->ver_o_c>>6));
32   if (nsh->ver_o_c & NSH_O_BIT)
33       s = format (s, "O-set ");
34
35   if (nsh->ver_o_c & NSH_C_BIT)
36       s = format (s, "C-set ");
37
38   s = format (s, "len %d (%d bytes) md_type %d next_protocol %d\n",
39               nsh->length, nsh->length * 4, nsh->md_type, nsh->next_protocol);
40   
41   s = format (s, "  service path %d service index %d\n",
42               (nsh->nsp_nsi>>NSH_NSP_SHIFT) & NSH_NSP_MASK,
43               nsh->nsp_nsi & NSH_NSI_MASK);
44
45   s = format (s, "  c1 %d c2 %d c3 %d c4 %d\n",
46               nsh->c1, nsh->c2, nsh->c3, nsh->c4);
47
48   return s;
49 }
50
51 u8 * format_nsh_map (u8 * s, va_list * args)
52 {
53   nsh_map_t * map = va_arg (*args, nsh_map_t *);
54
55   s = format (s, "nsh entry nsp: %d nsi: %d ",
56               (map->nsp_nsi>>NSH_NSP_SHIFT) & NSH_NSP_MASK,
57               map->nsp_nsi & NSH_NSI_MASK);
58   s = format (s, "maps to nsp: %d nsi: %d ",
59               (map->mapped_nsp_nsi>>NSH_NSP_SHIFT) & NSH_NSP_MASK,
60               map->mapped_nsp_nsi & NSH_NSI_MASK);
61   
62   switch (map->next_node)
63     {
64     case NSH_INPUT_NEXT_ENCAP_GRE:
65       {
66         s = format (s, "encapped by GRE intf: %d", map->sw_if_index);
67         break;
68       }
69     case NSH_INPUT_NEXT_ENCAP_VXLANGPE:
70       {
71         s = format (s, "encapped by VXLAN GPE intf: %d", map->sw_if_index);
72         break;
73       }
74     default:
75       s = format (s, "only GRE and VXLANGPE support in this rev");
76     }
77
78   return s;
79 }
80
81
82 #define foreach_copy_nshhdr_field               \
83 _(ver_o_c)                                      \
84 _(length)                                       \
85 _(md_type)                                      \
86 _(next_protocol)                                \
87 _(nsp_nsi)                                      \
88 _(c1)                                           \
89 _(c2)                                           \
90 _(c3)                                           \
91 _(c4)                                           
92 /* Temp killing tlvs as its causing pain - fix in NSH_SFC */
93
94
95 #define foreach_32bit_field                     \
96 _(nsp_nsi)                                      \
97 _(c1)                                           \
98 _(c2)                                           \
99 _(c3)                                           \
100 _(c4)
101
102
103 u8 * format_nsh_header_with_length (u8 * s, va_list * args)
104 {
105   nsh_header_t * h = va_arg (*args, nsh_header_t *);
106   u32 max_header_bytes = va_arg (*args, u32);
107   u32 tmp, header_bytes;
108
109   header_bytes = sizeof (h[0]);
110   if (max_header_bytes != 0 && header_bytes > max_header_bytes)
111     return format (s, "nsh header truncated");
112
113   tmp = clib_net_to_host_u32 (h->nsp_nsi);
114   s = format (s, "  nsp %d nsi %d ",
115               (tmp>>NSH_NSP_SHIFT) & NSH_NSP_MASK,
116               tmp & NSH_NSI_MASK);
117
118   s = format (s, "c1 %u c2 %u c3 %u c4 %u",
119               clib_net_to_host_u32 (h->c1),
120               clib_net_to_host_u32 (h->c2),
121               clib_net_to_host_u32 (h->c3),
122               clib_net_to_host_u32 (h->c4));
123
124   s = format (s, "ver %d ", h->ver_o_c>>6);
125
126   if (h->ver_o_c & NSH_O_BIT)
127       s = format (s, "O-set ");
128
129   if (h->ver_o_c & NSH_C_BIT)
130       s = format (s, "C-set ");
131
132   s = format (s, "len %d (%d bytes) md_type %d next_protocol %d\n",
133               h->length, h->length * 4, h->md_type, h->next_protocol);
134   return s;
135 }
136
137 u8 * format_nsh_input_map_trace (u8 * s, va_list * args)
138 {
139   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
140   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
141   nsh_input_trace_t * t
142       = va_arg (*args, nsh_input_trace_t *);
143
144   s = format (s, "\n  %U", format_nsh_header, &t->nsh_header, 
145               (u32) sizeof (t->nsh_header) ); 
146
147   return s;
148 }
149
150 static uword
151 nsh_input_map (vlib_main_t * vm,
152                vlib_node_runtime_t * node,
153                vlib_frame_t * from_frame)
154 {
155   u32 n_left_from, next_index, * from, * to_next;
156   nsh_main_t * nm = &nsh_main;
157
158   from = vlib_frame_vector_args (from_frame);
159   n_left_from = from_frame->n_vectors;
160
161   next_index = node->cached_next_index;
162
163   while (n_left_from > 0)
164     {
165       u32 n_left_to_next;
166
167       vlib_get_next_frame (vm, node, next_index,
168                            to_next, n_left_to_next);
169
170       while (n_left_from >= 4 && n_left_to_next >= 2)
171         {
172           u32 bi0, bi1;
173           vlib_buffer_t * b0, * b1;
174           u32 next0 = NSH_INPUT_NEXT_DROP, next1 = NSH_INPUT_NEXT_DROP; 
175           uword * entry0, * entry1;
176           nsh_header_t * hdr0 = 0, * hdr1 = 0;
177           u32 nsp_nsi0, nsp_nsi1;
178           u32 error0, error1;
179           nsh_map_t * map0 = 0, * map1 = 0;
180
181           /* Prefetch next iteration. */
182           {
183             vlib_buffer_t * p2, * p3;
184
185             p2 = vlib_get_buffer (vm, from[2]);
186             p3 = vlib_get_buffer (vm, from[3]);
187
188             vlib_prefetch_buffer_header (p2, LOAD);
189             vlib_prefetch_buffer_header (p3, LOAD);
190
191             CLIB_PREFETCH (p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
192             CLIB_PREFETCH (p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
193           }
194
195           bi0 = from[0];
196           bi1 = from[1];
197           to_next[0] = bi0;
198           to_next[1] = bi1;
199           from += 2;
200           to_next += 2;
201           n_left_from -= 2;
202           n_left_to_next -= 2;
203
204           error0 = 0;
205           error1 = 0;
206
207           b0 = vlib_get_buffer (vm, bi0);
208           hdr0 = vlib_buffer_get_current (b0);
209           nsp_nsi0 = clib_net_to_host_u32(hdr0->nsp_nsi);
210           entry0 = hash_get_mem (nm->nsh_mapping_by_key, &nsp_nsi0);
211
212           b1 = vlib_get_buffer (vm, bi1);
213           hdr1 = vlib_buffer_get_current (b1);
214           nsp_nsi1 = clib_net_to_host_u32(hdr1->nsp_nsi);
215           entry1 = hash_get_mem (nm->nsh_mapping_by_key, &nsp_nsi1);
216
217           if (PREDICT_FALSE(entry0 == 0))
218             {
219               error0 = NSH_INPUT_ERROR_NO_MAPPING;
220               goto trace0;
221             }
222           
223           if (PREDICT_FALSE(entry1 == 0))
224             {
225               error1 = NSH_INPUT_ERROR_NO_MAPPING;
226               goto trace1;
227             }
228           
229           /* Entry should point to a mapping ...*/
230           map0 = pool_elt_at_index (nm->nsh_mappings, entry0[0]);
231           map1 = pool_elt_at_index (nm->nsh_mappings, entry1[0]);
232
233           if (PREDICT_FALSE(map0 == 0))
234             {
235               error0 = NSH_INPUT_ERROR_NO_MAPPING;
236               goto trace0;
237             }
238
239           if (PREDICT_FALSE(map1 == 0))
240             {
241               error1 = NSH_INPUT_ERROR_NO_MAPPING;
242               goto trace1;
243             }
244
245           entry0 = hash_get_mem (nm->nsh_entry_by_key, &map0->mapped_nsp_nsi);
246           entry1 = hash_get_mem (nm->nsh_entry_by_key, &map1->mapped_nsp_nsi);
247
248           if (PREDICT_FALSE(entry0 == 0))
249             {
250               error0 = NSH_INPUT_ERROR_NO_MAPPING;
251               goto trace0;
252             }
253           if (PREDICT_FALSE(entry1 == 0))
254             {
255               error1 = NSH_INPUT_ERROR_NO_MAPPING;
256               goto trace1;
257             }
258
259           hdr0 = pool_elt_at_index (nm->nsh_entries, entry0[0]);
260           hdr1 = pool_elt_at_index (nm->nsh_entries, entry1[0]);
261
262           /* set up things for next node to transmit ie which node to handle it and where */
263           next0 = map0->next_node;
264           next1 = map1->next_node;
265           vnet_buffer(b0)->sw_if_index[VLIB_TX] = map0->sw_if_index;
266           vnet_buffer(b1)->sw_if_index[VLIB_TX] = map1->sw_if_index;
267
268         trace0:
269           b0->error = error0 ? node->errors[error0] : 0;
270
271           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
272             {
273               nsh_input_trace_t *tr =
274                 vlib_add_trace (vm, node, b0, sizeof (*tr));
275               tr->nsh_header = *hdr0; 
276             }
277
278         trace1:
279           b1->error = error1 ? node->errors[error1] : 0;
280
281           if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
282             {
283               nsh_input_trace_t *tr =
284                 vlib_add_trace (vm, node, b1, sizeof (*tr));
285               tr->nsh_header = *hdr1; 
286             }
287
288
289           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
290                                            to_next, n_left_to_next,
291                                            bi0, bi1, next0, next1);
292
293         }
294
295       while (n_left_from > 0 && n_left_to_next > 0)
296         {
297           u32 bi0;
298           vlib_buffer_t * b0;
299           u32 next0 = NSH_INPUT_NEXT_DROP; 
300           uword * entry0;
301           nsh_header_t * hdr0 = 0;
302           u32 nsp_nsi0;
303           u32 error0;
304           nsh_map_t * map0 = 0;
305
306           next_index = next0; 
307           bi0 = from[0];
308           to_next[0] = bi0;
309           from += 1;
310           to_next += 1;
311           n_left_from -= 1;
312           n_left_to_next -= 1;
313           error0 = 0;
314
315           b0 = vlib_get_buffer (vm, bi0);
316           hdr0 = vlib_buffer_get_current (b0);
317           nsp_nsi0 = clib_net_to_host_u32(hdr0->nsp_nsi);
318           entry0 = hash_get_mem (nm->nsh_mapping_by_key, &nsp_nsi0);
319
320           if (PREDICT_FALSE(entry0 == 0))
321             {
322               error0 = NSH_INPUT_ERROR_NO_MAPPING;
323               goto trace00;
324             }
325           
326           /* Entry should point to a mapping ...*/
327           map0 = pool_elt_at_index (nm->nsh_mappings, entry0[0]);
328
329           if (PREDICT_FALSE(map0 == 0))
330             {
331               error0 = NSH_INPUT_ERROR_NO_MAPPING;
332               goto trace00;
333             }
334
335           entry0 = hash_get_mem (nm->nsh_entry_by_key, &map0->mapped_nsp_nsi);
336
337           if (PREDICT_FALSE(entry0 == 0))
338             {
339               error0 = NSH_INPUT_ERROR_NO_MAPPING;
340               goto trace00;
341             }
342
343           hdr0 = pool_elt_at_index (nm->nsh_entries, entry0[0]);
344
345           /* set up things for next node to transmit ie which node to handle it and where */
346           next0 = map0->next_node;
347           vnet_buffer(b0)->sw_if_index[VLIB_TX] = map0->sw_if_index;
348
349         trace00:
350           b0->error = error0 ? node->errors[error0] : 0;
351
352           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
353             {
354               nsh_input_trace_t *tr =
355                 vlib_add_trace (vm, node, b0, sizeof (*tr));
356               tr->nsh_header = *hdr0; 
357             }
358
359
360           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
361                                            to_next, n_left_to_next,
362                                            bi0, next0);
363         }
364
365       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
366
367     }
368
369
370   return from_frame->n_vectors;
371 }
372
373
374 int vnet_nsh_add_del_map (vnet_nsh_add_del_map_args_t *a)
375 {
376   nsh_main_t * nm = &nsh_main;
377   nsh_map_t *map = 0;
378   u32 key, *key_copy;
379   uword * entry;
380   hash_pair_t *hp;
381
382   key = a->map.nsp_nsi;
383   
384   entry = hash_get_mem (nm->nsh_mapping_by_key, &key);
385
386   if (a->is_add)
387     {
388       /* adding an entry, must not already exist */
389       if (entry)
390         return VNET_API_ERROR_INVALID_VALUE;
391       
392       pool_get_aligned (nm->nsh_mappings, map, CLIB_CACHE_LINE_BYTES);
393       memset (map, 0, sizeof (*map));
394
395       /* copy from arg structure */
396       map->nsp_nsi = a->map.nsp_nsi;
397       map->mapped_nsp_nsi = a->map.mapped_nsp_nsi;
398       map->sw_if_index = a->map.sw_if_index;
399       map->next_node = a->map.next_node;
400       
401
402       key_copy = clib_mem_alloc (sizeof (*key_copy));
403       clib_memcpy (key_copy, &key, sizeof (*key_copy));
404
405       hash_set_mem (nm->nsh_mapping_by_key, key_copy,
406                     map - nm->nsh_mappings);
407     }
408   else
409     {
410       if (!entry)
411         return VNET_API_ERROR_NO_SUCH_ENTRY;
412
413       map = pool_elt_at_index (nm->nsh_mappings, entry[0]);
414       hp = hash_get_pair (nm->nsh_mapping_by_key, &key);
415       key_copy = (void *)(hp->key);
416       hash_unset_mem (nm->nsh_mapping_by_key, &key);
417       clib_mem_free (key_copy);
418
419       pool_put (nm->nsh_mappings, map);
420     }
421
422   return 0;
423 }
424
425 static clib_error_t *
426 nsh_add_del_map_command_fn (vlib_main_t * vm,
427                                    unformat_input_t * input,
428                                    vlib_cli_command_t * cmd)
429 {
430   unformat_input_t _line_input, * line_input = &_line_input;
431   u8 is_add = 1;
432   u32 nsp, nsi, mapped_nsp, mapped_nsi;
433   int nsp_set = 0, nsi_set = 0, mapped_nsp_set = 0, mapped_nsi_set = 0;
434   u32 next_node = ~0;
435   u32 sw_if_index = ~0; // temporary requirement to get this moved over to NSHSFC
436   vnet_nsh_add_del_map_args_t _a, * a = &_a;
437   int rv;
438
439   /* Get a line of input. */
440   if (! unformat_user (input, unformat_line_input, line_input))
441     return 0;
442   
443   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
444     if (unformat (line_input, "del"))
445       is_add = 0;
446     else if (unformat (line_input, "nsp %d", &nsp))
447       nsp_set = 1;
448     else if (unformat (line_input, "nsi %d", &nsi))
449       nsi_set = 1;
450     else if (unformat (line_input, "mapped-nsp %d", &mapped_nsp))
451       mapped_nsp_set = 1;
452     else if (unformat (line_input, "mapped-nsi %d", &mapped_nsi))
453       mapped_nsi_set = 1;
454     else if (unformat (line_input, "encap-gre-intf %d", &sw_if_index))
455       next_node = NSH_INPUT_NEXT_ENCAP_GRE;
456     else if (unformat (line_input, "encap-vxlan-gpe-intf %d", &sw_if_index))
457       next_node = NSH_INPUT_NEXT_ENCAP_VXLANGPE;
458     else if (unformat (line_input, "encap-none"))
459       next_node = NSH_INPUT_NEXT_DROP; // Once moved to NSHSFC see nsh.h:foreach_nsh_input_next to handle this case
460     else 
461       return clib_error_return (0, "parse error: '%U'", 
462                                 format_unformat_error, line_input);
463   }
464
465   unformat_free (line_input);
466
467   if (nsp_set == 0 || nsi_set == 0)
468     return clib_error_return (0, "nsp nsi pair required. Key: for NSH entry");
469
470   if (mapped_nsp_set == 0 || mapped_nsi_set == 0)
471     return clib_error_return (0, "mapped-nsp mapped-nsi pair required. Key: for NSH entry");
472
473   if (next_node == ~0)
474     return clib_error_return (0, "must specific action: [encap-gre-intf <nn> | encap-vxlan-gpe-intf <nn> | encap-none]");
475
476   memset (a, 0, sizeof (*a));
477
478   /* set args structure */
479   a->is_add = is_add;
480   a->map.nsp_nsi = (nsp<< NSH_NSP_SHIFT) | nsi;
481   a->map.mapped_nsp_nsi = (mapped_nsp<< NSH_NSP_SHIFT) | mapped_nsi;
482   a->map.sw_if_index = sw_if_index;
483   a->map.next_node = next_node;
484
485
486   rv = vnet_nsh_add_del_map (a);
487
488   switch(rv)
489     {
490     case 0:
491       break;
492     case VNET_API_ERROR_INVALID_VALUE:
493       return clib_error_return (0, "mapping already exists. Remove it first.");
494
495     case VNET_API_ERROR_NO_SUCH_ENTRY:
496       return clib_error_return (0, "mapping does not exist.");
497
498     default:
499       return clib_error_return 
500         (0, "vnet_nsh_add_del_map returned %d", rv);
501     }
502   return 0;
503 }
504
505
506 VLIB_CLI_COMMAND (create_nsh_map_command, static) = {
507   .path = "create nsh map",
508   .short_help = 
509   "create nsh map nsp <nn> nsi <nn> [del] map-nsp <nn> map-nsi <nn> [encap-gre-intf <nn> | encap-vxlan-gpe-intf <nn> | encap-none]\n",
510   .function = nsh_add_del_map_command_fn,
511 };
512
513 static clib_error_t *
514 show_nsh_map_command_fn (vlib_main_t * vm,
515                                       unformat_input_t * input,
516                                       vlib_cli_command_t * cmd)
517 {
518   nsh_main_t * nm = &nsh_main;
519   nsh_map_t * map;
520
521   if (pool_elts (nm->nsh_mappings) == 0)
522     vlib_cli_output (vm, "No nsh maps configured.");
523
524   pool_foreach (map, nm->nsh_mappings,
525                 ({
526                   vlib_cli_output (vm, "%U", format_nsh_map, map);
527                 }));
528
529   return 0;
530 }
531
532 VLIB_CLI_COMMAND (show_nsh_map_command, static) = {
533   .path = "show nsh map",
534   .function = show_nsh_map_command_fn,
535 };
536
537
538 int vnet_nsh_add_del_entry (vnet_nsh_add_del_entry_args_t *a)
539 {
540   nsh_main_t * nm = &nsh_main;
541   nsh_header_t *hdr = 0;
542   u32 key, *key_copy;
543   uword * entry;
544   hash_pair_t *hp;
545
546   key = a->nsh.nsp_nsi;
547   
548   entry = hash_get_mem (nm->nsh_entry_by_key, &key);
549
550   if (a->is_add)
551     {
552       /* adding an entry, must not already exist */
553       if (entry)
554         return VNET_API_ERROR_INVALID_VALUE;
555       
556       pool_get_aligned (nm->nsh_entries, hdr, CLIB_CACHE_LINE_BYTES);
557       memset (hdr, 0, sizeof (*hdr));
558
559       /* copy from arg structure */
560 #define _(x) hdr->x = a->nsh.x;
561       foreach_copy_nshhdr_field;
562 #undef _
563
564       key_copy = clib_mem_alloc (sizeof (*key_copy));
565       clib_memcpy (key_copy, &key, sizeof (*key_copy));
566
567       hash_set_mem (nm->nsh_entry_by_key, key_copy,
568                     hdr - nm->nsh_entries);
569     }
570   else
571     {
572       if (!entry)
573         return VNET_API_ERROR_NO_SUCH_ENTRY;
574
575       hdr = pool_elt_at_index (nm->nsh_entries, entry[0]);
576       hp = hash_get_pair (nm->nsh_entry_by_key, &key);
577       key_copy = (void *)(hp->key);
578       hash_unset_mem (nm->nsh_entry_by_key, &key);
579       clib_mem_free (key_copy);
580
581       pool_put (nm->nsh_entries, hdr);
582     }
583
584   return 0;
585 }
586
587
588 static clib_error_t *
589 nsh_add_del_entry_command_fn (vlib_main_t * vm,
590                                    unformat_input_t * input,
591                                    vlib_cli_command_t * cmd)
592 {
593   unformat_input_t _line_input, * line_input = &_line_input;
594   u8 is_add = 1;
595   u8 ver_o_c = 0;
596   u8 length = 0;
597   u8 md_type = 0;
598   u8 next_protocol = 1; /* default: ip4 */
599   u32 nsp;
600   u8 nsp_set = 0;
601   u32 nsi;
602   u8 nsi_set = 0;
603   u32 nsp_nsi;
604   u32 c1 = 0;
605   u32 c2 = 0;
606   u32 c3 = 0;
607   u32 c4 = 0;
608   u32 *tlvs = 0;
609   u32 tmp;
610   int rv;
611   vnet_nsh_add_del_entry_args_t _a, * a = &_a;
612   
613   /* Get a line of input. */
614   if (! unformat_user (input, unformat_line_input, line_input))
615     return 0;
616
617   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
618     if (unformat (line_input, "del"))
619       is_add = 0;
620     else if (unformat (line_input, "version %d", &tmp))
621       ver_o_c |= (tmp & 3) << 6;
622     else if (unformat (line_input, "o-bit %d", &tmp))
623       ver_o_c |= (tmp & 1) << 5;
624     else if (unformat (line_input, "c-bit %d", &tmp))
625       ver_o_c |= (tmp & 1) << 4;
626     else if (unformat (line_input, "md-type %d", &tmp))
627       md_type = tmp;
628     else if (unformat(line_input, "next-ip4"))
629       next_protocol = 1;
630     else if (unformat(line_input, "next-ip6"))
631       next_protocol = 2;
632     else if (unformat(line_input, "next-ethernet"))
633       next_protocol = 3;
634     else if (unformat (line_input, "c1 %d", &c1))
635       ;
636     else if (unformat (line_input, "c2 %d", &c2))
637       ;
638     else if (unformat (line_input, "c3 %d", &c3))
639       ;
640     else if (unformat (line_input, "c4 %d", &c4))
641       ;
642     else if (unformat (line_input, "nsp %d", &nsp))
643       nsp_set = 1;
644     else if (unformat (line_input, "nsi %d", &nsi))
645       nsi_set = 1;
646     else if (unformat (line_input, "tlv %x"))
647         vec_add1 (tlvs, tmp);
648     else 
649       return clib_error_return (0, "parse error: '%U'", 
650                                 format_unformat_error, line_input);
651   }
652
653   unformat_free (line_input);
654
655   if (nsp_set == 0)
656     return clib_error_return (0, "nsp not specified");
657   
658   if (nsi_set == 0)
659     return clib_error_return (0, "nsi not specified");
660
661   if (md_type != 1)
662     return clib_error_return (0, "md-type 1 only supported at this time");
663
664   md_type = 1;
665   length = 6; 
666
667   nsp_nsi = (nsp<<8) | nsi;
668   
669   memset (a, 0, sizeof (*a));
670
671   a->is_add = is_add;
672
673 #define _(x) a->nsh.x = x;
674   foreach_copy_nshhdr_field;
675 #undef _
676   
677   a->nsh.tlvs[0] = 0 ; // TODO FIXME this shouldn't be set 0 - in NSH_SFC project
678
679   rv = vnet_nsh_add_del_entry (a);
680
681   switch(rv)
682     {
683     case 0:
684       break;
685     default:
686       return clib_error_return 
687         (0, "vnet_nsh_add_del_entry returned %d", rv);
688     }
689
690   return 0;
691 }
692
693 VLIB_CLI_COMMAND (create_nsh_entry_command, static) = {
694   .path = "create nsh entry",
695   .short_help = 
696   "create nsh entry {nsp <nn> nsi <nn>} c1 <nn> c2 <nn> c3 <nn> c4 <nn>"
697   " [md-type <nn>] [tlv <xx>] [del]\n",
698   .function = nsh_add_del_entry_command_fn,
699 };
700
701 static clib_error_t *
702 show_nsh_entry_command_fn (vlib_main_t * vm,
703                                       unformat_input_t * input,
704                                       vlib_cli_command_t * cmd)
705 {
706   nsh_main_t * nm = &nsh_main;
707   nsh_header_t * hdr;
708
709   if (pool_elts (nm->nsh_entries) == 0)
710     vlib_cli_output (vm, "No nsh entries configured.");
711
712   pool_foreach (hdr, nm->nsh_entries,
713                 ({
714                   vlib_cli_output (vm, "%U", format_nsh_header, hdr);
715                 }));
716
717   return 0;
718 }
719
720 VLIB_CLI_COMMAND (show_nsh_entry_command, static) = {
721   .path = "show nsh entry",
722   .function = show_nsh_entry_command_fn,
723 };
724
725 static char * nsh_input_error_strings[] = {
726 #define _(sym,string) string,
727   foreach_nsh_input_error
728 #undef _
729 };
730
731 VLIB_REGISTER_NODE (nsh_input_node) = {
732   .function = nsh_input_map,
733   .name = "nsh-input",
734   .vector_size = sizeof (u32),
735   .format_trace = format_nsh_input_map_trace,
736   .format_buffer = format_nsh_header_with_length,
737   .type = VLIB_NODE_TYPE_INTERNAL,
738
739   .n_errors = ARRAY_LEN(nsh_input_error_strings),
740   .error_strings = nsh_input_error_strings,
741
742   .n_next_nodes = NSH_INPUT_N_NEXT,
743
744   .next_nodes = {
745 #define _(s,n) [NSH_INPUT_NEXT_##s] = n,
746     foreach_nsh_input_next
747 #undef _
748   },
749 };
750
751 clib_error_t *nsh_init (vlib_main_t *vm)
752 {
753   nsh_main_t *nm = &nsh_main;
754   
755   nm->vnet_main = vnet_get_main();
756   nm->vlib_main = vm;
757   
758   nm->nsh_mapping_by_key
759     = hash_create_mem (0, sizeof(u32), sizeof (uword));
760
761   nm->nsh_mapping_by_mapped_key
762     = hash_create_mem (0, sizeof(u32), sizeof (uword));
763
764   nm->nsh_entry_by_key
765     = hash_create_mem (0, sizeof(u32), sizeof (uword));
766
767   return 0;
768 }
769
770 VLIB_INIT_FUNCTION(nsh_init);