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