FD.io VPP  v18.10-34-gcce845e
Vector Packet Processing
nsh.c
Go to the documentation of this file.
1 /*
2  * nsh.c - nsh mapping
3  *
4  * Copyright (c) 2013 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include <vnet/vnet.h>
19 #include <vnet/plugin/plugin.h>
20 #include <nsh/nsh.h>
21 #include <vnet/gre/gre.h>
22 #include <vnet/vxlan/vxlan.h>
24 #include <vnet/l2/l2_classify.h>
25 #include <vnet/adj/adj.h>
26 
27 #include <vlibapi/api.h>
28 #include <vlibmemory/api.h>
29 #include <vpp/app/version.h>
30 
31 /* define message IDs */
32 #define vl_msg_id(n,h) n,
33 typedef enum
34 {
35 #include <nsh/nsh.api.h>
36  /* We'll want to know how many messages IDs we need... */
38 } vl_msg_id_t;
39 #undef vl_msg_id
40 
41 /* define message structures */
42 #define vl_typedefs
43 #include <nsh/nsh.api.h>
44 #undef vl_typedefs
45 
46 /* define generated endian-swappers */
47 #define vl_endianfun
48 #include <nsh/nsh.api.h>
49 #undef vl_endianfun
50 
51 /* instantiate all the print functions we know about */
52 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
53 #define vl_printfun
54 #include <nsh/nsh.api.h>
55 #undef vl_printfun
56 
57 /* Get the API version number */
58 #define vl_api_version(n,v) static u32 api_version=(v);
59 #include <nsh/nsh.api.h>
60 #undef vl_api_version
61 
62 #define vl_msg_name_crc_list
63 #include <nsh/nsh.api.h>
64 #undef vl_msg_name_crc_list
65 
66 /* Dummy Eth header */
67 const char dummy_dst_address[6] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
68 const char dummy_src_address[6] = { 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc };
69 
70 /*
71  * A handy macro to set up a message reply.
72  * Assumes that the following variables are available:
73  * mp - pointer to request message
74  * rmp - pointer to reply message type
75  * rv - return value
76  */
77 
78 #define REPLY_MACRO(t) \
79  do { \
80  unix_shared_memory_queue_t * q = \
81  vl_api_client_index_to_input_queue (mp->client_index); \
82  if (!q) \
83  return; \
84  \
85  rmp = vl_msg_api_alloc (sizeof (*rmp)); \
86  rmp->_vl_msg_id = ntohs((t)+nm->msg_id_base); \
87  rmp->context = mp->context; \
88  rmp->retval = ntohl(rv); \
89  \
90  vl_msg_api_send_shmem (q, (u8 *)&rmp); \
91  } while(0);
92 
93 #define REPLY_MACRO2(t, body) \
94  do { \
95  unix_shared_memory_queue_t * q; \
96  rv = vl_msg_api_pd_handler (mp, rv); \
97  q = vl_api_client_index_to_input_queue (mp->client_index); \
98  if (!q) \
99  return; \
100  \
101  rmp = vl_msg_api_alloc (sizeof (*rmp)); \
102  rmp->_vl_msg_id = ntohs((t)+nm->msg_id_base); \
103  rmp->context = mp->context; \
104  rmp->retval = ntohl(rv); \
105  do {body;} while (0); \
106  vl_msg_api_send_shmem (q, (u8 *)&rmp); \
107  } while(0);
108 
109 #define FINISH \
110  vec_add1 (s, 0); \
111  vl_print (handle, (char *)s); \
112  vec_free (s); \
113  return handle;
114 
115 /* List of message types that this plugin understands */
116 
117 #define foreach_nsh_plugin_api_msg \
118  _(NSH_ADD_DEL_ENTRY, nsh_add_del_entry) \
119  _(NSH_ENTRY_DUMP, nsh_entry_dump) \
120  _(NSH_ADD_DEL_MAP, nsh_add_del_map) \
121  _(NSH_MAP_DUMP, nsh_map_dump)
122 
123  /* Uses network order's class and type to register */
124 int
126  u8 type,
127  u8 option_size,
128  int add_options (u8 * opt,
129  u8 * opt_size),
130  int options (vlib_buffer_t * b,
131  nsh_tlv_header_t * opt),
132  int swap_options (vlib_buffer_t * b,
133  nsh_tlv_header_t * old_opt,
134  nsh_tlv_header_t * new_opt),
135  int pop_options (vlib_buffer_t * b,
136  nsh_tlv_header_t * opt),
137  u8 * trace (u8 * s, nsh_tlv_header_t * opt))
138 {
139  nsh_main_t *nm = &nsh_main;
140  nsh_option_map_by_key_t key, *key_copy;
141  uword *p;
142  nsh_option_map_t *nsh_option;
143 
144  key.class = class;
145  key.type = type;
146  key.pad = 0;
147 
148  p = hash_get_mem (nm->nsh_option_map_by_key, &key);
149  /* Already registered */
150  if (p != 0)
151  {
152  return (-1);
153  }
154 
155  pool_get_aligned (nm->nsh_option_mappings, nsh_option,
157  memset (nsh_option, 0, sizeof (*nsh_option));
158  nsh_option->option_id = nsh_option - nm->nsh_option_mappings;
159 
160  key_copy = clib_mem_alloc (sizeof (*key_copy));
161  clib_memcpy (key_copy, &key, sizeof (*key_copy));
162  hash_set_mem (nm->nsh_option_map_by_key, key_copy,
163  nsh_option - nm->nsh_option_mappings);
164 
165  if (option_size > (MAX_NSH_OPTION_LEN + sizeof (nsh_tlv_header_t)))
166  {
167  return (-1);
168  }
169  nm->options_size[nsh_option->option_id] = option_size;
170  nm->add_options[nsh_option->option_id] = add_options;
171  nm->options[nsh_option->option_id] = options;
172  nm->swap_options[nsh_option->option_id] = swap_options;
173  nm->pop_options[nsh_option->option_id] = pop_options;
174  nm->trace[nsh_option->option_id] = trace;
175 
176  return (0);
177 }
178 
179 /* Uses network order's class and type to lookup */
182 {
183  nsh_main_t *nm = &nsh_main;
185  uword *p;
186 
187  key.class = class;
188  key.type = type;
189  key.pad = 0;
190 
191  p = hash_get_mem (nm->nsh_option_map_by_key, &key);
192  /* not registered */
193  if (p == 0)
194  {
195  return NULL;
196  }
197 
198  return pool_elt_at_index (nm->nsh_option_mappings, p[0]);
199 
200 }
201 
202 /* Uses network order's class and type to unregister */
203 int
205  u8 type,
206  int options (vlib_buffer_t * b,
207  nsh_tlv_header_t * opt),
208  u8 * trace (u8 * s, nsh_tlv_header_t * opt))
209 {
210  nsh_main_t *nm = &nsh_main;
211  nsh_option_map_by_key_t key, *key_copy;
212  uword *p;
213  hash_pair_t *hp;
214  nsh_option_map_t *nsh_option;
215 
216  key.class = class;
217  key.type = type;
218  key.pad = 0;
219 
220  p = hash_get_mem (nm->nsh_option_map_by_key, &key);
221  /* not registered */
222  if (p == 0)
223  {
224  return (-1);
225  }
226 
227  nsh_option = pool_elt_at_index (nm->nsh_option_mappings, p[0]);
228  nm->options[nsh_option->option_id] = NULL;
229  nm->add_options[nsh_option->option_id] = NULL;
230  nm->pop_options[nsh_option->option_id] = NULL;
231  nm->trace[nsh_option->option_id] = NULL;
232 
233  hp = hash_get_pair (nm->nsh_option_map_by_key, &key);
234  key_copy = (void *) (hp->key);
235  hash_unset_mem (nm->nsh_option_map_by_key, &key_copy);
236  clib_mem_free (key_copy);
237 
238  pool_put (nm->nsh_option_mappings, nsh_option);
239 
240  return (0);
241 }
242 
243 /* format from network order */
244 u8 *
245 format_nsh_header (u8 * s, va_list * args)
246 {
247  nsh_main_t *nm = &nsh_main;
248  nsh_md2_data_t *opt0;
249  nsh_md2_data_t *limit0;
250  nsh_option_map_t *nsh_option;
251  u8 option_len = 0;
252 
253  u8 *header = va_arg (*args, u8 *);
254  nsh_base_header_t *nsh_base = (nsh_base_header_t *) header;
255  nsh_md1_data_t *nsh_md1 = (nsh_md1_data_t *) (nsh_base + 1);
256  nsh_md2_data_t *nsh_md2 = (nsh_md2_data_t *) (nsh_base + 1);
257  opt0 = (nsh_md2_data_t *) nsh_md2;
258  limit0 = (nsh_md2_data_t *) ((u8 *) nsh_md2 +
259  ((nsh_base->length & NSH_LEN_MASK) * 4
260  - sizeof (nsh_base_header_t)));
261 
262  s = format (s, "nsh ver %d ", (nsh_base->ver_o_c >> 6));
263  if (nsh_base->ver_o_c & NSH_O_BIT)
264  s = format (s, "O-set ");
265 
266  if (nsh_base->ver_o_c & NSH_C_BIT)
267  s = format (s, "C-set ");
268 
269  s = format (s, "ttl %d ", (nsh_base->ver_o_c & NSH_TTL_H4_MASK) << 2 |
270  (nsh_base->length & NSH_TTL_L2_MASK) >> 6);
271 
272  s = format (s, "len %d (%d bytes) md_type %d next_protocol %d\n",
273  (nsh_base->length & NSH_LEN_MASK),
274  (nsh_base->length & NSH_LEN_MASK) * 4,
275  nsh_base->md_type, nsh_base->next_protocol);
276 
277  s = format (s, " service path %d service index %d\n",
278  (clib_net_to_host_u32 (nsh_base->nsp_nsi) >> NSH_NSP_SHIFT) &
279  NSH_NSP_MASK,
280  clib_net_to_host_u32 (nsh_base->nsp_nsi) & NSH_NSI_MASK);
281 
282  if (nsh_base->md_type == 1)
283  {
284  s = format (s, " c1 %d c2 %d c3 %d c4 %d\n",
285  clib_net_to_host_u32 (nsh_md1->c1),
286  clib_net_to_host_u32 (nsh_md1->c2),
287  clib_net_to_host_u32 (nsh_md1->c3),
288  clib_net_to_host_u32 (nsh_md1->c4));
289  }
290  else if (nsh_base->md_type == 2)
291  {
292  s = format (s, " Supported TLVs: \n");
293 
294  /* Scan the set of variable metadata, network order */
295  while (opt0 < limit0)
296  {
297  nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type);
298  if (nsh_option != NULL)
299  {
300  if (nm->trace[nsh_option->option_id] != NULL)
301  {
302  s = (*nm->trace[nsh_option->option_id]) (s, opt0);
303  }
304  else
305  {
306  s =
307  format (s, "\n untraced option %d length %d",
308  opt0->type, opt0->length);
309  }
310  }
311  else
312  {
313  s =
314  format (s, "\n unrecognized option %d length %d",
315  opt0->type, opt0->length);
316  }
317 
318  /* round to 4-byte */
319  option_len = ((opt0->length + 3) >> 2) << 2;
320  opt0 =
321  (nsh_md2_data_t *) (((u8 *) opt0) + sizeof (nsh_md2_data_t) +
322  option_len);
323  }
324  }
325 
326  return s;
327 }
328 
329 static u8 *
330 format_nsh_action (u8 * s, va_list * args)
331 {
332  u32 nsh_action = va_arg (*args, u32);
333 
334  switch (nsh_action)
335  {
336  case NSH_ACTION_SWAP:
337  return format (s, "swap");
338  case NSH_ACTION_PUSH:
339  return format (s, "push");
340  case NSH_ACTION_POP:
341  return format (s, "pop");
342  default:
343  return format (s, "unknown %d", nsh_action);
344  }
345  return s;
346 }
347 
348 u8 *
349 format_nsh_map (u8 * s, va_list * args)
350 {
351  nsh_map_t *map = va_arg (*args, nsh_map_t *);
352 
353  s = format (s, "nsh entry nsp: %d nsi: %d ",
354  (map->nsp_nsi >> NSH_NSP_SHIFT) & NSH_NSP_MASK,
355  map->nsp_nsi & NSH_NSI_MASK);
356  s = format (s, "maps to nsp: %d nsi: %d ",
357  (map->mapped_nsp_nsi >> NSH_NSP_SHIFT) & NSH_NSP_MASK,
359 
360  s = format (s, " nsh_action %U\n", format_nsh_action, map->nsh_action);
361 
362  switch (map->next_node)
363  {
364  case NSH_NODE_NEXT_ENCAP_GRE4:
365  {
366  s = format (s, "encapped by GRE4 intf: %d", map->sw_if_index);
367  break;
368  }
369  case NSH_NODE_NEXT_ENCAP_GRE6:
370  {
371  s = format (s, "encapped by GRE6 intf: %d", map->sw_if_index);
372  break;
373  }
374  case NSH_NODE_NEXT_ENCAP_VXLANGPE:
375  {
376  s = format (s, "encapped by VXLAN GPE intf: %d", map->sw_if_index);
377  break;
378  }
379  case NSH_NODE_NEXT_ENCAP_VXLAN4:
380  {
381  s = format (s, "encapped by VXLAN4 intf: %d", map->sw_if_index);
382  break;
383  }
384  case NSH_NODE_NEXT_ENCAP_VXLAN6:
385  {
386  s = format (s, "encapped by VXLAN6 intf: %d", map->sw_if_index);
387  break;
388  }
389  case NSH_NODE_NEXT_DECAP_ETH_INPUT:
390  {
391  s = format (s, "encap-none");
392  break;
393  }
394  case NSH_NODE_NEXT_ENCAP_LISP_GPE:
395  {
396  s = format (s, "encapped by LISP GPE intf: %d", map->sw_if_index);
397  break;
398  }
399  case NSH_NODE_NEXT_ENCAP_ETHERNET:
400  {
401  s = format (s, "encapped by Ethernet intf: %d", map->sw_if_index);
402  break;
403  }
404  default:
405  s = format (s, "only GRE and VXLANGPE support in this rev");
406  }
407 
408  return s;
409 }
410 
411 u8 *
412 format_nsh_node_map_trace (u8 * s, va_list * args)
413 {
414  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
415  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
416  nsh_input_trace_t *t = va_arg (*args, nsh_input_trace_t *);
417 
418  s = format (s, "\n %U", format_nsh_header, &(t->trace_data));
419 
420  return s;
421 }
422 
423 /**
424  * @brief Naming for NSH tunnel
425  *
426  * @param *s formatting string
427  * @param *args
428  *
429  * @return *s formatted string
430  *
431  */
432 static u8 *
433 format_nsh_name (u8 * s, va_list * args)
434 {
435  u32 dev_instance = va_arg (*args, u32);
436  return format (s, "nsh_tunnel%d", dev_instance);
437 }
438 
439 /**
440  * @brief CLI function for NSH admin up/down
441  *
442  * @param *vnm
443  * @param nsh_hw_if
444  * @param flag
445  *
446  * @return *rc
447  *
448  */
449 static clib_error_t *
451 {
453  vnet_hw_interface_set_flags (vnm, nsh_hw_if,
455  else
456  vnet_hw_interface_set_flags (vnm, nsh_hw_if, 0);
457 
458  return 0;
459 }
460 
461 static uword
463  vlib_node_runtime_t * node, vlib_frame_t * frame)
464 {
465  clib_warning ("you shouldn't be here, leaking buffers...");
466  return frame->n_vectors;
467 }
468 
469 VNET_DEVICE_CLASS (nsh_device_class, static) =
470 {
471 .name = "NSH",.format_device_name = format_nsh_name,.tx_function =
472  dummy_interface_tx,.admin_up_down_function =
474 
475 /**
476  * @brief Formatting function for tracing VXLAN GPE with length
477  *
478  * @param *s
479  * @param *args
480  *
481  * @return *s
482  *
483  */
484 static u8 *
485 format_nsh_tunnel_with_length (u8 * s, va_list * args)
486 {
487  u32 dev_instance = va_arg (*args, u32);
488  s = format (s, "unimplemented dev %u", dev_instance);
489  return s;
490 }
491 
492 VNET_HW_INTERFACE_CLASS (nsh_hw_class) =
493 {
494 .name = "NSH",.format_header =
495  format_nsh_tunnel_with_length,.build_rewrite =
497 
498 
499 /**
500  * Action function to add or del an nsh map.
501  * Shared by both CLI and binary API
502  **/
503 
504 int
506 {
507  nsh_main_t *nm = &nsh_main;
508  vnet_main_t *vnm = nm->vnet_main;
509  nsh_map_t *map = 0;
510  u32 key, *key_copy;
511  uword *entry;
512  hash_pair_t *hp;
513  u32 map_index = ~0;
515  u32 nsh_hw_if = ~0;
516  u32 nsh_sw_if = ~0;
517 
518  /* net order, so data plane could use nsh header to lookup directly */
519  key = clib_host_to_net_u32 (a->map.nsp_nsi);
520 
521  entry = hash_get_mem (nm->nsh_mapping_by_key, &key);
522 
523  if (a->is_add)
524  {
525  /* adding an entry, must not already exist */
526  if (entry)
527  return -1; //TODO API_ERROR_INVALID_VALUE;
528 
530  memset (map, 0, sizeof (*map));
531 
532  /* copy from arg structure */
533  map->nsp_nsi = a->map.nsp_nsi;
535  map->nsh_action = a->map.nsh_action;
536  map->sw_if_index = a->map.sw_if_index;
538  map->next_node = a->map.next_node;
539  map->adj_index = a->map.adj_index;
540 
541 
542  key_copy = clib_mem_alloc (sizeof (*key_copy));
543  clib_memcpy (key_copy, &key, sizeof (*key_copy));
544 
545  hash_set_mem (nm->nsh_mapping_by_key, key_copy, map - nm->nsh_mappings);
546  map_index = map - nm->nsh_mappings;
547 
549  {
550  nsh_hw_if = nm->free_nsh_tunnel_hw_if_indices
552  _vec_len (nm->free_nsh_tunnel_hw_if_indices) -= 1;
553 
554  hi = vnet_get_hw_interface (vnm, nsh_hw_if);
555  hi->dev_instance = map_index;
556  hi->hw_instance = hi->dev_instance;
557  }
558  else
559  {
560  nsh_hw_if = vnet_register_interface
561  (vnm, nsh_device_class.index, map_index, nsh_hw_class.index,
562  map_index);
563  hi = vnet_get_hw_interface (vnm, nsh_hw_if);
564  hi->output_node_index = nsh_aware_vnf_proxy_node.index;
565  }
566 
567  map->nsh_hw_if = nsh_hw_if;
568  map->nsh_sw_if = nsh_sw_if = hi->sw_if_index;
570  ~0);
571  nm->tunnel_index_by_sw_if_index[nsh_sw_if] = key;
572 
575  }
576  else
577  {
578  if (!entry)
579  return -2; //TODO API_ERROR_NO_SUCH_ENTRY;
580 
581  map = pool_elt_at_index (nm->nsh_mappings, entry[0]);
582 
586  nm->tunnel_index_by_sw_if_index[map->nsh_sw_if] = ~0;
587 
588  hp = hash_get_pair (nm->nsh_mapping_by_key, &key);
589  key_copy = (void *) (hp->key);
591  clib_mem_free (key_copy);
592 
593  pool_put (nm->nsh_mappings, map);
594  }
595 
596  if (map_indexp)
597  *map_indexp = map_index;
598 
599  return 0;
600 }
601 
602 /**
603  * Action function to add or del an nsh-proxy-session.
604  * Shared by both CLI and binary API
605  **/
606 
607 int
609 {
610  nsh_main_t *nm = &nsh_main;
611  nsh_proxy_session_t *proxy = 0;
612  nsh_proxy_session_by_key_t key, *key_copy;
613  uword *entry;
614  hash_pair_t *hp;
615  u32 nsp = 0, nsi = 0;
616 
617  memset (&key, 0, sizeof (key));
618  key.transport_type = a->map.next_node;
620 
621  entry = hash_get_mem (nm->nsh_proxy_session_by_key, &key);
622 
623  if (a->is_add)
624  {
625  /* adding an entry, must not already exist */
626  if (entry)
627  return -1; //TODO API_ERROR_INVALID_VALUE;
628 
630  memset (proxy, 0, sizeof (*proxy));
631 
632  /* Nsi needs to minus 1 within NSH-Proxy */
633  nsp = (a->map.nsp_nsi >> NSH_NSP_SHIFT) & NSH_NSP_MASK;
634  nsi = a->map.nsp_nsi & NSH_NSI_MASK;
635  if (nsi == 0)
636  return -1;
637 
638  nsi = nsi - 1;
639  /* net order, so could use it to lookup nsh map table directly */
640  proxy->nsp_nsi = clib_host_to_net_u32 ((nsp << NSH_NSP_SHIFT) | nsi);
641 
642  key_copy = clib_mem_alloc (sizeof (*key_copy));
643  clib_memcpy (key_copy, &key, sizeof (*key_copy));
644 
645  hash_set_mem (nm->nsh_proxy_session_by_key, key_copy,
646  proxy - nm->nsh_proxy_sessions);
647  }
648  else
649  {
650  if (!entry)
651  return -2; //TODO API_ERROR_NO_SUCH_ENTRY;
652 
653  proxy = pool_elt_at_index (nm->nsh_proxy_sessions, entry[0]);
654  hp = hash_get_pair (nm->nsh_proxy_session_by_key, &key);
655  key_copy = (void *) (hp->key);
657  clib_mem_free (key_copy);
658 
659  pool_put (nm->nsh_proxy_sessions, proxy);
660  }
661 
662  return 0;
663 }
664 
665 /**
666  * CLI command for NSH map
667  */
668 
669 static uword
670 unformat_nsh_action (unformat_input_t * input, va_list * args)
671 {
672  u32 *result = va_arg (*args, u32 *);
673  u32 tmp;
674 
675  if (unformat (input, "swap"))
676  *result = NSH_ACTION_SWAP;
677  else if (unformat (input, "push"))
678  *result = NSH_ACTION_PUSH;
679  else if (unformat (input, "pop"))
680  *result = NSH_ACTION_POP;
681  else if (unformat (input, "%d", &tmp))
682  *result = tmp;
683  else
684  return 0;
685 
686  return 1;
687 }
688 
689 static adj_index_t
691 {
692  adj_index_t ai = ~0;
693 
694  /* *INDENT-OFF* */
696  ({
697  if (sw_if_index == adj_get_sw_if_index(ai))
698  {
699  return ai;
700  }
701  }));
702  /* *INDENT-ON* */
703 
704  return ~0;
705 }
706 
707 static clib_error_t *
709  unformat_input_t * input,
710  vlib_cli_command_t * cmd)
711 {
712  unformat_input_t _line_input, *line_input = &_line_input;
713  u8 is_add = 1;
714  u32 nsp, nsi, mapped_nsp, mapped_nsi, nsh_action;
715  int nsp_set = 0, nsi_set = 0, mapped_nsp_set = 0, mapped_nsi_set = 0;
716  int nsh_action_set = 0;
717  u32 next_node = ~0;
718  u32 adj_index = ~0;
719  u32 sw_if_index = ~0; // temporary requirement to get this moved over to NSHSFC
720  u32 rx_sw_if_index = ~0; // temporary requirement to get this moved over to NSHSFC
721  nsh_add_del_map_args_t _a, *a = &_a;
722  u32 map_index;
723  int rv;
724 
725  /* Get a line of input. */
726  if (!unformat_user (input, unformat_line_input, line_input))
727  return 0;
728 
729  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
730  {
731  if (unformat (line_input, "del"))
732  is_add = 0;
733  else if (unformat (line_input, "nsp %d", &nsp))
734  nsp_set = 1;
735  else if (unformat (line_input, "nsi %d", &nsi))
736  nsi_set = 1;
737  else if (unformat (line_input, "mapped-nsp %d", &mapped_nsp))
738  mapped_nsp_set = 1;
739  else if (unformat (line_input, "mapped-nsi %d", &mapped_nsi))
740  mapped_nsi_set = 1;
741  else if (unformat (line_input, "nsh_action %U", unformat_nsh_action,
742  &nsh_action))
743  nsh_action_set = 1;
744  else if (unformat (line_input, "encap-gre4-intf %d", &sw_if_index))
745  next_node = NSH_NODE_NEXT_ENCAP_GRE4;
746  else if (unformat (line_input, "encap-gre6-intf %d", &sw_if_index))
747  next_node = NSH_NODE_NEXT_ENCAP_GRE6;
748  else if (unformat (line_input, "encap-vxlan-gpe-intf %d", &sw_if_index))
749  next_node = NSH_NODE_NEXT_ENCAP_VXLANGPE;
750  else if (unformat (line_input, "encap-lisp-gpe-intf %d", &sw_if_index))
751  next_node = NSH_NODE_NEXT_ENCAP_LISP_GPE;
752  else if (unformat (line_input, "encap-vxlan4-intf %d", &sw_if_index))
753  next_node = NSH_NODE_NEXT_ENCAP_VXLAN4;
754  else if (unformat (line_input, "encap-vxlan6-intf %d", &sw_if_index))
755  next_node = NSH_NODE_NEXT_ENCAP_VXLAN6;
756  else if (unformat (line_input, "encap-eth-intf %d", &sw_if_index))
757  {
758  next_node = NSH_NODE_NEXT_ENCAP_ETHERNET;
759  adj_index = nsh_get_adj_by_sw_if_index (sw_if_index);
760  }
761  else
762  if (unformat
763  (line_input, "encap-none %d %d", &sw_if_index, &rx_sw_if_index))
764  next_node = NSH_NODE_NEXT_DECAP_ETH_INPUT;
765  else
766  return clib_error_return (0, "parse error: '%U'",
767  format_unformat_error, line_input);
768  }
769 
770  unformat_free (line_input);
771 
772  if (nsp_set == 0 || nsi_set == 0)
773  return clib_error_return (0, "nsp nsi pair required. Key: for NSH entry");
774 
775  if (mapped_nsp_set == 0 || mapped_nsi_set == 0)
776  return clib_error_return (0,
777  "mapped-nsp mapped-nsi pair required. Key: for NSH entry");
778 
779  if (nsh_action_set == 0)
780  return clib_error_return (0, "nsh_action required: swap|push|pop.");
781 
782  if (next_node == ~0)
783  return clib_error_return (0,
784  "must specific action: [encap-gre-intf <nn> | encap-vxlan-gpe-intf <nn> | encap-lisp-gpe-intf <nn> | encap-none <tx_sw_if_index> <rx_sw_if_index>]");
785 
786  memset (a, 0, sizeof (*a));
787 
788  /* set args structure */
789  a->is_add = is_add;
790  a->map.nsp_nsi = (nsp << NSH_NSP_SHIFT) | nsi;
791  a->map.mapped_nsp_nsi = (mapped_nsp << NSH_NSP_SHIFT) | mapped_nsi;
792  a->map.nsh_action = nsh_action;
794  a->map.rx_sw_if_index = rx_sw_if_index;
795  a->map.next_node = next_node;
796  a->map.adj_index = adj_index;
797 
798  rv = nsh_add_del_map (a, &map_index);
799 
800  switch (rv)
801  {
802  case 0:
803  break;
804  case -1: //TODO API_ERROR_INVALID_VALUE:
805  return clib_error_return (0,
806  "mapping already exists. Remove it first.");
807 
808  case -2: // TODO API_ERROR_NO_SUCH_ENTRY:
809  return clib_error_return (0, "mapping does not exist.");
810 
811  default:
812  return clib_error_return (0, "nsh_add_del_map returned %d", rv);
813  }
814 
815  if ((a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN4)
816  | (a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN6))
817  {
818  rv = nsh_add_del_proxy_session (a);
819 
820  switch (rv)
821  {
822  case 0:
823  break;
824  case -1: //TODO API_ERROR_INVALID_VALUE:
825  return clib_error_return (0,
826  "nsh-proxy-session already exists. Remove it first.");
827 
828  case -2: // TODO API_ERROR_NO_SUCH_ENTRY:
829  return clib_error_return (0, "nsh-proxy-session does not exist.");
830 
831  default:
832  return clib_error_return
833  (0, "nsh_add_del_proxy_session() returned %d", rv);
834  }
835  }
836 
837  return 0;
838 }
839 
840 VLIB_CLI_COMMAND (create_nsh_map_command, static) =
841 {
842 .path = "create nsh map",.short_help =
843  "create nsh map nsp <nn> nsi <nn> [del] mapped-nsp <nn> mapped-nsi <nn> nsh_action [swap|push|pop] "
844  "[encap-gre4-intf <nn> | encap-gre4-intf <nn> | encap-vxlan-gpe-intf <nn> | encap-lisp-gpe-intf <nn> "
845  " encap-vxlan4-intf <nn> | encap-vxlan6-intf <nn>| encap-eth-intf <nn> | encap-none]\n",.function
847 
848 /** API message handler */
849 static void
851 {
853  nsh_main_t *nm = &nsh_main;
854  int rv;
855  nsh_add_del_map_args_t _a, *a = &_a;
856  u32 map_index = ~0;
857 
858  a->is_add = mp->is_add;
859  a->map.nsp_nsi = ntohl (mp->nsp_nsi);
860  a->map.mapped_nsp_nsi = ntohl (mp->mapped_nsp_nsi);
861  a->map.nsh_action = ntohl (mp->nsh_action);
862  a->map.sw_if_index = ntohl (mp->sw_if_index);
863  a->map.rx_sw_if_index = ntohl (mp->rx_sw_if_index);
864  a->map.next_node = ntohl (mp->next_node);
865 
866  rv = nsh_add_del_map (a, &map_index);
867 
868  if ((a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN4)
869  | (a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN6))
870  {
871  rv = nsh_add_del_proxy_session (a);
872  }
873 
874  REPLY_MACRO2 (VL_API_NSH_ADD_DEL_MAP_REPLY, (
875  {
876  rmp->map_index =
877  htonl (map_index);
878  }
879  ));
880 }
881 
882 /**
883  * CLI command for showing the mapping between NSH entries
884  */
885 static clib_error_t *
887  unformat_input_t * input, vlib_cli_command_t * cmd)
888 {
889  nsh_main_t *nm = &nsh_main;
890  nsh_map_t *map;
891 
892  if (pool_elts (nm->nsh_mappings) == 0)
893  vlib_cli_output (vm, "No nsh maps configured.");
894 
895  pool_foreach (map, nm->nsh_mappings, (
896  {
897  vlib_cli_output (vm, "%U",
898  format_nsh_map,
899  map);
900  }
901  ));
902 
903  return 0;
904 }
905 
906 VLIB_CLI_COMMAND (show_nsh_map_command, static) =
907 {
908 .path = "show nsh map",.function = show_nsh_map_command_fn,};
909 
910 int
912 {
913  u8 *rw = 0;
914  int len = 0;
915  nsh_base_header_t *nsh_base;
916  nsh_md1_data_t *nsh_md1;
917  nsh_main_t *nm = &nsh_main;
918  nsh_md2_data_t *opt0;
919  nsh_md2_data_t *limit0;
920  nsh_md2_data_t *nsh_md2;
921  nsh_option_map_t _nsh_option, *nsh_option = &_nsh_option;
922  u8 old_option_size = 0;
923  u8 new_option_size = 0;
924 
925  vec_free (nsh_entry->rewrite);
926  if (nsh_entry->nsh_base.md_type == 1)
927  {
928  len = sizeof (nsh_base_header_t) + sizeof (nsh_md1_data_t);
929  }
930  else if (nsh_entry->nsh_base.md_type == 2)
931  {
932  /* set to maxim, maybe dataplane will add more TLVs */
933  len = MAX_NSH_HEADER_LEN;
934  }
936  memset (rw, 0, len);
937 
938  nsh_base = (nsh_base_header_t *) rw;
939  nsh_base->ver_o_c = nsh_entry->nsh_base.ver_o_c;
940  nsh_base->length = nsh_entry->nsh_base.length;
941  nsh_base->md_type = nsh_entry->nsh_base.md_type;
942  nsh_base->next_protocol = nsh_entry->nsh_base.next_protocol;
943  nsh_base->nsp_nsi = clib_host_to_net_u32 (nsh_entry->nsh_base.nsp_nsi);
944 
945  if (nsh_base->md_type == 1)
946  {
947  nsh_md1 = (nsh_md1_data_t *) (rw + sizeof (nsh_base_header_t));
948  nsh_md1->c1 = clib_host_to_net_u32 (nsh_entry->md.md1_data.c1);
949  nsh_md1->c2 = clib_host_to_net_u32 (nsh_entry->md.md1_data.c2);
950  nsh_md1->c3 = clib_host_to_net_u32 (nsh_entry->md.md1_data.c3);
951  nsh_md1->c4 = clib_host_to_net_u32 (nsh_entry->md.md1_data.c4);
952  nsh_entry->rewrite_size = 24;
953  }
954  else if (nsh_base->md_type == 2)
955  {
956  opt0 = (nsh_md2_data_t *) (nsh_entry->tlvs_data);
957  limit0 = (nsh_md2_data_t *) ((u8 *) opt0 + nsh_entry->tlvs_len);
958 
959  nsh_md2 = (nsh_md2_data_t *) (rw + sizeof (nsh_base_header_t));
960  nsh_entry->rewrite_size = sizeof (nsh_base_header_t);
961 
962  while (opt0 < limit0)
963  {
964  old_option_size = sizeof (nsh_md2_data_t) + opt0->length;
965  /* round to 4-byte */
966  old_option_size = ((old_option_size + 3) >> 2) << 2;
967 
968  nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type);
969  if (nsh_option == NULL)
970  {
971  goto next_tlv_md2;
972  }
973 
974  if (nm->add_options[nsh_option->option_id] != NULL)
975  {
976  if (0 != nm->add_options[nsh_option->option_id] ((u8 *) nsh_md2,
977  &new_option_size))
978  {
979  goto next_tlv_md2;
980  }
981 
982  /* round to 4-byte */
983  new_option_size = ((new_option_size + 3) >> 2) << 2;
984 
985  nsh_entry->rewrite_size += new_option_size;
986  nsh_md2 =
987  (nsh_md2_data_t *) (((u8 *) nsh_md2) + new_option_size);
988  opt0 = (nsh_md2_data_t *) (((u8 *) opt0) + old_option_size);
989  }
990  else
991  {
992  next_tlv_md2:
993  opt0 = (nsh_md2_data_t *) (((u8 *) opt0) + old_option_size);
994  }
995 
996  }
997  }
998 
999  nsh_entry->rewrite = rw;
1000  nsh_base->length = (nsh_base->length & NSH_TTL_L2_MASK) |
1001  ((nsh_entry->rewrite_size >> 2) & NSH_LEN_MASK);
1002 
1003  return 0;
1004 }
1005 
1006 
1007 /**
1008  * Action function for adding an NSH entry
1009  * nsh_add_del_entry_args_t *a: host order
1010  */
1011 
1012 int
1014 {
1015  nsh_main_t *nm = &nsh_main;
1016  nsh_entry_t *nsh_entry = 0;
1017  u32 key, *key_copy;
1018  uword *entry_id;
1019  hash_pair_t *hp;
1020  u32 entry_index = ~0;
1021  u8 tlvs_len = 0;
1022  u8 *data = 0;
1023 
1024  /* host order, because nsh map table stores nsp_nsi in host order */
1025  key = a->nsh_entry.nsh_base.nsp_nsi;
1026 
1027  entry_id = hash_get_mem (nm->nsh_entry_by_key, &key);
1028 
1029  if (a->is_add)
1030  {
1031  /* adding an entry, must not already exist */
1032  if (entry_id)
1033  return -1; // TODO VNET_API_ERROR_INVALID_VALUE;
1034 
1036  memset (nsh_entry, 0, sizeof (*nsh_entry));
1037 
1038  /* copy from arg structure */
1039 #define _(x) nsh_entry->nsh_base.x = a->nsh_entry.nsh_base.x;
1041 #undef _
1042 
1043  if (a->nsh_entry.nsh_base.md_type == 1)
1044  {
1045  nsh_entry->md.md1_data.c1 = a->nsh_entry.md.md1_data.c1;
1046  nsh_entry->md.md1_data.c2 = a->nsh_entry.md.md1_data.c2;
1047  nsh_entry->md.md1_data.c3 = a->nsh_entry.md.md1_data.c3;
1048  nsh_entry->md.md1_data.c4 = a->nsh_entry.md.md1_data.c4;
1049  }
1050  else if (a->nsh_entry.nsh_base.md_type == 2)
1051  {
1052  vec_free (nsh_entry->tlvs_data);
1053  tlvs_len = a->nsh_entry.tlvs_len;
1054  vec_validate_aligned (data, tlvs_len - 1, CLIB_CACHE_LINE_BYTES);
1055 
1056  clib_memcpy (data, a->nsh_entry.tlvs_data, tlvs_len);
1057  nsh_entry->tlvs_data = data;
1058  nsh_entry->tlvs_len = tlvs_len;
1060  }
1061 
1062  nsh_header_rewrite (nsh_entry);
1063 
1064  key_copy = clib_mem_alloc (sizeof (*key_copy));
1065  clib_memcpy (key_copy, &key, sizeof (*key_copy));
1066 
1067  hash_set_mem (nm->nsh_entry_by_key, key_copy,
1068  nsh_entry - nm->nsh_entries);
1069  entry_index = nsh_entry - nm->nsh_entries;
1070  }
1071  else
1072  {
1073  if (!entry_id)
1074  return -2; //TODO API_ERROR_NO_SUCH_ENTRY;
1075 
1076  nsh_entry = pool_elt_at_index (nm->nsh_entries, entry_id[0]);
1077  hp = hash_get_pair (nm->nsh_entry_by_key, &key);
1078  key_copy = (void *) (hp->key);
1079  hash_unset_mem (nm->nsh_entry_by_key, &key);
1080  clib_mem_free (key_copy);
1081 
1082  vec_free (nsh_entry->tlvs_data);
1083  vec_free (nsh_entry->rewrite);
1084  pool_put (nm->nsh_entries, nsh_entry);
1085  }
1086 
1087  if (entry_indexp)
1088  *entry_indexp = entry_index;
1089 
1090  return 0;
1091 }
1092 
1093 
1094 /**
1095  * CLI command for adding NSH entry
1096  */
1097 
1098 static clib_error_t *
1100  unformat_input_t * input,
1101  vlib_cli_command_t * cmd)
1102 {
1103  unformat_input_t _line_input, *line_input = &_line_input;
1104  u8 is_add = 1;
1105  u8 ver_o_c = 0;
1106  u8 ttl = 63;
1107  u8 length = 0;
1108  u8 md_type = 0;
1109  u8 next_protocol = 1; /* default: ip4 */
1110  u32 nsp;
1111  u8 nsp_set = 0;
1112  u32 nsi;
1113  u8 nsi_set = 0;
1114  u32 nsp_nsi;
1115  u32 c1 = 0;
1116  u32 c2 = 0;
1117  u32 c3 = 0;
1118  u32 c4 = 0;
1119  u8 *data = 0;
1120  nsh_tlv_header_t tlv_header;
1121  u8 cur_len = 0, tlvs_len = 0;
1122  u8 *current;
1123  nsh_main_t *nm = &nsh_main;
1124  nsh_option_map_t _nsh_option, *nsh_option = &_nsh_option;
1125  u8 option_size = 0;
1126  u32 tmp;
1127  int rv;
1128  u32 entry_index;
1129  nsh_add_del_entry_args_t _a, *a = &_a;
1130  u8 has_ioam_trace_option = 0;
1131 
1132  /* Get a line of input. */
1133  if (!unformat_user (input, unformat_line_input, line_input))
1134  return 0;
1135 
1136  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1137  {
1138  if (unformat (line_input, "del"))
1139  is_add = 0;
1140  else if (unformat (line_input, "version %d", &tmp))
1141  ver_o_c |= (tmp & 3) << 6;
1142  else if (unformat (line_input, "o-bit %d", &tmp))
1143  ver_o_c |= (tmp & 1) << 5;
1144  else if (unformat (line_input, "c-bit %d", &tmp))
1145  ver_o_c |= (tmp & 1) << 4;
1146  else if (unformat (line_input, "ttl %d", &ttl))
1147  ver_o_c |= (ttl & NSH_LEN_MASK) >> 2;
1148  else if (unformat (line_input, "md-type %d", &tmp))
1149  md_type = tmp;
1150  else if (unformat (line_input, "next-ip4"))
1151  next_protocol = 1;
1152  else if (unformat (line_input, "next-ip6"))
1153  next_protocol = 2;
1154  else if (unformat (line_input, "next-ethernet"))
1155  next_protocol = 3;
1156  else if (unformat (line_input, "c1 %d", &c1))
1157  ;
1158  else if (unformat (line_input, "c2 %d", &c2))
1159  ;
1160  else if (unformat (line_input, "c3 %d", &c3))
1161  ;
1162  else if (unformat (line_input, "c4 %d", &c4))
1163  ;
1164  else if (unformat (line_input, "nsp %d", &nsp))
1165  nsp_set = 1;
1166  else if (unformat (line_input, "nsi %d", &nsi))
1167  nsi_set = 1;
1168  else if (unformat (line_input, "tlv-ioam-trace"))
1169  has_ioam_trace_option = 1;
1170  else
1171  return clib_error_return (0, "parse error: '%U'",
1172  format_unformat_error, line_input);
1173  }
1174 
1175  unformat_free (line_input);
1176 
1177  if (nsp_set == 0)
1178  return clib_error_return (0, "nsp not specified");
1179 
1180  if (nsi_set == 0)
1181  return clib_error_return (0, "nsi not specified");
1182 
1183  if (md_type == 1 && has_ioam_trace_option == 1)
1184  return clib_error_return (0, "Invalid MD Type");
1185 
1186  nsp_nsi = (nsp << 8) | nsi;
1187 
1188  memset (a, 0, sizeof (*a));
1189  a->is_add = is_add;
1190 
1191  if (md_type == 1)
1192  {
1193  a->nsh_entry.md.md1_data.c1 = c1;
1194  a->nsh_entry.md.md1_data.c2 = c2;
1195  a->nsh_entry.md.md1_data.c3 = c3;
1196  a->nsh_entry.md.md1_data.c4 = c4;
1197  length = (sizeof (nsh_base_header_t) + sizeof (nsh_md1_data_t)) >> 2;
1198  }
1199  else if (md_type == 2)
1200  {
1201  length = sizeof (nsh_base_header_t) >> 2;
1202 
1204  tlvs_len = (MAX_METADATA_LEN << 2);
1205  vec_validate_aligned (data, tlvs_len - 1, CLIB_CACHE_LINE_BYTES);
1206  a->nsh_entry.tlvs_data = data;
1207  current = data;
1208 
1209  if (has_ioam_trace_option)
1210  {
1211  tlv_header.class = clib_host_to_net_u16 (NSH_MD2_IOAM_CLASS);
1212  tlv_header.type = NSH_MD2_IOAM_OPTION_TYPE_TRACE;
1213  /* Uses network order's class and type to lookup */
1214  nsh_option =
1215  nsh_md2_lookup_option (tlv_header.class, tlv_header.type);
1216  if (nsh_option == NULL)
1217  return clib_error_return (0, "iOAM Trace not registered");
1218 
1219  if (nm->add_options[nsh_option->option_id] != NULL)
1220  {
1221  if (0 != nm->add_options[nsh_option->option_id] ((u8 *) current,
1222  &option_size))
1223  {
1224  return clib_error_return (0, "Invalid MD Type");
1225  }
1226  }
1227 
1228  nm->options_size[nsh_option->option_id] = option_size;
1229  /* round to 4-byte */
1230  option_size = (((option_size + 3) >> 2) << 2);
1231 
1232  cur_len += option_size;
1233  current = data + option_size;
1234  }
1235 
1236  /* Add more options' parsing */
1237 
1238  a->nsh_entry.tlvs_len = cur_len;
1239  length += (cur_len >> 2);
1240  }
1241  length = (length & NSH_LEN_MASK) | ((ttl & 0x3) << 6);
1242 
1243 #define _(x) a->nsh_entry.nsh_base.x = x;
1245 #undef _
1246 
1247  rv = nsh_add_del_entry (a, &entry_index);
1248 
1249  switch (rv)
1250  {
1251  case 0:
1252  break;
1253  default:
1254  return clib_error_return (0, "nsh_add_del_entry returned %d", rv);
1255  }
1256 
1257  return 0;
1258 }
1259 
1260 VLIB_CLI_COMMAND (create_nsh_entry_command, static) =
1261 {
1262 .path = "create nsh entry",.short_help =
1263  "create nsh entry {nsp <nn> nsi <nn>} [ttl <nn>] [md-type <nn>]"
1264  " [c1 <nn> c2 <nn> c3 <nn> c4 <nn>] [tlv-ioam-trace] [del]\n",.function
1266 
1267 /** API message handler */
1270 {
1272  nsh_main_t *nm = &nsh_main;
1273  int rv;
1274  nsh_add_del_entry_args_t _a, *a = &_a;
1275  u32 entry_index = ~0;
1276  u8 tlvs_len = 0;
1277  u8 *data = 0;
1278 
1279  a->is_add = mp->is_add;
1280  a->nsh_entry.nsh_base.ver_o_c =
1281  (mp->ver_o_c & 0xF0) | ((mp->ttl & NSH_LEN_MASK) >> 2);
1282  a->nsh_entry.nsh_base.length =
1283  (mp->length & NSH_LEN_MASK) | ((mp->ttl & 0x3) << 6);
1284  a->nsh_entry.nsh_base.md_type = mp->md_type;
1285  a->nsh_entry.nsh_base.next_protocol = mp->next_protocol;
1286  a->nsh_entry.nsh_base.nsp_nsi = ntohl (mp->nsp_nsi);
1287  if (mp->md_type == 1)
1288  {
1289  a->nsh_entry.md.md1_data.c1 = ntohl (mp->c1);
1290  a->nsh_entry.md.md1_data.c2 = ntohl (mp->c2);
1291  a->nsh_entry.md.md1_data.c3 = ntohl (mp->c3);
1292  a->nsh_entry.md.md1_data.c4 = ntohl (mp->c4);
1293  }
1294  else if (mp->md_type == 2)
1295  {
1296  tlvs_len = mp->tlv_length;
1297  vec_validate_aligned (data, tlvs_len - 1, CLIB_CACHE_LINE_BYTES);
1298 
1299  clib_memcpy (data, mp->tlv, tlvs_len);
1300  a->nsh_entry.tlvs_data = data;
1301  a->nsh_entry.tlvs_len = tlvs_len;
1302  }
1303 
1304  rv = nsh_add_del_entry (a, &entry_index);
1305 
1306  REPLY_MACRO2 (VL_API_NSH_ADD_DEL_ENTRY_REPLY, (
1307  {
1308  rmp->entry_index =
1309  htonl (entry_index);
1310  }
1311  ));
1312 }
1313 
1314 static void send_nsh_entry_details
1316 {
1318  nsh_main_t *nm = &nsh_main;
1319 
1320  rmp = vl_msg_api_alloc (sizeof (*rmp));
1321  memset (rmp, 0, sizeof (*rmp));
1322 
1323  rmp->_vl_msg_id = ntohs ((VL_API_NSH_ENTRY_DETAILS) + nm->msg_id_base);
1324  rmp->ver_o_c = t->nsh_base.ver_o_c;
1325  rmp->ttl = (t->nsh_base.ver_o_c & NSH_TTL_H4_MASK) << 2 |
1326  (t->nsh_base.length & NSH_TTL_L2_MASK) >> 6;
1327  rmp->length = t->nsh_base.length & NSH_LEN_MASK;
1328  rmp->md_type = t->nsh_base.md_type;
1329  rmp->next_protocol = t->nsh_base.next_protocol;
1330  rmp->nsp_nsi = htonl (t->nsh_base.nsp_nsi);
1331 
1332  if (t->nsh_base.md_type == 1)
1333  {
1334  rmp->tlv_length = 4;
1335  rmp->c1 = htonl (t->md.md1_data.c1);
1336  rmp->c2 = htonl (t->md.md1_data.c2);
1337  rmp->c3 = htonl (t->md.md1_data.c3);
1338  rmp->c4 = htonl (t->md.md1_data.c4);
1339  }
1340  else if (t->nsh_base.md_type == 2)
1341  {
1342  rmp->tlv_length = t->tlvs_len;
1343  clib_memcpy (rmp->tlv, t->tlvs_data, t->tlvs_len);
1344  }
1345 
1346  rmp->context = context;
1347 
1348  vl_msg_api_send_shmem (q, (u8 *) & rmp);
1349 }
1350 
1351 static void
1353 {
1355  nsh_main_t *nm = &nsh_main;
1356  nsh_entry_t *t;
1357  u32 entry_index;
1358 
1360  if (q == 0)
1361  {
1362  return;
1363  }
1364 
1365  entry_index = ntohl (mp->entry_index);
1366 
1367  if (~0 == entry_index)
1368  {
1369  pool_foreach (t, nm->nsh_entries, (
1370  {
1371  send_nsh_entry_details (t, q,
1372  mp->context);
1373  }
1374  ));
1375  }
1376  else
1377  {
1378  if (entry_index >= vec_len (nm->nsh_entries))
1379  {
1380  return;
1381  }
1382  t = &nm->nsh_entries[entry_index];
1383  send_nsh_entry_details (t, q, mp->context);
1384  }
1385 }
1386 
1387 static void send_nsh_map_details
1389 {
1391  nsh_main_t *nm = &nsh_main;
1392 
1393  rmp = vl_msg_api_alloc (sizeof (*rmp));
1394  memset (rmp, 0, sizeof (*rmp));
1395 
1396  rmp->_vl_msg_id = ntohs ((VL_API_NSH_MAP_DETAILS) + nm->msg_id_base);
1397  rmp->nsp_nsi = htonl (t->nsp_nsi);
1398  rmp->mapped_nsp_nsi = htonl (t->mapped_nsp_nsi);
1399  rmp->nsh_action = htonl (t->nsh_action);
1400  rmp->sw_if_index = htonl (t->sw_if_index);
1401  rmp->rx_sw_if_index = htonl (t->rx_sw_if_index);
1402  rmp->next_node = htonl (t->next_node);
1403 
1404  rmp->context = context;
1405 
1406  vl_msg_api_send_shmem (q, (u8 *) & rmp);
1407 }
1408 
1409 static void
1411 {
1413  nsh_main_t *nm = &nsh_main;
1414  nsh_map_t *t;
1415  u32 map_index;
1416 
1418  if (q == 0)
1419  {
1420  return;
1421  }
1422 
1423  map_index = ntohl (mp->map_index);
1424 
1425  if (~0 == map_index)
1426  {
1427  pool_foreach (t, nm->nsh_mappings, (
1428  {
1429  send_nsh_map_details (t, q,
1430  mp->context);
1431  }
1432  ));
1433  }
1434  else
1435  {
1436  if (map_index >= vec_len (nm->nsh_mappings))
1437  {
1438  return;
1439  }
1440  t = &nm->nsh_mappings[map_index];
1441  send_nsh_map_details (t, q, mp->context);
1442  }
1443 }
1444 
1445 static clib_error_t *
1447  unformat_input_t * input, vlib_cli_command_t * cmd)
1448 {
1449  nsh_main_t *nm = &nsh_main;
1450  nsh_entry_t *nsh_entry;
1451 
1452  if (pool_elts (nm->nsh_entries) == 0)
1453  vlib_cli_output (vm, "No nsh entries configured.");
1454 
1455  pool_foreach (nsh_entry, nm->nsh_entries, (
1456  {
1457  vlib_cli_output (vm, "%U",
1458  format_nsh_header,
1459  nsh_entry->rewrite);
1460  vlib_cli_output (vm,
1461  " rewrite_size: %d bytes",
1462  nsh_entry->rewrite_size);
1463  }
1464  ));
1465 
1466  return 0;
1467 }
1468 
1469 VLIB_CLI_COMMAND (show_nsh_entry_command, static) =
1470 {
1471 .path = "show nsh entry",.function = show_nsh_entry_command_fn,};
1472 
1473 
1474 /* Set up the API message handling tables */
1475 static clib_error_t *
1477 {
1478  nsh_main_t *nm __attribute__ ((unused)) = &nsh_main;
1479 #define _(N,n) \
1480  vl_msg_api_set_handlers((VL_API_##N + nm->msg_id_base), \
1481  #n, \
1482  vl_api_##n##_t_handler, \
1483  vl_noop_handler, \
1484  vl_api_##n##_t_endian, \
1485  vl_api_##n##_t_print, \
1486  sizeof(vl_api_##n##_t), 1);
1488 #undef _
1489 
1490  return 0;
1491 }
1492 
1493 static void
1495 {
1496 #define _(id,n,crc) \
1497  vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + nm->msg_id_base);
1498  foreach_vl_msg_name_crc_nsh;
1499 #undef _
1500 }
1501 
1502 always_inline void
1503 nsh_md2_encap (vlib_buffer_t * b, nsh_base_header_t * hdr,
1504  nsh_entry_t * nsh_entry)
1505 {
1506  nsh_main_t *nm = &nsh_main;
1507  nsh_base_header_t *nsh_base;
1508  nsh_tlv_header_t *opt0;
1509  nsh_tlv_header_t *limit0;
1510  nsh_tlv_header_t *nsh_md2;
1511  nsh_option_map_t *nsh_option;
1512  u8 old_option_size = 0;
1513  u8 new_option_size = 0;
1514 
1515  /* Populate the NSH Header */
1516  opt0 = (nsh_tlv_header_t *) (nsh_entry->tlvs_data);
1517  limit0 = (nsh_tlv_header_t *) (nsh_entry->tlvs_data + nsh_entry->tlvs_len);
1518 
1519  nsh_md2 = (nsh_tlv_header_t *) ((u8 *) hdr /*nsh_entry->rewrite */ +
1520  sizeof (nsh_base_header_t));
1521  nsh_entry->rewrite_size = sizeof (nsh_base_header_t);
1522 
1523  /* Scan the set of variable metadata, process ones that we understand */
1524  while (opt0 < limit0)
1525  {
1526  old_option_size = sizeof (nsh_tlv_header_t) + opt0->length;
1527  /* round to 4-byte */
1528  old_option_size = ((old_option_size + 3) >> 2) << 2;
1529 
1530  nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type);
1531  if (nsh_option == NULL)
1532  {
1533  goto next_tlv_md2;
1534  }
1535 
1536  if (nm->options[nsh_option->option_id])
1537  {
1538  if ((*nm->options[nsh_option->option_id]) (b, nsh_md2))
1539  {
1540  goto next_tlv_md2;
1541  }
1542 
1543  /* option length may be varied */
1544  new_option_size = sizeof (nsh_tlv_header_t) + nsh_md2->length;
1545  /* round to 4-byte */
1546  new_option_size = ((new_option_size + 3) >> 2) << 2;
1547  nsh_entry->rewrite_size += new_option_size;
1548 
1549  nsh_md2 = (nsh_tlv_header_t *) (((u8 *) nsh_md2) + new_option_size);
1550  opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size);
1551 
1552  }
1553  else
1554  {
1555  next_tlv_md2:
1556  opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size);
1557  }
1558  }
1559 
1560  /* update nsh header's length */
1561  nsh_base = (nsh_base_header_t *) nsh_entry->rewrite;
1562  nsh_base->length = (nsh_base->length & NSH_TTL_L2_MASK) |
1563  ((nsh_entry->rewrite_size >> 2) & NSH_LEN_MASK);
1564  return;
1565 }
1566 
1567 always_inline void
1569  nsh_base_header_t * hdr,
1570  u32 header_len,
1571  nsh_entry_t * nsh_entry, u32 * next, u32 drop_node_val)
1572 {
1573  nsh_main_t *nm = &nsh_main;
1574  nsh_base_header_t *nsh_base;
1575  nsh_tlv_header_t *opt0;
1576  nsh_tlv_header_t *limit0;
1577  nsh_tlv_header_t *nsh_md2;
1578  nsh_option_map_t *nsh_option;
1579  u8 old_option_size = 0;
1580  u8 new_option_size = 0;
1581 
1582  /* Populate the NSH Header */
1583  opt0 = (nsh_md2_data_t *) (hdr + 1);
1584  limit0 = (nsh_md2_data_t *) ((u8 *) hdr + header_len);
1585 
1586  nsh_md2 =
1587  (nsh_tlv_header_t *) (nsh_entry->rewrite + sizeof (nsh_base_header_t));
1588  nsh_entry->rewrite_size = sizeof (nsh_base_header_t);
1589 
1590  /* Scan the set of variable metadata, process ones that we understand */
1591  while (opt0 < limit0)
1592  {
1593  old_option_size = sizeof (nsh_tlv_header_t) + opt0->length;
1594  /* round to 4-byte */
1595  old_option_size = ((old_option_size + 3) >> 2) << 2;
1596 
1597  nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type);
1598  if (nsh_option == NULL)
1599  {
1600  goto next_tlv_md2;
1601  }
1602 
1603  if (nm->swap_options[nsh_option->option_id])
1604  {
1605  if ((*nm->swap_options[nsh_option->option_id]) (b, opt0, nsh_md2))
1606  {
1607  goto next_tlv_md2;
1608  }
1609 
1610  /* option length may be varied */
1611  new_option_size = sizeof (nsh_tlv_header_t) + nsh_md2->length;
1612  /* round to 4-byte */
1613  new_option_size = ((new_option_size + 3) >> 2) << 2;
1614  nsh_entry->rewrite_size += new_option_size;
1615  nsh_md2 = (nsh_tlv_header_t *) (((u8 *) nsh_md2) + new_option_size);
1616 
1617  opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size);
1618 
1619  }
1620  else
1621  {
1622  next_tlv_md2:
1623  opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size);
1624  }
1625  }
1626 
1627  /* update nsh header's length */
1628  nsh_base = (nsh_base_header_t *) nsh_entry->rewrite;
1629  nsh_base->length = (nsh_base->length & NSH_TTL_L2_MASK) |
1630  ((nsh_entry->rewrite_size >> 2) & NSH_LEN_MASK);
1631  return;
1632 }
1633 
1634 always_inline void
1636  nsh_base_header_t * hdr,
1637  u32 * header_len, u32 * next, u32 drop_node_val)
1638 {
1639  nsh_main_t *nm = &nsh_main;
1640  nsh_md2_data_t *opt0;
1641  nsh_md2_data_t *limit0;
1642  nsh_option_map_t *nsh_option;
1643  u8 option_len = 0;
1644 
1645  /* Populate the NSH Header */
1646  opt0 = (nsh_md2_data_t *) (hdr + 1);
1647  limit0 = (nsh_md2_data_t *) ((u8 *) hdr + *header_len);
1648 
1649  /* Scan the set of variable metadata, process ones that we understand */
1650  while (opt0 < limit0)
1651  {
1652  nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type);
1653  if (nsh_option == NULL)
1654  {
1655  *next = drop_node_val;
1656  return;
1657  }
1658 
1659  if (nm->pop_options[nsh_option->option_id])
1660  {
1661  if ((*nm->pop_options[nsh_option->option_id]) (b, opt0))
1662  {
1663  *next = drop_node_val;
1664  return;
1665  }
1666  }
1667  /* round to 4-byte */
1668  option_len = ((opt0->length + 3) >> 2) << 2;
1669  opt0 =
1670  (nsh_md2_data_t *) (((u8 *) opt0) + sizeof (nsh_md2_data_t) +
1671  option_len);
1672  *next =
1673  (nm->decap_v4_next_override) ? (nm->decap_v4_next_override) : (*next);
1674  *header_len = (nm->decap_v4_next_override) ? 0 : (*header_len);
1675  }
1676 
1677  return;
1678 }
1679 
1680 static uword
1682  vlib_node_runtime_t * node,
1683  vlib_frame_t * from_frame, u32 node_type)
1684 {
1685  u32 n_left_from, next_index, *from, *to_next;
1686  nsh_main_t *nm = &nsh_main;
1687 
1688  from = vlib_frame_vector_args (from_frame);
1689  n_left_from = from_frame->n_vectors;
1690 
1691  next_index = node->cached_next_index;
1692 
1693  while (n_left_from > 0)
1694  {
1695  u32 n_left_to_next;
1696 
1697  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1698 
1699  while (n_left_from >= 4 && n_left_to_next >= 2)
1700  {
1701  u32 bi0, bi1;
1702  vlib_buffer_t *b0, *b1;
1703  u32 next0 = NSH_NODE_NEXT_DROP, next1 = NSH_NODE_NEXT_DROP;
1704  uword *entry0, *entry1;
1705  nsh_base_header_t *hdr0 = 0, *hdr1 = 0;
1706  u32 header_len0 = 0, header_len1 = 0;
1707  u32 nsp_nsi0, nsp_nsi1;
1708  u32 ttl0, ttl1;
1709  u32 error0, error1;
1710  nsh_map_t *map0 = 0, *map1 = 0;
1711  nsh_entry_t *nsh_entry0 = 0, *nsh_entry1 = 0;
1712  nsh_base_header_t *encap_hdr0 = 0, *encap_hdr1 = 0;
1713  u32 encap_hdr_len0 = 0, encap_hdr_len1 = 0;
1714  nsh_proxy_session_by_key_t key0, key1;
1715  uword *p0, *p1;
1716  nsh_proxy_session_t *proxy0, *proxy1;
1717  u32 sw_if_index0 = 0, sw_if_index1 = 0;
1718  ethernet_header_t dummy_eth0, dummy_eth1;
1719 
1720  /* Prefetch next iteration. */
1721  {
1722  vlib_buffer_t *p2, *p3;
1723 
1724  p2 = vlib_get_buffer (vm, from[2]);
1725  p3 = vlib_get_buffer (vm, from[3]);
1726 
1727  vlib_prefetch_buffer_header (p2, LOAD);
1728  vlib_prefetch_buffer_header (p3, LOAD);
1729 
1730  CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
1731  CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
1732  }
1733 
1734  bi0 = from[0];
1735  bi1 = from[1];
1736  to_next[0] = bi0;
1737  to_next[1] = bi1;
1738  from += 2;
1739  to_next += 2;
1740  n_left_from -= 2;
1741  n_left_to_next -= 2;
1742 
1743  error0 = 0;
1744  error1 = 0;
1745 
1746  b0 = vlib_get_buffer (vm, bi0);
1747  b1 = vlib_get_buffer (vm, bi1);
1748  hdr0 = vlib_buffer_get_current (b0);
1749  hdr1 = vlib_buffer_get_current (b1);
1750 
1751  /* Process packet 0 */
1752  if (node_type == NSH_INPUT_TYPE)
1753  {
1754  nsp_nsi0 = hdr0->nsp_nsi;
1755  header_len0 = (hdr0->length & NSH_LEN_MASK) * 4;
1756  ttl0 = (hdr0->ver_o_c & NSH_TTL_H4_MASK) << 2 |
1757  (hdr0->length & NSH_TTL_L2_MASK) >> 6;
1758  ttl0 = ttl0 - 1;
1759  if (PREDICT_FALSE (ttl0 == 0))
1760  {
1761  error0 = NSH_NODE_ERROR_INVALID_TTL;
1762  goto trace0;
1763  }
1764  }
1765  else if (node_type == NSH_CLASSIFIER_TYPE)
1766  {
1767  nsp_nsi0 =
1768  clib_host_to_net_u32 (vnet_buffer (b0)->
1769  l2_classify.opaque_index);
1770  }
1771  else if (node_type == NSH_AWARE_VNF_PROXY_TYPE)
1772  {
1773  /* Push dummy Eth header */
1774  clib_memcpy (dummy_eth0.dst_address, dummy_dst_address, 6);
1775  clib_memcpy (dummy_eth0.src_address, dummy_src_address, 6);
1776  dummy_eth0.type = 0x0800;
1777  vlib_buffer_advance (b0, -(word) sizeof (ethernet_header_t));
1778  hdr0 = vlib_buffer_get_current (b0);
1779  clib_memcpy (hdr0, &dummy_eth0,
1780  (word) sizeof (ethernet_header_t));
1781 
1782  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
1783  nsp_nsi0 = nm->tunnel_index_by_sw_if_index[sw_if_index0];
1784  }
1785  else
1786  {
1787  memset (&key0, 0, sizeof (key0));
1788  key0.transport_type = NSH_NODE_NEXT_ENCAP_VXLAN4;
1789  key0.transport_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1790 
1791  p0 = hash_get_mem (nm->nsh_proxy_session_by_key, &key0);
1792  if (PREDICT_FALSE (p0 == 0))
1793  {
1794  error0 = NSH_NODE_ERROR_NO_PROXY;
1795  goto trace0;
1796  }
1797 
1798  proxy0 = pool_elt_at_index (nm->nsh_proxy_sessions, p0[0]);
1799  if (PREDICT_FALSE (proxy0 == 0))
1800  {
1801  error0 = NSH_NODE_ERROR_NO_PROXY;
1802  goto trace0;
1803  }
1804  nsp_nsi0 = proxy0->nsp_nsi;
1805  }
1806 
1807  entry0 = hash_get_mem (nm->nsh_mapping_by_key, &nsp_nsi0);
1808  if (PREDICT_FALSE (entry0 == 0))
1809  {
1810  error0 = NSH_NODE_ERROR_NO_MAPPING;
1811  goto trace0;
1812  }
1813 
1814  /* Entry should point to a mapping ... */
1815  map0 = pool_elt_at_index (nm->nsh_mappings, entry0[0]);
1816  if (PREDICT_FALSE (map0 == 0))
1817  {
1818  error0 = NSH_NODE_ERROR_NO_MAPPING;
1819  goto trace0;
1820  }
1821 
1822  /* set up things for next node to transmit ie which node to handle it and where */
1823  next0 = map0->next_node;
1824  vnet_buffer (b0)->sw_if_index[VLIB_TX] = map0->sw_if_index;
1825  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = map0->adj_index;
1826 
1827  if (PREDICT_FALSE (map0->nsh_action == NSH_ACTION_POP))
1828  {
1829  /* Manipulate MD2 */
1830  if (PREDICT_FALSE (hdr0->md_type == 2))
1831  {
1832  nsh_md2_decap (b0, hdr0, &header_len0, &next0,
1833  NSH_NODE_NEXT_DROP);
1834  if (PREDICT_FALSE (next0 == NSH_NODE_NEXT_DROP))
1835  {
1836  error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
1837  goto trace0;
1838  }
1839  vnet_buffer (b0)->sw_if_index[VLIB_RX] =
1840  map0->rx_sw_if_index;
1841  }
1842 
1843  /* Pop NSH header */
1844  vlib_buffer_advance (b0, (word) header_len0);
1845  goto trace0;
1846  }
1847 
1848  entry0 = hash_get_mem (nm->nsh_entry_by_key, &map0->mapped_nsp_nsi);
1849  if (PREDICT_FALSE (entry0 == 0))
1850  {
1851  error0 = NSH_NODE_ERROR_NO_ENTRY;
1852  goto trace0;
1853  }
1854 
1855  nsh_entry0 =
1856  (nsh_entry_t *) pool_elt_at_index (nm->nsh_entries, entry0[0]);
1857  encap_hdr0 = (nsh_base_header_t *) (nsh_entry0->rewrite);
1858  /* rewrite_size should equal to (encap_hdr0->length * 4) */
1859  encap_hdr_len0 = nsh_entry0->rewrite_size;
1860 
1861  if (PREDICT_TRUE (map0->nsh_action == NSH_ACTION_SWAP))
1862  {
1863  /* Manipulate MD2 */
1864  if (PREDICT_FALSE (hdr0->md_type == 2))
1865  {
1866  nsh_md2_swap (b0, hdr0, header_len0, nsh_entry0,
1867  &next0, NSH_NODE_NEXT_DROP);
1868  if (PREDICT_FALSE (next0 == NSH_NODE_NEXT_DROP))
1869  {
1870  error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
1871  goto trace0;
1872  }
1873  }
1874 
1875  /* Pop old NSH header */
1876  vlib_buffer_advance (b0, (word) header_len0);
1877 
1878  /* After processing, md2's length may be varied */
1879  encap_hdr_len0 = nsh_entry0->rewrite_size;
1880  /* Push new NSH header */
1881  vlib_buffer_advance (b0, -(word) encap_hdr_len0);
1882  hdr0 = vlib_buffer_get_current (b0);
1883  clib_memcpy (hdr0, encap_hdr0, (word) encap_hdr_len0);
1884 
1885  goto trace0;
1886  }
1887 
1888  if (PREDICT_TRUE (map0->nsh_action == NSH_ACTION_PUSH))
1889  {
1890  /* After processing, md2's length may be varied */
1891  encap_hdr_len0 = nsh_entry0->rewrite_size;
1892  /* Push new NSH header */
1893  vlib_buffer_advance (b0, -(word) encap_hdr_len0);
1894  hdr0 = vlib_buffer_get_current (b0);
1895  clib_memcpy (hdr0, encap_hdr0, (word) encap_hdr_len0);
1896 
1897  /* Manipulate MD2 */
1898  if (PREDICT_FALSE (nsh_entry0->nsh_base.md_type == 2))
1899  {
1900  nsh_md2_encap (b0, hdr0, nsh_entry0);
1901  }
1902 
1903  }
1904 
1905  trace0:
1906  b0->error = error0 ? node->errors[error0] : 0;
1907 
1908  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1909  {
1910  nsh_input_trace_t *tr =
1911  vlib_add_trace (vm, node, b0, sizeof (*tr));
1912  clib_memcpy (&(tr->trace_data), hdr0,
1913  ((hdr0->length & NSH_LEN_MASK) * 4));
1914  }
1915 
1916  /* Process packet 1 */
1917  if (node_type == NSH_INPUT_TYPE)
1918  {
1919  nsp_nsi1 = hdr1->nsp_nsi;
1920  header_len1 = (hdr1->length & NSH_LEN_MASK) * 4;
1921  ttl1 = (hdr1->ver_o_c & NSH_TTL_H4_MASK) << 2 |
1922  (hdr1->length & NSH_TTL_L2_MASK) >> 6;
1923  ttl1 = ttl1 - 1;
1924  if (PREDICT_FALSE (ttl1 == 0))
1925  {
1926  error1 = NSH_NODE_ERROR_INVALID_TTL;
1927  goto trace1;
1928  }
1929  }
1930  else if (node_type == NSH_CLASSIFIER_TYPE)
1931  {
1932  nsp_nsi1 =
1933  clib_host_to_net_u32 (vnet_buffer (b1)->
1934  l2_classify.opaque_index);
1935  }
1936  else if (node_type == NSH_AWARE_VNF_PROXY_TYPE)
1937  {
1938  /* Push dummy Eth header */
1939  clib_memcpy (dummy_eth1.dst_address, dummy_dst_address, 6);
1940  clib_memcpy (dummy_eth1.src_address, dummy_src_address, 6);
1941  dummy_eth1.type = 0x0800;
1942  vlib_buffer_advance (b1, -(word) sizeof (ethernet_header_t));
1943  hdr1 = vlib_buffer_get_current (b1);
1944  clib_memcpy (hdr1, &dummy_eth1,
1945  (word) sizeof (ethernet_header_t));
1946 
1947  sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_TX];
1948  nsp_nsi1 = nm->tunnel_index_by_sw_if_index[sw_if_index1];
1949  }
1950  else
1951  {
1952  memset (&key1, 0, sizeof (key1));
1953  key1.transport_type = NSH_NODE_NEXT_ENCAP_VXLAN4;
1954  key1.transport_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];
1955 
1956  p1 = hash_get_mem (nm->nsh_proxy_session_by_key, &key1);
1957  if (PREDICT_FALSE (p1 == 0))
1958  {
1959  error1 = NSH_NODE_ERROR_NO_PROXY;
1960  goto trace1;
1961  }
1962 
1963  proxy1 = pool_elt_at_index (nm->nsh_proxy_sessions, p1[0]);
1964  if (PREDICT_FALSE (proxy1 == 0))
1965  {
1966  error1 = NSH_NODE_ERROR_NO_PROXY;
1967  goto trace1;
1968  }
1969  nsp_nsi1 = proxy1->nsp_nsi;
1970  }
1971 
1972  entry1 = hash_get_mem (nm->nsh_mapping_by_key, &nsp_nsi1);
1973  if (PREDICT_FALSE (entry1 == 0))
1974  {
1975  error1 = NSH_NODE_ERROR_NO_MAPPING;
1976  goto trace1;
1977  }
1978 
1979  /* Entry should point to a mapping ... */
1980  map1 = pool_elt_at_index (nm->nsh_mappings, entry1[0]);
1981  if (PREDICT_FALSE (map1 == 0))
1982  {
1983  error1 = NSH_NODE_ERROR_NO_MAPPING;
1984  goto trace1;
1985  }
1986 
1987  /* set up things for next node to transmit ie which node to handle it and where */
1988  next1 = map1->next_node;
1989  vnet_buffer (b1)->sw_if_index[VLIB_TX] = map1->sw_if_index;
1990  vnet_buffer (b1)->ip.adj_index[VLIB_TX] = map1->adj_index;
1991 
1992  if (PREDICT_FALSE (map1->nsh_action == NSH_ACTION_POP))
1993  {
1994  /* Manipulate MD2 */
1995  if (PREDICT_FALSE (hdr1->md_type == 2))
1996  {
1997  nsh_md2_decap (b1, hdr1, &header_len1, &next1,
1998  NSH_NODE_NEXT_DROP);
1999  if (PREDICT_FALSE (next1 == NSH_NODE_NEXT_DROP))
2000  {
2001  error1 = NSH_NODE_ERROR_INVALID_OPTIONS;
2002  goto trace1;
2003  }
2004  vnet_buffer (b1)->sw_if_index[VLIB_RX] =
2005  map1->rx_sw_if_index;
2006  }
2007 
2008  /* Pop NSH header */
2009  vlib_buffer_advance (b1, (word) header_len1);
2010  goto trace1;
2011  }
2012 
2013  entry1 = hash_get_mem (nm->nsh_entry_by_key, &map1->mapped_nsp_nsi);
2014  if (PREDICT_FALSE (entry1 == 0))
2015  {
2016  error1 = NSH_NODE_ERROR_NO_ENTRY;
2017  goto trace1;
2018  }
2019 
2020  nsh_entry1 =
2021  (nsh_entry_t *) pool_elt_at_index (nm->nsh_entries, entry1[0]);
2022  encap_hdr1 = (nsh_base_header_t *) (nsh_entry1->rewrite);
2023  /* rewrite_size should equal to (encap_hdr0->length * 4) */
2024  encap_hdr_len1 = nsh_entry1->rewrite_size;
2025 
2026  if (PREDICT_TRUE (map1->nsh_action == NSH_ACTION_SWAP))
2027  {
2028  /* Manipulate MD2 */
2029  if (PREDICT_FALSE (hdr1->md_type == 2))
2030  {
2031  nsh_md2_swap (b1, hdr1, header_len1, nsh_entry1,
2032  &next1, NSH_NODE_NEXT_DROP);
2033  if (PREDICT_FALSE (next1 == NSH_NODE_NEXT_DROP))
2034  {
2035  error1 = NSH_NODE_ERROR_INVALID_OPTIONS;
2036  goto trace1;
2037  }
2038  }
2039 
2040  /* Pop old NSH header */
2041  vlib_buffer_advance (b1, (word) header_len1);
2042 
2043  /* After processing, md2's length may be varied */
2044  encap_hdr_len1 = nsh_entry1->rewrite_size;
2045  /* Push new NSH header */
2046  vlib_buffer_advance (b1, -(word) encap_hdr_len1);
2047  hdr1 = vlib_buffer_get_current (b1);
2048  clib_memcpy (hdr1, encap_hdr1, (word) encap_hdr_len1);
2049 
2050  goto trace1;
2051  }
2052 
2053  if (PREDICT_FALSE (map1->nsh_action == NSH_ACTION_PUSH))
2054  {
2055  /* After processing, md2's length may be varied */
2056  encap_hdr_len1 = nsh_entry1->rewrite_size;
2057  /* Push new NSH header */
2058  vlib_buffer_advance (b1, -(word) encap_hdr_len1);
2059  hdr1 = vlib_buffer_get_current (b1);
2060  clib_memcpy (hdr1, encap_hdr1, (word) encap_hdr_len1);
2061 
2062  /* Manipulate MD2 */
2063  if (PREDICT_FALSE (nsh_entry1->nsh_base.md_type == 2))
2064  {
2065  nsh_md2_encap (b1, hdr1, nsh_entry1);
2066  }
2067 
2068  }
2069 
2070  trace1:
2071  b1->error = error1 ? node->errors[error1] : 0;
2072 
2073  if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2074  {
2075  nsh_input_trace_t *tr =
2076  vlib_add_trace (vm, node, b1, sizeof (*tr));
2077  clib_memcpy (&(tr->trace_data), hdr1,
2078  ((hdr1->length & NSH_LEN_MASK) * 4));
2079  }
2080 
2081  vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
2082  n_left_to_next, bi0, bi1, next0,
2083  next1);
2084 
2085  }
2086 
2087  while (n_left_from > 0 && n_left_to_next > 0)
2088  {
2089  u32 bi0 = 0;
2090  vlib_buffer_t *b0 = NULL;
2091  u32 next0 = NSH_NODE_NEXT_DROP;
2092  uword *entry0;
2093  nsh_base_header_t *hdr0 = 0;
2094  u32 header_len0 = 0;
2095  u32 nsp_nsi0;
2096  u32 ttl0;
2097  u32 error0;
2098  nsh_map_t *map0 = 0;
2099  nsh_entry_t *nsh_entry0 = 0;
2100  nsh_base_header_t *encap_hdr0 = 0;
2101  u32 encap_hdr_len0 = 0;
2103  uword *p0;
2104  nsh_proxy_session_t *proxy0 = 0;
2105  u32 sw_if_index0 = 0;
2106  ethernet_header_t dummy_eth0;
2107 
2108  bi0 = from[0];
2109  to_next[0] = bi0;
2110  from += 1;
2111  to_next += 1;
2112  n_left_from -= 1;
2113  n_left_to_next -= 1;
2114  error0 = 0;
2115 
2116  b0 = vlib_get_buffer (vm, bi0);
2117  hdr0 = vlib_buffer_get_current (b0);
2118 
2119  if (node_type == NSH_INPUT_TYPE)
2120  {
2121  nsp_nsi0 = hdr0->nsp_nsi;
2122  header_len0 = (hdr0->length & NSH_LEN_MASK) * 4;
2123  ttl0 = (hdr0->ver_o_c & NSH_TTL_H4_MASK) << 2 |
2124  (hdr0->length & NSH_TTL_L2_MASK) >> 6;
2125  ttl0 = ttl0 - 1;
2126  if (PREDICT_FALSE (ttl0 == 0))
2127  {
2128  error0 = NSH_NODE_ERROR_INVALID_TTL;
2129  goto trace00;
2130  }
2131  }
2132  else if (node_type == NSH_CLASSIFIER_TYPE)
2133  {
2134  nsp_nsi0 =
2135  clib_host_to_net_u32 (vnet_buffer (b0)->
2136  l2_classify.opaque_index);
2137  }
2138  else if (node_type == NSH_AWARE_VNF_PROXY_TYPE)
2139  {
2140  /* Push dummy Eth header */
2141  clib_memcpy (dummy_eth0.dst_address, dummy_dst_address, 6);
2142  clib_memcpy (dummy_eth0.src_address, dummy_src_address, 6);
2143  dummy_eth0.type = 0x0800;
2144  vlib_buffer_advance (b0, -(word) sizeof (ethernet_header_t));
2145  hdr0 = vlib_buffer_get_current (b0);
2146  clib_memcpy (hdr0, &dummy_eth0,
2147  (word) sizeof (ethernet_header_t));
2148 
2149  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
2150  nsp_nsi0 = nm->tunnel_index_by_sw_if_index[sw_if_index0];
2151  }
2152  else
2153  {
2154  memset (&key0, 0, sizeof (key0));
2155  key0.transport_type = NSH_NODE_NEXT_ENCAP_VXLAN4;
2156  key0.transport_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
2157 
2158  p0 = hash_get_mem (nm->nsh_proxy_session_by_key, &key0);
2159  if (PREDICT_FALSE (p0 == 0))
2160  {
2161  error0 = NSH_NODE_ERROR_NO_PROXY;
2162  goto trace00;
2163  }
2164 
2165  proxy0 = pool_elt_at_index (nm->nsh_proxy_sessions, p0[0]);
2166  if (PREDICT_FALSE (proxy0 == 0))
2167  {
2168  error0 = NSH_NODE_ERROR_NO_PROXY;
2169  goto trace00;
2170  }
2171  nsp_nsi0 = proxy0->nsp_nsi;
2172  }
2173 
2174  entry0 = hash_get_mem (nm->nsh_mapping_by_key, &nsp_nsi0);
2175 
2176  if (PREDICT_FALSE (entry0 == 0))
2177  {
2178  error0 = NSH_NODE_ERROR_NO_MAPPING;
2179  goto trace00;
2180  }
2181 
2182  /* Entry should point to a mapping ... */
2183  map0 = pool_elt_at_index (nm->nsh_mappings, entry0[0]);
2184 
2185  if (PREDICT_FALSE (map0 == 0))
2186  {
2187  error0 = NSH_NODE_ERROR_NO_MAPPING;
2188  goto trace00;
2189  }
2190 
2191  /* set up things for next node to transmit ie which node to handle it and where */
2192  next0 = map0->next_node;
2193  vnet_buffer (b0)->sw_if_index[VLIB_TX] = map0->sw_if_index;
2194  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = map0->adj_index;
2195  vnet_buffer (b0)->sw_if_index[VLIB_RX] = map0->nsh_sw_if;
2196 
2197  if (PREDICT_FALSE (map0->nsh_action == NSH_ACTION_POP))
2198  {
2199  /* Manipulate MD2 */
2200  if (PREDICT_FALSE (hdr0->md_type == 2))
2201  {
2202  nsh_md2_decap (b0, hdr0, &header_len0, &next0,
2203  NSH_NODE_NEXT_DROP);
2204  if (PREDICT_FALSE (next0 == NSH_NODE_NEXT_DROP))
2205  {
2206  error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
2207  goto trace00;
2208  }
2209  vnet_buffer (b0)->sw_if_index[VLIB_RX] =
2210  map0->rx_sw_if_index;
2211  }
2212 
2213  /* Pop NSH header */
2214  vlib_buffer_advance (b0, (word) header_len0);
2215  goto trace00;
2216  }
2217 
2218  entry0 = hash_get_mem (nm->nsh_entry_by_key, &map0->mapped_nsp_nsi);
2219  if (PREDICT_FALSE (entry0 == 0))
2220  {
2221  error0 = NSH_NODE_ERROR_NO_ENTRY;
2222  goto trace00;
2223  }
2224 
2225  nsh_entry0 =
2226  (nsh_entry_t *) pool_elt_at_index (nm->nsh_entries, entry0[0]);
2227  encap_hdr0 = (nsh_base_header_t *) (nsh_entry0->rewrite);
2228  /* rewrite_size should equal to (encap_hdr0->length * 4) */
2229  encap_hdr_len0 = nsh_entry0->rewrite_size;
2230 
2231  if (PREDICT_TRUE (map0->nsh_action == NSH_ACTION_SWAP))
2232  {
2233  /* Manipulate MD2 */
2234  if (PREDICT_FALSE (hdr0->md_type == 2))
2235  {
2236  nsh_md2_swap (b0, hdr0, header_len0, nsh_entry0,
2237  &next0, NSH_NODE_NEXT_DROP);
2238  if (PREDICT_FALSE (next0 == NSH_NODE_NEXT_DROP))
2239  {
2240  error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
2241  goto trace00;
2242  }
2243  }
2244 
2245  /* Pop old NSH header */
2246  vlib_buffer_advance (b0, (word) header_len0);
2247 
2248  /* After processing, md2's length may be varied */
2249  encap_hdr_len0 = nsh_entry0->rewrite_size;
2250  /* Push new NSH header */
2251  vlib_buffer_advance (b0, -(word) encap_hdr_len0);
2252  hdr0 = vlib_buffer_get_current (b0);
2253  clib_memcpy (hdr0, encap_hdr0, (word) encap_hdr_len0);
2254 
2255  goto trace00;
2256  }
2257 
2258  if (PREDICT_TRUE (map0->nsh_action == NSH_ACTION_PUSH))
2259  {
2260  /* After processing, md2's length may be varied */
2261  encap_hdr_len0 = nsh_entry0->rewrite_size;
2262  /* Push new NSH header */
2263  vlib_buffer_advance (b0, -(word) encap_hdr_len0);
2264  hdr0 = vlib_buffer_get_current (b0);
2265  clib_memcpy (hdr0, encap_hdr0, (word) encap_hdr_len0);
2266  /* Manipulate MD2 */
2267  if (PREDICT_FALSE (nsh_entry0->nsh_base.md_type == 2))
2268  {
2269  nsh_md2_encap (b0, hdr0, nsh_entry0);
2270  }
2271 
2272  }
2273 
2274  trace00:b0->error = error0 ? node->errors[error0] : 0;
2275 
2276  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2277  {
2278  nsh_input_trace_t *tr =
2279  vlib_add_trace (vm, node, b0, sizeof (*tr));
2280  clib_memcpy (&(tr->trace_data[0]), hdr0,
2281  ((hdr0->length & NSH_LEN_MASK) * 4));
2282  }
2283 
2284  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2285  n_left_to_next, bi0, next0);
2286  }
2287 
2288  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2289 
2290  }
2291 
2292  return from_frame->n_vectors;
2293 }
2294 
2295 /**
2296  * @brief Graph processing dispatch function for NSH Input
2297  *
2298  * @node nsh_input
2299  * @param *vm
2300  * @param *node
2301  * @param *from_frame
2302  *
2303  * @return from_frame->n_vectors
2304  *
2305  */
2306 static uword
2308  vlib_frame_t * from_frame)
2309 {
2310  return nsh_input_map (vm, node, from_frame, NSH_INPUT_TYPE);
2311 }
2312 
2313 /**
2314  * @brief Graph processing dispatch function for NSH-Proxy
2315  *
2316  * @node nsh_proxy
2317  * @param *vm
2318  * @param *node
2319  * @param *from_frame
2320  *
2321  * @return from_frame->n_vectors
2322  *
2323  */
2324 static uword
2326  vlib_frame_t * from_frame)
2327 {
2328  return nsh_input_map (vm, node, from_frame, NSH_PROXY_TYPE);
2329 }
2330 
2331 /**
2332  * @brief Graph processing dispatch function for NSH Classifier
2333  *
2334  * @node nsh_classifier
2335  * @param *vm
2336  * @param *node
2337  * @param *from_frame
2338  *
2339  * @return from_frame->n_vectors
2340  *
2341  */
2342 static uword
2344  vlib_frame_t * from_frame)
2345 {
2346  return nsh_input_map (vm, node, from_frame, NSH_CLASSIFIER_TYPE);
2347 }
2348 
2349 /**
2350  * @brief Graph processing dispatch function for NSH-AWARE-VNF-PROXY
2351  *
2352  * @node nsh_aware_vnf_proxy
2353  * @param *vm
2354  * @param *node
2355  * @param *from_frame
2356  *
2357  * @return from_frame->n_vectors
2358  *
2359  */
2360 static uword
2362  vlib_frame_t * from_frame)
2363 {
2364  return nsh_input_map (vm, node, from_frame, NSH_AWARE_VNF_PROXY_TYPE);
2365 }
2366 
2367 static char *nsh_node_error_strings[] = {
2368 #define _(sym,string) string,
2370 #undef _
2371 };
2372 
2373 /* register nsh-input node */
2374 VLIB_REGISTER_NODE (nsh_input_node) =
2375 {
2376  .function = nsh_input,.name = "nsh-input",.vector_size =
2377  sizeof (u32),.format_trace = format_nsh_node_map_trace,.format_buffer =
2378  format_nsh_header,.type = VLIB_NODE_TYPE_INTERNAL,.n_errors =
2379  ARRAY_LEN (nsh_node_error_strings),.error_strings =
2380  nsh_node_error_strings,.n_next_nodes = NSH_NODE_N_NEXT,.next_nodes =
2381  {
2382 #define _(s,n) [NSH_NODE_NEXT_##s] = n,
2384 #undef _
2385  }
2386 ,};
2387 
2388 VLIB_NODE_FUNCTION_MULTIARCH (nsh_input_node, nsh_input);
2389 
2390 /* register nsh-proxy node */
2391 VLIB_REGISTER_NODE (nsh_proxy_node) =
2392 {
2393  .function = nsh_proxy,.name = "nsh-proxy",.vector_size =
2394  sizeof (u32),.format_trace = format_nsh_node_map_trace,.format_buffer =
2395  format_nsh_header,.type = VLIB_NODE_TYPE_INTERNAL,.n_errors =
2396  ARRAY_LEN (nsh_node_error_strings),.error_strings =
2397  nsh_node_error_strings,.n_next_nodes = NSH_NODE_N_NEXT,.next_nodes =
2398  {
2399 #define _(s,n) [NSH_NODE_NEXT_##s] = n,
2401 #undef _
2402  }
2403 ,};
2404 
2405 VLIB_NODE_FUNCTION_MULTIARCH (nsh_proxy_node, nsh_proxy);
2406 
2407 /* register nsh-classifier node */
2408 VLIB_REGISTER_NODE (nsh_classifier_node) =
2409 {
2410  .function = nsh_classifier,.name = "nsh-classifier",.vector_size =
2411  sizeof (u32),.format_trace = format_nsh_node_map_trace,.format_buffer =
2412  format_nsh_header,.type = VLIB_NODE_TYPE_INTERNAL,.n_errors =
2413  ARRAY_LEN (nsh_node_error_strings),.error_strings =
2414  nsh_node_error_strings,.n_next_nodes = NSH_NODE_N_NEXT,.next_nodes =
2415  {
2416 #define _(s,n) [NSH_NODE_NEXT_##s] = n,
2418 #undef _
2419  }
2420 ,};
2421 
2422 VLIB_NODE_FUNCTION_MULTIARCH (nsh_classifier_node, nsh_classifier);
2423 
2424 /* register nsh-aware-vnf-proxy node */
2425 VLIB_REGISTER_NODE (nsh_aware_vnf_proxy_node) =
2426 {
2427  .function = nsh_aware_vnf_proxy,.name = "nsh-aware-vnf-proxy",.vector_size =
2428  sizeof (u32),.format_trace = format_nsh_node_map_trace,.format_buffer =
2429  format_nsh_header,.type = VLIB_NODE_TYPE_INTERNAL,.n_errors =
2430  ARRAY_LEN (nsh_node_error_strings),.error_strings =
2431  nsh_node_error_strings,.n_next_nodes = NSH_NODE_N_NEXT,.next_nodes =
2432  {
2433 #define _(s,n) [NSH_NODE_NEXT_##s] = n,
2435 #undef _
2436  }
2437 ,};
2438 
2439 VLIB_NODE_FUNCTION_MULTIARCH (nsh_aware_vnf_proxy_node, nsh_aware_vnf_proxy);
2440 
2441 void
2443 {
2444  nsh_main_t *hm = &nsh_main;
2445  hm->decap_v4_next_override = next;
2446  return;
2447 }
2448 
2449 
2450 clib_error_t *
2452 {
2453  nsh_main_t *nm = &nsh_main;
2454  clib_error_t *error = 0;
2455  u8 *name;
2456  uword next_node;
2457 
2458  /* Init the main structures from VPP */
2459  nm->vlib_main = vm;
2460  nm->vnet_main = vnet_get_main ();
2461 
2462  /* Various state maintenance mappings */
2463  nm->nsh_mapping_by_key = hash_create_mem (0, sizeof (u32), sizeof (uword));
2464 
2466  = hash_create_mem (0, sizeof (u32), sizeof (uword));
2467 
2468  nm->nsh_entry_by_key = hash_create_mem (0, sizeof (u32), sizeof (uword));
2469 
2471  =
2472  hash_create_mem (0, sizeof (nsh_proxy_session_by_key_t), sizeof (uword));
2473 
2475  = hash_create_mem (0, sizeof (nsh_option_map_by_key_t), sizeof (uword));
2476 
2477  name = format (0, "nsh_%08x%c", api_version, 0);
2478 
2479  /* Set up the API */
2481  ((char *) name, VL_MSG_FIRST_AVAILABLE);
2482 
2483  error = nsh_plugin_api_hookup (vm);
2484 
2485  /* Add our API messages to the global name_crc hash table */
2487 
2488  /* Add dispositions to nodes that feed nsh-input */
2489  //alagalah - validate we don't really need to use the node value
2490  next_node =
2492  nsh_input_node.index);
2493  vlib_node_add_next (vm, vxlan4_gpe_input_node.index, nsh_proxy_node.index);
2495  nsh_aware_vnf_proxy_node.index);
2496  vxlan_gpe_register_decap_protocol (VXLAN_GPE_PROTOCOL_NSH, next_node);
2497 
2498  vlib_node_add_next (vm, vxlan6_gpe_input_node.index, nsh_input_node.index);
2499  vlib_node_add_next (vm, vxlan6_gpe_input_node.index, nsh_proxy_node.index);
2501  nsh_aware_vnf_proxy_node.index);
2502 
2503  vlib_node_add_next (vm, gre4_input_node.index, nsh_input_node.index);
2504  vlib_node_add_next (vm, gre4_input_node.index, nsh_proxy_node.index);
2506  nsh_aware_vnf_proxy_node.index);
2507 
2508  vlib_node_add_next (vm, gre6_input_node.index, nsh_input_node.index);
2509  vlib_node_add_next (vm, gre6_input_node.index, nsh_proxy_node.index);
2511  nsh_aware_vnf_proxy_node.index);
2512 
2513  /* Add NSH-Proxy support */
2514  vlib_node_add_next (vm, vxlan4_input_node.index, nsh_proxy_node.index);
2515  vlib_node_add_next (vm, vxlan6_input_node.index, nsh_proxy_node.index);
2516 
2517  /* Add NSH-Classifier support */
2518  vlib_node_add_next (vm, ip4_classify_node.index, nsh_classifier_node.index);
2519  vlib_node_add_next (vm, ip6_classify_node.index, nsh_classifier_node.index);
2521  nsh_classifier_node.index);
2522 
2523  /* Add Ethernet+NSH support */
2524  ethernet_register_input_type (vm, ETHERNET_TYPE_NSH, nsh_input_node.index);
2525 
2526  vec_free (name);
2527 
2528  return error;
2529 }
2530 
2532 
2533 /* *INDENT-OFF* */
2534 VLIB_PLUGIN_REGISTER () = {
2535  .version = VPP_BUILD_VER,
2536  .description = "Network Service Header",
2537 };
2538 /* *INDENT-ON* */
2539 
2540 /*
2541  * fd.io coding-style-patch-verification: ON
2542  *
2543  * Local Variables:
2544  * eval: (c-set-style "gnu")
2545  * End:
2546  */
u32 entry_index
Definition: nsh.api:44
u32 sw_if_index
Definition: nsh.h:82
vmrglw vmrglh hi
u32 nsh_action
Definition: nsh.h:74
#define VNET_SW_INTERFACE_FLAG_ADMIN_DOWN
Definition: nsh.h:238
static clib_error_t * show_nsh_map_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
CLI command for showing the mapping between NSH entries.
Definition: nsh.c:886
#define NSH_MD2_IOAM_CLASS
Definition: nsh.h:241
vlib_node_registration_t gre4_input_node
(constructor) VLIB_REGISTER_NODE (gre4_input_node)
Definition: node.c:575
static vlib_cli_command_t trace
(constructor) VLIB_CLI_COMMAND (trace)
Definition: vlib_api_cli.c:862
Reply from adding NSH entry (nsh_add_del_entry)
Definition: nsh.api:41
static u8 * format_nsh_tunnel_with_length(u8 *s, va_list *args)
Formatting function for tracing VXLAN GPE with length.
Definition: nsh.c:485
#define NSH_NSP_MASK
Definition: nsh_packet.h:113
ip_adjacency_t * adj_pool
The global adjacnecy pool.
Definition: adj.c:33
#define CLIB_UNUSED(x)
Definition: clib.h:81
int nsh_add_del_map(nsh_add_del_map_args_t *a, u32 *map_indexp)
Action function to add or del an nsh map.
Definition: nsh.c:505
u32 * tunnel_index_by_sw_if_index
Mapping from sw_if_index to tunnel index.
Definition: nsh.h:131
clib_error_t * vnet_hw_interface_set_flags(vnet_main_t *vnm, u32 hw_if_index, u32 flags)
Definition: interface.c:469
u8 tlv[248]
Definition: nsh.api:34
a
Definition: bitmap.h:538
static clib_error_t * nsh_add_del_map_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: nsh.c:708
vnet_main_t * vnet_get_main(void)
Definition: misc.c:47
static char * nsh_node_error_strings[]
Definition: nsh.c:2367
vlib_node_registration_t vxlan4_gpe_input_node
(constructor) VLIB_REGISTER_NODE (vxlan4_gpe_input_node)
Definition: decap.c:730
vlib_node_registration_t vxlan4_input_node
(constructor) VLIB_REGISTER_NODE (vxlan4_input_node)
Definition: decap.c:23
#define PREDICT_TRUE(x)
Definition: clib.h:108
u32 c4
Definition: nsh.api:32
u8 *(* trace[MAX_MD2_OPTIONS])(u8 *s, nsh_tlv_header_t *opt)
Definition: nsh.h:155
#define NULL
Definition: clib.h:57
u32 c1
Definition: nsh.api:63
u32 next_node
Definition: nsh.h:84
#define foreach_nsh_node_next
Definition: nsh.h:205
u8 src_address[6]
Definition: packet.h:56
VXLAN GPE definitions.
static vnet_hw_interface_t * vnet_get_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:523
u8 ver_o_c
Definition: nsh.api:25
vlib_node_registration_t vxlan6_gpe_input_node
(constructor) VLIB_REGISTER_NODE (vxlan6_gpe_input_node)
Definition: decap.c:755
u32 nsh_sw_if
Definition: nsh.h:79
#define NSH_LEN_MASK
Definition: nsh_packet.h:109
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:983
#define hash_set_mem(h, key, value)
Definition: hash.h:275
static u8 * format_nsh_name(u8 *s, va_list *args)
Naming for NSH tunnel.
Definition: nsh.c:433
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
#define VNET_HW_INTERFACE_FLAG_LINK_UP
Definition: interface.h:494
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:448
u32 nsp_nsi
Definition: nsh.api:23
static clib_error_t * nsh_interface_admin_up_down(vnet_main_t *vnm, u32 nsh_hw_if, u32 flags)
CLI function for NSH admin up/down.
Definition: nsh.c:450
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:472
u8 * format_nsh_node_map_trace(u8 *s, va_list *args)
Definition: nsh.c:412
int nsh_add_del_entry(nsh_add_del_entry_args_t *a, u32 *entry_indexp)
Action function for adding an NSH entry nsh_add_del_entry_args_t *a: host order.
Definition: nsh.c:1013
u32 context
Definition: nsh.api:50
const char dummy_dst_address[6]
Definition: nsh.c:67
void * vl_msg_api_alloc(int nbytes)
u32 c1
Definition: nsh.api:29
#define foreach_nsh_plugin_api_msg
Definition: nsh.c:117
static uword vlib_node_add_next(vlib_main_t *vm, uword node, uword next_node)
Definition: node_funcs.h:1118
unsigned char u8
Definition: types.h:56
static adj_index_t nsh_get_adj_by_sw_if_index(u32 sw_if_index)
Definition: nsh.c:690
u8 tlv[248]
Definition: nsh.api:68
nsh_base_header_t nsh_base
Definition: nsh.h:40
u32 c2
Definition: nsh.api:30
vlib_node_registration_t ip4_classify_node
(constructor) VLIB_REGISTER_NODE (ip4_classify_node)
Definition: ip_classify.c:40
/**
Definition: nsh.api:19
nsh_proxy_session_t * nsh_proxy_sessions
Definition: nsh.h:123
u32 client_index
Definition: nsh.api:49
u8 length
Definition: nsh.api:61
u8 options_size[MAX_MD2_OPTIONS]
Definition: nsh.h:145
static void nsh_md2_decap(vlib_buffer_t *b, nsh_base_header_t *hdr, u32 *header_len, u32 *next, u32 drop_node_val)
Definition: nsh.c:1635
memset(h->entries, 0, sizeof(h->entries[0])*entries)
u32 context
Definition: nsh.api:55
vlib_node_registration_t l2_input_classify_node
(constructor) VLIB_REGISTER_NODE (l2_input_classify_node)
i64 word
Definition: types.h:111
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:443
int(* add_options[MAX_MD2_OPTIONS])(u8 *opt, u8 *opt_size)
Definition: nsh.h:146
u8 is_add
Definition: nsh.h:55
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:163
u8 next_protocol
Definition: nsh.api:28
u32 sw_if_index
Definition: vxlan_gbp.api:39
#define always_inline
Definition: clib.h:94
u8 dst_address[6]
Definition: packet.h:55
svm_queue_t unix_shared_memory_queue_t
Definition: queue.h:132
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:187
#define clib_error_return(e, args...)
Definition: error.h:99
#define foreach_copy_nsh_base_hdr_field
Definition: nsh.h:180
nsh_entry_t * nsh_entries
Definition: nsh.h:110
vl_msg_id_t
Definition: nsh.c:33
u32 adj_index
Definition: nsh.h:85
#define hash_get_pair(h, key)
Definition: hash.h:252
unsigned int u32
Definition: types.h:88
u32 * free_nsh_tunnel_hw_if_indices
Free vlib hw_if_indices.
Definition: nsh.h:129
void vxlan_gpe_register_decap_protocol(u8 protocol_id, uword next_node_index)
Definition: decap.c:685
u32 vnet_register_interface(vnet_main_t *vnm, u32 dev_class_index, u32 dev_instance, u32 hw_class_index, u32 hw_instance)
Definition: interface.c:703
static uword nsh_aware_vnf_proxy(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Graph processing dispatch function for NSH-AWARE-VNF-PROXY.
Definition: nsh.c:2361
u16 msg_id_base
Definition: nsh.h:107
static u8 * format_nsh_action(u8 *s, va_list *args)
Definition: nsh.c:330
VLIB_NODE_FUNCTION_MULTIARCH(nsh_input_node, nsh_input)
static uword nsh_proxy(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Graph processing dispatch function for NSH-Proxy.
Definition: nsh.c:2325
static uword unformat_nsh_action(unformat_input_t *input, va_list *args)
CLI command for NSH map.
Definition: nsh.c:670
unformat_function_t unformat_line_input
Definition: format.h:282
u32 c3
Definition: nsh.api:31
static uword nsh_classifier(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Graph processing dispatch function for NSH Classifier.
Definition: nsh.c:2343
u32 c2
Definition: nsh.api:64
#define hash_create_mem(elts, key_bytes, value_bytes)
Definition: hash.h:661
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:464
#define hash_unset_mem(h, key)
Definition: hash.h:291
Definition: nsh.h:59
nsh_map_t * nsh_mappings
Definition: nsh.h:116
u32 adj_get_sw_if_index(adj_index_t ai)
Return the sw interface index of the adjacency.
Definition: adj.c:413
uword * nsh_entry_by_key
Definition: nsh.h:113
VLIB_PLUGIN_REGISTER()
#define NSH_O_BIT
Definition: nsh_packet.h:104
struct _unformat_input_t unformat_input_t
u8 * rewrite
Rewrite string.
Definition: nsh.h:50
unsigned short u16
Definition: types.h:57
static void vl_api_nsh_add_del_entry_t_handler(vl_api_nsh_add_del_entry_t *mp)
API message handler.
Definition: nsh.c:1269
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:205
int nsh_md2_unregister_option(u16 class, u8 type, int options(vlib_buffer_t *b, nsh_tlv_header_t *opt), u8 *trace(u8 *s, nsh_tlv_header_t *opt))
Definition: nsh.c:204
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:274
union nsh_entry_t::@534 md
static void send_nsh_map_details(nsh_map_t *t, unix_shared_memory_queue_t *q, u32 context)
Definition: nsh.c:1388
#define PREDICT_FALSE(x)
Definition: clib.h:107
u8 tlv_length
Definition: nsh.api:67
nsh_option_map_t * nsh_option_mappings
Definition: nsh.h:134
vlib_node_registration_t vxlan6_input_node
(constructor) VLIB_REGISTER_NODE (vxlan6_input_node)
Definition: decap.c:24
#define vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next, n_left_to_next, bi0, bi1, next0, next1)
Finish enqueueing two buffers forward in the graph.
Definition: buffer_node.h:70
u32 c4
Definition: nsh.api:66
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:218
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:364
u8 name[64]
Definition: memclnt.api:151
uword decap_v4_next_override
Definition: nsh.h:156
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:138
static uword dummy_interface_tx(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: nsh.c:462
int(* pop_options[MAX_MD2_OPTIONS])(vlib_buffer_t *b, nsh_tlv_header_t *opt)
Definition: nsh.h:153
API main structure, used by both vpp and binary API clients.
Definition: api_common.h:201
u32 flags
Definition: vhost_user.h:115
Definition: nsh.h:54
#define pool_get_aligned(P, E, A)
Allocate an object E from a pool P (general version).
Definition: pool.h:188
int(* swap_options[MAX_MD2_OPTIONS])(vlib_buffer_t *b, nsh_tlv_header_t *old_opt, nsh_tlv_header_t *new_opt)
Definition: nsh.h:150
clib_error_t * nsh_init(vlib_main_t *vm)
Definition: nsh.c:2451
void vl_msg_api_send_shmem(svm_queue_t *q, u8 *elem)
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:155
#define UNFORMAT_END_OF_INPUT
Definition: format.h:144
u16 n_vectors
Definition: node.h:401
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:79
vlib_main_t * vm
Definition: buffer.c:294
VNET_HW_INTERFACE_CLASS(nsh_hw_class)
static void send_nsh_entry_details(nsh_entry_t *t, unix_shared_memory_queue_t *q, u32 context)
Definition: nsh.c:1315
u8 md_type
Definition: nsh.api:24
svm_queue_t * vl_api_client_index_to_input_queue(u32 index)
Definition: memory_api.c:759
nsh_option_map_t * nsh_md2_lookup_option(u16 class, u8 type)
Definition: nsh.c:181
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:339
static clib_error_t * nsh_plugin_api_hookup(vlib_main_t *vm)
Definition: nsh.c:1476
u8 length
Definition: nsh.api:27
#define MAX_NSH_HEADER_LEN
Definition: nsh.h:247
#define clib_warning(format, args...)
Definition: error.h:59
uword * nsh_proxy_session_by_key
Definition: nsh.h:126
u32 nsp_nsi
Key for nsh_header_t entry: 24bit NSP 8bit NSI.
Definition: nsh.h:64
#define clib_memcpy(a, b, c)
Definition: string.h:75
static void nsh_md2_swap(vlib_buffer_t *b, nsh_base_header_t *hdr, u32 header_len, nsh_entry_t *nsh_entry, u32 *next, u32 drop_node_val)
Definition: nsh.c:1568
#define NSH_NSI_MASK
Definition: nsh_packet.h:112
int nsh_add_del_proxy_session(nsh_add_del_map_args_t *a)
Action function to add or del an nsh-proxy-session.
Definition: nsh.c:608
u32 nsh_hw_if
vnet intfc hw_if_index
Definition: nsh.h:77
u8 tlvs_len
Definition: nsh.h:45
u32 adj_index_t
An index for adjacencies.
Definition: adj_types.h:30
#define ARRAY_LEN(x)
Definition: clib.h:61
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:455
VNET_DEVICE_CLASS(nsh_device_class, static)
#define MAX_METADATA_LEN
Definition: nsh.h:32
void nsh_md2_set_next_ioam_export_override(uword next)
Definition: nsh.c:2442
#define foreach_nsh_node_error
Definition: nsh.h:188
#define MAX_NSH_OPTION_LEN
Definition: nsh.h:248
u8 * default_build_rewrite(vnet_main_t *vnm, u32 sw_if_index, vnet_link_t link_type, const void *dst_address)
Return a complete, zero-length (aka dummy) rewrite.
Definition: interface.c:1513
u32 nsp_nsi
Definition: nsh.api:57
nsh_tlv_header_t nsh_md2_data_t
Definition: nsh_packet.h:93
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:155
u32 mapped_nsp_nsi
Key for nsh_header_t entry to map to.
Definition: nsh.h:72
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:513
static uword nsh_input_map(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame, u32 node_type)
Definition: nsh.c:1681
u8 next_protocol
Definition: nsh.api:62
u32 rx_sw_if_index
Definition: nsh.h:83
u32 option_id
Definition: nsh.h:29
nsh_map_t map
Definition: nsh.h:90
static void clib_mem_free(void *p)
Definition: mem.h:205
Set or delete a mapping from one NSH header to another and its egress (decap to inner packet...
Definition: nsh.api:86
nsh_md1_data_t md1_data
Definition: nsh.h:42
Definition: nsh.api:48
u8 ver_o_c
Definition: nsh.api:59
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:218
static clib_error_t * show_nsh_entry_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: nsh.c:1446
u8 ttl
Definition: nsh.api:60
static void setup_message_id_table(nsh_main_t *nm, api_main_t *am)
Definition: nsh.c:1494
vlib_main_t * vlib_main
Definition: nsh.h:163
static void * clib_mem_alloc(uword size)
Definition: mem.h:132
u8 rewrite_size
Definition: nsh.h:51
u8 is_add
Definition: nsh.api:22
void ethernet_register_input_type(vlib_main_t *vm, ethernet_type_t type, u32 node_index)
Definition: node.c:1322
static clib_error_t * nsh_add_del_entry_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
CLI command for adding NSH entry.
Definition: nsh.c:1099
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:57
int(* options[MAX_MD2_OPTIONS])(vlib_buffer_t *b, nsh_tlv_header_t *opt)
Definition: nsh.h:148
Definition: defs.h:47
u8 tlv_length
Definition: nsh.api:33
u8 * tlvs_data
Definition: nsh.h:46
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
static void vl_api_nsh_add_del_map_t_handler(vl_api_nsh_add_del_map_t *mp)
API message handler.
Definition: nsh.c:850
Definition: nsh.api:54
u64 uword
Definition: types.h:112
u8 trace_data[256]
Definition: nsh.h:173
static void unformat_free(unformat_input_t *i)
Definition: format.h:162
u8 md_type
Definition: nsh.api:58
#define NSH_NSP_SHIFT
Definition: nsh_packet.h:114
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:267
u32 c3
Definition: nsh.api:65
uword * nsh_option_map_by_key
Definition: nsh.h:136
a point 2 point interface
Definition: interface.h:381
vnet_main_t * vnet_main
Definition: nsh.h:164
#define NSH_TTL_L2_MASK
Definition: nsh_packet.h:108
#define hash_get_mem(h, key)
Definition: hash.h:269
int nsh_header_rewrite(nsh_entry_t *nsh_entry)
Definition: nsh.c:911
#define vnet_buffer(b)
Definition: buffer.h:344
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
Reply from adding NSH map (nsh_add_del_map)
Definition: nsh.api:102
static void vl_api_nsh_entry_dump_t_handler(vl_api_nsh_entry_dump_t *mp)
Definition: nsh.c:1352
int nsh_md2_register_option(u16 class, u8 type, u8 option_size, int add_options(u8 *opt, u8 *opt_size), int options(vlib_buffer_t *b, nsh_tlv_header_t *opt), int swap_options(vlib_buffer_t *b, nsh_tlv_header_t *old_opt, nsh_tlv_header_t *new_opt), int pop_options(vlib_buffer_t *b, nsh_tlv_header_t *opt), u8 *trace(u8 *s, nsh_tlv_header_t *opt))
Definition: nsh.c:125
u8 ttl
Definition: nsh.api:26
static void nsh_md2_encap(vlib_buffer_t *b, nsh_base_header_t *hdr, nsh_entry_t *nsh_entry)
Definition: nsh.c:1503
static void vl_api_nsh_map_dump_t_handler(vl_api_nsh_map_dump_t *mp)
Definition: nsh.c:1410
vlib_node_registration_t gre6_input_node
(constructor) VLIB_REGISTER_NODE (gre6_input_node)
Definition: node.c:596
u8 data[0]
Packet data.
Definition: buffer.h:175
static uword nsh_input(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Graph processing dispatch function for NSH Input.
Definition: nsh.c:2307
clib_error_t * vnet_sw_interface_set_flags(vnet_main_t *vnm, u32 sw_if_index, u32 flags)
Definition: interface.c:477
uword * nsh_mapping_by_mapped_key
Definition: nsh.h:120
Note: rewrite and rewrite_size used to support varied nsh header.
Definition: nsh.h:36
u8 * format_nsh_header(u8 *s, va_list *args)
Definition: nsh.c:245
#define NSH_TTL_H4_MASK
Definition: nsh_packet.h:107
nsh_main_t nsh_main
Definition: nsh.h:167
vlib_node_registration_t ip6_classify_node
(constructor) VLIB_REGISTER_NODE (ip6_classify_node)
Definition: ip_classify.c:41
#define pool_foreach_index(i, v, body)
Iterate pool by index.
Definition: pool.h:488
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header, unspecified alignment)
Definition: vec.h:486
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:116
u32 entry_index
Definition: nsh.api:51
api_main_t api_main
Definition: api_shared.c:35
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:725
uword * nsh_mapping_by_key
Definition: nsh.h:119
#define NSH_C_BIT
Definition: nsh_packet.h:105
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:58
uword key
Definition: hash.h:162
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
Definition: defs.h:46
#define REPLY_MACRO2(t, body)
Definition: nsh.c:93
nsh_entry_t nsh_entry
Definition: nsh.h:56
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:170
u8 * format_nsh_map(u8 *s, va_list *args)
Definition: nsh.c:349
const char dummy_src_address[6]
Definition: nsh.c:68
u16 vl_msg_api_get_msg_ids(const char *name, int n)
Definition: api_shared.c:865
#define NSH_MD2_IOAM_OPTION_TYPE_TRACE
Definition: nsh.h:242
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128