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