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