nsh.c revision 210d3940
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  _(NSH_CONTROL_PING, nsh_control_ping)
103
104clib_error_t *
105vlib_plugin_register (vlib_main_t * vm, vnet_plugin_handoff_t * h,
106                      int from_early_init)
107{
108  nsh_main_t * nm = &nsh_main;
109  clib_error_t * error = 0;
110
111  nm->vlib_main = vm;
112  nm->vnet_main = h->vnet_main;
113
114  return error;
115}
116
117typedef struct {
118  nsh_header_t nsh_header;
119} nsh_input_trace_t;
120
121
122static void vl_api_nsh_control_ping_t_handler
123(vl_api_nsh_control_ping_t *mp)
124{
125    nsh_main_t * nm = &nsh_main;
126    vl_api_nsh_control_ping_reply_t * rmp;
127    int rv = 0;
128
129    REPLY_MACRO2(VL_API_NSH_CONTROL_PING_REPLY,
130    ({
131	rmp->vpe_pid = ntohl (getpid());
132    }));
133}
134
135u8 * format_nsh_header (u8 * s, va_list * args)
136{
137  nsh_header_t * nsh = va_arg (*args, nsh_header_t *);
138
139  s = format (s, "nsh ver %d ", (nsh->ver_o_c>>6));
140  if (nsh->ver_o_c & NSH_O_BIT)
141    s = format (s, "O-set ");
142
143  if (nsh->ver_o_c & NSH_C_BIT)
144    s = format (s, "C-set ");
145
146  s = format (s, "len %d (%d bytes) md_type %d next_protocol %d\n",
147              nsh->length, nsh->length * 4, nsh->md_type, nsh->next_protocol);
148
149  s = format (s, "  service path %d service index %d\n",
150              (nsh->nsp_nsi>>NSH_NSP_SHIFT) & NSH_NSP_MASK,
151              nsh->nsp_nsi & NSH_NSI_MASK);
152
153  s = format (s, "  c1 %d c2 %d c3 %d c4 %d\n",
154              nsh->c1, nsh->c2, nsh->c3, nsh->c4);
155
156  return s;
157}
158
159static u8 * format_nsh_action (u8 * s, va_list * args)
160{
161  u32 nsh_action = va_arg (*args, u32);
162
163  switch (nsh_action)
164    {
165    case NSH_ACTION_SWAP:
166      return format (s, "swap");
167    case NSH_ACTION_PUSH:
168      return format (s, "push");
169    case NSH_ACTION_POP:
170      return format (s, "pop");
171    default:
172      return format (s, "unknown %d", nsh_action);
173    }
174  return s;
175}
176
177u8 * format_nsh_map (u8 * s, va_list * args)
178{
179  nsh_map_t * map = va_arg (*args, nsh_map_t *);
180
181  s = format (s, "nsh entry nsp: %d nsi: %d ",
182              (map->nsp_nsi>>NSH_NSP_SHIFT) & NSH_NSP_MASK,
183              map->nsp_nsi & NSH_NSI_MASK);
184  s = format (s, "maps to nsp: %d nsi: %d ",
185              (map->mapped_nsp_nsi>>NSH_NSP_SHIFT) & NSH_NSP_MASK,
186              map->mapped_nsp_nsi & NSH_NSI_MASK);
187
188  s = format (s, " nsh_action %U\n", format_nsh_action, map->nsh_action);
189
190  switch (map->next_node)
191    {
192    case NSH_INPUT_NEXT_ENCAP_GRE:
193      {
194	s = format (s, "encapped by GRE intf: %d", map->sw_if_index);
195	break;
196      }
197    case NSH_INPUT_NEXT_ENCAP_VXLANGPE:
198      {
199	s = format (s, "encapped by VXLAN GPE intf: %d", map->sw_if_index);
200	break;
201      }
202    default:
203      s = format (s, "only GRE and VXLANGPE support in this rev");
204    }
205
206  return s;
207}
208
209u8 * format_nsh_header_with_length (u8 * s, va_list * args)
210{
211  nsh_header_t * h = va_arg (*args, nsh_header_t *);
212  u32 max_header_bytes = va_arg (*args, u32);
213  u32 tmp, header_bytes;
214
215  header_bytes = sizeof (h[0]);
216  if (max_header_bytes != 0 && header_bytes > max_header_bytes)
217    return format (s, "nsh header truncated");
218
219  tmp = clib_net_to_host_u32 (h->nsp_nsi);
220  s = format (s, "  nsp %d nsi %d ",
221              (tmp>>NSH_NSP_SHIFT) & NSH_NSP_MASK,
222              tmp & NSH_NSI_MASK);
223
224  s = format (s, "c1 %u c2 %u c3 %u c4 %u",
225              clib_net_to_host_u32 (h->c1),
226              clib_net_to_host_u32 (h->c2),
227              clib_net_to_host_u32 (h->c3),
228              clib_net_to_host_u32 (h->c4));
229
230  s = format (s, "ver %d ", h->ver_o_c>>6);
231
232  if (h->ver_o_c & NSH_O_BIT)
233    s = format (s, "O-set ");
234
235  if (h->ver_o_c & NSH_C_BIT)
236    s = format (s, "C-set ");
237
238  s = format (s, "len %d (%d bytes) md_type %d next_protocol %d\n",
239              h->length, h->length * 4, h->md_type, h->next_protocol);
240  return s;
241}
242
243u8 * format_nsh_input_map_trace (u8 * s, va_list * args)
244{
245  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
246  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
247  nsh_input_trace_t * t
248    = va_arg (*args, nsh_input_trace_t *);
249
250  s = format (s, "\n  %U", format_nsh_header, &t->nsh_header,
251              (u32) sizeof (t->nsh_header) );
252
253  return s;
254}
255
256/**
257 * Action function to add or del an nsh map.
258 * Shared by both CLI and binary API
259 **/
260
261int nsh_add_del_map (nsh_add_del_map_args_t *a, u32 * map_indexp)
262{
263  nsh_main_t * nm = &nsh_main;
264  nsh_map_t *map = 0;
265  u32 key, *key_copy;
266  uword * entry;
267  hash_pair_t *hp;
268  u32 map_index = ~0;
269
270  key = a->map.nsp_nsi;
271
272  entry = hash_get_mem (nm->nsh_mapping_by_key, &key);
273
274  if (a->is_add)
275    {
276      /* adding an entry, must not already exist */
277      if (entry)
278        return -1; //TODO API_ERROR_INVALID_VALUE;
279
280      pool_get_aligned (nm->nsh_mappings, map, CLIB_CACHE_LINE_BYTES);
281      memset (map, 0, sizeof (*map));
282
283      /* copy from arg structure */
284      map->nsp_nsi = a->map.nsp_nsi;
285      map->mapped_nsp_nsi = a->map.mapped_nsp_nsi;
286      map->nsh_action = a->map.nsh_action;
287      map->sw_if_index = a->map.sw_if_index;
288      map->next_node = a->map.next_node;
289
290
291      key_copy = clib_mem_alloc (sizeof (*key_copy));
292      clib_memcpy (key_copy, &key, sizeof (*key_copy));
293
294      hash_set_mem (nm->nsh_mapping_by_key, key_copy,
295                    map - nm->nsh_mappings);
296      map_index = map - nm->nsh_mappings;
297    }
298  else
299    {
300      if (!entry)
301	return -2 ; //TODO API_ERROR_NO_SUCH_ENTRY;
302
303      map = pool_elt_at_index (nm->nsh_mappings, entry[0]);
304      hp = hash_get_pair (nm->nsh_mapping_by_key, &key);
305      key_copy = (void *)(hp->key);
306      hash_unset_mem (nm->nsh_mapping_by_key, &key);
307      clib_mem_free (key_copy);
308
309      pool_put (nm->nsh_mappings, map);
310    }
311
312  if (map_indexp)
313      *map_indexp = map_index;
314
315  return 0;
316}
317
318/**
319 * CLI command for NSH map
320 */
321
322static uword unformat_nsh_action (unformat_input_t * input, va_list * args)
323{
324  u32 * result = va_arg (*args, u32 *);
325  u32 tmp;
326
327  if (unformat (input, "swap"))
328    *result = NSH_ACTION_SWAP;
329  if (unformat (input, "push"))
330    *result = NSH_ACTION_PUSH;
331  if (unformat (input, "pop"))
332    *result = NSH_ACTION_POP;
333  else if (unformat (input, "%d", &tmp))
334    *result = tmp;
335  else
336    return 0;
337  return 1;
338}
339
340static clib_error_t *
341nsh_add_del_map_command_fn (vlib_main_t * vm,
342			    unformat_input_t * input,
343			    vlib_cli_command_t * cmd)
344{
345  unformat_input_t _line_input, * line_input = &_line_input;
346  u8 is_add = 1;
347  u32 nsp, nsi, mapped_nsp, mapped_nsi, nsh_action;
348  int nsp_set = 0, nsi_set = 0, mapped_nsp_set = 0, mapped_nsi_set = 0;
349  int nsh_action_set = 0;
350  u32 next_node = ~0;
351  u32 sw_if_index = ~0; // temporary requirement to get this moved over to NSHSFC
352  nsh_add_del_map_args_t _a, * a = &_a;
353  u32 map_index;
354  int rv;
355
356  /* Get a line of input. */
357  if (! unformat_user (input, unformat_line_input, line_input))
358    return 0;
359
360  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
361    if (unformat (line_input, "del"))
362      is_add = 0;
363    else if (unformat (line_input, "nsp %d", &nsp))
364      nsp_set = 1;
365    else if (unformat (line_input, "nsi %d", &nsi))
366      nsi_set = 1;
367    else if (unformat (line_input, "mapped-nsp %d", &mapped_nsp))
368      mapped_nsp_set = 1;
369    else if (unformat (line_input, "mapped-nsi %d", &mapped_nsi))
370      mapped_nsi_set = 1;
371    else if (unformat (line_input, "nsh_action %U", unformat_nsh_action,
372                       &nsh_action))
373      nsh_action_set = 1;
374    else if (unformat (line_input, "encap-gre-intf %d", &sw_if_index))
375      next_node = NSH_INPUT_NEXT_ENCAP_GRE;
376    else if (unformat (line_input, "encap-vxlan-gpe-intf %d", &sw_if_index))
377      next_node = NSH_INPUT_NEXT_ENCAP_VXLANGPE;
378    else if (unformat (line_input, "encap-none"))
379      next_node = NSH_INPUT_NEXT_DROP; // Once moved to NSHSFC see nsh.h:foreach_nsh_input_next to handle this case
380    else
381      return clib_error_return (0, "parse error: '%U'",
382                                format_unformat_error, line_input);
383  }
384
385  unformat_free (line_input);
386
387  if (nsp_set == 0 || nsi_set == 0)
388    return clib_error_return (0, "nsp nsi pair required. Key: for NSH entry");
389
390  if (mapped_nsp_set == 0 || mapped_nsi_set == 0)
391    return clib_error_return (0, "mapped-nsp mapped-nsi pair required. Key: for NSH entry");
392
393  if (nsh_action_set == 0 )
394    return clib_error_return (0, "nsh_action required: swap|push|pop.");
395
396  if (next_node == ~0)
397    return clib_error_return (0, "must specific action: [encap-gre-intf <nn> | encap-vxlan-gpe-intf <nn> | encap-none]");
398
399  memset (a, 0, sizeof (*a));
400
401  /* set args structure */
402  a->is_add = is_add;
403  a->map.nsp_nsi = (nsp<< NSH_NSP_SHIFT) | nsi;
404  a->map.mapped_nsp_nsi = (mapped_nsp<< NSH_NSP_SHIFT) | mapped_nsi;
405  a->map.nsh_action = nsh_action;
406  a->map.sw_if_index = sw_if_index;
407  a->map.next_node = next_node;
408
409
410  rv = nsh_add_del_map (a, &map_index);
411
412  switch(rv)
413    {
414    case 0:
415      break;
416    case -1: //TODO API_ERROR_INVALID_VALUE:
417      return clib_error_return (0, "mapping already exists. Remove it first.");
418
419    case -2: // TODO API_ERROR_NO_SUCH_ENTRY:
420      return clib_error_return (0, "mapping does not exist.");
421
422    default:
423      return clib_error_return
424        (0, "nsh_add_del_map returned %d", rv);
425    }
426  return 0;
427}
428
429VLIB_CLI_COMMAND (create_nsh_map_command, static) = {
430  .path = "create nsh map",
431  .short_help =
432  "create nsh map nsp <nn> nsi <nn> [del] mapped-nsp <nn> mapped-nsi <nn> nsh_action [swap|push|pop] "
433  "[encap-gre-intf <nn> | encap-vxlan-gpe-intf <nn> | encap-none]\n",
434  .function = nsh_add_del_map_command_fn,
435};
436
437/** API message handler */
438static void vl_api_nsh_add_del_map_t_handler
439(vl_api_nsh_add_del_map_t * mp)
440{
441  vl_api_nsh_add_del_map_reply_t * rmp;
442  nsh_main_t * nm = &nsh_main;
443  int rv;
444  nsh_add_del_map_args_t _a, *a = &_a;
445  u32 map_index = ~0;
446
447  a->is_add = mp->is_add;
448  a->map.nsp_nsi = ntohl(mp->nsp_nsi);
449  a->map.mapped_nsp_nsi = ntohl(mp->mapped_nsp_nsi);
450  a->map.nsh_action = ntohl(mp->nsh_action);
451  a->map.sw_if_index = ntohl(mp->sw_if_index);
452  a->map.next_node = ntohl(mp->next_node);
453
454  rv = nsh_add_del_map (a, &map_index);
455
456  REPLY_MACRO2(VL_API_NSH_ADD_DEL_MAP_REPLY,
457  ({
458    rmp->map_index = htonl (map_index);
459  }));
460}
461
462/**
463 * CLI command for showing the mapping between NSH entries
464 */
465static clib_error_t *
466show_nsh_map_command_fn (vlib_main_t * vm,
467			 unformat_input_t * input,
468			 vlib_cli_command_t * cmd)
469{
470  nsh_main_t * nm = &nsh_main;
471  nsh_map_t * map;
472
473  if (pool_elts (nm->nsh_mappings) == 0)
474    vlib_cli_output (vm, "No nsh maps configured.");
475
476  pool_foreach (map, nm->nsh_mappings,
477		({
478		  vlib_cli_output (vm, "%U", format_nsh_map, map);
479		}));
480
481  return 0;
482}
483
484VLIB_CLI_COMMAND (show_nsh_map_command, static) = {
485  .path = "show nsh map",
486  .function = show_nsh_map_command_fn,
487};
488
489/**
490 * Action function for adding an NSH entry
491 */
492
493int nsh_add_del_entry (nsh_add_del_entry_args_t *a, u32 * entry_indexp)
494{
495  nsh_main_t * nm = &nsh_main;
496  nsh_header_t *hdr = 0;
497  u32 key, *key_copy;
498  uword * entry;
499  hash_pair_t *hp;
500  u32 entry_index = ~0;
501
502  key = a->nsh.nsp_nsi;
503
504  entry = hash_get_mem (nm->nsh_entry_by_key, &key);
505
506  if (a->is_add)
507    {
508      /* adding an entry, must not already exist */
509      if (entry)
510        return -1; // TODO VNET_API_ERROR_INVALID_VALUE;
511
512      pool_get_aligned (nm->nsh_entries, hdr, CLIB_CACHE_LINE_BYTES);
513      memset (hdr, 0, sizeof (*hdr));
514
515      /* copy from arg structure */
516#define _(x) hdr->x = a->nsh.x;
517      foreach_copy_nshhdr_field;
518#undef _
519
520      key_copy = clib_mem_alloc (sizeof (*key_copy));
521      clib_memcpy (key_copy, &key, sizeof (*key_copy));
522
523      hash_set_mem (nm->nsh_entry_by_key, key_copy,
524                    hdr - nm->nsh_entries);
525      entry_index = hdr - nm->nsh_entries;
526    }
527  else
528    {
529      if (!entry)
530	return -2; //TODO API_ERROR_NO_SUCH_ENTRY;
531
532      hdr = pool_elt_at_index (nm->nsh_entries, entry[0]);
533      hp = hash_get_pair (nm->nsh_entry_by_key, &key);
534      key_copy = (void *)(hp->key);
535      hash_unset_mem (nm->nsh_entry_by_key, &key);
536      clib_mem_free (key_copy);
537
538      pool_put (nm->nsh_entries, hdr);
539    }
540
541  if (entry_indexp)
542      *entry_indexp = entry_index;
543
544  return 0;
545}
546
547
548/**
549 * CLI command for adding NSH entry
550 */
551
552static clib_error_t *
553nsh_add_del_entry_command_fn (vlib_main_t * vm,
554			      unformat_input_t * input,
555			      vlib_cli_command_t * cmd)
556{
557  unformat_input_t _line_input, * line_input = &_line_input;
558  u8 is_add = 1;
559  u8 ver_o_c = 0;
560  u8 length = 0;
561  u8 md_type = 0;
562  u8 next_protocol = 1; /* default: ip4 */
563  u32 nsp;
564  u8 nsp_set = 0;
565  u32 nsi;
566  u8 nsi_set = 0;
567  u32 nsp_nsi;
568  u32 c1 = 0;
569  u32 c2 = 0;
570  u32 c3 = 0;
571  u32 c4 = 0;
572  u32 tmp;
573  int rv;
574  u32 entry_index;
575  nsh_add_del_entry_args_t _a, * a = &_a;
576
577  /* Get a line of input. */
578  if (! unformat_user (input, unformat_line_input, line_input))
579    return 0;
580
581  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
582    if (unformat (line_input, "del"))
583      is_add = 0;
584    else if (unformat (line_input, "version %d", &tmp))
585      ver_o_c |= (tmp & 3) << 6;
586    else if (unformat (line_input, "o-bit %d", &tmp))
587      ver_o_c |= (tmp & 1) << 5;
588    else if (unformat (line_input, "c-bit %d", &tmp))
589      ver_o_c |= (tmp & 1) << 4;
590    else if (unformat (line_input, "md-type %d", &tmp))
591      md_type = tmp;
592    else if (unformat(line_input, "next-ip4"))
593      next_protocol = 1;
594    else if (unformat(line_input, "next-ip6"))
595      next_protocol = 2;
596    else if (unformat(line_input, "next-ethernet"))
597      next_protocol = 3;
598    else if (unformat (line_input, "c1 %d", &c1))
599      ;
600    else if (unformat (line_input, "c2 %d", &c2))
601      ;
602    else if (unformat (line_input, "c3 %d", &c3))
603      ;
604    else if (unformat (line_input, "c4 %d", &c4))
605      ;
606    else if (unformat (line_input, "nsp %d", &nsp))
607      nsp_set = 1;
608    else if (unformat (line_input, "nsi %d", &nsi))
609      nsi_set = 1;
610    else
611      return clib_error_return (0, "parse error: '%U'",
612                                format_unformat_error, line_input);
613  }
614
615  unformat_free (line_input);
616
617  if (nsp_set == 0)
618    return clib_error_return (0, "nsp not specified");
619
620  if (nsi_set == 0)
621    return clib_error_return (0, "nsi not specified");
622
623  if (md_type != 1)
624    return clib_error_return (0, "md-type 1 only supported at this time");
625
626  md_type = 1;
627  length = 6;
628
629  nsp_nsi = (nsp<<8) | nsi;
630
631  memset (a, 0, sizeof (*a));
632
633  a->is_add = is_add;
634
635#define _(x) a->nsh.x = x;
636  foreach_copy_nshhdr_field;
637#undef _
638
639  rv = nsh_add_del_entry (a, &entry_index);
640
641  switch(rv)
642    {
643    case 0:
644      break;
645    default:
646      return clib_error_return
647        (0, "nsh_add_del_entry returned %d", rv);
648    }
649
650  return 0;
651}
652
653VLIB_CLI_COMMAND (create_nsh_entry_command, static) = {
654  .path = "create nsh entry",
655  .short_help =
656  "create nsh entry {nsp <nn> nsi <nn>} c1 <nn> c2 <nn> c3 <nn> c4 <nn>"
657  " [md-type <nn>] [tlv <xx>] [del]\n",
658  .function = nsh_add_del_entry_command_fn,
659};
660
661/** API message handler */
662static void vl_api_nsh_add_del_entry_t_handler
663(vl_api_nsh_add_del_entry_t * mp)
664{
665  vl_api_nsh_add_del_entry_reply_t * rmp;
666  nsh_main_t * nm = &nsh_main;
667  int rv;
668  nsh_add_del_entry_args_t _a, *a = &_a;
669  u32 entry_index = ~0;
670
671  a->is_add = mp->is_add;
672  a->nsh.ver_o_c = mp->ver_o_c;
673  a->nsh.length = mp->length;
674  a->nsh.md_type = mp->md_type;
675  a->nsh.next_protocol = mp->next_protocol;
676  a->nsh.nsp_nsi = ntohl(mp->nsp_nsi);
677  a->nsh.c1 = ntohl(mp->c1);
678  a->nsh.c2 = ntohl(mp->c2);
679  a->nsh.c3 = ntohl(mp->c3);
680  a->nsh.c4 = ntohl(mp->c4);
681
682  rv = nsh_add_del_entry (a, &entry_index);
683
684  REPLY_MACRO2(VL_API_NSH_ADD_DEL_ENTRY_REPLY,
685  ({
686    rmp->entry_index = htonl (entry_index);
687  }));
688}
689
690static void send_nsh_entry_details
691(nsh_header_t * t, unix_shared_memory_queue_t * q, u32 context)
692{
693    vl_api_nsh_entry_details_t * rmp;
694    nsh_main_t * nm = &nsh_main;
695
696    rmp = vl_msg_api_alloc (sizeof (*rmp));
697    memset (rmp, 0, sizeof (*rmp));
698
699    rmp->_vl_msg_id = ntohs((VL_API_NSH_ENTRY_DETAILS)+nm->msg_id_base);
700    rmp->ver_o_c = t->ver_o_c;
701    rmp->length = t->length;
702    rmp->md_type = t->md_type;
703    rmp->next_protocol = t->next_protocol;
704    rmp->nsp_nsi = htonl(t->nsp_nsi);
705    rmp->c1 = htonl(t->c1);
706    rmp->c2 = htonl(t->c2);
707    rmp->c3 = htonl(t->c3);
708    rmp->c4 = htonl(t->c4);
709
710    rmp->context = context;
711
712    vl_msg_api_send_shmem (q, (u8 *)&rmp);
713}
714
715static void vl_api_nsh_entry_dump_t_handler
716(vl_api_nsh_entry_dump_t * mp)
717{
718    unix_shared_memory_queue_t * q;
719    nsh_main_t * nm = &nsh_main;
720    nsh_header_t * t;
721    u32 entry_index;
722
723    q = vl_api_client_index_to_input_queue (mp->client_index);
724    if (q == 0) {
725        return;
726    }
727
728    entry_index = ntohl (mp->entry_index);
729
730    if (~0 == entry_index)
731      {
732	pool_foreach (t, nm->nsh_entries,
733	({
734	    send_nsh_entry_details(t, q, mp->context);
735	}));
736      }
737    else
738      {
739        if (entry_index >= vec_len (nm->nsh_entries))
740  	{
741  	  return;
742  	}
743        t = &nm->nsh_entries[entry_index];
744        send_nsh_entry_details(t, q, mp->context);
745      }
746}
747
748static void send_nsh_map_details
749(nsh_map_t * t, unix_shared_memory_queue_t * q, u32 context)
750{
751    vl_api_nsh_map_details_t * rmp;
752    nsh_main_t * nm = &nsh_main;
753
754    rmp = vl_msg_api_alloc (sizeof (*rmp));
755    memset (rmp, 0, sizeof (*rmp));
756
757    rmp->_vl_msg_id = ntohs((VL_API_NSH_MAP_DETAILS)+nm->msg_id_base);
758    rmp->nsp_nsi = htonl(t->nsp_nsi);
759    rmp->mapped_nsp_nsi = htonl(t->mapped_nsp_nsi);
760    rmp->nsh_action = htonl(t->nsh_action);
761    rmp->sw_if_index = htonl(t->sw_if_index);
762    rmp->next_node = htonl(t->next_node);
763
764    rmp->context = context;
765
766    vl_msg_api_send_shmem (q, (u8 *)&rmp);
767}
768
769static void vl_api_nsh_map_dump_t_handler
770(vl_api_nsh_map_dump_t * mp)
771{
772    unix_shared_memory_queue_t * q;
773    nsh_main_t * nm = &nsh_main;
774    nsh_map_t * t;
775    u32 map_index;
776
777    q = vl_api_client_index_to_input_queue (mp->client_index);
778    if (q == 0) {
779        return;
780    }
781
782    map_index = ntohl (mp->map_index);
783
784    if (~0 == map_index)
785      {
786	pool_foreach (t, nm->nsh_mappings,
787	({
788	    send_nsh_map_details(t, q, mp->context);
789	}));
790      }
791    else
792      {
793        if (map_index >= vec_len (nm->nsh_mappings))
794  	{
795  	  return;
796  	}
797        t = &nm->nsh_mappings[map_index];
798        send_nsh_map_details(t, q, mp->context);
799      }
800}
801
802static clib_error_t *
803show_nsh_entry_command_fn (vlib_main_t * vm,
804			   unformat_input_t * input,
805			   vlib_cli_command_t * cmd)
806{
807  nsh_main_t * nm = &nsh_main;
808  nsh_header_t * hdr;
809
810  if (pool_elts (nm->nsh_entries) == 0)
811    vlib_cli_output (vm, "No nsh entries configured.");
812
813  pool_foreach (hdr, nm->nsh_entries,
814		({
815		  vlib_cli_output (vm, "%U", format_nsh_header, hdr);
816		}));
817
818  return 0;
819}
820
821VLIB_CLI_COMMAND (show_nsh_entry_command, static) = {
822  .path = "show nsh entry",
823  .function = show_nsh_entry_command_fn,
824};
825
826
827/* Set up the API message handling tables */
828static clib_error_t *
829nsh_plugin_api_hookup (vlib_main_t *vm)
830{
831  nsh_main_t * nm = &nsh_main;
832#define _(N,n)                                                  \
833  vl_msg_api_set_handlers((VL_API_##N + nm->msg_id_base),	\
834			  #n,					\
835			  vl_api_##n##_t_handler,		\
836			  vl_noop_handler,			\
837			  vl_api_##n##_t_endian,		\
838			  vl_api_##n##_t_print,			\
839			  sizeof(vl_api_##n##_t), 1);
840  foreach_nsh_plugin_api_msg;
841#undef _
842
843  return 0;
844}
845
846
847
848
849static uword
850nsh_input_map (vlib_main_t * vm,
851               vlib_node_runtime_t * node,
852               vlib_frame_t * from_frame)
853{
854  u32 n_left_from, next_index, *from, *to_next;
855  nsh_main_t * nm = &nsh_main;
856
857  from = vlib_frame_vector_args(from_frame);
858  n_left_from = from_frame->n_vectors;
859
860  next_index = node->cached_next_index;
861
862  while (n_left_from > 0)
863    {
864      u32 n_left_to_next;
865
866      vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
867
868      while (n_left_from >= 4 && n_left_to_next >= 2)
869	{
870	  u32 bi0, bi1;
871	  vlib_buffer_t * b0, *b1;
872	  u32 next0 = NSH_INPUT_NEXT_DROP, next1 = NSH_INPUT_NEXT_DROP;
873	  uword * entry0, *entry1;
874	  nsh_header_t * hdr0 = 0, *hdr1 = 0;
875	  u32 nsp_nsi0, nsp_nsi1;
876	  u32 error0, error1;
877	  nsh_map_t * map0 = 0, *map1 = 0;
878
879	  /* Prefetch next iteration. */
880	  {
881	    vlib_buffer_t * p2, *p3;
882
883	    p2 = vlib_get_buffer(vm, from[2]);
884	    p3 = vlib_get_buffer(vm, from[3]);
885
886	    vlib_prefetch_buffer_header(p2, LOAD);
887	    vlib_prefetch_buffer_header(p3, LOAD);
888
889	    CLIB_PREFETCH(p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
890	    CLIB_PREFETCH(p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
891	  }
892
893	  bi0 = from[0];
894	  bi1 = from[1];
895	  to_next[0] = bi0;
896	  to_next[1] = bi1;
897	  from += 2;
898	  to_next += 2;
899	  n_left_from -= 2;
900	  n_left_to_next -= 2;
901
902	  error0 = 0;
903	  error1 = 0;
904
905	  b0 = vlib_get_buffer(vm, bi0);
906	  hdr0 = vlib_buffer_get_current(b0);
907	  nsp_nsi0 = clib_net_to_host_u32(hdr0->nsp_nsi);
908	  entry0 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi0);
909
910	  b1 = vlib_get_buffer(vm, bi1);
911	  hdr1 = vlib_buffer_get_current(b1);
912	  nsp_nsi1 = clib_net_to_host_u32(hdr1->nsp_nsi);
913	  entry1 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi1);
914
915	  if (PREDICT_FALSE(entry0 == 0))
916	    {
917	      error0 = NSH_INPUT_ERROR_NO_MAPPING;
918	      goto trace0;
919	    }
920
921	  if (PREDICT_FALSE(entry1 == 0))
922	    {
923	      error1 = NSH_INPUT_ERROR_NO_MAPPING;
924	      goto trace1;
925	    }
926
927	  /* Entry should point to a mapping ...*/
928	  map0 = pool_elt_at_index(nm->nsh_mappings, entry0[0]);
929	  map1 = pool_elt_at_index(nm->nsh_mappings, entry1[0]);
930
931	  if (PREDICT_FALSE(map0 == 0))
932	    {
933	      error0 = NSH_INPUT_ERROR_NO_MAPPING;
934	      goto trace0;
935	    }
936
937	  if (PREDICT_FALSE(map1 == 0))
938	    {
939	      error1 = NSH_INPUT_ERROR_NO_MAPPING;
940	      goto trace1;
941	    }
942
943	  entry0 = hash_get_mem(nm->nsh_entry_by_key, &map0->mapped_nsp_nsi);
944	  entry1 = hash_get_mem(nm->nsh_entry_by_key, &map1->mapped_nsp_nsi);
945
946	  if (PREDICT_FALSE(entry0 == 0))
947	    {
948	      error0 = NSH_INPUT_ERROR_NO_MAPPING;
949	      goto trace0;
950	    }
951	  if (PREDICT_FALSE(entry1 == 0))
952	    {
953	      error1 = NSH_INPUT_ERROR_NO_MAPPING;
954	      goto trace1;
955	    }
956
957	  hdr0 = pool_elt_at_index(nm->nsh_entries, entry0[0]);
958	  hdr1 = pool_elt_at_index(nm->nsh_entries, entry1[0]);
959
960	  /* set up things for next node to transmit ie which node to handle it and where */
961	  next0 = map0->next_node;
962	  next1 = map1->next_node;
963	  vnet_buffer(b0)->sw_if_index[VLIB_TX] = map0->sw_if_index;
964	  vnet_buffer(b1)->sw_if_index[VLIB_TX] = map1->sw_if_index;
965
966	trace0: b0->error = error0 ? node->errors[error0] : 0;
967
968	  if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
969	    {
970	      nsh_input_trace_t *tr = vlib_add_trace(vm, node, b0, sizeof(*tr));
971	      tr->nsh_header = *hdr0;
972	    }
973
974	trace1: b1->error = error1 ? node->errors[error1] : 0;
975
976	  if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
977	    {
978	      nsh_input_trace_t *tr = vlib_add_trace(vm, node, b1, sizeof(*tr));
979	      tr->nsh_header = *hdr1;
980	    }
981
982	  vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
983					  n_left_to_next, bi0, bi1, next0, next1);
984
985	}
986
987      while (n_left_from > 0 && n_left_to_next > 0)
988	{
989	  u32 bi0;
990	  vlib_buffer_t * b0;
991	  u32 next0 = NSH_INPUT_NEXT_DROP;
992	  uword * entry0;
993	  nsh_header_t * hdr0 = 0;
994	  u32 nsp_nsi0;
995	  u32 error0;
996	  nsh_map_t * map0 = 0;
997
998	  bi0 = from[0];
999	  to_next[0] = bi0;
1000	  from += 1;
1001	  to_next += 1;
1002	  n_left_from -= 1;
1003	  n_left_to_next -= 1;
1004	  error0 = 0;
1005
1006	  b0 = vlib_get_buffer(vm, bi0);
1007	  hdr0 = vlib_buffer_get_current(b0);
1008	  nsp_nsi0 = clib_net_to_host_u32(hdr0->nsp_nsi);
1009	  entry0 = hash_get_mem(nm->nsh_mapping_by_key, &nsp_nsi0);
1010
1011	  if (PREDICT_FALSE(entry0 == 0))
1012	    {
1013	      error0 = NSH_INPUT_ERROR_NO_MAPPING;
1014	      goto trace00;
1015	    }
1016
1017	  /* Entry should point to a mapping ...*/
1018	  map0 = pool_elt_at_index(nm->nsh_mappings, entry0[0]);
1019
1020	  if (PREDICT_FALSE(map0 == 0))
1021	    {
1022	      error0 = NSH_INPUT_ERROR_NO_MAPPING;
1023	      goto trace00;
1024	    }
1025
1026	  entry0 = hash_get_mem(nm->nsh_entry_by_key, &map0->mapped_nsp_nsi);
1027
1028	  if (PREDICT_FALSE(entry0 == 0))
1029	    {
1030	      error0 = NSH_INPUT_ERROR_NO_MAPPING;
1031	      goto trace00;
1032	    }
1033
1034	  hdr0 = pool_elt_at_index(nm->nsh_entries, entry0[0]);
1035
1036	  /* set up things for next node to transmit ie which node to handle it and where */
1037	  next0 = map0->next_node;
1038	  vnet_buffer(b0)->sw_if_index[VLIB_TX] = map0->sw_if_index;
1039
1040	trace00: b0->error = error0 ? node->errors[error0] : 0;
1041
1042	  if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
1043	    {
1044	      nsh_input_trace_t *tr = vlib_add_trace(vm, node, b0, sizeof(*tr));
1045	      tr->nsh_header = *hdr0;
1046	    }
1047
1048	  vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
1049					  n_left_to_next, bi0, next0);
1050	}
1051
1052      vlib_put_next_frame(vm, node, next_index, n_left_to_next);
1053
1054    }
1055
1056  return from_frame->n_vectors;
1057}
1058
1059
1060static char * nsh_input_error_strings[] = {
1061#define _(sym,string) string,
1062  foreach_nsh_input_error
1063#undef _
1064};
1065
1066VLIB_REGISTER_NODE (nsh_input_node) = {
1067  .function = nsh_input_map,
1068  .name = "nsh-input",
1069  .vector_size = sizeof (u32),
1070  .format_trace = format_nsh_input_map_trace,
1071  .format_buffer = format_nsh_header_with_length,
1072  .type = VLIB_NODE_TYPE_INTERNAL,
1073
1074  .n_errors = ARRAY_LEN(nsh_input_error_strings),
1075  .error_strings = nsh_input_error_strings,
1076
1077  .n_next_nodes = NSH_INPUT_N_NEXT,
1078
1079  .next_nodes = {
1080#define _(s,n) [NSH_INPUT_NEXT_##s] = n,
1081    foreach_nsh_input_next
1082#undef _
1083  },
1084};
1085
1086clib_error_t *nsh_init (vlib_main_t *vm)
1087{
1088  nsh_main_t *nm = &nsh_main;
1089  clib_error_t * error = 0;
1090  vlib_node_t * vxlan4_gpe_input_node = 0;
1091  vlib_node_t * vxlan6_gpe_input_node = 0;
1092  vlib_node_t * gre_input_node = 0;
1093  u8 * name;
1094
1095  /* Init the main structures from VPP */
1096  nm->vlib_main = vm;
1097  nm->vnet_main = vnet_get_main();
1098
1099  /* Various state maintenance mappings */
1100  nm->nsh_mapping_by_key
1101    = hash_create_mem (0, sizeof(u32), sizeof (uword));
1102
1103  nm->nsh_mapping_by_mapped_key
1104    = hash_create_mem (0, sizeof(u32), sizeof (uword));
1105
1106  nm->nsh_entry_by_key
1107    = hash_create_mem (0, sizeof(u32), sizeof (uword));
1108
1109  name = format (0, "nsh_%08x%c", api_version, 0);
1110
1111  /* Set up the API */
1112  nm->msg_id_base = vl_msg_api_get_msg_ids
1113    ((char *) name, VL_MSG_FIRST_AVAILABLE);
1114
1115  error = nsh_plugin_api_hookup (vm);
1116
1117  /* Add dispositions to nodes that feed nsh-input */
1118  vxlan4_gpe_input_node = vlib_get_node_by_name (vm, (u8 *)"vxlan4-gpe-input");
1119  ASSERT(vxlan4_gpe_input_node);
1120  //alagalah - validate we don't really need to use the node value
1121  vlib_node_add_next (vm, vxlan4_gpe_input_node->index, nsh_input_node.index);
1122
1123  vxlan6_gpe_input_node = vlib_get_node_by_name (vm, (u8 *)"vxlan6-gpe-input");
1124  ASSERT(vxlan6_gpe_input_node);
1125  vlib_node_add_next (vm, vxlan6_gpe_input_node->index, nsh_input_node.index);
1126
1127  gre_input_node = vlib_get_node_by_name (vm, (u8 *)"gre-input");
1128  ASSERT(gre_input_node);
1129  vlib_node_add_next (vm, gre_input_node->index, nsh_input_node.index);
1130
1131  vec_free(name);
1132
1133  return error;
1134}
1135
1136VLIB_INIT_FUNCTION(nsh_init);
1137