nsh.c revision e5fb3446
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
25#include <vlibapi/api.h>
26#include <vlibmemory/api.h>
27#include <vlibsocket/api.h>
28
29/* define message IDs */
30#include <vpp-api/nsh_msg_enum.h>
31
32/* define message structures */
33#define vl_typedefs
34#include <vpp-api/nsh_all_api_h.h>
35#undef vl_typedefs
36
37/* define generated endian-swappers */
38#define vl_endianfun
39#include <vpp-api/nsh_all_api_h.h>
40#undef vl_endianfun
41
42/* instantiate all the print functions we know about */
43#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
44#define vl_printfun
45#include <vpp-api/nsh_all_api_h.h>
46#undef vl_printfun
47
48/* Get the API version number */
49#define vl_api_version(n,v) static u32 api_version=(v);
50#include <vpp-api/nsh_all_api_h.h>
51#undef vl_api_version
52
53/*
54 * A handy macro to set up a message reply.
55 * Assumes that the following variables are available:
56 * mp - pointer to request message
57 * rmp - pointer to reply message type
58 * rv - return value
59 */
60
61#define REPLY_MACRO(t)                                          \
62  do {								\
63    unix_shared_memory_queue_t * q =                            \
64      vl_api_client_index_to_input_queue (mp->client_index);	\
65    if (!q)                                                     \
66      return;							\
67                                                                \
68    rmp = vl_msg_api_alloc (sizeof (*rmp));                     \
69    rmp->_vl_msg_id = ntohs((t)+nm->msg_id_base);               \
70    rmp->context = mp->context;                                 \
71    rmp->retval = ntohl(rv);                                    \
72                                                                \
73    vl_msg_api_send_shmem (q, (u8 *)&rmp);                      \
74  } while(0);
75
76#define REPLY_MACRO2(t, body)                                   \
77  do {                                                          \
78    unix_shared_memory_queue_t * q;                             \
79    rv = vl_msg_api_pd_handler (mp, rv);                        \
80    q = vl_api_client_index_to_input_queue (mp->client_index);  \
81    if (!q)                                                     \
82        return;                                                 \
83                                                                \
84    rmp = vl_msg_api_alloc (sizeof (*rmp));                     \
85    rmp->_vl_msg_id = ntohs((t)+nm->msg_id_base);               \
86    rmp->context = mp->context;                                 \
87    rmp->retval = ntohl(rv);                                    \
88    do {body;} while (0);                                       \
89    vl_msg_api_send_shmem (q, (u8 *)&rmp);                      \
90  } while(0);
91
92#define FINISH                                  \
93    vec_add1 (s, 0);                            \
94    vl_print (handle, (char *)s);               \
95    vec_free (s);                               \
96    return handle;
97
98/* List of message types that this plugin understands */
99
100#define foreach_nsh_plugin_api_msg		\
101  _(NSH_ADD_DEL_ENTRY, nsh_add_del_entry)	\
102  _(NSH_ENTRY_DUMP, nsh_entry_dump)             \
103  _(NSH_ADD_DEL_MAP, nsh_add_del_map)           \
104  _(NSH_MAP_DUMP, nsh_map_dump)
105
106clib_error_t *
107vlib_plugin_register (vlib_main_t * vm, vnet_plugin_handoff_t * h,
108                      int from_early_init)
109{
110  nsh_main_t * nm = &nsh_main;
111  clib_error_t * error = 0;
112
113  nm->vlib_main = vm;
114  nm->vnet_main = h->vnet_main;
115
116  return error;
117}
118
119typedef struct {
120  nsh_header_t nsh_header;
121} nsh_input_trace_t;
122
123u8 * format_nsh_header (u8 * s, va_list * args)
124{
125  nsh_header_t * nsh = va_arg (*args, nsh_header_t *);
126
127  s = format (s, "nsh ver %d ", (nsh->ver_o_c>>6));
128  if (nsh->ver_o_c & NSH_O_BIT)
129    s = format (s, "O-set ");
130
131  if (nsh->ver_o_c & NSH_C_BIT)
132    s = format (s, "C-set ");
133
134  s = format (s, "len %d (%d bytes) md_type %d next_protocol %d\n",
135              nsh->length, nsh->length * 4, nsh->md_type, nsh->next_protocol);
136
137  s = format (s, "  service path %d service index %d\n",
138              (nsh->nsp_nsi>>NSH_NSP_SHIFT) & NSH_NSP_MASK,
139              nsh->nsp_nsi & NSH_NSI_MASK);
140
141  s = format (s, "  c1 %d c2 %d c3 %d c4 %d\n",
142              nsh->c1, nsh->c2, nsh->c3, nsh->c4);
143
144  return s;
145}
146
147static u8 * format_nsh_action (u8 * s, va_list * args)
148{
149  u32 nsh_action = va_arg (*args, u32);
150
151  switch (nsh_action)
152    {
153    case NSH_ACTION_SWAP:
154      return format (s, "swap");
155    case NSH_ACTION_PUSH:
156      return format (s, "push");
157    case NSH_ACTION_POP:
158      return format (s, "pop");
159    default:
160      return format (s, "unknown %d", nsh_action);
161    }
162  return s;
163}
164
165u8 * format_nsh_map (u8 * s, va_list * args)
166{
167  nsh_map_t * map = va_arg (*args, nsh_map_t *);
168
169  s = format (s, "nsh entry nsp: %d nsi: %d ",
170              (map->nsp_nsi>>NSH_NSP_SHIFT) & NSH_NSP_MASK,
171              map->nsp_nsi & NSH_NSI_MASK);
172  s = format (s, "maps to nsp: %d nsi: %d ",
173              (map->mapped_nsp_nsi>>NSH_NSP_SHIFT) & NSH_NSP_MASK,
174              map->mapped_nsp_nsi & NSH_NSI_MASK);
175
176  s = format (s, " nsh_action %U\n", format_nsh_action, map->nsh_action);
177
178  switch (map->next_node)
179    {
180    case NSH_NODE_NEXT_ENCAP_GRE:
181      {
182	s = format (s, "encapped by GRE intf: %d", map->sw_if_index);
183	break;
184      }
185    case NSH_NODE_NEXT_ENCAP_VXLANGPE:
186      {
187	s = format (s, "encapped by VXLAN GPE intf: %d", map->sw_if_index);
188	break;
189      }
190    case NSH_NODE_NEXT_ENCAP_VXLAN4:
191      {
192	s = format (s, "encapped by VXLAN4 intf: %d", map->sw_if_index);
193	break;
194      }
195    case NSH_NODE_NEXT_ENCAP_VXLAN6:
196      {
197	s = format (s, "encapped by VXLAN6 intf: %d", map->sw_if_index);
198	break;
199      }
200    default:
201      s = format (s, "only GRE and VXLANGPE support in this rev");
202    }
203
204  return s;
205}
206
207u8 * format_nsh_header_with_length (u8 * s, va_list * args)
208{
209  nsh_header_t * h = va_arg (*args, nsh_header_t *);
210  u32 max_header_bytes = va_arg (*args, u32);
211  u32 tmp, header_bytes;
212
213  header_bytes = sizeof (h[0]);
214  if (max_header_bytes != 0 && header_bytes > max_header_bytes)
215    return format (s, "nsh header truncated");
216
217  tmp = clib_net_to_host_u32 (h->nsp_nsi);
218  s = format (s, "  nsp %d nsi %d ",
219              (tmp>>NSH_NSP_SHIFT) & NSH_NSP_MASK,
220              tmp & NSH_NSI_MASK);
221
222  s = format (s, "c1 %u c2 %u c3 %u c4 %u",
223              clib_net_to_host_u32 (h->c1),
224              clib_net_to_host_u32 (h->c2),
225              clib_net_to_host_u32 (h->c3),
226              clib_net_to_host_u32 (h->c4));
227
228  s = format (s, "ver %d ", h->ver_o_c>>6);
229
230  if (h->ver_o_c & NSH_O_BIT)
231    s = format (s, "O-set ");
232
233  if (h->ver_o_c & NSH_C_BIT)
234    s = format (s, "C-set ");
235
236  s = format (s, "len %d (%d bytes) md_type %d next_protocol %d\n",
237              h->length, h->length * 4, h->md_type, h->next_protocol);
238  return s;
239}
240
241u8 * format_nsh_node_map_trace (u8 * s, va_list * args)
242{
243  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
244  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
245  nsh_input_trace_t * t
246    = va_arg (*args, nsh_input_trace_t *);
247
248  s = format (s, "\n  %U", format_nsh_header, &t->nsh_header,
249              (u32) sizeof (t->nsh_header) );
250
251  return s;
252}
253
254/**
255 * Action function to add or del an nsh map.
256 * Shared by both CLI and binary API
257 **/
258
259int nsh_add_del_map (nsh_add_del_map_args_t *a, u32 * map_indexp)
260{
261  nsh_main_t * nm = &nsh_main;
262  nsh_map_t *map = 0;
263  u32 key, *key_copy;
264  uword * entry;
265  hash_pair_t *hp;
266  u32 map_index = ~0;
267
268  key = a->map.nsp_nsi;
269
270  entry = hash_get_mem (nm->nsh_mapping_by_key, &key);
271
272  if (a->is_add)
273    {
274      /* adding an entry, must not already exist */
275      if (entry)
276        return -1; //TODO API_ERROR_INVALID_VALUE;
277
278      pool_get_aligned (nm->nsh_mappings, map, CLIB_CACHE_LINE_BYTES);
279      memset (map, 0, sizeof (*map));
280
281      /* copy from arg structure */
282      map->nsp_nsi = a->map.nsp_nsi;
283      map->mapped_nsp_nsi = a->map.mapped_nsp_nsi;
284      map->nsh_action = a->map.nsh_action;
285      map->sw_if_index = a->map.sw_if_index;
286      map->next_node = a->map.next_node;
287
288
289      key_copy = clib_mem_alloc (sizeof (*key_copy));
290      clib_memcpy (key_copy, &key, sizeof (*key_copy));
291
292      hash_set_mem (nm->nsh_mapping_by_key, key_copy,
293                    map - nm->nsh_mappings);
294      map_index = map - nm->nsh_mappings;
295    }
296  else
297    {
298      if (!entry)
299	return -2 ; //TODO API_ERROR_NO_SUCH_ENTRY;
300
301      map = pool_elt_at_index (nm->nsh_mappings, entry[0]);
302      hp = hash_get_pair (nm->nsh_mapping_by_key, &key);
303      key_copy = (void *)(hp->key);
304      hash_unset_mem (nm->nsh_mapping_by_key, &key);
305      clib_mem_free (key_copy);
306
307      pool_put (nm->nsh_mappings, map);
308    }
309
310  if (map_indexp)
311      *map_indexp = map_index;
312
313  return 0;
314}
315
316/**
317 * Action function to add or del an nsh-proxy-session.
318 * Shared by both CLI and binary API
319 **/
320
321int nsh_add_del_proxy_session (nsh_add_del_map_args_t *a)
322{
323  nsh_main_t * nm = &nsh_main;
324  nsh_proxy_session_t *proxy = 0;
325  nsh_proxy_session_by_key_t key, *key_copy;
326  uword * entry;
327  hash_pair_t *hp;
328  u32 nsp = 0, nsi = 0;
329
330  memset (&key, 0, sizeof (key));
331  key.transport_type = a->map.next_node;
332  key.transport_index = a->map.sw_if_index;
333
334  entry = hash_get_mem (nm->nsh_proxy_session_by_key, &key);
335
336  if (a->is_add)
337    {
338      /* adding an entry, must not already exist */
339      if (entry)
340        return -1; //TODO API_ERROR_INVALID_VALUE;
341
342      pool_get_aligned (nm->nsh_proxy_sessions, proxy, CLIB_CACHE_LINE_BYTES);
343      memset (proxy, 0, sizeof (*proxy));
344
345      /* Nsi needs to minus 1 within NSH-Proxy */
346      nsp = (a->map.nsp_nsi>>NSH_NSP_SHIFT) & NSH_NSP_MASK;
347      nsi = a->map.nsp_nsi & NSH_NSI_MASK;
348      if (nsi == 0 )
349	return -1;
350
351      nsi = nsi -1;
352      proxy->nsp_nsi = (nsp<< NSH_NSP_SHIFT) | nsi;
353
354      key_copy = clib_mem_alloc (sizeof (*key_copy));
355      clib_memcpy (key_copy, &key, sizeof (*key_copy));
356
357      hash_set_mem (nm->nsh_proxy_session_by_key, key_copy,
358		    proxy - nm->nsh_proxy_sessions);
359    }
360  else
361    {
362      if (!entry)
363	return -2 ; //TODO API_ERROR_NO_SUCH_ENTRY;
364
365      proxy = pool_elt_at_index (nm->nsh_proxy_sessions, entry[0]);
366      hp = hash_get_pair (nm->nsh_proxy_session_by_key, &key);
367      key_copy = (void *)(hp->key);
368      hash_unset_mem (nm->nsh_proxy_session_by_key, &key);
369      clib_mem_free (key_copy);
370
371      pool_put (nm->nsh_proxy_sessions, proxy);
372    }
373
374  return 0;
375}
376
377/**
378 * CLI command for NSH map
379 */
380
381static uword unformat_nsh_action (unformat_input_t * input, va_list * args)
382{
383  u32 * result = va_arg (*args, u32 *);
384  u32 tmp;
385
386  if (unformat (input, "swap"))
387    *result = NSH_ACTION_SWAP;
388  else if (unformat (input, "push"))
389    *result = NSH_ACTION_PUSH;
390  else if (unformat (input, "pop"))
391    *result = NSH_ACTION_POP;
392  else if (unformat (input, "%d", &tmp))
393    *result = tmp;
394  else
395    return 0;
396
397  return 1;
398}
399
400static clib_error_t *
401nsh_add_del_map_command_fn (vlib_main_t * vm,
402			    unformat_input_t * input,
403			    vlib_cli_command_t * cmd)
404{
405  unformat_input_t _line_input, * line_input = &_line_input;
406  u8 is_add = 1;
407  u32 nsp, nsi, mapped_nsp, mapped_nsi, nsh_action;
408  int nsp_set = 0, nsi_set = 0, mapped_nsp_set = 0, mapped_nsi_set = 0;
409  int nsh_action_set = 0;
410  u32 next_node = ~0;
411  u32 sw_if_index = ~0; // temporary requirement to get this moved over to NSHSFC
412  nsh_add_del_map_args_t _a, * a = &_a;
413  u32 map_index;
414  int rv;
415
416  /* Get a line of input. */
417  if (! unformat_user (input, unformat_line_input, line_input))
418    return 0;
419
420  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
421    if (unformat (line_input, "del"))
422      is_add = 0;
423    else if (unformat (line_input, "nsp %d", &nsp))
424      nsp_set = 1;
425    else if (unformat (line_input, "nsi %d", &nsi))
426      nsi_set = 1;
427    else if (unformat (line_input, "mapped-nsp %d", &mapped_nsp))
428      mapped_nsp_set = 1;
429    else if (unformat (line_input, "mapped-nsi %d", &mapped_nsi))
430      mapped_nsi_set = 1;
431    else if (unformat (line_input, "nsh_action %U", unformat_nsh_action,
432                       &nsh_action))
433      nsh_action_set = 1;
434    else if (unformat (line_input, "encap-gre-intf %d", &sw_if_index))
435      next_node = NSH_NODE_NEXT_ENCAP_GRE;
436    else if (unformat (line_input, "encap-vxlan-gpe-intf %d", &sw_if_index))
437      next_node = NSH_NODE_NEXT_ENCAP_VXLANGPE;
438    else if (unformat (line_input, "encap-vxlan4-intf %d", &sw_if_index))
439      next_node = NSH_NODE_NEXT_ENCAP_VXLAN4;
440    else if (unformat (line_input, "encap-vxlan6-intf %d", &sw_if_index))
441      next_node = NSH_NODE_NEXT_ENCAP_VXLAN6;
442    else if (unformat (line_input, "encap-none"))
443      next_node = NSH_NODE_NEXT_DROP; // Once moved to NSHSFC see nsh.h:foreach_nsh_input_next to handle this case
444    else
445      return clib_error_return (0, "parse error: '%U'",
446                                format_unformat_error, line_input);
447  }
448
449  unformat_free (line_input);
450
451  if (nsp_set == 0 || nsi_set == 0)
452    return clib_error_return (0, "nsp nsi pair required. Key: for NSH entry");
453
454  if (mapped_nsp_set == 0 || mapped_nsi_set == 0)
455    return clib_error_return (0, "mapped-nsp mapped-nsi pair required. Key: for NSH entry");
456
457  if (nsh_action_set == 0 )
458    return clib_error_return (0, "nsh_action required: swap|push|pop.");
459
460  if (next_node == ~0)
461    return clib_error_return (0, "must specific action: [encap-gre-intf <nn> | encap-vxlan-gpe-intf <nn> | encap-none]");
462
463  memset (a, 0, sizeof (*a));
464
465  /* set args structure */
466  a->is_add = is_add;
467  a->map.nsp_nsi = (nsp<< NSH_NSP_SHIFT) | nsi;
468  a->map.mapped_nsp_nsi = (mapped_nsp<< NSH_NSP_SHIFT) | mapped_nsi;
469  a->map.nsh_action = nsh_action;
470  a->map.sw_if_index = sw_if_index;
471  a->map.next_node = next_node;
472
473  rv = nsh_add_del_map(a, &map_index);
474
475  switch(rv)
476    {
477    case 0:
478      break;
479    case -1: //TODO API_ERROR_INVALID_VALUE:
480      return clib_error_return (0, "mapping already exists. Remove it first.");
481
482    case -2: // TODO API_ERROR_NO_SUCH_ENTRY:
483      return clib_error_return (0, "mapping does not exist.");
484
485    default:
486      return clib_error_return
487        (0, "nsh_add_del_map returned %d", rv);
488    }
489
490  if((a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN4)
491      | (a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN6))
492    {
493      rv = nsh_add_del_proxy_session(a);
494
495      switch(rv)
496        {
497        case 0:
498          break;
499        case -1: //TODO API_ERROR_INVALID_VALUE:
500          return clib_error_return (0, "nsh-proxy-session already exists. Remove it first.");
501
502        case -2: // TODO API_ERROR_NO_SUCH_ENTRY:
503          return clib_error_return (0, "nsh-proxy-session does not exist.");
504
505        default:
506          return clib_error_return
507            (0, "nsh_add_del_proxy_session() returned %d", rv);
508        }
509    }
510
511  return 0;
512}
513
514VLIB_CLI_COMMAND (create_nsh_map_command, static) = {
515  .path = "create nsh map",
516  .short_help =
517  "create nsh map nsp <nn> nsi <nn> [del] mapped-nsp <nn> mapped-nsi <nn> nsh_action [swap|push|pop] "
518  "[encap-gre-intf <nn> | encap-vxlan-gpe-intf <nn> | encap-none]\n",
519  .function = nsh_add_del_map_command_fn,
520};
521
522/** API message handler */
523static void vl_api_nsh_add_del_map_t_handler
524(vl_api_nsh_add_del_map_t * mp)
525{
526  vl_api_nsh_add_del_map_reply_t * rmp;
527  nsh_main_t * nm = &nsh_main;
528  int rv;
529  nsh_add_del_map_args_t _a, *a = &_a;
530  u32 map_index = ~0;
531
532  a->is_add = mp->is_add;
533  a->map.nsp_nsi = ntohl(mp->nsp_nsi);
534  a->map.mapped_nsp_nsi = ntohl(mp->mapped_nsp_nsi);
535  a->map.nsh_action = ntohl(mp->nsh_action);
536  a->map.sw_if_index = ntohl(mp->sw_if_index);
537  a->map.next_node = ntohl(mp->next_node);
538
539  rv = nsh_add_del_map (a, &map_index);
540
541  REPLY_MACRO2(VL_API_NSH_ADD_DEL_MAP_REPLY,
542  ({
543    rmp->map_index = htonl (map_index);
544  }));
545}
546
547/**
548 * CLI command for showing the mapping between NSH entries
549 */
550static clib_error_t *
551show_nsh_map_command_fn (vlib_main_t * vm,
552			 unformat_input_t * input,
553			 vlib_cli_command_t * cmd)
554{
555  nsh_main_t * nm = &nsh_main;
556  nsh_map_t * map;
557
558  if (pool_elts (nm->nsh_mappings) == 0)
559    vlib_cli_output (vm, "No nsh maps configured.");
560
561  pool_foreach (map, nm->nsh_mappings,
562		({
563		  vlib_cli_output (vm, "%U", format_nsh_map, map);
564		}));
565
566  return 0;
567}
568
569VLIB_CLI_COMMAND (show_nsh_map_command, static) = {
570  .path = "show nsh map",
571  .function = show_nsh_map_command_fn,
572};
573
574/**
575 * Action function for adding an NSH entry
576 */
577
578int nsh_add_del_entry (nsh_add_del_entry_args_t *a, u32 * entry_indexp)
579{
580  nsh_main_t * nm = &nsh_main;
581  nsh_header_t *hdr = 0;
582  u32 key, *key_copy;
583  uword * entry;
584  hash_pair_t *hp;
585  u32 entry_index = ~0;
586
587  key = a->nsh.nsp_nsi;
588
589  entry = hash_get_mem (nm->nsh_entry_by_key, &key);
590
591  if (a->is_add)
592    {
593      /* adding an entry, must not already exist */
594      if (entry)
595        return -1; // TODO VNET_API_ERROR_INVALID_VALUE;
596
597      pool_get_aligned (nm->nsh_entries, hdr, CLIB_CACHE_LINE_BYTES);
598      memset (hdr, 0, sizeof (*hdr));
599
600      /* copy from arg structure */
601#define _(x) hdr->x = a->nsh.x;
602      foreach_copy_nshhdr_field;
603#undef _
604
605      key_copy = clib_mem_alloc (sizeof (*key_copy));
606      clib_memcpy (key_copy, &key, sizeof (*key_copy));
607
608      hash_set_mem (nm->nsh_entry_by_key, key_copy,
609                    hdr - nm->nsh_entries);
610      entry_index = hdr - nm->nsh_entries;
611    }
612  else
613    {
614      if (!entry)
615	return -2; //TODO API_ERROR_NO_SUCH_ENTRY;
616
617      hdr = pool_elt_at_index (nm->nsh_entries, entry[0]);
618      hp = hash_get_pair (nm->nsh_entry_by_key, &key);
619      key_copy = (void *)(hp->key);
620      hash_unset_mem (nm->nsh_entry_by_key, &key);
621      clib_mem_free (key_copy);
622
623      pool_put (nm->nsh_entries, hdr);
624    }
625
626  if (entry_indexp)
627      *entry_indexp = entry_index;
628
629  return 0;
630}
631
632
633/**
634 * CLI command for adding NSH entry
635 */
636
637static clib_error_t *
638nsh_add_del_entry_command_fn (vlib_main_t * vm,
639			      unformat_input_t * input,
640			      vlib_cli_command_t * cmd)
641{
642  unformat_input_t _line_input, * line_input = &_line_input;
643  u8 is_add = 1;
644  u8 ver_o_c = 0;
645  u8 length = 0;
646  u8 md_type = 0;
647  u8 next_protocol = 1; /* default: ip4 */
648  u32 nsp;
649  u8 nsp_set = 0;
650  u32 nsi;
651  u8 nsi_set = 0;
652  u32 nsp_nsi;
653  u32 c1 = 0;
654  u32 c2 = 0;
655  u32 c3 = 0;
656  u32 c4 = 0;
657  u32 tmp;
658  int rv;
659  u32 entry_index;
660  nsh_add_del_entry_args_t _a, * a = &_a;
661
662  /* Get a line of input. */
663  if (! unformat_user (input, unformat_line_input, line_input))
664    return 0;
665
666  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
667    if (unformat (line_input, "del"))
668      is_add = 0;
669    else if (unformat (line_input, "version %d", &tmp))
670      ver_o_c |= (tmp & 3) << 6;
671    else if (unformat (line_input, "o-bit %d", &tmp))
672      ver_o_c |= (tmp & 1) << 5;
673    else if (unformat (line_input, "c-bit %d", &tmp))
674      ver_o_c |= (tmp & 1) << 4;
675    else if (unformat (line_input, "md-type %d", &tmp))
676      md_type = tmp;
677    else if (unformat(line_input, "next-ip4"))
678      next_protocol = 1;
679    else if (unformat(line_input, "next-ip6"))
680      next_protocol = 2;
681    else if (unformat(line_input, "next-ethernet"))
682      next_protocol = 3;
683    else if (unformat (line_input, "c1 %d", &c1))
684      ;
685    else if (unformat (line_input, "c2 %d", &c2))
686      ;
687    else if (unformat (line_input, "c3 %d", &c3))
688      ;
689    else if (unformat (line_input, "c4 %d", &c4))
690      ;
691    else if (unformat (line_input, "nsp %d", &nsp))
692      nsp_set = 1;
693    else if (unformat (line_input, "nsi %d", &nsi))
694      nsi_set = 1;
695    else
696      return clib_error_return (0, "parse error: '%U'",
697                                format_unformat_error, line_input);
698  }
699
700  unformat_free (line_input);
701
702  if (nsp_set == 0)
703    return clib_error_return (0, "nsp not specified");
704
705  if (nsi_set == 0)
706    return clib_error_return (0, "nsi not specified");
707
708  if (md_type != 1)
709    return clib_error_return (0, "md-type 1 only supported at this time");
710
711  md_type = 1;
712  length = 6;
713
714  nsp_nsi = (nsp<<8) | nsi;
715
716  memset (a, 0, sizeof (*a));
717
718  a->is_add = is_add;
719
720#define _(x) a->nsh.x = x;
721  foreach_copy_nshhdr_field;
722#undef _
723
724  rv = nsh_add_del_entry (a, &entry_index);
725
726  switch(rv)
727    {
728    case 0:
729      break;
730    default:
731      return clib_error_return
732        (0, "nsh_add_del_entry returned %d", rv);
733    }
734
735  return 0;
736}
737
738VLIB_CLI_COMMAND (create_nsh_entry_command, static) = {
739  .path = "create nsh entry",
740  .short_help =
741  "create nsh entry {nsp <nn> nsi <nn>} c1 <nn> c2 <nn> c3 <nn> c4 <nn>"
742  " [md-type <nn>] [tlv <xx>] [del]\n",
743  .function = nsh_add_del_entry_command_fn,
744};
745
746/** API message handler */
747static void vl_api_nsh_add_del_entry_t_handler
748(vl_api_nsh_add_del_entry_t * mp)
749{
750  vl_api_nsh_add_del_entry_reply_t * rmp;
751  nsh_main_t * nm = &nsh_main;
752  int rv;
753  nsh_add_del_entry_args_t _a, *a = &_a;
754  u32 entry_index = ~0;
755
756  a->is_add = mp->is_add;
757  a->nsh.ver_o_c = mp->ver_o_c;
758  a->nsh.length = mp->length;
759  a->nsh.md_type = mp->md_type;
760  a->nsh.next_protocol = mp->next_protocol;
761  a->nsh.nsp_nsi = ntohl(mp->nsp_nsi);
762  a->nsh.c1 = ntohl(mp->c1);
763  a->nsh.c2 = ntohl(mp->c2);
764  a->nsh.c3 = ntohl(mp->c3);
765  a->nsh.c4 = ntohl(mp->c4);
766
767  rv = nsh_add_del_entry (a, &entry_index);
768
769  REPLY_MACRO2(VL_API_NSH_ADD_DEL_ENTRY_REPLY,
770  ({
771    rmp->entry_index = htonl (entry_index);
772  }));
773}
774
775static void send_nsh_entry_details
776(nsh_header_t * t, unix_shared_memory_queue_t * q, u32 context)
777{
778    vl_api_nsh_entry_details_t * rmp;
779    nsh_main_t * nm = &nsh_main;
780
781    rmp = vl_msg_api_alloc (sizeof (*rmp));
782    memset (rmp, 0, sizeof (*rmp));
783
784    rmp->_vl_msg_id = ntohs((VL_API_NSH_ENTRY_DETAILS)+nm->msg_id_base);
785    rmp->ver_o_c = t->ver_o_c;
786    rmp->length = t->length;
787    rmp->md_type = t->md_type;
788    rmp->next_protocol = t->next_protocol;
789    rmp->nsp_nsi = htonl(t->nsp_nsi);
790    rmp->c1 = htonl(t->c1);
791    rmp->c2 = htonl(t->c2);
792    rmp->c3 = htonl(t->c3);
793    rmp->c4 = htonl(t->c4);
794
795    rmp->context = context;
796
797    vl_msg_api_send_shmem (q, (u8 *)&rmp);
798}
799
800static void vl_api_nsh_entry_dump_t_handler
801(vl_api_nsh_entry_dump_t * mp)
802{
803    unix_shared_memory_queue_t * q;
804    nsh_main_t * nm = &nsh_main;
805    nsh_header_t * t;
806    u32 entry_index;
807
808    q = vl_api_client_index_to_input_queue (mp->client_index);
809    if (q == 0) {
810        return;
811    }
812
813    entry_index = ntohl (mp->entry_index);
814
815    if (~0 == entry_index)
816      {
817	pool_foreach (t, nm->nsh_entries,
818	({
819	    send_nsh_entry_details(t, q, mp->context);
820	}));
821      }
822    else
823      {
824        if (entry_index >= vec_len (nm->nsh_entries))
825  	{
826  	  return;
827  	}
828        t = &nm->nsh_entries[entry_index];
829        send_nsh_entry_details(t, q, mp->context);
830      }
831}
832
833static void send_nsh_map_details
834(nsh_map_t * t, unix_shared_memory_queue_t * q, u32 context)
835{
836    vl_api_nsh_map_details_t * rmp;
837    nsh_main_t * nm = &nsh_main;
838
839    rmp = vl_msg_api_alloc (sizeof (*rmp));
840    memset (rmp, 0, sizeof (*rmp));
841
842    rmp->_vl_msg_id = ntohs((VL_API_NSH_MAP_DETAILS)+nm->msg_id_base);
843    rmp->nsp_nsi = htonl(t->nsp_nsi);
844    rmp->mapped_nsp_nsi = htonl(t->mapped_nsp_nsi);
845    rmp->nsh_action = htonl(t->nsh_action);
846    rmp->sw_if_index = htonl(t->sw_if_index);
847    rmp->next_node = htonl(t->next_node);
848
849    rmp->context = context;
850
851    vl_msg_api_send_shmem (q, (u8 *)&rmp);
852}
853
854static void vl_api_nsh_map_dump_t_handler
855(vl_api_nsh_map_dump_t * mp)
856{
857    unix_shared_memory_queue_t * q;
858    nsh_main_t * nm = &nsh_main;
859    nsh_map_t * t;
860    u32 map_index;
861
862    q = vl_api_client_index_to_input_queue (mp->client_index);
863    if (q == 0) {
864        return;
865    }
866
867    map_index = ntohl (mp->map_index);
868
869    if (~0 == map_index)
870      {
871	pool_foreach (t, nm->nsh_mappings,
872	({
873	    send_nsh_map_details(t, q, mp->context);
874	}));
875      }
876    else
877      {
878        if (map_index >= vec_len (nm->nsh_mappings))
879  	{
880  	  return;
881  	}
882        t = &nm->nsh_mappings[map_index];
883        send_nsh_map_details(t, q, mp->context);
884      }
885}
886
887static clib_error_t *
888show_nsh_entry_command_fn (vlib_main_t * vm,
889			   unformat_input_t * input,
890			   vlib_cli_command_t * cmd)
891{
892  nsh_main_t * nm = &nsh_main;
893  nsh_header_t * hdr;
894
895  if (pool_elts (nm->nsh_entries) == 0)
896    vlib_cli_output (vm, "No nsh entries configured.");
897
898  pool_foreach (hdr, nm->nsh_entries,
899		({
900		  vlib_cli_output (vm, "%U", format_nsh_header, hdr);
901		}));
902
903  return 0;
904}
905
906VLIB_CLI_COMMAND (show_nsh_entry_command, static) = {
907  .path = "show nsh entry",
908  .function = show_nsh_entry_command_fn,
909};
910
911
912/* Set up the API message handling tables */
913static clib_error_t *
914nsh_plugin_api_hookup (vlib_main_t *vm)
915{
916  nsh_main_t * nm = &nsh_main;
917#define _(N,n)                                                  \
918  vl_msg_api_set_handlers((VL_API_##N + nm->msg_id_base),	\
919			  #n,					\
920			  vl_api_##n##_t_handler,		\
921			  vl_noop_handler,			\
922			  vl_api_##n##_t_endian,		\
923			  vl_api_##n##_t_print,			\
924			  sizeof(vl_api_##n##_t), 1);
925  foreach_nsh_plugin_api_msg;
926#undef _
927
928  return 0;
929}
930
931
932
933
934static uword
935nsh_input_map (vlib_main_t * vm,
936               vlib_node_runtime_t * node,
937               vlib_frame_t * from_frame,
938	       u32 node_type)
939{
940  u32 n_left_from, next_index, *from, *to_next;
941  nsh_main_t * nm = &nsh_main;
942
943  from = vlib_frame_vector_args(from_frame);
944  n_left_from = from_frame->n_vectors;
945
946  next_index = node->cached_next_index;
947
948  while (n_left_from > 0)
949    {
950      u32 n_left_to_next;
951
952      vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
953
954      while (n_left_from >= 4 && n_left_to_next >= 2)
955	{
956	  u32 bi0, bi1;
957	  vlib_buffer_t * b0, *b1;
958	  u32 next0 = NSH_NODE_NEXT_DROP, next1 = NSH_NODE_NEXT_DROP;
959	  uword * entry0, *entry1;
960	  nsh_header_t * hdr0 = 0, *hdr1 = 0;
961	  u32 header_len0 = 0, header_len1 = 0;
962	  u32 nsp_nsi0, nsp_nsi1;
963	  u32 error0, error1;
964	  nsh_map_t * map0 = 0, *map1 = 0;
965	  nsh_header_t *encap_hdr0 = 0, *encap_hdr1 = 0;
966	  u32 encap_hdr_len0 = 0, encap_hdr_len1 = 0;
967	  nsh_proxy_session_by_key_t key0, key1;
968	  uword *p0, *p1;
969	  nsh_proxy_session_t *proxy0, *proxy1;
970
971	  /* Prefetch next iteration. */
972	  {
973	    vlib_buffer_t * p2, *p3;
974
975	    p2 = vlib_get_buffer(vm, from[2]);
976	    p3 = vlib_get_buffer(vm, from[3]);
977
978	    vlib_prefetch_buffer_header(p2, LOAD);
979	    vlib_prefetch_buffer_header(p3, LOAD);
980
981	    CLIB_PREFETCH(p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
982	    CLIB_PREFETCH(p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
983	  }
984
985	  bi0 = from[0];
986	  bi1 = from[1];
987	  to_next[0] = bi0;
988	  to_next[1] = bi1;
989	  from += 2;
990	  to_next += 2;
991	  n_left_from -= 2;
992	  n_left_to_next -= 2;
993
994	  error0 = 0;
995	  error1 = 0;
996
997	  b0 = vlib_get_buffer(vm, bi0);
998	  hdr0 = vlib_buffer_get_current(b0);
999          if(node_type == NSH_INPUT_TYPE)
1000            {
1001              nsp_nsi0 = clib_net_to_host_u32(hdr0->nsp_nsi);
1002              header_len0 = hdr0->length * 4;
1003            }
1004          else if(node_type == NSH_CLASSIFIER_TYPE)
1005            {
1006              nsp_nsi0 = vnet_buffer(b0)->l2_classify.opaque_index;
1007            }
1008          else
1009	    {
1010	      memset (&key0, 0, sizeof(key0));
1011	      key0.transport_type = NSH_NODE_NEXT_ENCAP_VXLAN4;
1012              key0.transport_index = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1013
1014              p0 = hash_get_mem(nm->nsh_proxy_session_by_key, &key0);
1015	      if (PREDICT_FALSE(p0 == 0))
1016		{
1017		  error0 = NSH_NODE_ERROR_NO_PROXY;
1018		  goto trace0;
1019		}
1020
1021	      proxy0 = pool_elt_at_index(nm->nsh_proxy_sessions, p0[0]);
1022              if (PREDICT_FALSE(proxy0 == 0))
1023                {
1024                  error0 = NSH_NODE_ERROR_NO_PROXY;
1025                  goto trace0;
1026                }
1027              nsp_nsi0 = proxy0->nsp_nsi;
1028	    }
1029
1030	  entry0 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi0);
1031
1032	  b1 = vlib_get_buffer(vm, bi1);
1033          hdr1 = vlib_buffer_get_current(b1);
1034          if(node_type == NSH_INPUT_TYPE)
1035	    {
1036	      nsp_nsi1 = clib_net_to_host_u32(hdr1->nsp_nsi);
1037	      header_len1 = hdr1->length * 4;
1038	    }
1039          else if(node_type == NSH_CLASSIFIER_TYPE)
1040            {
1041              nsp_nsi1 = vnet_buffer(b1)->l2_classify.opaque_index;
1042            }
1043          else
1044	    {
1045	      memset (&key1, 0, sizeof(key1));
1046	      key1.transport_type = NSH_NODE_NEXT_ENCAP_VXLAN4;
1047              key1.transport_index = vnet_buffer(b1)->sw_if_index[VLIB_RX];
1048
1049              p1 = hash_get_mem(nm->nsh_proxy_session_by_key, &key1);
1050	      if (PREDICT_FALSE(p1 == 0))
1051		{
1052		  error1 = NSH_NODE_ERROR_NO_PROXY;
1053		  goto trace1;
1054		}
1055
1056	      proxy1 = pool_elt_at_index(nm->nsh_proxy_sessions, p1[0]);
1057              if (PREDICT_FALSE(proxy1 == 0))
1058                {
1059                  error1 = NSH_NODE_ERROR_NO_PROXY;
1060                  goto trace1;
1061                }
1062              nsp_nsi1 = proxy1->nsp_nsi;
1063	    }
1064
1065          entry1 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi1);
1066
1067	  /* Process packet 0 */
1068	  entry0 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi0);
1069	  if (PREDICT_FALSE(entry0 == 0))
1070	    {
1071	      error0 = NSH_NODE_ERROR_NO_MAPPING;
1072	      goto trace0;
1073	    }
1074
1075	  /* Entry should point to a mapping ...*/
1076	  map0 = pool_elt_at_index(nm->nsh_mappings, entry0[0]);
1077	  if (PREDICT_FALSE(map0 == 0))
1078	    {
1079	      error0 = NSH_NODE_ERROR_NO_MAPPING;
1080	      goto trace0;
1081	    }
1082
1083	  /* set up things for next node to transmit ie which node to handle it and where */
1084	  next0 = map0->next_node;
1085	  vnet_buffer(b0)->sw_if_index[VLIB_TX] = map0->sw_if_index;
1086
1087	  if(PREDICT_FALSE(map0->nsh_action == NSH_ACTION_POP))
1088	    {
1089              /* Pop NSH header */
1090	      vlib_buffer_advance(b0, (word)header_len0);
1091	      goto trace0;
1092	    }
1093
1094	  entry0 = hash_get_mem(nm->nsh_entry_by_key, &map0->mapped_nsp_nsi);
1095	  if (PREDICT_FALSE(entry0 == 0))
1096	    {
1097	      error0 = NSH_NODE_ERROR_NO_ENTRY;
1098	      goto trace0;
1099	    }
1100
1101	  encap_hdr0 = pool_elt_at_index(nm->nsh_entries, entry0[0]);
1102	  encap_hdr_len0 = encap_hdr0->length * 4;
1103
1104	  if(PREDICT_TRUE(map0->nsh_action == NSH_ACTION_SWAP))
1105	    {
1106              /* Pop old NSH header */
1107	      vlib_buffer_advance(b0, (word)header_len0);
1108
1109	      /* Push new NSH header */
1110	      vlib_buffer_advance(b0, -(word)encap_hdr_len0);
1111	      hdr0 = vlib_buffer_get_current(b0);
1112	      clib_memcpy(hdr0, encap_hdr0, (word)encap_hdr_len0);
1113
1114	      goto trace0;
1115	    }
1116
1117	  if(PREDICT_TRUE(map0->nsh_action == NSH_ACTION_PUSH))
1118	    {
1119	      /* Push new NSH header */
1120	      vlib_buffer_advance(b0, -(word)encap_hdr_len0);
1121	      hdr0 = vlib_buffer_get_current(b0);
1122	      clib_memcpy(hdr0, encap_hdr0, (word)encap_hdr_len0);
1123	    }
1124
1125        trace0: b0->error = error0 ? node->errors[error0] : 0;
1126
1127          if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
1128            {
1129              nsh_input_trace_t *tr = vlib_add_trace(vm, node, b0, sizeof(*tr));
1130              tr->nsh_header = *hdr0;
1131            }
1132
1133	  /* Process packet 1 */
1134	  entry1 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi1);
1135	  if (PREDICT_FALSE(entry1 == 0))
1136	    {
1137	      error1 = NSH_NODE_ERROR_NO_MAPPING;
1138	      goto trace1;
1139	    }
1140
1141	  /* Entry should point to a mapping ...*/
1142	  map1 = pool_elt_at_index(nm->nsh_mappings, entry1[0]);
1143	  if (PREDICT_FALSE(map1 == 0))
1144	    {
1145	      error1 = NSH_NODE_ERROR_NO_MAPPING;
1146	      goto trace1;
1147	    }
1148
1149	  /* set up things for next node to transmit ie which node to handle it and where */
1150	  next1 = map1->next_node;
1151	  vnet_buffer(b1)->sw_if_index[VLIB_TX] = map1->sw_if_index;
1152
1153	  if(PREDICT_FALSE(map1->nsh_action == NSH_ACTION_POP))
1154	    {
1155              /* Pop NSH header */
1156	      vlib_buffer_advance(b1, (word)header_len1);
1157	      goto trace1;
1158	    }
1159
1160	  entry1 = hash_get_mem(nm->nsh_entry_by_key, &map1->mapped_nsp_nsi);
1161	  if (PREDICT_FALSE(entry1 == 0))
1162	    {
1163	      error1 = NSH_NODE_ERROR_NO_ENTRY;
1164	      goto trace1;
1165	    }
1166
1167	  encap_hdr1 = pool_elt_at_index(nm->nsh_entries, entry1[0]);
1168	  encap_hdr_len1 = encap_hdr1->length * 4;
1169
1170          if(PREDICT_TRUE(map1->nsh_action == NSH_ACTION_SWAP))
1171            {
1172              /* Pop old NSH header */
1173              vlib_buffer_advance(b1, (word)header_len1);
1174
1175              /* Push new NSH header */
1176              vlib_buffer_advance(b1, -(word)encap_hdr_len1);
1177              hdr1 = vlib_buffer_get_current(b1);
1178              clib_memcpy(hdr1, encap_hdr1, (word)encap_hdr_len1);
1179
1180              goto trace1;
1181            }
1182
1183          if(PREDICT_FALSE(map1->nsh_action == NSH_ACTION_PUSH))
1184            {
1185              /* Push new NSH header */
1186              vlib_buffer_advance(b1, -(word)encap_hdr_len1);
1187              hdr1 = vlib_buffer_get_current(b1);
1188              clib_memcpy(hdr1, encap_hdr1, (word)encap_hdr_len1);
1189            }
1190
1191	trace1: b1->error = error1 ? node->errors[error1] : 0;
1192
1193	  if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
1194	    {
1195	      nsh_input_trace_t *tr = vlib_add_trace(vm, node, b1, sizeof(*tr));
1196	      tr->nsh_header = *hdr1;
1197	    }
1198
1199	  vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
1200					  n_left_to_next, bi0, bi1, next0, next1);
1201
1202	}
1203
1204      while (n_left_from > 0 && n_left_to_next > 0)
1205	{
1206	  u32 bi0;
1207	  vlib_buffer_t * b0;
1208	  u32 next0 = NSH_NODE_NEXT_DROP;
1209	  uword * entry0;
1210	  nsh_header_t * hdr0 = 0;
1211	  u32 header_len0 = 0;
1212	  u32 nsp_nsi0;
1213	  u32 error0;
1214	  nsh_map_t * map0 = 0;
1215	  nsh_header_t * encap_hdr0 = 0;
1216	  u32 encap_hdr_len0 = 0;
1217	  nsh_proxy_session_by_key_t key0;
1218	  uword *p0;
1219	  nsh_proxy_session_t *proxy0 = 0;
1220
1221	  bi0 = from[0];
1222	  to_next[0] = bi0;
1223	  from += 1;
1224	  to_next += 1;
1225	  n_left_from -= 1;
1226	  n_left_to_next -= 1;
1227	  error0 = 0;
1228
1229	  b0 = vlib_get_buffer(vm, bi0);
1230	  hdr0 = vlib_buffer_get_current(b0);
1231
1232          if(node_type == NSH_INPUT_TYPE)
1233            {
1234              nsp_nsi0 = clib_net_to_host_u32(hdr0->nsp_nsi);
1235              header_len0 = hdr0->length * 4;
1236            }
1237          else if(node_type == NSH_CLASSIFIER_TYPE)
1238            {
1239              nsp_nsi0 = vnet_buffer(b0)->l2_classify.opaque_index;
1240            }
1241          else
1242	    {
1243	      memset (&key0, 0, sizeof(key0));
1244	      key0.transport_type = NSH_NODE_NEXT_ENCAP_VXLAN4;
1245	      key0.transport_index = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1246
1247	      p0 = hash_get_mem(nm->nsh_proxy_session_by_key, &key0);
1248	      if (PREDICT_FALSE(p0 == 0))
1249		{
1250		  error0 = NSH_NODE_ERROR_NO_PROXY;
1251		  goto trace00;
1252		}
1253
1254	      proxy0 = pool_elt_at_index(nm->nsh_proxy_sessions, p0[0]);
1255	      if (PREDICT_FALSE(proxy0 == 0))
1256		{
1257		  error0 = NSH_NODE_ERROR_NO_PROXY;
1258		  goto trace00;
1259		}
1260	      nsp_nsi0 = proxy0->nsp_nsi;
1261	    }
1262
1263	  entry0 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi0);
1264
1265	  if (PREDICT_FALSE(entry0 == 0))
1266	    {
1267	      error0 = NSH_NODE_ERROR_NO_MAPPING;
1268	      goto trace00;
1269	    }
1270
1271	  /* Entry should point to a mapping ...*/
1272	  map0 = pool_elt_at_index(nm->nsh_mappings, entry0[0]);
1273
1274	  if (PREDICT_FALSE(map0 == 0))
1275	    {
1276	      error0 = NSH_NODE_ERROR_NO_MAPPING;
1277	      goto trace00;
1278	    }
1279
1280	  /* set up things for next node to transmit ie which node to handle it and where */
1281	  next0 = map0->next_node;
1282	  vnet_buffer(b0)->sw_if_index[VLIB_TX] = map0->sw_if_index;
1283
1284	  if(PREDICT_FALSE(map0->nsh_action == NSH_ACTION_POP))
1285	    {
1286              /* Pop NSH header */
1287	      vlib_buffer_advance(b0, (word)header_len0);
1288	      goto trace00;
1289	    }
1290
1291	  entry0 = hash_get_mem(nm->nsh_entry_by_key, &map0->mapped_nsp_nsi);
1292	  if (PREDICT_FALSE(entry0 == 0))
1293	    {
1294	      error0 = NSH_NODE_ERROR_NO_ENTRY;
1295	      goto trace00;
1296	    }
1297
1298	  encap_hdr0 = pool_elt_at_index(nm->nsh_entries, entry0[0]);
1299	  encap_hdr_len0 = encap_hdr0->length * 4;
1300
1301	  if(PREDICT_TRUE(map0->nsh_action == NSH_ACTION_SWAP))
1302	    {
1303              /* Pop old NSH header */
1304	      vlib_buffer_advance(b0, (word)header_len0);
1305
1306	      /* Push new NSH header */
1307	      vlib_buffer_advance(b0, -(word)encap_hdr_len0);
1308	      hdr0 = vlib_buffer_get_current(b0);
1309	      clib_memcpy(hdr0, encap_hdr0, (word)encap_hdr_len0);
1310
1311	      goto trace00;
1312	    }
1313
1314	  if(PREDICT_TRUE(map0->nsh_action == NSH_ACTION_PUSH))
1315	    {
1316	      /* Push new NSH header */
1317	      vlib_buffer_advance(b0, -(word)encap_hdr_len0);
1318	      hdr0 = vlib_buffer_get_current(b0);
1319	      clib_memcpy(hdr0, encap_hdr0, (word)encap_hdr_len0);
1320	    }
1321
1322	  trace00: b0->error = error0 ? node->errors[error0] : 0;
1323
1324	  if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
1325	    {
1326	      nsh_input_trace_t *tr = vlib_add_trace(vm, node, b0, sizeof(*tr));
1327	      tr->nsh_header = *hdr0;
1328	    }
1329
1330	  vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
1331					  n_left_to_next, bi0, next0);
1332	}
1333
1334      vlib_put_next_frame(vm, node, next_index, n_left_to_next);
1335
1336    }
1337
1338  return from_frame->n_vectors;
1339}
1340
1341/**
1342 * @brief Graph processing dispatch function for NSH Input
1343 *
1344 * @node nsh_input
1345 * @param *vm
1346 * @param *node
1347 * @param *from_frame
1348 *
1349 * @return from_frame->n_vectors
1350 *
1351 */
1352static uword
1353nsh_input (vlib_main_t * vm, vlib_node_runtime_t * node,
1354                  vlib_frame_t * from_frame)
1355{
1356  return nsh_input_map (vm, node, from_frame, NSH_INPUT_TYPE);
1357}
1358
1359/**
1360 * @brief Graph processing dispatch function for NSH-Proxy
1361 *
1362 * @node nsh_proxy
1363 * @param *vm
1364 * @param *node
1365 * @param *from_frame
1366 *
1367 * @return from_frame->n_vectors
1368 *
1369 */
1370static uword
1371nsh_proxy (vlib_main_t * vm, vlib_node_runtime_t * node,
1372                  vlib_frame_t * from_frame)
1373{
1374  return nsh_input_map (vm, node, from_frame, NSH_PROXY_TYPE);
1375}
1376
1377/**
1378 * @brief Graph processing dispatch function for NSH Classifier
1379 *
1380 * @node nsh_classifier
1381 * @param *vm
1382 * @param *node
1383 * @param *from_frame
1384 *
1385 * @return from_frame->n_vectors
1386 *
1387 */
1388static uword
1389nsh_classifier (vlib_main_t * vm, vlib_node_runtime_t * node,
1390                  vlib_frame_t * from_frame)
1391{
1392  return nsh_input_map (vm, node, from_frame, NSH_CLASSIFIER_TYPE);
1393}
1394
1395static char * nsh_node_error_strings[] = {
1396#define _(sym,string) string,
1397  foreach_nsh_node_error
1398#undef _
1399};
1400
1401/* register nsh-input node */
1402VLIB_REGISTER_NODE (nsh_input_node) = {
1403  .function = nsh_input,
1404  .name = "nsh-input",
1405  .vector_size = sizeof (u32),
1406  .format_trace = format_nsh_node_map_trace,
1407  .format_buffer = format_nsh_header_with_length,
1408  .type = VLIB_NODE_TYPE_INTERNAL,
1409
1410  .n_errors = ARRAY_LEN(nsh_node_error_strings),
1411  .error_strings = nsh_node_error_strings,
1412
1413  .n_next_nodes = NSH_NODE_N_NEXT,
1414
1415  .next_nodes = {
1416#define _(s,n) [NSH_NODE_NEXT_##s] = n,
1417    foreach_nsh_node_next
1418#undef _
1419  },
1420};
1421
1422VLIB_NODE_FUNCTION_MULTIARCH (nsh_input_node, nsh_input);
1423
1424/* register nsh-proxy node */
1425VLIB_REGISTER_NODE (nsh_proxy_node) = {
1426  .function = nsh_proxy,
1427  .name = "nsh-proxy",
1428  .vector_size = sizeof (u32),
1429  .format_trace = format_nsh_node_map_trace,
1430  .format_buffer = format_nsh_header_with_length,
1431  .type = VLIB_NODE_TYPE_INTERNAL,
1432
1433  .n_errors = ARRAY_LEN(nsh_node_error_strings),
1434  .error_strings = nsh_node_error_strings,
1435
1436  .n_next_nodes = NSH_NODE_N_NEXT,
1437
1438  .next_nodes = {
1439#define _(s,n) [NSH_NODE_NEXT_##s] = n,
1440    foreach_nsh_node_next
1441#undef _
1442  },
1443};
1444
1445VLIB_NODE_FUNCTION_MULTIARCH (nsh_proxy_node, nsh_proxy);
1446
1447/* register nsh-classifier node */
1448VLIB_REGISTER_NODE (nsh_classifier_node) = {
1449  .function = nsh_classifier,
1450  .name = "nsh-classifier",
1451  .vector_size = sizeof (u32),
1452  .format_trace = format_nsh_node_map_trace,
1453  .format_buffer = format_nsh_header_with_length,
1454  .type = VLIB_NODE_TYPE_INTERNAL,
1455
1456  .n_errors = ARRAY_LEN(nsh_node_error_strings),
1457  .error_strings = nsh_node_error_strings,
1458
1459  .n_next_nodes = NSH_NODE_N_NEXT,
1460
1461  .next_nodes = {
1462#define _(s,n) [NSH_NODE_NEXT_##s] = n,
1463    foreach_nsh_node_next
1464#undef _
1465  },
1466};
1467
1468VLIB_NODE_FUNCTION_MULTIARCH (nsh_classifier_node, nsh_classifier);
1469
1470clib_error_t *nsh_init (vlib_main_t *vm)
1471{
1472  nsh_main_t *nm = &nsh_main;
1473  clib_error_t * error = 0;
1474  u8 * name;
1475
1476  /* Init the main structures from VPP */
1477  nm->vlib_main = vm;
1478  nm->vnet_main = vnet_get_main();
1479
1480  /* Various state maintenance mappings */
1481  nm->nsh_mapping_by_key
1482    = hash_create_mem (0, sizeof(u32), sizeof (uword));
1483
1484  nm->nsh_mapping_by_mapped_key
1485    = hash_create_mem (0, sizeof(u32), sizeof (uword));
1486
1487  nm->nsh_entry_by_key
1488    = hash_create_mem (0, sizeof(u32), sizeof (uword));
1489
1490  nm->nsh_proxy_session_by_key
1491    = hash_create_mem (0, sizeof(nsh_proxy_session_by_key_t), sizeof (uword));
1492
1493  name = format (0, "nsh_%08x%c", api_version, 0);
1494
1495  /* Set up the API */
1496  nm->msg_id_base = vl_msg_api_get_msg_ids
1497    ((char *) name, VL_MSG_FIRST_AVAILABLE);
1498
1499  error = nsh_plugin_api_hookup (vm);
1500
1501  /* Add dispositions to nodes that feed nsh-input */
1502  //alagalah - validate we don't really need to use the node value
1503  vlib_node_add_next (vm, vxlan4_gpe_input_node.index, nsh_input_node.index);
1504  vlib_node_add_next (vm, vxlan4_gpe_input_node.index, nsh_proxy_node.index);
1505
1506  vlib_node_add_next (vm, vxlan6_gpe_input_node.index, nsh_input_node.index);
1507  vlib_node_add_next (vm, vxlan6_gpe_input_node.index, nsh_proxy_node.index);
1508
1509  vlib_node_add_next (vm, gre_input_node.index, nsh_input_node.index);
1510  vlib_node_add_next (vm, gre_input_node.index, nsh_proxy_node.index);
1511
1512  /* Add NSH-Proxy support */
1513  vlib_node_add_next (vm, vxlan4_input_node.index, nsh_proxy_node.index);
1514  vlib_node_add_next (vm, vxlan6_input_node.index, nsh_proxy_node.index);
1515
1516  /* Add NSH-Classifier support */
1517  vlib_node_add_next (vm, ip4_classify_node.index, nsh_classifier_node.index);
1518  vlib_node_add_next (vm, ip6_classify_node.index, nsh_classifier_node.index);
1519
1520  vec_free(name);
1521
1522  return error;
1523}
1524
1525VLIB_INIT_FUNCTION(nsh_init);
1526