nsh.c revision ed5a133e
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
22#include <vlibapi/api.h>
23#include <vlibmemory/api.h>
24#include <vlibsocket/api.h>
25
26/* define message IDs */
27#include <nsh/nsh_msg_enum.h>
28
29/* define message structures */
30#define vl_typedefs
31#include <nsh/nsh_all_api_h.h>
32#undef vl_typedefs
33
34/* define generated endian-swappers */
35#define vl_endianfun
36#include <nsh/nsh_all_api_h.h>
37#undef vl_endianfun
38
39/* instantiate all the print functions we know about */
40#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
41#define vl_printfun
42#include <nsh/nsh_all_api_h.h>
43#undef vl_printfun
44
45/* Get the API version number */
46#define vl_api_version(n,v) static u32 api_version=(v);
47#include <nsh/nsh_all_api_h.h>
48#undef vl_api_version
49
50/*
51 * A handy macro to set up a message reply.
52 * Assumes that the following variables are available:
53 * mp - pointer to request message
54 * rmp - pointer to reply message type
55 * rv - return value
56 */
57
58#define REPLY_MACRO(t)                                          \
59  do {								\
60    unix_shared_memory_queue_t * q =                            \
61      vl_api_client_index_to_input_queue (mp->client_index);	\
62    if (!q)                                                     \
63      return;							\
64                                                                \
65    rmp = vl_msg_api_alloc (sizeof (*rmp));                     \
66    rmp->_vl_msg_id = ntohs((t)+nm->msg_id_base);               \
67    rmp->context = mp->context;                                 \
68    rmp->retval = ntohl(rv);                                    \
69                                                                \
70    vl_msg_api_send_shmem (q, (u8 *)&rmp);                      \
71  } while(0);
72
73/* List of message types that this plugin understands */
74
75#define foreach_nsh_plugin_api_msg		\
76  _(NSH_ADD_DEL_ENTRY, nsh_add_del_entry)	\
77  _(NSH_ADD_DEL_MAP, nsh_add_del_map)
78
79clib_error_t *
80vlib_plugin_register (vlib_main_t * vm, vnet_plugin_handoff_t * h,
81                      int from_early_init)
82{
83  nsh_main_t * nm = &nsh_main;
84  clib_error_t * error = 0;
85
86  nm->vlib_main = vm;
87  nm->vnet_main = h->vnet_main;
88
89  return error;
90}
91
92typedef struct {
93  nsh_header_t nsh_header;
94} nsh_input_trace_t;
95
96u8 * format_nsh_header (u8 * s, va_list * args)
97{
98  nsh_header_t * nsh = va_arg (*args, nsh_header_t *);
99
100  s = format (s, "nsh ver %d ", (nsh->ver_o_c>>6));
101  if (nsh->ver_o_c & NSH_O_BIT)
102    s = format (s, "O-set ");
103
104  if (nsh->ver_o_c & NSH_C_BIT)
105    s = format (s, "C-set ");
106
107  s = format (s, "len %d (%d bytes) md_type %d next_protocol %d\n",
108              nsh->length, nsh->length * 4, nsh->md_type, nsh->next_protocol);
109
110  s = format (s, "  service path %d service index %d\n",
111              (nsh->nsp_nsi>>NSH_NSP_SHIFT) & NSH_NSP_MASK,
112              nsh->nsp_nsi & NSH_NSI_MASK);
113
114  s = format (s, "  c1 %d c2 %d c3 %d c4 %d\n",
115              nsh->c1, nsh->c2, nsh->c3, nsh->c4);
116
117  return s;
118}
119
120u8 * format_nsh_map (u8 * s, va_list * args)
121{
122  nsh_map_t * map = va_arg (*args, nsh_map_t *);
123
124  s = format (s, "nsh entry nsp: %d nsi: %d ",
125              (map->nsp_nsi>>NSH_NSP_SHIFT) & NSH_NSP_MASK,
126              map->nsp_nsi & NSH_NSI_MASK);
127  s = format (s, "maps to nsp: %d nsi: %d ",
128              (map->mapped_nsp_nsi>>NSH_NSP_SHIFT) & NSH_NSP_MASK,
129              map->mapped_nsp_nsi & NSH_NSI_MASK);
130
131  switch (map->next_node)
132    {
133    case NSH_INPUT_NEXT_ENCAP_GRE:
134      {
135	s = format (s, "encapped by GRE intf: %d", map->sw_if_index);
136	break;
137      }
138    case NSH_INPUT_NEXT_ENCAP_VXLANGPE:
139      {
140	s = format (s, "encapped by VXLAN GPE intf: %d", map->sw_if_index);
141	break;
142      }
143    default:
144      s = format (s, "only GRE and VXLANGPE support in this rev");
145    }
146
147  return s;
148}
149
150u8 * format_nsh_header_with_length (u8 * s, va_list * args)
151{
152  nsh_header_t * h = va_arg (*args, nsh_header_t *);
153  u32 max_header_bytes = va_arg (*args, u32);
154  u32 tmp, header_bytes;
155
156  header_bytes = sizeof (h[0]);
157  if (max_header_bytes != 0 && header_bytes > max_header_bytes)
158    return format (s, "nsh header truncated");
159
160  tmp = clib_net_to_host_u32 (h->nsp_nsi);
161  s = format (s, "  nsp %d nsi %d ",
162              (tmp>>NSH_NSP_SHIFT) & NSH_NSP_MASK,
163              tmp & NSH_NSI_MASK);
164
165  s = format (s, "c1 %u c2 %u c3 %u c4 %u",
166              clib_net_to_host_u32 (h->c1),
167              clib_net_to_host_u32 (h->c2),
168              clib_net_to_host_u32 (h->c3),
169              clib_net_to_host_u32 (h->c4));
170
171  s = format (s, "ver %d ", h->ver_o_c>>6);
172
173  if (h->ver_o_c & NSH_O_BIT)
174    s = format (s, "O-set ");
175
176  if (h->ver_o_c & NSH_C_BIT)
177    s = format (s, "C-set ");
178
179  s = format (s, "len %d (%d bytes) md_type %d next_protocol %d\n",
180              h->length, h->length * 4, h->md_type, h->next_protocol);
181  return s;
182}
183
184u8 * format_nsh_input_map_trace (u8 * s, va_list * args)
185{
186  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
187  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
188  nsh_input_trace_t * t
189    = va_arg (*args, nsh_input_trace_t *);
190
191  s = format (s, "\n  %U", format_nsh_header, &t->nsh_header,
192              (u32) sizeof (t->nsh_header) );
193
194  return s;
195}
196
197/**
198 * Action function to add or del an nsh map.
199 * Shared by both CLI and binary API
200 **/
201
202int nsh_add_del_map (nsh_add_del_map_args_t *a)
203{
204  nsh_main_t * nm = &nsh_main;
205  nsh_map_t *map = 0;
206  u32 key, *key_copy;
207  uword * entry;
208  hash_pair_t *hp;
209
210  key = a->map.nsp_nsi;
211
212  entry = hash_get_mem (nm->nsh_mapping_by_key, &key);
213
214  if (a->is_add)
215    {
216      /* adding an entry, must not already exist */
217      if (entry)
218        return -1; //TODO API_ERROR_INVALID_VALUE;
219
220      pool_get_aligned (nm->nsh_mappings, map, CLIB_CACHE_LINE_BYTES);
221      memset (map, 0, sizeof (*map));
222
223      /* copy from arg structure */
224      map->nsp_nsi = a->map.nsp_nsi;
225      map->mapped_nsp_nsi = a->map.mapped_nsp_nsi;
226      map->sw_if_index = a->map.sw_if_index;
227      map->next_node = a->map.next_node;
228
229
230      key_copy = clib_mem_alloc (sizeof (*key_copy));
231      clib_memcpy (key_copy, &key, sizeof (*key_copy));
232
233      hash_set_mem (nm->nsh_mapping_by_key, key_copy,
234                    map - nm->nsh_mappings);
235    }
236  else
237    {
238      if (!entry)
239	return -2 ; //TODO API_ERROR_NO_SUCH_ENTRY;
240
241      map = pool_elt_at_index (nm->nsh_mappings, entry[0]);
242      hp = hash_get_pair (nm->nsh_mapping_by_key, &key);
243      key_copy = (void *)(hp->key);
244      hash_unset_mem (nm->nsh_mapping_by_key, &key);
245      clib_mem_free (key_copy);
246
247      pool_put (nm->nsh_mappings, map);
248    }
249
250  return 0;
251}
252
253/**
254 * CLI command for NSH map
255 */
256
257
258static clib_error_t *
259nsh_add_del_map_command_fn (vlib_main_t * vm,
260			    unformat_input_t * input,
261			    vlib_cli_command_t * cmd)
262{
263  unformat_input_t _line_input, * line_input = &_line_input;
264  u8 is_add = 1;
265  u32 nsp, nsi, mapped_nsp, mapped_nsi;
266  int nsp_set = 0, nsi_set = 0, mapped_nsp_set = 0, mapped_nsi_set = 0;
267  u32 next_node = ~0;
268  u32 sw_if_index = ~0; // temporary requirement to get this moved over to NSHSFC
269  nsh_add_del_map_args_t _a, * a = &_a;
270  int rv;
271
272  /* Get a line of input. */
273  if (! unformat_user (input, unformat_line_input, line_input))
274    return 0;
275
276  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
277    if (unformat (line_input, "del"))
278      is_add = 0;
279    else if (unformat (line_input, "nsp %d", &nsp))
280      nsp_set = 1;
281    else if (unformat (line_input, "nsi %d", &nsi))
282      nsi_set = 1;
283    else if (unformat (line_input, "mapped-nsp %d", &mapped_nsp))
284      mapped_nsp_set = 1;
285    else if (unformat (line_input, "mapped-nsi %d", &mapped_nsi))
286      mapped_nsi_set = 1;
287    else if (unformat (line_input, "encap-gre-intf %d", &sw_if_index))
288      next_node = NSH_INPUT_NEXT_ENCAP_GRE;
289    else if (unformat (line_input, "encap-vxlan-gpe-intf %d", &sw_if_index))
290      next_node = NSH_INPUT_NEXT_ENCAP_VXLANGPE;
291    else if (unformat (line_input, "encap-none"))
292      next_node = NSH_INPUT_NEXT_DROP; // Once moved to NSHSFC see nsh.h:foreach_nsh_input_next to handle this case
293    else
294      return clib_error_return (0, "parse error: '%U'",
295                                format_unformat_error, line_input);
296  }
297
298  unformat_free (line_input);
299
300  if (nsp_set == 0 || nsi_set == 0)
301    return clib_error_return (0, "nsp nsi pair required. Key: for NSH entry");
302
303  if (mapped_nsp_set == 0 || mapped_nsi_set == 0)
304    return clib_error_return (0, "mapped-nsp mapped-nsi pair required. Key: for NSH entry");
305
306  if (next_node == ~0)
307    return clib_error_return (0, "must specific action: [encap-gre-intf <nn> | encap-vxlan-gpe-intf <nn> | encap-none]");
308
309  memset (a, 0, sizeof (*a));
310
311  /* set args structure */
312  a->is_add = is_add;
313  a->map.nsp_nsi = (nsp<< NSH_NSP_SHIFT) | nsi;
314  a->map.mapped_nsp_nsi = (mapped_nsp<< NSH_NSP_SHIFT) | mapped_nsi;
315  a->map.sw_if_index = sw_if_index;
316  a->map.next_node = next_node;
317
318
319  rv = nsh_add_del_map (a);
320
321  switch(rv)
322    {
323    case 0:
324      break;
325    case -1: //TODO API_ERROR_INVALID_VALUE:
326      return clib_error_return (0, "mapping already exists. Remove it first.");
327
328    case -2: // TODO API_ERROR_NO_SUCH_ENTRY:
329      return clib_error_return (0, "mapping does not exist.");
330
331    default:
332      return clib_error_return
333        (0, "nsh_add_del_map returned %d", rv);
334    }
335  return 0;
336}
337
338VLIB_CLI_COMMAND (create_nsh_map_command, static) = {
339  .path = "create nsh map",
340  .short_help =
341  "create nsh map nsp <nn> nsi <nn> [del] mapped-nsp <nn> mapped-nsi <nn> [encap-gre-intf <nn> | encap-vxlan-gpe-intf <nn> | encap-none]\n",
342  .function = nsh_add_del_map_command_fn,
343};
344
345/** API message handler */
346static void vl_api_nsh_add_del_map_t_handler
347(vl_api_nsh_add_del_map_t * mp)
348{
349  vl_api_nsh_add_del_map_reply_t * rmp;
350  nsh_main_t * nm = &nsh_main;
351  int rv;
352  nsh_add_del_map_args_t _a, *a = &_a;
353
354  a->is_add = mp->is_add;
355  a->map.nsp_nsi = mp->nsp_nsi;
356  a->map.mapped_nsp_nsi = mp->mapped_nsp_nsi;
357  a->map.sw_if_index = mp->sw_if_index;
358  a->map.next_node = mp->next_node;
359
360  rv = nsh_add_del_map (a);
361
362  REPLY_MACRO(VL_API_NSH_ADD_DEL_MAP_REPLY);
363}
364
365/**
366 * CLI command for showing the mapping between NSH entries
367 */
368static clib_error_t *
369show_nsh_map_command_fn (vlib_main_t * vm,
370			 unformat_input_t * input,
371			 vlib_cli_command_t * cmd)
372{
373  nsh_main_t * nm = &nsh_main;
374  nsh_map_t * map;
375
376  if (pool_elts (nm->nsh_mappings) == 0)
377    vlib_cli_output (vm, "No nsh maps configured.");
378
379  pool_foreach (map, nm->nsh_mappings,
380		({
381		  vlib_cli_output (vm, "%U", format_nsh_map, map);
382		}));
383
384  return 0;
385}
386
387VLIB_CLI_COMMAND (show_nsh_map_command, static) = {
388  .path = "show nsh map",
389  .function = show_nsh_map_command_fn,
390};
391
392/**
393 * Action function for adding an NSH entry
394 */
395
396int nsh_add_del_entry (nsh_add_del_entry_args_t *a)
397{
398  nsh_main_t * nm = &nsh_main;
399  nsh_header_t *hdr = 0;
400  u32 key, *key_copy;
401  uword * entry;
402  hash_pair_t *hp;
403
404  key = a->nsh.nsp_nsi;
405
406  entry = hash_get_mem (nm->nsh_entry_by_key, &key);
407
408  if (a->is_add)
409    {
410      /* adding an entry, must not already exist */
411      if (entry)
412        return -1; // TODO VNET_API_ERROR_INVALID_VALUE;
413
414      pool_get_aligned (nm->nsh_entries, hdr, CLIB_CACHE_LINE_BYTES);
415      memset (hdr, 0, sizeof (*hdr));
416
417      /* copy from arg structure */
418#define _(x) hdr->x = a->nsh.x;
419      foreach_copy_nshhdr_field;
420#undef _
421
422      key_copy = clib_mem_alloc (sizeof (*key_copy));
423      clib_memcpy (key_copy, &key, sizeof (*key_copy));
424
425      hash_set_mem (nm->nsh_entry_by_key, key_copy,
426                    hdr - nm->nsh_entries);
427    }
428  else
429    {
430      if (!entry)
431	return -2; //TODO API_ERROR_NO_SUCH_ENTRY;
432
433      hdr = pool_elt_at_index (nm->nsh_entries, entry[0]);
434      hp = hash_get_pair (nm->nsh_entry_by_key, &key);
435      key_copy = (void *)(hp->key);
436      hash_unset_mem (nm->nsh_entry_by_key, &key);
437      clib_mem_free (key_copy);
438
439      pool_put (nm->nsh_entries, hdr);
440    }
441
442  return 0;
443}
444
445
446/**
447 * CLI command for adding NSH entry
448 */
449
450static clib_error_t *
451nsh_add_del_entry_command_fn (vlib_main_t * vm,
452			      unformat_input_t * input,
453			      vlib_cli_command_t * cmd)
454{
455  unformat_input_t _line_input, * line_input = &_line_input;
456  u8 is_add = 1;
457  u8 ver_o_c = 0;
458  u8 length = 0;
459  u8 md_type = 0;
460  u8 next_protocol = 1; /* default: ip4 */
461  u32 nsp;
462  u8 nsp_set = 0;
463  u32 nsi;
464  u8 nsi_set = 0;
465  u32 nsp_nsi;
466  u32 c1 = 0;
467  u32 c2 = 0;
468  u32 c3 = 0;
469  u32 c4 = 0;
470  u32 *tlvs = 0;
471  u32 tmp;
472  int rv;
473  nsh_add_del_entry_args_t _a, * a = &_a;
474
475  /* Get a line of input. */
476  if (! unformat_user (input, unformat_line_input, line_input))
477    return 0;
478
479  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
480    if (unformat (line_input, "del"))
481      is_add = 0;
482    else if (unformat (line_input, "version %d", &tmp))
483      ver_o_c |= (tmp & 3) << 6;
484    else if (unformat (line_input, "o-bit %d", &tmp))
485      ver_o_c |= (tmp & 1) << 5;
486    else if (unformat (line_input, "c-bit %d", &tmp))
487      ver_o_c |= (tmp & 1) << 4;
488    else if (unformat (line_input, "md-type %d", &tmp))
489      md_type = tmp;
490    else if (unformat(line_input, "next-ip4"))
491      next_protocol = 1;
492    else if (unformat(line_input, "next-ip6"))
493      next_protocol = 2;
494    else if (unformat(line_input, "next-ethernet"))
495      next_protocol = 3;
496    else if (unformat (line_input, "c1 %d", &c1))
497      ;
498    else if (unformat (line_input, "c2 %d", &c2))
499      ;
500    else if (unformat (line_input, "c3 %d", &c3))
501      ;
502    else if (unformat (line_input, "c4 %d", &c4))
503      ;
504    else if (unformat (line_input, "nsp %d", &nsp))
505      nsp_set = 1;
506    else if (unformat (line_input, "nsi %d", &nsi))
507      nsi_set = 1;
508    else if (unformat (line_input, "tlv %x"))
509      vec_add1 (tlvs, tmp);
510    else
511      return clib_error_return (0, "parse error: '%U'",
512                                format_unformat_error, line_input);
513  }
514
515  unformat_free (line_input);
516
517  if (nsp_set == 0)
518    return clib_error_return (0, "nsp not specified");
519
520  if (nsi_set == 0)
521    return clib_error_return (0, "nsi not specified");
522
523  if (md_type != 1)
524    return clib_error_return (0, "md-type 1 only supported at this time");
525
526  md_type = 1;
527  length = 6;
528
529  nsp_nsi = (nsp<<8) | nsi;
530
531  memset (a, 0, sizeof (*a));
532
533  a->is_add = is_add;
534
535#define _(x) a->nsh.x = x;
536  foreach_copy_nshhdr_field;
537#undef _
538
539  a->nsh.tlvs[0] = 0 ; // TODO FIXME this shouldn't be set 0 - in NSH_SFC project
540
541  rv = nsh_add_del_entry (a);
542
543  switch(rv)
544    {
545    case 0:
546      break;
547    default:
548      return clib_error_return
549        (0, "nsh_add_del_entry returned %d", rv);
550    }
551
552  return 0;
553}
554
555VLIB_CLI_COMMAND (create_nsh_entry_command, static) = {
556  .path = "create nsh entry",
557  .short_help =
558  "create nsh entry {nsp <nn> nsi <nn>} c1 <nn> c2 <nn> c3 <nn> c4 <nn>"
559  " [md-type <nn>] [tlv <xx>] [del]\n",
560  .function = nsh_add_del_entry_command_fn,
561};
562
563/** API message handler */
564static void vl_api_nsh_add_del_entry_t_handler
565(vl_api_nsh_add_del_entry_t * mp)
566{
567  vl_api_nsh_add_del_entry_reply_t * rmp;
568  nsh_main_t * nm = &nsh_main;
569  int rv;
570  nsh_add_del_entry_args_t _a, *a = &_a;
571
572  a->is_add = mp->is_add;
573  a->nsh.ver_o_c = mp->ver_o_c;
574  a->nsh.length = mp->length;
575  a->nsh.md_type = mp->md_type;
576  a->nsh.next_protocol = mp->next_protocol;
577  a->nsh.nsp_nsi = mp->nsp_nsi;
578  a->nsh.c1 = mp->c1;
579  a->nsh.c2 = mp->c2;
580  a->nsh.c3 = mp->c3;
581  a->nsh.c4 = mp->c4;
582
583  rv = nsh_add_del_entry (a);
584
585  REPLY_MACRO(VL_API_NSH_ADD_DEL_ENTRY_REPLY);
586}
587
588static clib_error_t *
589show_nsh_entry_command_fn (vlib_main_t * vm,
590			   unformat_input_t * input,
591			   vlib_cli_command_t * cmd)
592{
593  nsh_main_t * nm = &nsh_main;
594  nsh_header_t * hdr;
595
596  if (pool_elts (nm->nsh_entries) == 0)
597    vlib_cli_output (vm, "No nsh entries configured.");
598
599  pool_foreach (hdr, nm->nsh_entries,
600		({
601		  vlib_cli_output (vm, "%U", format_nsh_header, hdr);
602		}));
603
604  return 0;
605}
606
607VLIB_CLI_COMMAND (show_nsh_entry_command, static) = {
608  .path = "show nsh entry",
609  .function = show_nsh_entry_command_fn,
610};
611
612
613/* Set up the API message handling tables */
614static clib_error_t *
615nsh_plugin_api_hookup (vlib_main_t *vm)
616{
617  nsh_main_t * nm = &nsh_main;
618#define _(N,n)                                                  \
619  vl_msg_api_set_handlers((VL_API_##N + nm->msg_id_base),	\
620			  #n,					\
621			  vl_api_##n##_t_handler,		\
622			  vl_noop_handler,			\
623			  vl_api_##n##_t_endian,		\
624			  vl_api_##n##_t_print,			\
625			  sizeof(vl_api_##n##_t), 1);
626  foreach_nsh_plugin_api_msg;
627#undef _
628
629  return 0;
630}
631
632
633
634
635static uword
636nsh_input_map (vlib_main_t * vm,
637               vlib_node_runtime_t * node,
638               vlib_frame_t * from_frame)
639{
640  u32 n_left_from, next_index, *from, *to_next;
641  nsh_main_t * nm = &nsh_main;
642
643  from = vlib_frame_vector_args(from_frame);
644  n_left_from = from_frame->n_vectors;
645
646  next_index = node->cached_next_index;
647
648  while (n_left_from > 0)
649    {
650      u32 n_left_to_next;
651
652      vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
653
654      while (n_left_from >= 4 && n_left_to_next >= 2)
655	{
656	  u32 bi0, bi1;
657	  vlib_buffer_t * b0, *b1;
658	  u32 next0 = NSH_INPUT_NEXT_DROP, next1 = NSH_INPUT_NEXT_DROP;
659	  uword * entry0, *entry1;
660	  nsh_header_t * hdr0 = 0, *hdr1 = 0;
661	  u32 nsp_nsi0, nsp_nsi1;
662	  u32 error0, error1;
663	  nsh_map_t * map0 = 0, *map1 = 0;
664
665	  /* Prefetch next iteration. */
666	  {
667	    vlib_buffer_t * p2, *p3;
668
669	    p2 = vlib_get_buffer(vm, from[2]);
670	    p3 = vlib_get_buffer(vm, from[3]);
671
672	    vlib_prefetch_buffer_header(p2, LOAD);
673	    vlib_prefetch_buffer_header(p3, LOAD);
674
675	    CLIB_PREFETCH(p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
676	    CLIB_PREFETCH(p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
677	  }
678
679	  bi0 = from[0];
680	  bi1 = from[1];
681	  to_next[0] = bi0;
682	  to_next[1] = bi1;
683	  from += 2;
684	  to_next += 2;
685	  n_left_from -= 2;
686	  n_left_to_next -= 2;
687
688	  error0 = 0;
689	  error1 = 0;
690
691	  b0 = vlib_get_buffer(vm, bi0);
692	  hdr0 = vlib_buffer_get_current(b0);
693	  nsp_nsi0 = clib_net_to_host_u32(hdr0->nsp_nsi);
694	  entry0 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi0);
695
696	  b1 = vlib_get_buffer(vm, bi1);
697	  hdr1 = vlib_buffer_get_current(b1);
698	  nsp_nsi1 = clib_net_to_host_u32(hdr1->nsp_nsi);
699	  entry1 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi1);
700
701	  if (PREDICT_FALSE(entry0 == 0))
702	    {
703	      error0 = NSH_INPUT_ERROR_NO_MAPPING;
704	      goto trace0;
705	    }
706
707	  if (PREDICT_FALSE(entry1 == 0))
708	    {
709	      error1 = NSH_INPUT_ERROR_NO_MAPPING;
710	      goto trace1;
711	    }
712
713	  /* Entry should point to a mapping ...*/
714	  map0 = pool_elt_at_index(nm->nsh_mappings, entry0[0]);
715	  map1 = pool_elt_at_index(nm->nsh_mappings, entry1[0]);
716
717	  if (PREDICT_FALSE(map0 == 0))
718	    {
719	      error0 = NSH_INPUT_ERROR_NO_MAPPING;
720	      goto trace0;
721	    }
722
723	  if (PREDICT_FALSE(map1 == 0))
724	    {
725	      error1 = NSH_INPUT_ERROR_NO_MAPPING;
726	      goto trace1;
727	    }
728
729	  entry0 = hash_get_mem(nm->nsh_entry_by_key, &map0->mapped_nsp_nsi);
730	  entry1 = hash_get_mem(nm->nsh_entry_by_key, &map1->mapped_nsp_nsi);
731
732	  if (PREDICT_FALSE(entry0 == 0))
733	    {
734	      error0 = NSH_INPUT_ERROR_NO_MAPPING;
735	      goto trace0;
736	    }
737	  if (PREDICT_FALSE(entry1 == 0))
738	    {
739	      error1 = NSH_INPUT_ERROR_NO_MAPPING;
740	      goto trace1;
741	    }
742
743	  hdr0 = pool_elt_at_index(nm->nsh_entries, entry0[0]);
744	  hdr1 = pool_elt_at_index(nm->nsh_entries, entry1[0]);
745
746	  /* set up things for next node to transmit ie which node to handle it and where */
747	  next0 = map0->next_node;
748	  next1 = map1->next_node;
749	  vnet_buffer(b0)->sw_if_index[VLIB_TX] = map0->sw_if_index;
750	  vnet_buffer(b1)->sw_if_index[VLIB_TX] = map1->sw_if_index;
751
752	trace0: b0->error = error0 ? node->errors[error0] : 0;
753
754	  if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
755	    {
756	      nsh_input_trace_t *tr = vlib_add_trace(vm, node, b0, sizeof(*tr));
757	      tr->nsh_header = *hdr0;
758	    }
759
760	trace1: b1->error = error1 ? node->errors[error1] : 0;
761
762	  if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
763	    {
764	      nsh_input_trace_t *tr = vlib_add_trace(vm, node, b1, sizeof(*tr));
765	      tr->nsh_header = *hdr1;
766	    }
767
768	  vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
769					  n_left_to_next, bi0, bi1, next0, next1);
770
771	}
772
773      while (n_left_from > 0 && n_left_to_next > 0)
774	{
775	  u32 bi0;
776	  vlib_buffer_t * b0;
777	  u32 next0 = NSH_INPUT_NEXT_DROP;
778	  uword * entry0;
779	  nsh_header_t * hdr0 = 0;
780	  u32 nsp_nsi0;
781	  u32 error0;
782	  nsh_map_t * map0 = 0;
783
784	  bi0 = from[0];
785	  to_next[0] = bi0;
786	  from += 1;
787	  to_next += 1;
788	  n_left_from -= 1;
789	  n_left_to_next -= 1;
790	  error0 = 0;
791
792	  b0 = vlib_get_buffer(vm, bi0);
793	  hdr0 = vlib_buffer_get_current(b0);
794	  nsp_nsi0 = clib_net_to_host_u32(hdr0->nsp_nsi);
795	  entry0 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi0);
796
797	  if (PREDICT_FALSE(entry0 == 0))
798	    {
799	      error0 = NSH_INPUT_ERROR_NO_MAPPING;
800	      goto trace00;
801	    }
802
803	  /* Entry should point to a mapping ...*/
804	  map0 = pool_elt_at_index(nm->nsh_mappings, entry0[0]);
805
806	  if (PREDICT_FALSE(map0 == 0))
807	    {
808	      error0 = NSH_INPUT_ERROR_NO_MAPPING;
809	      goto trace00;
810	    }
811
812	  entry0 = hash_get_mem(nm->nsh_entry_by_key, &map0->mapped_nsp_nsi);
813
814	  if (PREDICT_FALSE(entry0 == 0))
815	    {
816	      error0 = NSH_INPUT_ERROR_NO_MAPPING;
817	      goto trace00;
818	    }
819
820	  hdr0 = pool_elt_at_index(nm->nsh_entries, entry0[0]);
821
822	  /* set up things for next node to transmit ie which node to handle it and where */
823	  next0 = map0->next_node;
824	  vnet_buffer(b0)->sw_if_index[VLIB_TX] = map0->sw_if_index;
825
826	trace00: b0->error = error0 ? node->errors[error0] : 0;
827
828	  if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
829	    {
830	      nsh_input_trace_t *tr = vlib_add_trace(vm, node, b0, sizeof(*tr));
831	      tr->nsh_header = *hdr0;
832	    }
833
834	  vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
835					  n_left_to_next, bi0, next0);
836	}
837
838      vlib_put_next_frame(vm, node, next_index, n_left_to_next);
839
840    }
841
842  return from_frame->n_vectors;
843}
844
845
846static char * nsh_input_error_strings[] = {
847#define _(sym,string) string,
848  foreach_nsh_input_error
849#undef _
850};
851
852VLIB_REGISTER_NODE (nsh_input_node) = {
853  .function = nsh_input_map,
854  .name = "nsh-input",
855  .vector_size = sizeof (u32),
856  .format_trace = format_nsh_input_map_trace,
857  .format_buffer = format_nsh_header_with_length,
858  .type = VLIB_NODE_TYPE_INTERNAL,
859
860  .n_errors = ARRAY_LEN(nsh_input_error_strings),
861  .error_strings = nsh_input_error_strings,
862
863  .n_next_nodes = NSH_INPUT_N_NEXT,
864
865  .next_nodes = {
866#define _(s,n) [NSH_INPUT_NEXT_##s] = n,
867    foreach_nsh_input_next
868#undef _
869  },
870};
871
872clib_error_t *nsh_init (vlib_main_t *vm)
873{
874  nsh_main_t *nm = &nsh_main;
875  clib_error_t * error = 0;
876  vlib_node_t * vxlan4_gpe_input_node = 0;
877  vlib_node_t * vxlan6_gpe_input_node = 0;
878  vlib_node_t * gre_input_node = 0;
879  u8 * name;
880
881  /* Init the main structures from VPP */
882  nm->vlib_main = vm;
883  nm->vnet_main = vnet_get_main();
884
885  /* Various state maintenance mappings */
886  nm->nsh_mapping_by_key
887    = hash_create_mem (0, sizeof(u32), sizeof (uword));
888
889  nm->nsh_mapping_by_mapped_key
890    = hash_create_mem (0, sizeof(u32), sizeof (uword));
891
892  nm->nsh_entry_by_key
893    = hash_create_mem (0, sizeof(u32), sizeof (uword));
894
895  name = format (0, "nsh_%08x%c", api_version, 0);
896
897  /* Set up the API */
898  nm->msg_id_base = vl_msg_api_get_msg_ids
899    ((char *) name, VL_MSG_FIRST_AVAILABLE);
900
901  error = nsh_plugin_api_hookup (vm);
902
903  /* Add dispositions to nodes that feed nsh-input */
904  vxlan4_gpe_input_node = vlib_get_node_by_name (vm, (u8 *)"vxlan4-gpe-input");
905  ASSERT(vxlan4_gpe_input_node);
906  //alagalah - validate we don't really need to use the node value
907  vlib_node_add_next (vm, vxlan4_gpe_input_node->index, nsh_input_node.index);
908
909  vxlan6_gpe_input_node = vlib_get_node_by_name (vm, (u8 *)"vxlan6-gpe-input");
910  ASSERT(vxlan6_gpe_input_node);
911  vlib_node_add_next (vm, vxlan6_gpe_input_node->index, nsh_input_node.index);
912
913  gre_input_node = vlib_get_node_by_name (vm, (u8 *)"gre-input");
914  ASSERT(gre_input_node);
915  vlib_node_add_next (vm, gre_input_node->index, nsh_input_node.index);
916
917  vec_free(name);
918
919  return error;
920}
921
922VLIB_INIT_FUNCTION(nsh_init);
923