nsh.c revision 8c6aec0a
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  REPLY_MACRO2(VL_API_NSH_ADD_DEL_MAP_REPLY,
543  ({
544    rmp->map_index = htonl (map_index);
545  }));
546}
547
548/**
549 * CLI command for showing the mapping between NSH entries
550 */
551static clib_error_t *
552show_nsh_map_command_fn (vlib_main_t * vm,
553			 unformat_input_t * input,
554			 vlib_cli_command_t * cmd)
555{
556  nsh_main_t * nm = &nsh_main;
557  nsh_map_t * map;
558
559  if (pool_elts (nm->nsh_mappings) == 0)
560    vlib_cli_output (vm, "No nsh maps configured.");
561
562  pool_foreach (map, nm->nsh_mappings,
563		({
564		  vlib_cli_output (vm, "%U", format_nsh_map, map);
565		}));
566
567  return 0;
568}
569
570VLIB_CLI_COMMAND (show_nsh_map_command, static) = {
571  .path = "show nsh map",
572  .function = show_nsh_map_command_fn,
573};
574
575/**
576 * Action function for adding an NSH entry
577 */
578
579int nsh_add_del_entry (nsh_add_del_entry_args_t *a, u32 * entry_indexp)
580{
581  nsh_main_t * nm = &nsh_main;
582  nsh_header_t *hdr = 0;
583  u32 key, *key_copy;
584  uword * entry;
585  hash_pair_t *hp;
586  u32 entry_index = ~0;
587
588  key = a->nsh.nsp_nsi;
589
590  entry = hash_get_mem (nm->nsh_entry_by_key, &key);
591
592  if (a->is_add)
593    {
594      /* adding an entry, must not already exist */
595      if (entry)
596        return -1; // TODO VNET_API_ERROR_INVALID_VALUE;
597
598      pool_get_aligned (nm->nsh_entries, hdr, CLIB_CACHE_LINE_BYTES);
599      memset (hdr, 0, sizeof (*hdr));
600
601      /* copy from arg structure */
602#define _(x) hdr->x = a->nsh.x;
603      foreach_copy_nshhdr_field;
604#undef _
605
606      key_copy = clib_mem_alloc (sizeof (*key_copy));
607      clib_memcpy (key_copy, &key, sizeof (*key_copy));
608
609      hash_set_mem (nm->nsh_entry_by_key, key_copy,
610                    hdr - nm->nsh_entries);
611      entry_index = hdr - nm->nsh_entries;
612    }
613  else
614    {
615      if (!entry)
616	return -2; //TODO API_ERROR_NO_SUCH_ENTRY;
617
618      hdr = pool_elt_at_index (nm->nsh_entries, entry[0]);
619      hp = hash_get_pair (nm->nsh_entry_by_key, &key);
620      key_copy = (void *)(hp->key);
621      hash_unset_mem (nm->nsh_entry_by_key, &key);
622      clib_mem_free (key_copy);
623
624      pool_put (nm->nsh_entries, hdr);
625    }
626
627  if (entry_indexp)
628      *entry_indexp = entry_index;
629
630  return 0;
631}
632
633
634/**
635 * CLI command for adding NSH entry
636 */
637
638static clib_error_t *
639nsh_add_del_entry_command_fn (vlib_main_t * vm,
640			      unformat_input_t * input,
641			      vlib_cli_command_t * cmd)
642{
643  unformat_input_t _line_input, * line_input = &_line_input;
644  u8 is_add = 1;
645  u8 ver_o_c = 0;
646  u8 length = 0;
647  u8 md_type = 0;
648  u8 next_protocol = 1; /* default: ip4 */
649  u32 nsp;
650  u8 nsp_set = 0;
651  u32 nsi;
652  u8 nsi_set = 0;
653  u32 nsp_nsi;
654  u32 c1 = 0;
655  u32 c2 = 0;
656  u32 c3 = 0;
657  u32 c4 = 0;
658  u32 tmp;
659  int rv;
660  u32 entry_index;
661  nsh_add_del_entry_args_t _a, * a = &_a;
662
663  /* Get a line of input. */
664  if (! unformat_user (input, unformat_line_input, line_input))
665    return 0;
666
667  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
668    if (unformat (line_input, "del"))
669      is_add = 0;
670    else if (unformat (line_input, "version %d", &tmp))
671      ver_o_c |= (tmp & 3) << 6;
672    else if (unformat (line_input, "o-bit %d", &tmp))
673      ver_o_c |= (tmp & 1) << 5;
674    else if (unformat (line_input, "c-bit %d", &tmp))
675      ver_o_c |= (tmp & 1) << 4;
676    else if (unformat (line_input, "md-type %d", &tmp))
677      md_type = tmp;
678    else if (unformat(line_input, "next-ip4"))
679      next_protocol = 1;
680    else if (unformat(line_input, "next-ip6"))
681      next_protocol = 2;
682    else if (unformat(line_input, "next-ethernet"))
683      next_protocol = 3;
684    else if (unformat (line_input, "c1 %d", &c1))
685      ;
686    else if (unformat (line_input, "c2 %d", &c2))
687      ;
688    else if (unformat (line_input, "c3 %d", &c3))
689      ;
690    else if (unformat (line_input, "c4 %d", &c4))
691      ;
692    else if (unformat (line_input, "nsp %d", &nsp))
693      nsp_set = 1;
694    else if (unformat (line_input, "nsi %d", &nsi))
695      nsi_set = 1;
696    else
697      return clib_error_return (0, "parse error: '%U'",
698                                format_unformat_error, line_input);
699  }
700
701  unformat_free (line_input);
702
703  if (nsp_set == 0)
704    return clib_error_return (0, "nsp not specified");
705
706  if (nsi_set == 0)
707    return clib_error_return (0, "nsi not specified");
708
709  if (md_type != 1)
710    return clib_error_return (0, "md-type 1 only supported at this time");
711
712  md_type = 1;
713  length = 6;
714
715  nsp_nsi = (nsp<<8) | nsi;
716
717  memset (a, 0, sizeof (*a));
718
719  a->is_add = is_add;
720
721#define _(x) a->nsh.x = x;
722  foreach_copy_nshhdr_field;
723#undef _
724
725  rv = nsh_add_del_entry (a, &entry_index);
726
727  switch(rv)
728    {
729    case 0:
730      break;
731    default:
732      return clib_error_return
733        (0, "nsh_add_del_entry returned %d", rv);
734    }
735
736  return 0;
737}
738
739VLIB_CLI_COMMAND (create_nsh_entry_command, static) = {
740  .path = "create nsh entry",
741  .short_help =
742  "create nsh entry {nsp <nn> nsi <nn>} c1 <nn> c2 <nn> c3 <nn> c4 <nn>"
743  " [md-type <nn>] [tlv <xx>] [del]\n",
744  .function = nsh_add_del_entry_command_fn,
745};
746
747/** API message handler */
748static void vl_api_nsh_add_del_entry_t_handler
749(vl_api_nsh_add_del_entry_t * mp)
750{
751  vl_api_nsh_add_del_entry_reply_t * rmp;
752  nsh_main_t * nm = &nsh_main;
753  int rv;
754  nsh_add_del_entry_args_t _a, *a = &_a;
755  u32 entry_index = ~0;
756
757  a->is_add = mp->is_add;
758  a->nsh.ver_o_c = mp->ver_o_c;
759  a->nsh.length = mp->length;
760  a->nsh.md_type = mp->md_type;
761  a->nsh.next_protocol = mp->next_protocol;
762  a->nsh.nsp_nsi = ntohl(mp->nsp_nsi);
763  a->nsh.c1 = ntohl(mp->c1);
764  a->nsh.c2 = ntohl(mp->c2);
765  a->nsh.c3 = ntohl(mp->c3);
766  a->nsh.c4 = ntohl(mp->c4);
767
768  rv = nsh_add_del_entry (a, &entry_index);
769
770  REPLY_MACRO2(VL_API_NSH_ADD_DEL_ENTRY_REPLY,
771  ({
772    rmp->entry_index = htonl (entry_index);
773  }));
774}
775
776static void send_nsh_entry_details
777(nsh_header_t * t, unix_shared_memory_queue_t * q, u32 context)
778{
779    vl_api_nsh_entry_details_t * rmp;
780    nsh_main_t * nm = &nsh_main;
781
782    rmp = vl_msg_api_alloc (sizeof (*rmp));
783    memset (rmp, 0, sizeof (*rmp));
784
785    rmp->_vl_msg_id = ntohs((VL_API_NSH_ENTRY_DETAILS)+nm->msg_id_base);
786    rmp->ver_o_c = t->ver_o_c;
787    rmp->length = t->length;
788    rmp->md_type = t->md_type;
789    rmp->next_protocol = t->next_protocol;
790    rmp->nsp_nsi = htonl(t->nsp_nsi);
791    rmp->c1 = htonl(t->c1);
792    rmp->c2 = htonl(t->c2);
793    rmp->c3 = htonl(t->c3);
794    rmp->c4 = htonl(t->c4);
795
796    rmp->context = context;
797
798    vl_msg_api_send_shmem (q, (u8 *)&rmp);
799}
800
801static void vl_api_nsh_entry_dump_t_handler
802(vl_api_nsh_entry_dump_t * mp)
803{
804    unix_shared_memory_queue_t * q;
805    nsh_main_t * nm = &nsh_main;
806    nsh_header_t * t;
807    u32 entry_index;
808
809    q = vl_api_client_index_to_input_queue (mp->client_index);
810    if (q == 0) {
811        return;
812    }
813
814    entry_index = ntohl (mp->entry_index);
815
816    if (~0 == entry_index)
817      {
818	pool_foreach (t, nm->nsh_entries,
819	({
820	    send_nsh_entry_details(t, q, mp->context);
821	}));
822      }
823    else
824      {
825        if (entry_index >= vec_len (nm->nsh_entries))
826  	{
827  	  return;
828  	}
829        t = &nm->nsh_entries[entry_index];
830        send_nsh_entry_details(t, q, mp->context);
831      }
832}
833
834static void send_nsh_map_details
835(nsh_map_t * t, unix_shared_memory_queue_t * q, u32 context)
836{
837    vl_api_nsh_map_details_t * rmp;
838    nsh_main_t * nm = &nsh_main;
839
840    rmp = vl_msg_api_alloc (sizeof (*rmp));
841    memset (rmp, 0, sizeof (*rmp));
842
843    rmp->_vl_msg_id = ntohs((VL_API_NSH_MAP_DETAILS)+nm->msg_id_base);
844    rmp->nsp_nsi = htonl(t->nsp_nsi);
845    rmp->mapped_nsp_nsi = htonl(t->mapped_nsp_nsi);
846    rmp->nsh_action = htonl(t->nsh_action);
847    rmp->sw_if_index = htonl(t->sw_if_index);
848    rmp->next_node = htonl(t->next_node);
849
850    rmp->context = context;
851
852    vl_msg_api_send_shmem (q, (u8 *)&rmp);
853}
854
855static void vl_api_nsh_map_dump_t_handler
856(vl_api_nsh_map_dump_t * mp)
857{
858    unix_shared_memory_queue_t * q;
859    nsh_main_t * nm = &nsh_main;
860    nsh_map_t * t;
861    u32 map_index;
862
863    q = vl_api_client_index_to_input_queue (mp->client_index);
864    if (q == 0) {
865        return;
866    }
867
868    map_index = ntohl (mp->map_index);
869
870    if (~0 == map_index)
871      {
872	pool_foreach (t, nm->nsh_mappings,
873	({
874	    send_nsh_map_details(t, q, mp->context);
875	}));
876      }
877    else
878      {
879        if (map_index >= vec_len (nm->nsh_mappings))
880  	{
881  	  return;
882  	}
883        t = &nm->nsh_mappings[map_index];
884        send_nsh_map_details(t, q, mp->context);
885      }
886}
887
888static clib_error_t *
889show_nsh_entry_command_fn (vlib_main_t * vm,
890			   unformat_input_t * input,
891			   vlib_cli_command_t * cmd)
892{
893  nsh_main_t * nm = &nsh_main;
894  nsh_header_t * hdr;
895
896  if (pool_elts (nm->nsh_entries) == 0)
897    vlib_cli_output (vm, "No nsh entries configured.");
898
899  pool_foreach (hdr, nm->nsh_entries,
900		({
901		  vlib_cli_output (vm, "%U", format_nsh_header, hdr);
902		}));
903
904  return 0;
905}
906
907VLIB_CLI_COMMAND (show_nsh_entry_command, static) = {
908  .path = "show nsh entry",
909  .function = show_nsh_entry_command_fn,
910};
911
912
913/* Set up the API message handling tables */
914static clib_error_t *
915nsh_plugin_api_hookup (vlib_main_t *vm)
916{
917  nsh_main_t * nm = &nsh_main;
918#define _(N,n)                                                  \
919  vl_msg_api_set_handlers((VL_API_##N + nm->msg_id_base),	\
920			  #n,					\
921			  vl_api_##n##_t_handler,		\
922			  vl_noop_handler,			\
923			  vl_api_##n##_t_endian,		\
924			  vl_api_##n##_t_print,			\
925			  sizeof(vl_api_##n##_t), 1);
926  foreach_nsh_plugin_api_msg;
927#undef _
928
929  return 0;
930}
931
932
933
934
935static uword
936nsh_input_map (vlib_main_t * vm,
937               vlib_node_runtime_t * node,
938               vlib_frame_t * from_frame,
939	       u32 node_type)
940{
941  u32 n_left_from, next_index, *from, *to_next;
942  nsh_main_t * nm = &nsh_main;
943
944  from = vlib_frame_vector_args(from_frame);
945  n_left_from = from_frame->n_vectors;
946
947  next_index = node->cached_next_index;
948
949  while (n_left_from > 0)
950    {
951      u32 n_left_to_next;
952
953      vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
954
955      while (n_left_from >= 4 && n_left_to_next >= 2)
956	{
957	  u32 bi0, bi1;
958	  vlib_buffer_t * b0, *b1;
959	  u32 next0 = NSH_NODE_NEXT_DROP, next1 = NSH_NODE_NEXT_DROP;
960	  uword * entry0, *entry1;
961	  nsh_header_t * hdr0 = 0, *hdr1 = 0;
962	  u32 header_len0 = 0, header_len1 = 0;
963	  u32 nsp_nsi0, nsp_nsi1;
964	  u32 error0, error1;
965	  nsh_map_t * map0 = 0, *map1 = 0;
966	  nsh_header_t *encap_hdr0 = 0, *encap_hdr1 = 0;
967	  u32 encap_hdr_len0 = 0, encap_hdr_len1 = 0;
968	  nsh_proxy_session_by_key_t key0, key1;
969	  uword *p0, *p1;
970	  nsh_proxy_session_t *proxy0, *proxy1;
971
972	  /* Prefetch next iteration. */
973	  {
974	    vlib_buffer_t * p2, *p3;
975
976	    p2 = vlib_get_buffer(vm, from[2]);
977	    p3 = vlib_get_buffer(vm, from[3]);
978
979	    vlib_prefetch_buffer_header(p2, LOAD);
980	    vlib_prefetch_buffer_header(p3, LOAD);
981
982	    CLIB_PREFETCH(p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
983	    CLIB_PREFETCH(p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
984	  }
985
986	  bi0 = from[0];
987	  bi1 = from[1];
988	  to_next[0] = bi0;
989	  to_next[1] = bi1;
990	  from += 2;
991	  to_next += 2;
992	  n_left_from -= 2;
993	  n_left_to_next -= 2;
994
995	  error0 = 0;
996	  error1 = 0;
997
998	  b0 = vlib_get_buffer(vm, bi0);
999	  hdr0 = vlib_buffer_get_current(b0);
1000          if(node_type == NSH_INPUT_TYPE)
1001            {
1002              nsp_nsi0 = clib_net_to_host_u32(hdr0->nsp_nsi);
1003              header_len0 = hdr0->length * 4;
1004            }
1005          else if(node_type == NSH_CLASSIFIER_TYPE)
1006            {
1007              nsp_nsi0 = vnet_buffer(b0)->l2_classify.opaque_index;
1008            }
1009          else
1010	    {
1011	      memset (&key0, 0, sizeof(key0));
1012	      key0.transport_type = NSH_NODE_NEXT_ENCAP_VXLAN4;
1013              key0.transport_index = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1014
1015              p0 = hash_get_mem(nm->nsh_proxy_session_by_key, &key0);
1016	      if (PREDICT_FALSE(p0 == 0))
1017		{
1018		  error0 = NSH_NODE_ERROR_NO_PROXY;
1019		  goto trace0;
1020		}
1021
1022	      proxy0 = pool_elt_at_index(nm->nsh_proxy_sessions, p0[0]);
1023              if (PREDICT_FALSE(proxy0 == 0))
1024                {
1025                  error0 = NSH_NODE_ERROR_NO_PROXY;
1026                  goto trace0;
1027                }
1028              nsp_nsi0 = proxy0->nsp_nsi;
1029	    }
1030
1031	  entry0 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi0);
1032
1033	  b1 = vlib_get_buffer(vm, bi1);
1034          hdr1 = vlib_buffer_get_current(b1);
1035          if(node_type == NSH_INPUT_TYPE)
1036	    {
1037	      nsp_nsi1 = clib_net_to_host_u32(hdr1->nsp_nsi);
1038	      header_len1 = hdr1->length * 4;
1039	    }
1040          else if(node_type == NSH_CLASSIFIER_TYPE)
1041            {
1042              nsp_nsi1 = vnet_buffer(b1)->l2_classify.opaque_index;
1043            }
1044          else
1045	    {
1046	      memset (&key1, 0, sizeof(key1));
1047	      key1.transport_type = NSH_NODE_NEXT_ENCAP_VXLAN4;
1048              key1.transport_index = vnet_buffer(b1)->sw_if_index[VLIB_RX];
1049
1050              p1 = hash_get_mem(nm->nsh_proxy_session_by_key, &key1);
1051	      if (PREDICT_FALSE(p1 == 0))
1052		{
1053		  error1 = NSH_NODE_ERROR_NO_PROXY;
1054		  goto trace1;
1055		}
1056
1057	      proxy1 = pool_elt_at_index(nm->nsh_proxy_sessions, p1[0]);
1058              if (PREDICT_FALSE(proxy1 == 0))
1059                {
1060                  error1 = NSH_NODE_ERROR_NO_PROXY;
1061                  goto trace1;
1062                }
1063              nsp_nsi1 = proxy1->nsp_nsi;
1064	    }
1065
1066          entry1 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi1);
1067
1068	  /* Process packet 0 */
1069	  entry0 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi0);
1070	  if (PREDICT_FALSE(entry0 == 0))
1071	    {
1072	      error0 = NSH_NODE_ERROR_NO_MAPPING;
1073	      goto trace0;
1074	    }
1075
1076	  /* Entry should point to a mapping ...*/
1077	  map0 = pool_elt_at_index(nm->nsh_mappings, entry0[0]);
1078	  if (PREDICT_FALSE(map0 == 0))
1079	    {
1080	      error0 = NSH_NODE_ERROR_NO_MAPPING;
1081	      goto trace0;
1082	    }
1083
1084	  /* set up things for next node to transmit ie which node to handle it and where */
1085	  next0 = map0->next_node;
1086	  vnet_buffer(b0)->sw_if_index[VLIB_TX] = map0->sw_if_index;
1087
1088	  if(PREDICT_FALSE(map0->nsh_action == NSH_ACTION_POP))
1089	    {
1090              /* Pop NSH header */
1091	      vlib_buffer_advance(b0, (word)header_len0);
1092	      goto trace0;
1093	    }
1094
1095	  entry0 = hash_get_mem(nm->nsh_entry_by_key, &map0->mapped_nsp_nsi);
1096	  if (PREDICT_FALSE(entry0 == 0))
1097	    {
1098	      error0 = NSH_NODE_ERROR_NO_ENTRY;
1099	      goto trace0;
1100	    }
1101
1102	  encap_hdr0 = pool_elt_at_index(nm->nsh_entries, entry0[0]);
1103	  encap_hdr_len0 = encap_hdr0->length * 4;
1104
1105	  if(PREDICT_TRUE(map0->nsh_action == NSH_ACTION_SWAP))
1106	    {
1107              /* Pop old NSH header */
1108	      vlib_buffer_advance(b0, (word)header_len0);
1109
1110	      /* Push new NSH header */
1111	      vlib_buffer_advance(b0, -(word)encap_hdr_len0);
1112	      hdr0 = vlib_buffer_get_current(b0);
1113	      clib_memcpy(hdr0, encap_hdr0, (word)encap_hdr_len0);
1114
1115	      goto trace0;
1116	    }
1117
1118	  if(PREDICT_TRUE(map0->nsh_action == NSH_ACTION_PUSH))
1119	    {
1120	      /* Push new NSH header */
1121	      vlib_buffer_advance(b0, -(word)encap_hdr_len0);
1122	      hdr0 = vlib_buffer_get_current(b0);
1123	      clib_memcpy(hdr0, encap_hdr0, (word)encap_hdr_len0);
1124	    }
1125
1126        trace0: b0->error = error0 ? node->errors[error0] : 0;
1127
1128          if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
1129            {
1130              nsh_input_trace_t *tr = vlib_add_trace(vm, node, b0, sizeof(*tr));
1131              tr->nsh_header = *hdr0;
1132            }
1133
1134	  /* Process packet 1 */
1135	  entry1 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi1);
1136	  if (PREDICT_FALSE(entry1 == 0))
1137	    {
1138	      error1 = NSH_NODE_ERROR_NO_MAPPING;
1139	      goto trace1;
1140	    }
1141
1142	  /* Entry should point to a mapping ...*/
1143	  map1 = pool_elt_at_index(nm->nsh_mappings, entry1[0]);
1144	  if (PREDICT_FALSE(map1 == 0))
1145	    {
1146	      error1 = NSH_NODE_ERROR_NO_MAPPING;
1147	      goto trace1;
1148	    }
1149
1150	  /* set up things for next node to transmit ie which node to handle it and where */
1151	  next1 = map1->next_node;
1152	  vnet_buffer(b1)->sw_if_index[VLIB_TX] = map1->sw_if_index;
1153
1154	  if(PREDICT_FALSE(map1->nsh_action == NSH_ACTION_POP))
1155	    {
1156              /* Pop NSH header */
1157	      vlib_buffer_advance(b1, (word)header_len1);
1158	      goto trace1;
1159	    }
1160
1161	  entry1 = hash_get_mem(nm->nsh_entry_by_key, &map1->mapped_nsp_nsi);
1162	  if (PREDICT_FALSE(entry1 == 0))
1163	    {
1164	      error1 = NSH_NODE_ERROR_NO_ENTRY;
1165	      goto trace1;
1166	    }
1167
1168	  encap_hdr1 = pool_elt_at_index(nm->nsh_entries, entry1[0]);
1169	  encap_hdr_len1 = encap_hdr1->length * 4;
1170
1171          if(PREDICT_TRUE(map1->nsh_action == NSH_ACTION_SWAP))
1172            {
1173              /* Pop old NSH header */
1174              vlib_buffer_advance(b1, (word)header_len1);
1175
1176              /* Push new NSH header */
1177              vlib_buffer_advance(b1, -(word)encap_hdr_len1);
1178              hdr1 = vlib_buffer_get_current(b1);
1179              clib_memcpy(hdr1, encap_hdr1, (word)encap_hdr_len1);
1180
1181              goto trace1;
1182            }
1183
1184          if(PREDICT_FALSE(map1->nsh_action == NSH_ACTION_PUSH))
1185            {
1186              /* Push new NSH header */
1187              vlib_buffer_advance(b1, -(word)encap_hdr_len1);
1188              hdr1 = vlib_buffer_get_current(b1);
1189              clib_memcpy(hdr1, encap_hdr1, (word)encap_hdr_len1);
1190            }
1191
1192	trace1: b1->error = error1 ? node->errors[error1] : 0;
1193
1194	  if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
1195	    {
1196	      nsh_input_trace_t *tr = vlib_add_trace(vm, node, b1, sizeof(*tr));
1197	      tr->nsh_header = *hdr1;
1198	    }
1199
1200	  vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
1201					  n_left_to_next, bi0, bi1, next0, next1);
1202
1203	}
1204
1205      while (n_left_from > 0 && n_left_to_next > 0)
1206	{
1207	  u32 bi0;
1208	  vlib_buffer_t * b0;
1209	  u32 next0 = NSH_NODE_NEXT_DROP;
1210	  uword * entry0;
1211	  nsh_header_t * hdr0 = 0;
1212	  u32 header_len0 = 0;
1213	  u32 nsp_nsi0;
1214	  u32 error0;
1215	  nsh_map_t * map0 = 0;
1216	  nsh_header_t * encap_hdr0 = 0;
1217	  u32 encap_hdr_len0 = 0;
1218	  nsh_proxy_session_by_key_t key0;
1219	  uword *p0;
1220	  nsh_proxy_session_t *proxy0 = 0;
1221
1222	  bi0 = from[0];
1223	  to_next[0] = bi0;
1224	  from += 1;
1225	  to_next += 1;
1226	  n_left_from -= 1;
1227	  n_left_to_next -= 1;
1228	  error0 = 0;
1229
1230	  b0 = vlib_get_buffer(vm, bi0);
1231	  hdr0 = vlib_buffer_get_current(b0);
1232
1233          if(node_type == NSH_INPUT_TYPE)
1234            {
1235              nsp_nsi0 = clib_net_to_host_u32(hdr0->nsp_nsi);
1236              header_len0 = hdr0->length * 4;
1237            }
1238          else if(node_type == NSH_CLASSIFIER_TYPE)
1239            {
1240              nsp_nsi0 = vnet_buffer(b0)->l2_classify.opaque_index;
1241            }
1242          else
1243	    {
1244	      memset (&key0, 0, sizeof(key0));
1245	      key0.transport_type = NSH_NODE_NEXT_ENCAP_VXLAN4;
1246	      key0.transport_index = vnet_buffer(b0)->sw_if_index[VLIB_RX];
1247
1248	      p0 = hash_get_mem(nm->nsh_proxy_session_by_key, &key0);
1249	      if (PREDICT_FALSE(p0 == 0))
1250		{
1251		  error0 = NSH_NODE_ERROR_NO_PROXY;
1252		  goto trace00;
1253		}
1254
1255	      proxy0 = pool_elt_at_index(nm->nsh_proxy_sessions, p0[0]);
1256	      if (PREDICT_FALSE(proxy0 == 0))
1257		{
1258		  error0 = NSH_NODE_ERROR_NO_PROXY;
1259		  goto trace00;
1260		}
1261	      nsp_nsi0 = proxy0->nsp_nsi;
1262	    }
1263
1264	  entry0 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi0);
1265
1266	  if (PREDICT_FALSE(entry0 == 0))
1267	    {
1268	      error0 = NSH_NODE_ERROR_NO_MAPPING;
1269	      goto trace00;
1270	    }
1271
1272	  /* Entry should point to a mapping ...*/
1273	  map0 = pool_elt_at_index(nm->nsh_mappings, entry0[0]);
1274
1275	  if (PREDICT_FALSE(map0 == 0))
1276	    {
1277	      error0 = NSH_NODE_ERROR_NO_MAPPING;
1278	      goto trace00;
1279	    }
1280
1281	  /* set up things for next node to transmit ie which node to handle it and where */
1282	  next0 = map0->next_node;
1283	  vnet_buffer(b0)->sw_if_index[VLIB_TX] = map0->sw_if_index;
1284
1285	  if(PREDICT_FALSE(map0->nsh_action == NSH_ACTION_POP))
1286	    {
1287              /* Pop NSH header */
1288	      vlib_buffer_advance(b0, (word)header_len0);
1289	      goto trace00;
1290	    }
1291
1292	  entry0 = hash_get_mem(nm->nsh_entry_by_key, &map0->mapped_nsp_nsi);
1293	  if (PREDICT_FALSE(entry0 == 0))
1294	    {
1295	      error0 = NSH_NODE_ERROR_NO_ENTRY;
1296	      goto trace00;
1297	    }
1298
1299	  encap_hdr0 = pool_elt_at_index(nm->nsh_entries, entry0[0]);
1300	  encap_hdr_len0 = encap_hdr0->length * 4;
1301
1302	  if(PREDICT_TRUE(map0->nsh_action == NSH_ACTION_SWAP))
1303	    {
1304              /* Pop old NSH header */
1305	      vlib_buffer_advance(b0, (word)header_len0);
1306
1307	      /* Push new NSH header */
1308	      vlib_buffer_advance(b0, -(word)encap_hdr_len0);
1309	      hdr0 = vlib_buffer_get_current(b0);
1310	      clib_memcpy(hdr0, encap_hdr0, (word)encap_hdr_len0);
1311
1312	      goto trace00;
1313	    }
1314
1315	  if(PREDICT_TRUE(map0->nsh_action == NSH_ACTION_PUSH))
1316	    {
1317	      /* Push new NSH header */
1318	      vlib_buffer_advance(b0, -(word)encap_hdr_len0);
1319	      hdr0 = vlib_buffer_get_current(b0);
1320	      clib_memcpy(hdr0, encap_hdr0, (word)encap_hdr_len0);
1321	    }
1322
1323	  trace00: b0->error = error0 ? node->errors[error0] : 0;
1324
1325	  if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
1326	    {
1327	      nsh_input_trace_t *tr = vlib_add_trace(vm, node, b0, sizeof(*tr));
1328	      tr->nsh_header = *hdr0;
1329	    }
1330
1331	  vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
1332					  n_left_to_next, bi0, next0);
1333	}
1334
1335      vlib_put_next_frame(vm, node, next_index, n_left_to_next);
1336
1337    }
1338
1339  return from_frame->n_vectors;
1340}
1341
1342/**
1343 * @brief Graph processing dispatch function for NSH Input
1344 *
1345 * @node nsh_input
1346 * @param *vm
1347 * @param *node
1348 * @param *from_frame
1349 *
1350 * @return from_frame->n_vectors
1351 *
1352 */
1353static uword
1354nsh_input (vlib_main_t * vm, vlib_node_runtime_t * node,
1355                  vlib_frame_t * from_frame)
1356{
1357  return nsh_input_map (vm, node, from_frame, NSH_INPUT_TYPE);
1358}
1359
1360/**
1361 * @brief Graph processing dispatch function for NSH-Proxy
1362 *
1363 * @node nsh_proxy
1364 * @param *vm
1365 * @param *node
1366 * @param *from_frame
1367 *
1368 * @return from_frame->n_vectors
1369 *
1370 */
1371static uword
1372nsh_proxy (vlib_main_t * vm, vlib_node_runtime_t * node,
1373                  vlib_frame_t * from_frame)
1374{
1375  return nsh_input_map (vm, node, from_frame, NSH_PROXY_TYPE);
1376}
1377
1378/**
1379 * @brief Graph processing dispatch function for NSH Classifier
1380 *
1381 * @node nsh_classifier
1382 * @param *vm
1383 * @param *node
1384 * @param *from_frame
1385 *
1386 * @return from_frame->n_vectors
1387 *
1388 */
1389static uword
1390nsh_classifier (vlib_main_t * vm, vlib_node_runtime_t * node,
1391                  vlib_frame_t * from_frame)
1392{
1393  return nsh_input_map (vm, node, from_frame, NSH_CLASSIFIER_TYPE);
1394}
1395
1396static char * nsh_node_error_strings[] = {
1397#define _(sym,string) string,
1398  foreach_nsh_node_error
1399#undef _
1400};
1401
1402/* register nsh-input node */
1403VLIB_REGISTER_NODE (nsh_input_node) = {
1404  .function = nsh_input,
1405  .name = "nsh-input",
1406  .vector_size = sizeof (u32),
1407  .format_trace = format_nsh_node_map_trace,
1408  .format_buffer = format_nsh_header_with_length,
1409  .type = VLIB_NODE_TYPE_INTERNAL,
1410
1411  .n_errors = ARRAY_LEN(nsh_node_error_strings),
1412  .error_strings = nsh_node_error_strings,
1413
1414  .n_next_nodes = NSH_NODE_N_NEXT,
1415
1416  .next_nodes = {
1417#define _(s,n) [NSH_NODE_NEXT_##s] = n,
1418    foreach_nsh_node_next
1419#undef _
1420  },
1421};
1422
1423VLIB_NODE_FUNCTION_MULTIARCH (nsh_input_node, nsh_input);
1424
1425/* register nsh-proxy node */
1426VLIB_REGISTER_NODE (nsh_proxy_node) = {
1427  .function = nsh_proxy,
1428  .name = "nsh-proxy",
1429  .vector_size = sizeof (u32),
1430  .format_trace = format_nsh_node_map_trace,
1431  .format_buffer = format_nsh_header_with_length,
1432  .type = VLIB_NODE_TYPE_INTERNAL,
1433
1434  .n_errors = ARRAY_LEN(nsh_node_error_strings),
1435  .error_strings = nsh_node_error_strings,
1436
1437  .n_next_nodes = NSH_NODE_N_NEXT,
1438
1439  .next_nodes = {
1440#define _(s,n) [NSH_NODE_NEXT_##s] = n,
1441    foreach_nsh_node_next
1442#undef _
1443  },
1444};
1445
1446VLIB_NODE_FUNCTION_MULTIARCH (nsh_proxy_node, nsh_proxy);
1447
1448/* register nsh-classifier node */
1449VLIB_REGISTER_NODE (nsh_classifier_node) = {
1450  .function = nsh_classifier,
1451  .name = "nsh-classifier",
1452  .vector_size = sizeof (u32),
1453  .format_trace = format_nsh_node_map_trace,
1454  .format_buffer = format_nsh_header_with_length,
1455  .type = VLIB_NODE_TYPE_INTERNAL,
1456
1457  .n_errors = ARRAY_LEN(nsh_node_error_strings),
1458  .error_strings = nsh_node_error_strings,
1459
1460  .n_next_nodes = NSH_NODE_N_NEXT,
1461
1462  .next_nodes = {
1463#define _(s,n) [NSH_NODE_NEXT_##s] = n,
1464    foreach_nsh_node_next
1465#undef _
1466  },
1467};
1468
1469VLIB_NODE_FUNCTION_MULTIARCH (nsh_classifier_node, nsh_classifier);
1470
1471clib_error_t *nsh_init (vlib_main_t *vm)
1472{
1473  nsh_main_t *nm = &nsh_main;
1474  clib_error_t * error = 0;
1475  u8 * name;
1476  uword next_node;
1477
1478  /* Init the main structures from VPP */
1479  nm->vlib_main = vm;
1480  nm->vnet_main = vnet_get_main();
1481
1482  /* Various state maintenance mappings */
1483  nm->nsh_mapping_by_key
1484    = hash_create_mem (0, sizeof(u32), sizeof (uword));
1485
1486  nm->nsh_mapping_by_mapped_key
1487    = hash_create_mem (0, sizeof(u32), sizeof (uword));
1488
1489  nm->nsh_entry_by_key
1490    = hash_create_mem (0, sizeof(u32), sizeof (uword));
1491
1492  nm->nsh_proxy_session_by_key
1493    = hash_create_mem (0, sizeof(nsh_proxy_session_by_key_t), sizeof (uword));
1494
1495  name = format (0, "nsh_%08x%c", api_version, 0);
1496
1497  /* Set up the API */
1498  nm->msg_id_base = vl_msg_api_get_msg_ids
1499    ((char *) name, VL_MSG_FIRST_AVAILABLE);
1500
1501  error = nsh_plugin_api_hookup (vm);
1502
1503  /* Add dispositions to nodes that feed nsh-input */
1504  //alagalah - validate we don't really need to use the node value
1505  next_node = vlib_node_add_next (vm, vxlan4_gpe_input_node.index, nsh_input_node.index);
1506  vlib_node_add_next (vm, vxlan4_gpe_input_node.index, nsh_proxy_node.index);
1507  vxlan_gpe_register_decap_protocol (VXLAN_GPE_PROTOCOL_NSH, next_node);
1508
1509  vlib_node_add_next (vm, vxlan6_gpe_input_node.index, nsh_input_node.index);
1510  vlib_node_add_next (vm, vxlan6_gpe_input_node.index, nsh_proxy_node.index);
1511
1512  vlib_node_add_next (vm, gre_input_node.index, nsh_input_node.index);
1513  vlib_node_add_next (vm, gre_input_node.index, nsh_proxy_node.index);
1514
1515  /* Add NSH-Proxy support */
1516  vlib_node_add_next (vm, vxlan4_input_node.index, nsh_proxy_node.index);
1517  vlib_node_add_next (vm, vxlan6_input_node.index, nsh_proxy_node.index);
1518
1519  /* Add NSH-Classifier support */
1520  vlib_node_add_next (vm, ip4_classify_node.index, nsh_classifier_node.index);
1521  vlib_node_add_next (vm, ip6_classify_node.index, nsh_classifier_node.index);
1522  vlib_node_add_next (vm, l2_input_classify_node.index, nsh_classifier_node.index);
1523
1524  vec_free(name);
1525
1526  return error;
1527}
1528
1529VLIB_INIT_FUNCTION(nsh_init);
1530