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