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