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