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