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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <vnet/vnet.h>
19 #include <vnet/plugin/plugin.h>
21 #include <vnet/gre/gre.h>
22 #include <vnet/vxlan/vxlan.h>
23 #include <vnet/vxlan-gpe/vxlan_gpe.h>
24 #include <vnet/l2/l2_classify.h>
25 #include <vnet/adj/adj.h>
27 #include <vlibapi/api.h>
28 #include <vlibmemory/api.h>
29 #include <vpp/app/version.h>
31 /* define message IDs */
32 #define vl_msg_id(n,h) n,
35 #include <nsh/nsh.api.h>
36 /* We'll want to know how many messages IDs we need... */
37 VL_MSG_FIRST_AVAILABLE,
41 /* define message structures */
43 #include <nsh/nsh.api.h>
46 /* define generated endian-swappers */
48 #include <nsh/nsh.api.h>
51 /* instantiate all the print functions we know about */
52 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
54 #include <nsh/nsh.api.h>
57 /* Get the API version number */
58 #define vl_api_version(n,v) static u32 api_version=(v);
59 #include <nsh/nsh.api.h>
62 #define vl_msg_name_crc_list
63 #include <nsh/nsh.api.h>
64 #undef vl_msg_name_crc_list
67 * A handy macro to set up a message reply.
68 * Assumes that the following variables are available:
69 * mp - pointer to request message
70 * rmp - pointer to reply message type
74 #define REPLY_MACRO(t) \
76 unix_shared_memory_queue_t * q = \
77 vl_api_client_index_to_input_queue (mp->client_index); \
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); \
86 vl_msg_api_send_shmem (q, (u8 *)&rmp); \
89 #define REPLY_MACRO2(t, body) \
91 unix_shared_memory_queue_t * q; \
92 rv = vl_msg_api_pd_handler (mp, rv); \
93 q = vl_api_client_index_to_input_queue (mp->client_index); \
97 rmp = vl_msg_api_alloc (sizeof (*rmp)); \
98 rmp->_vl_msg_id = ntohs((t)+nm->msg_id_base); \
99 rmp->context = mp->context; \
100 rmp->retval = ntohl(rv); \
101 do {body;} while (0); \
102 vl_msg_api_send_shmem (q, (u8 *)&rmp); \
107 vl_print (handle, (char *)s); \
111 /* List of message types that this plugin understands */
113 #define foreach_nsh_plugin_api_msg \
114 _(NSH_ADD_DEL_ENTRY, nsh_add_del_entry) \
115 _(NSH_ENTRY_DUMP, nsh_entry_dump) \
116 _(NSH_ADD_DEL_MAP, nsh_add_del_map) \
117 _(NSH_MAP_DUMP, nsh_map_dump)
119 /* Uses network order's class and type to register */
121 nsh_md2_register_option (u16 class,
124 int add_options (u8 * opt,
126 int options (vlib_buffer_t * b,
127 nsh_tlv_header_t * opt),
128 int swap_options (vlib_buffer_t * b,
129 nsh_tlv_header_t * old_opt,
130 nsh_tlv_header_t * new_opt),
131 int pop_options (vlib_buffer_t * b,
132 nsh_tlv_header_t * opt),
133 u8 * trace (u8 * s, nsh_tlv_header_t * opt))
135 nsh_main_t *nm = &nsh_main;
136 nsh_option_map_by_key_t key, *key_copy;
138 nsh_option_map_t *nsh_option;
144 p = hash_get_mem (nm->nsh_option_map_by_key, &key);
145 /* Already registered */
151 pool_get_aligned (nm->nsh_option_mappings, nsh_option,
152 CLIB_CACHE_LINE_BYTES);
153 memset (nsh_option, 0, sizeof (*nsh_option));
154 nsh_option->option_id = nsh_option - nm->nsh_option_mappings;
156 key_copy = clib_mem_alloc (sizeof (*key_copy));
157 clib_memcpy (key_copy, &key, sizeof (*key_copy));
158 hash_set_mem (nm->nsh_option_map_by_key, key_copy,
159 nsh_option - nm->nsh_option_mappings);
161 if (option_size > (MAX_NSH_OPTION_LEN + sizeof (nsh_tlv_header_t)))
165 nm->options_size[nsh_option->option_id] = option_size;
166 nm->add_options[nsh_option->option_id] = add_options;
167 nm->options[nsh_option->option_id] = options;
168 nm->swap_options[nsh_option->option_id] = swap_options;
169 nm->pop_options[nsh_option->option_id] = pop_options;
170 nm->trace[nsh_option->option_id] = trace;
175 /* Uses network order's class and type to lookup */
177 nsh_md2_lookup_option (u16 class, u8 type)
179 nsh_main_t *nm = &nsh_main;
180 nsh_option_map_by_key_t key;
187 p = hash_get_mem (nm->nsh_option_map_by_key, &key);
194 return pool_elt_at_index (nm->nsh_option_mappings, p[0]);
198 /* Uses network order's class and type to unregister */
200 nsh_md2_unregister_option (u16 class,
202 int options (vlib_buffer_t * b,
203 nsh_tlv_header_t * opt),
204 u8 * trace (u8 * s, nsh_tlv_header_t * opt))
206 nsh_main_t *nm = &nsh_main;
207 nsh_option_map_by_key_t key, *key_copy;
210 nsh_option_map_t *nsh_option;
216 p = hash_get_mem (nm->nsh_option_map_by_key, &key);
223 nsh_option = pool_elt_at_index (nm->nsh_option_mappings, p[0]);
224 nm->options[nsh_option->option_id] = NULL;
225 nm->add_options[nsh_option->option_id] = NULL;
226 nm->pop_options[nsh_option->option_id] = NULL;
227 nm->trace[nsh_option->option_id] = NULL;
229 hp = hash_get_pair (nm->nsh_option_map_by_key, &key);
230 key_copy = (void *) (hp->key);
231 hash_unset_mem (nm->nsh_option_map_by_key, &key_copy);
232 clib_mem_free (key_copy);
234 pool_put (nm->nsh_option_mappings, nsh_option);
239 /* format from network order */
241 format_nsh_header (u8 * s, va_list * args)
243 nsh_main_t *nm = &nsh_main;
244 nsh_md2_data_t *opt0;
245 nsh_md2_data_t *limit0;
246 nsh_option_map_t *nsh_option;
249 u8 *header = va_arg (*args, u8 *);
250 nsh_base_header_t *nsh_base = (nsh_base_header_t *) header;
251 nsh_md1_data_t *nsh_md1 = (nsh_md1_data_t *) (nsh_base + 1);
252 nsh_md2_data_t *nsh_md2 = (nsh_md2_data_t *) (nsh_base + 1);
253 opt0 = (nsh_md2_data_t *) nsh_md2;
254 limit0 = (nsh_md2_data_t *) ((u8 *) nsh_md2 +
255 ((nsh_base->length & NSH_LEN_MASK) * 4
256 - sizeof (nsh_base_header_t)));
258 s = format (s, "nsh ver %d ", (nsh_base->ver_o_c >> 6));
259 if (nsh_base->ver_o_c & NSH_O_BIT)
260 s = format (s, "O-set ");
262 if (nsh_base->ver_o_c & NSH_C_BIT)
263 s = format (s, "C-set ");
265 s = format (s, "ttl %d ", (nsh_base->ver_o_c & NSH_TTL_H4_MASK) << 2 |
266 (nsh_base->length & NSH_TTL_L2_MASK) >> 6);
268 s = format (s, "len %d (%d bytes) md_type %d next_protocol %d\n",
269 (nsh_base->length & NSH_LEN_MASK),
270 (nsh_base->length & NSH_LEN_MASK) * 4,
271 nsh_base->md_type, nsh_base->next_protocol);
273 s = format (s, " service path %d service index %d\n",
274 (clib_net_to_host_u32 (nsh_base->nsp_nsi) >> NSH_NSP_SHIFT) &
276 clib_net_to_host_u32 (nsh_base->nsp_nsi) & NSH_NSI_MASK);
278 if (nsh_base->md_type == 1)
280 s = format (s, " c1 %d c2 %d c3 %d c4 %d\n",
281 clib_net_to_host_u32 (nsh_md1->c1),
282 clib_net_to_host_u32 (nsh_md1->c2),
283 clib_net_to_host_u32 (nsh_md1->c3),
284 clib_net_to_host_u32 (nsh_md1->c4));
286 else if (nsh_base->md_type == 2)
288 s = format (s, " Supported TLVs: \n");
290 /* Scan the set of variable metadata, network order */
291 while (opt0 < limit0)
293 nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type);
294 if (nsh_option != NULL)
296 if (nm->trace[nsh_option->option_id] != NULL)
298 s = (*nm->trace[nsh_option->option_id]) (s, opt0);
303 format (s, "\n untraced option %d length %d",
304 opt0->type, opt0->length);
310 format (s, "\n unrecognized option %d length %d",
311 opt0->type, opt0->length);
314 /* round to 4-byte */
315 option_len = ((opt0->length + 3) >> 2) << 2;
317 (nsh_md2_data_t *) (((u8 *) opt0) + sizeof (nsh_md2_data_t) +
326 format_nsh_action (u8 * s, va_list * args)
328 u32 nsh_action = va_arg (*args, u32);
332 case NSH_ACTION_SWAP:
333 return format (s, "swap");
334 case NSH_ACTION_PUSH:
335 return format (s, "push");
337 return format (s, "pop");
339 return format (s, "unknown %d", nsh_action);
345 format_nsh_map (u8 * s, va_list * args)
347 nsh_map_t *map = va_arg (*args, nsh_map_t *);
349 s = format (s, "nsh entry nsp: %d nsi: %d ",
350 (map->nsp_nsi >> NSH_NSP_SHIFT) & NSH_NSP_MASK,
351 map->nsp_nsi & NSH_NSI_MASK);
352 s = format (s, "maps to nsp: %d nsi: %d ",
353 (map->mapped_nsp_nsi >> NSH_NSP_SHIFT) & NSH_NSP_MASK,
354 map->mapped_nsp_nsi & NSH_NSI_MASK);
356 s = format (s, " nsh_action %U\n", format_nsh_action, map->nsh_action);
358 switch (map->next_node)
360 case NSH_NODE_NEXT_ENCAP_GRE4:
362 s = format (s, "encapped by GRE4 intf: %d", map->sw_if_index);
365 case NSH_NODE_NEXT_ENCAP_GRE6:
367 s = format (s, "encapped by GRE6 intf: %d", map->sw_if_index);
370 case NSH_NODE_NEXT_ENCAP_VXLANGPE:
372 s = format (s, "encapped by VXLAN GPE intf: %d", map->sw_if_index);
375 case NSH_NODE_NEXT_ENCAP_VXLAN4:
377 s = format (s, "encapped by VXLAN4 intf: %d", map->sw_if_index);
380 case NSH_NODE_NEXT_ENCAP_VXLAN6:
382 s = format (s, "encapped by VXLAN6 intf: %d", map->sw_if_index);
385 case NSH_NODE_NEXT_DECAP_ETH_INPUT:
387 s = format (s, "encap-none");
390 case NSH_NODE_NEXT_ENCAP_LISP_GPE:
392 s = format (s, "encapped by LISP GPE intf: %d", map->sw_if_index);
395 case NSH_NODE_NEXT_ENCAP_ETHERNET:
397 s = format (s, "encapped by Ethernet intf: %d", map->sw_if_index);
401 s = format (s, "only GRE and VXLANGPE support in this rev");
408 format_nsh_node_map_trace (u8 * s, va_list * args)
410 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
411 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
412 nsh_input_trace_t *t = va_arg (*args, nsh_input_trace_t *);
414 s = format (s, "\n %U", format_nsh_header, &(t->trace_data));
420 * @brief Naming for NSH tunnel
422 * @param *s formatting string
425 * @return *s formatted string
429 format_nsh_name (u8 * s, va_list * args)
431 u32 dev_instance = va_arg (*args, u32);
432 return format (s, "nsh_tunnel%d", dev_instance);
436 * @brief CLI function for NSH admin up/down
445 static clib_error_t *
446 nsh_interface_admin_up_down (vnet_main_t * vnm, u32 nsh_hw_if, u32 flags)
448 if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
449 vnet_hw_interface_set_flags (vnm, nsh_hw_if,
450 VNET_HW_INTERFACE_FLAG_LINK_UP);
452 vnet_hw_interface_set_flags (vnm, nsh_hw_if, 0);
458 dummy_interface_tx (vlib_main_t * vm,
459 vlib_node_runtime_t * node, vlib_frame_t * frame)
461 clib_warning ("you shouldn't be here, leaking buffers...");
462 return frame->n_vectors;
465 VNET_DEVICE_CLASS (nsh_device_class, static) =
467 .name = "NSH",.format_device_name = format_nsh_name,.tx_function =
468 dummy_interface_tx,.admin_up_down_function =
469 nsh_interface_admin_up_down,};
472 * @brief Formatting function for tracing VXLAN GPE with length
481 format_nsh_tunnel_with_length (u8 * s, va_list * args)
483 u32 dev_instance = va_arg (*args, u32);
484 s = format (s, "unimplemented dev %u", dev_instance);
488 VNET_HW_INTERFACE_CLASS (nsh_hw_class) =
490 .name = "NSH",.format_header =
491 format_nsh_tunnel_with_length,.build_rewrite =
492 default_build_rewrite,.flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,};
496 * Action function to add or del an nsh map.
497 * Shared by both CLI and binary API
501 nsh_add_del_map (nsh_add_del_map_args_t * a, u32 * map_indexp)
503 nsh_main_t *nm = &nsh_main;
504 vnet_main_t *vnm = nm->vnet_main;
510 vnet_hw_interface_t *hi;
514 /* net order, so data plane could use nsh header to lookup directly */
515 key = clib_host_to_net_u32 (a->map.nsp_nsi);
517 entry = hash_get_mem (nm->nsh_mapping_by_key, &key);
521 /* adding an entry, must not already exist */
523 return -1; //TODO API_ERROR_INVALID_VALUE;
525 pool_get_aligned (nm->nsh_mappings, map, CLIB_CACHE_LINE_BYTES);
526 memset (map, 0, sizeof (*map));
528 /* copy from arg structure */
529 map->nsp_nsi = a->map.nsp_nsi;
530 map->mapped_nsp_nsi = a->map.mapped_nsp_nsi;
531 map->nsh_action = a->map.nsh_action;
532 map->sw_if_index = a->map.sw_if_index;
533 map->rx_sw_if_index = a->map.rx_sw_if_index;
534 map->next_node = a->map.next_node;
535 map->adj_index = a->map.adj_index;
538 key_copy = clib_mem_alloc (sizeof (*key_copy));
539 clib_memcpy (key_copy, &key, sizeof (*key_copy));
541 hash_set_mem (nm->nsh_mapping_by_key, key_copy, map - nm->nsh_mappings);
542 map_index = map - nm->nsh_mappings;
544 if (vec_len (nm->free_nsh_tunnel_hw_if_indices) > 0)
546 nsh_hw_if = nm->free_nsh_tunnel_hw_if_indices
547 [vec_len (nm->free_nsh_tunnel_hw_if_indices) - 1];
548 _vec_len (nm->free_nsh_tunnel_hw_if_indices) -= 1;
550 hi = vnet_get_hw_interface (vnm, nsh_hw_if);
551 hi->dev_instance = map_index;
552 hi->hw_instance = hi->dev_instance;
556 nsh_hw_if = vnet_register_interface
557 (vnm, nsh_device_class.index, map_index, nsh_hw_class.index,
559 hi = vnet_get_hw_interface (vnm, nsh_hw_if);
560 hi->output_node_index = nsh_aware_vnf_proxy_node.index;
563 map->nsh_hw_if = nsh_hw_if;
564 map->nsh_sw_if = nsh_sw_if = hi->sw_if_index;
565 vec_validate_init_empty (nm->tunnel_index_by_sw_if_index, nsh_sw_if,
567 nm->tunnel_index_by_sw_if_index[nsh_sw_if] = key;
569 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
570 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
575 return -2; //TODO API_ERROR_NO_SUCH_ENTRY;
577 map = pool_elt_at_index (nm->nsh_mappings, entry[0]);
579 vnet_sw_interface_set_flags (vnm, map->nsh_sw_if,
580 VNET_SW_INTERFACE_FLAG_ADMIN_DOWN);
581 vec_add1 (nm->free_nsh_tunnel_hw_if_indices, map->nsh_sw_if);
582 nm->tunnel_index_by_sw_if_index[map->nsh_sw_if] = ~0;
584 hp = hash_get_pair (nm->nsh_mapping_by_key, &key);
585 key_copy = (void *) (hp->key);
586 hash_unset_mem (nm->nsh_mapping_by_key, &key);
587 clib_mem_free (key_copy);
589 pool_put (nm->nsh_mappings, map);
593 *map_indexp = map_index;
599 * Action function to add or del an nsh-proxy-session.
600 * Shared by both CLI and binary API
604 nsh_add_del_proxy_session (nsh_add_del_map_args_t * a)
606 nsh_main_t *nm = &nsh_main;
607 nsh_proxy_session_t *proxy = 0;
608 nsh_proxy_session_by_key_t key, *key_copy;
611 u32 nsp = 0, nsi = 0;
613 memset (&key, 0, sizeof (key));
614 key.transport_type = a->map.next_node;
615 key.transport_index = a->map.sw_if_index;
617 entry = hash_get_mem (nm->nsh_proxy_session_by_key, &key);
621 /* adding an entry, must not already exist */
623 return -1; //TODO API_ERROR_INVALID_VALUE;
625 pool_get_aligned (nm->nsh_proxy_sessions, proxy, CLIB_CACHE_LINE_BYTES);
626 memset (proxy, 0, sizeof (*proxy));
628 /* Nsi needs to minus 1 within NSH-Proxy */
629 nsp = (a->map.nsp_nsi >> NSH_NSP_SHIFT) & NSH_NSP_MASK;
630 nsi = a->map.nsp_nsi & NSH_NSI_MASK;
635 /* net order, so could use it to lookup nsh map table directly */
636 proxy->nsp_nsi = clib_host_to_net_u32 ((nsp << NSH_NSP_SHIFT) | nsi);
638 key_copy = clib_mem_alloc (sizeof (*key_copy));
639 clib_memcpy (key_copy, &key, sizeof (*key_copy));
641 hash_set_mem (nm->nsh_proxy_session_by_key, key_copy,
642 proxy - nm->nsh_proxy_sessions);
647 return -2; //TODO API_ERROR_NO_SUCH_ENTRY;
649 proxy = pool_elt_at_index (nm->nsh_proxy_sessions, entry[0]);
650 hp = hash_get_pair (nm->nsh_proxy_session_by_key, &key);
651 key_copy = (void *) (hp->key);
652 hash_unset_mem (nm->nsh_proxy_session_by_key, &key);
653 clib_mem_free (key_copy);
655 pool_put (nm->nsh_proxy_sessions, proxy);
662 * CLI command for NSH map
666 unformat_nsh_action (unformat_input_t * input, va_list * args)
668 u32 *result = va_arg (*args, u32 *);
671 if (unformat (input, "swap"))
672 *result = NSH_ACTION_SWAP;
673 else if (unformat (input, "push"))
674 *result = NSH_ACTION_PUSH;
675 else if (unformat (input, "pop"))
676 *result = NSH_ACTION_POP;
677 else if (unformat (input, "%d", &tmp))
686 nsh_get_adj_by_sw_if_index (u32 sw_if_index)
691 pool_foreach_index(ai, adj_pool,
693 if (sw_if_index == adj_get_sw_if_index(ai))
703 static clib_error_t *
704 nsh_add_del_map_command_fn (vlib_main_t * vm,
705 unformat_input_t * input,
706 vlib_cli_command_t * cmd)
708 unformat_input_t _line_input, *line_input = &_line_input;
710 u32 nsp, nsi, mapped_nsp, mapped_nsi, nsh_action;
711 int nsp_set = 0, nsi_set = 0, mapped_nsp_set = 0, mapped_nsi_set = 0;
712 int nsh_action_set = 0;
715 u32 sw_if_index = ~0; // temporary requirement to get this moved over to NSHSFC
716 u32 rx_sw_if_index = ~0; // temporary requirement to get this moved over to NSHSFC
717 nsh_add_del_map_args_t _a, *a = &_a;
721 /* Get a line of input. */
722 if (!unformat_user (input, unformat_line_input, line_input))
725 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
727 if (unformat (line_input, "del"))
729 else if (unformat (line_input, "nsp %d", &nsp))
731 else if (unformat (line_input, "nsi %d", &nsi))
733 else if (unformat (line_input, "mapped-nsp %d", &mapped_nsp))
735 else if (unformat (line_input, "mapped-nsi %d", &mapped_nsi))
737 else if (unformat (line_input, "nsh_action %U", unformat_nsh_action,
740 else if (unformat (line_input, "encap-gre4-intf %d", &sw_if_index))
741 next_node = NSH_NODE_NEXT_ENCAP_GRE4;
742 else if (unformat (line_input, "encap-gre6-intf %d", &sw_if_index))
743 next_node = NSH_NODE_NEXT_ENCAP_GRE6;
744 else if (unformat (line_input, "encap-vxlan-gpe-intf %d", &sw_if_index))
745 next_node = NSH_NODE_NEXT_ENCAP_VXLANGPE;
746 else if (unformat (line_input, "encap-lisp-gpe-intf %d", &sw_if_index))
747 next_node = NSH_NODE_NEXT_ENCAP_LISP_GPE;
748 else if (unformat (line_input, "encap-vxlan4-intf %d", &sw_if_index))
749 next_node = NSH_NODE_NEXT_ENCAP_VXLAN4;
750 else if (unformat (line_input, "encap-vxlan6-intf %d", &sw_if_index))
751 next_node = NSH_NODE_NEXT_ENCAP_VXLAN6;
752 else if (unformat (line_input, "encap-eth-intf %d", &sw_if_index))
754 next_node = NSH_NODE_NEXT_ENCAP_ETHERNET;
755 adj_index = nsh_get_adj_by_sw_if_index (sw_if_index);
759 (line_input, "encap-none %d %d", &sw_if_index, &rx_sw_if_index))
760 next_node = NSH_NODE_NEXT_DECAP_ETH_INPUT;
762 return clib_error_return (0, "parse error: '%U'",
763 format_unformat_error, line_input);
766 unformat_free (line_input);
768 if (nsp_set == 0 || nsi_set == 0)
769 return clib_error_return (0, "nsp nsi pair required. Key: for NSH entry");
771 if (mapped_nsp_set == 0 || mapped_nsi_set == 0)
772 return clib_error_return (0,
773 "mapped-nsp mapped-nsi pair required. Key: for NSH entry");
775 if (nsh_action_set == 0)
776 return clib_error_return (0, "nsh_action required: swap|push|pop.");
779 return clib_error_return (0,
780 "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>]");
782 memset (a, 0, sizeof (*a));
784 /* set args structure */
786 a->map.nsp_nsi = (nsp << NSH_NSP_SHIFT) | nsi;
787 a->map.mapped_nsp_nsi = (mapped_nsp << NSH_NSP_SHIFT) | mapped_nsi;
788 a->map.nsh_action = nsh_action;
789 a->map.sw_if_index = sw_if_index;
790 a->map.rx_sw_if_index = rx_sw_if_index;
791 a->map.next_node = next_node;
792 a->map.adj_index = adj_index;
794 rv = nsh_add_del_map (a, &map_index);
800 case -1: //TODO API_ERROR_INVALID_VALUE:
801 return clib_error_return (0,
802 "mapping already exists. Remove it first.");
804 case -2: // TODO API_ERROR_NO_SUCH_ENTRY:
805 return clib_error_return (0, "mapping does not exist.");
808 return clib_error_return (0, "nsh_add_del_map returned %d", rv);
811 if ((a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN4)
812 | (a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN6))
814 rv = nsh_add_del_proxy_session (a);
820 case -1: //TODO API_ERROR_INVALID_VALUE:
821 return clib_error_return (0,
822 "nsh-proxy-session already exists. Remove it first.");
824 case -2: // TODO API_ERROR_NO_SUCH_ENTRY:
825 return clib_error_return (0, "nsh-proxy-session does not exist.");
828 return clib_error_return
829 (0, "nsh_add_del_proxy_session() returned %d", rv);
836 VLIB_CLI_COMMAND (create_nsh_map_command, static) =
838 .path = "create nsh map",.short_help =
839 "create nsh map nsp <nn> nsi <nn> [del] mapped-nsp <nn> mapped-nsi <nn> nsh_action [swap|push|pop] "
840 "[encap-gre4-intf <nn> | encap-gre4-intf <nn> | encap-vxlan-gpe-intf <nn> | encap-lisp-gpe-intf <nn> "
841 " encap-vxlan4-intf <nn> | encap-vxlan6-intf <nn>| encap-eth-intf <nn> | encap-none]\n",.function
842 = nsh_add_del_map_command_fn,};
844 /** API message handler */
846 vl_api_nsh_add_del_map_t_handler (vl_api_nsh_add_del_map_t * mp)
848 vl_api_nsh_add_del_map_reply_t *rmp;
849 nsh_main_t *nm = &nsh_main;
851 nsh_add_del_map_args_t _a, *a = &_a;
854 a->is_add = mp->is_add;
855 a->map.nsp_nsi = ntohl (mp->nsp_nsi);
856 a->map.mapped_nsp_nsi = ntohl (mp->mapped_nsp_nsi);
857 a->map.nsh_action = ntohl (mp->nsh_action);
858 a->map.sw_if_index = ntohl (mp->sw_if_index);
859 a->map.rx_sw_if_index = ntohl (mp->rx_sw_if_index);
860 a->map.next_node = ntohl (mp->next_node);
862 rv = nsh_add_del_map (a, &map_index);
864 if ((a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN4)
865 | (a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN6))
867 rv = nsh_add_del_proxy_session (a);
870 REPLY_MACRO2 (VL_API_NSH_ADD_DEL_MAP_REPLY, (
879 * CLI command for showing the mapping between NSH entries
881 static clib_error_t *
882 show_nsh_map_command_fn (vlib_main_t * vm,
883 unformat_input_t * input, vlib_cli_command_t * cmd)
885 nsh_main_t *nm = &nsh_main;
888 if (pool_elts (nm->nsh_mappings) == 0)
889 vlib_cli_output (vm, "No nsh maps configured.");
891 pool_foreach (map, nm->nsh_mappings, (
893 vlib_cli_output (vm, "%U",
902 VLIB_CLI_COMMAND (show_nsh_map_command, static) =
904 .path = "show nsh map",.function = show_nsh_map_command_fn,};
907 nsh_header_rewrite (nsh_entry_t * nsh_entry)
911 nsh_base_header_t *nsh_base;
912 nsh_md1_data_t *nsh_md1;
913 nsh_main_t *nm = &nsh_main;
914 nsh_md2_data_t *opt0;
915 nsh_md2_data_t *limit0;
916 nsh_md2_data_t *nsh_md2;
917 nsh_option_map_t _nsh_option, *nsh_option = &_nsh_option;
918 u8 old_option_size = 0;
919 u8 new_option_size = 0;
921 vec_free (nsh_entry->rewrite);
922 if (nsh_entry->nsh_base.md_type == 1)
924 len = sizeof (nsh_base_header_t) + sizeof (nsh_md1_data_t);
926 else if (nsh_entry->nsh_base.md_type == 2)
928 /* set to maxim, maybe dataplane will add more TLVs */
929 len = MAX_NSH_HEADER_LEN;
931 vec_validate_aligned (rw, len - 1, CLIB_CACHE_LINE_BYTES);
934 nsh_base = (nsh_base_header_t *) rw;
935 nsh_base->ver_o_c = nsh_entry->nsh_base.ver_o_c;
936 nsh_base->length = nsh_entry->nsh_base.length;
937 nsh_base->md_type = nsh_entry->nsh_base.md_type;
938 nsh_base->next_protocol = nsh_entry->nsh_base.next_protocol;
939 nsh_base->nsp_nsi = clib_host_to_net_u32 (nsh_entry->nsh_base.nsp_nsi);
941 if (nsh_base->md_type == 1)
943 nsh_md1 = (nsh_md1_data_t *) (rw + sizeof (nsh_base_header_t));
944 nsh_md1->c1 = clib_host_to_net_u32 (nsh_entry->md.md1_data.c1);
945 nsh_md1->c2 = clib_host_to_net_u32 (nsh_entry->md.md1_data.c2);
946 nsh_md1->c3 = clib_host_to_net_u32 (nsh_entry->md.md1_data.c3);
947 nsh_md1->c4 = clib_host_to_net_u32 (nsh_entry->md.md1_data.c4);
948 nsh_entry->rewrite_size = 24;
950 else if (nsh_base->md_type == 2)
952 opt0 = (nsh_md2_data_t *) (nsh_entry->tlvs_data);
953 limit0 = (nsh_md2_data_t *) ((u8 *) opt0 + nsh_entry->tlvs_len);
955 nsh_md2 = (nsh_md2_data_t *) (rw + sizeof (nsh_base_header_t));
956 nsh_entry->rewrite_size = sizeof (nsh_base_header_t);
958 while (opt0 < limit0)
960 old_option_size = sizeof (nsh_md2_data_t) + opt0->length;
961 /* round to 4-byte */
962 old_option_size = ((old_option_size + 3) >> 2) << 2;
964 nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type);
965 if (nsh_option == NULL)
970 if (nm->add_options[nsh_option->option_id] != NULL)
972 if (0 != nm->add_options[nsh_option->option_id] ((u8 *) nsh_md2,
978 /* round to 4-byte */
979 new_option_size = ((new_option_size + 3) >> 2) << 2;
981 nsh_entry->rewrite_size += new_option_size;
983 (nsh_md2_data_t *) (((u8 *) nsh_md2) + new_option_size);
984 opt0 = (nsh_md2_data_t *) (((u8 *) opt0) + old_option_size);
989 opt0 = (nsh_md2_data_t *) (((u8 *) opt0) + old_option_size);
995 nsh_entry->rewrite = rw;
996 nsh_base->length = (nsh_base->length & NSH_TTL_L2_MASK) |
997 ((nsh_entry->rewrite_size >> 2) & NSH_LEN_MASK);
1004 * Action function for adding an NSH entry
1005 * nsh_add_del_entry_args_t *a: host order
1009 nsh_add_del_entry (nsh_add_del_entry_args_t * a, u32 * entry_indexp)
1011 nsh_main_t *nm = &nsh_main;
1012 nsh_entry_t *nsh_entry = 0;
1016 u32 entry_index = ~0;
1020 /* host order, because nsh map table stores nsp_nsi in host order */
1021 key = a->nsh_entry.nsh_base.nsp_nsi;
1023 entry_id = hash_get_mem (nm->nsh_entry_by_key, &key);
1027 /* adding an entry, must not already exist */
1029 return -1; // TODO VNET_API_ERROR_INVALID_VALUE;
1031 pool_get_aligned (nm->nsh_entries, nsh_entry, CLIB_CACHE_LINE_BYTES);
1032 memset (nsh_entry, 0, sizeof (*nsh_entry));
1034 /* copy from arg structure */
1035 #define _(x) nsh_entry->nsh_base.x = a->nsh_entry.nsh_base.x;
1036 foreach_copy_nsh_base_hdr_field;
1039 if (a->nsh_entry.nsh_base.md_type == 1)
1041 nsh_entry->md.md1_data.c1 = a->nsh_entry.md.md1_data.c1;
1042 nsh_entry->md.md1_data.c2 = a->nsh_entry.md.md1_data.c2;
1043 nsh_entry->md.md1_data.c3 = a->nsh_entry.md.md1_data.c3;
1044 nsh_entry->md.md1_data.c4 = a->nsh_entry.md.md1_data.c4;
1046 else if (a->nsh_entry.nsh_base.md_type == 2)
1048 vec_free (nsh_entry->tlvs_data);
1049 tlvs_len = a->nsh_entry.tlvs_len;
1050 vec_validate_aligned (data, tlvs_len - 1, CLIB_CACHE_LINE_BYTES);
1052 clib_memcpy (data, a->nsh_entry.tlvs_data, tlvs_len);
1053 nsh_entry->tlvs_data = data;
1054 nsh_entry->tlvs_len = tlvs_len;
1055 vec_free (a->nsh_entry.tlvs_data);
1058 nsh_header_rewrite (nsh_entry);
1060 key_copy = clib_mem_alloc (sizeof (*key_copy));
1061 clib_memcpy (key_copy, &key, sizeof (*key_copy));
1063 hash_set_mem (nm->nsh_entry_by_key, key_copy,
1064 nsh_entry - nm->nsh_entries);
1065 entry_index = nsh_entry - nm->nsh_entries;
1070 return -2; //TODO API_ERROR_NO_SUCH_ENTRY;
1072 nsh_entry = pool_elt_at_index (nm->nsh_entries, entry_id[0]);
1073 hp = hash_get_pair (nm->nsh_entry_by_key, &key);
1074 key_copy = (void *) (hp->key);
1075 hash_unset_mem (nm->nsh_entry_by_key, &key);
1076 clib_mem_free (key_copy);
1078 vec_free (nsh_entry->tlvs_data);
1079 vec_free (nsh_entry->rewrite);
1080 pool_put (nm->nsh_entries, nsh_entry);
1084 *entry_indexp = entry_index;
1091 * CLI command for adding NSH entry
1094 static clib_error_t *
1095 nsh_add_del_entry_command_fn (vlib_main_t * vm,
1096 unformat_input_t * input,
1097 vlib_cli_command_t * cmd)
1099 unformat_input_t _line_input, *line_input = &_line_input;
1105 u8 next_protocol = 1; /* default: ip4 */
1116 nsh_tlv_header_t tlv_header;
1117 u8 cur_len = 0, tlvs_len = 0;
1119 nsh_main_t *nm = &nsh_main;
1120 nsh_option_map_t _nsh_option, *nsh_option = &_nsh_option;
1125 nsh_add_del_entry_args_t _a, *a = &_a;
1126 u8 has_ioam_trace_option = 0;
1128 /* Get a line of input. */
1129 if (!unformat_user (input, unformat_line_input, line_input))
1132 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1134 if (unformat (line_input, "del"))
1136 else if (unformat (line_input, "version %d", &tmp))
1137 ver_o_c |= (tmp & 3) << 6;
1138 else if (unformat (line_input, "o-bit %d", &tmp))
1139 ver_o_c |= (tmp & 1) << 5;
1140 else if (unformat (line_input, "c-bit %d", &tmp))
1141 ver_o_c |= (tmp & 1) << 4;
1142 else if (unformat (line_input, "ttl %d", &ttl))
1143 ver_o_c |= (ttl & NSH_LEN_MASK) >> 2;
1144 else if (unformat (line_input, "md-type %d", &tmp))
1146 else if (unformat (line_input, "next-ip4"))
1148 else if (unformat (line_input, "next-ip6"))
1150 else if (unformat (line_input, "next-ethernet"))
1152 else if (unformat (line_input, "c1 %d", &c1))
1154 else if (unformat (line_input, "c2 %d", &c2))
1156 else if (unformat (line_input, "c3 %d", &c3))
1158 else if (unformat (line_input, "c4 %d", &c4))
1160 else if (unformat (line_input, "nsp %d", &nsp))
1162 else if (unformat (line_input, "nsi %d", &nsi))
1164 else if (unformat (line_input, "tlv-ioam-trace"))
1165 has_ioam_trace_option = 1;
1167 return clib_error_return (0, "parse error: '%U'",
1168 format_unformat_error, line_input);
1171 unformat_free (line_input);
1174 return clib_error_return (0, "nsp not specified");
1177 return clib_error_return (0, "nsi not specified");
1179 if (md_type == 1 && has_ioam_trace_option == 1)
1180 return clib_error_return (0, "Invalid MD Type");
1182 nsp_nsi = (nsp << 8) | nsi;
1184 memset (a, 0, sizeof (*a));
1189 a->nsh_entry.md.md1_data.c1 = c1;
1190 a->nsh_entry.md.md1_data.c2 = c2;
1191 a->nsh_entry.md.md1_data.c3 = c3;
1192 a->nsh_entry.md.md1_data.c4 = c4;
1193 length = (sizeof (nsh_base_header_t) + sizeof (nsh_md1_data_t)) >> 2;
1195 else if (md_type == 2)
1197 length = sizeof (nsh_base_header_t) >> 2;
1199 vec_free (a->nsh_entry.tlvs_data);
1200 tlvs_len = (MAX_METADATA_LEN << 2);
1201 vec_validate_aligned (data, tlvs_len - 1, CLIB_CACHE_LINE_BYTES);
1202 a->nsh_entry.tlvs_data = data;
1205 if (has_ioam_trace_option)
1207 tlv_header.class = clib_host_to_net_u16 (NSH_MD2_IOAM_CLASS);
1208 tlv_header.type = NSH_MD2_IOAM_OPTION_TYPE_TRACE;
1209 /* Uses network order's class and type to lookup */
1211 nsh_md2_lookup_option (tlv_header.class, tlv_header.type);
1212 if (nsh_option == NULL)
1213 return clib_error_return (0, "iOAM Trace not registered");
1215 if (nm->add_options[nsh_option->option_id] != NULL)
1217 if (0 != nm->add_options[nsh_option->option_id] ((u8 *) current,
1220 return clib_error_return (0, "Invalid MD Type");
1224 nm->options_size[nsh_option->option_id] = option_size;
1225 /* round to 4-byte */
1226 option_size = (((option_size + 3) >> 2) << 2);
1228 cur_len += option_size;
1229 current = data + option_size;
1232 /* Add more options' parsing */
1234 a->nsh_entry.tlvs_len = cur_len;
1235 length += (cur_len >> 2);
1237 length = (length & NSH_LEN_MASK) | ((ttl & 0x3) << 6);
1239 #define _(x) a->nsh_entry.nsh_base.x = x;
1240 foreach_copy_nsh_base_hdr_field;
1243 rv = nsh_add_del_entry (a, &entry_index);
1250 return clib_error_return (0, "nsh_add_del_entry returned %d", rv);
1256 VLIB_CLI_COMMAND (create_nsh_entry_command, static) =
1258 .path = "create nsh entry",.short_help =
1259 "create nsh entry {nsp <nn> nsi <nn>} [ttl <nn>] [md-type <nn>]"
1260 " [c1 <nn> c2 <nn> c3 <nn> c4 <nn>] [tlv-ioam-trace] [del]\n",.function
1261 = nsh_add_del_entry_command_fn,};
1263 /** API message handler */
1264 static void vl_api_nsh_add_del_entry_t_handler
1265 (vl_api_nsh_add_del_entry_t * mp)
1267 vl_api_nsh_add_del_entry_reply_t *rmp;
1268 nsh_main_t *nm = &nsh_main;
1270 nsh_add_del_entry_args_t _a, *a = &_a;
1271 u32 entry_index = ~0;
1275 a->is_add = mp->is_add;
1276 a->nsh_entry.nsh_base.ver_o_c =
1277 (mp->ver_o_c & 0xF0) | ((mp->ttl & NSH_LEN_MASK) >> 2);
1278 a->nsh_entry.nsh_base.length =
1279 (mp->length & NSH_LEN_MASK) | ((mp->ttl & 0x3) << 6);
1280 a->nsh_entry.nsh_base.md_type = mp->md_type;
1281 a->nsh_entry.nsh_base.next_protocol = mp->next_protocol;
1282 a->nsh_entry.nsh_base.nsp_nsi = ntohl (mp->nsp_nsi);
1283 if (mp->md_type == 1)
1285 a->nsh_entry.md.md1_data.c1 = ntohl (mp->c1);
1286 a->nsh_entry.md.md1_data.c2 = ntohl (mp->c2);
1287 a->nsh_entry.md.md1_data.c3 = ntohl (mp->c3);
1288 a->nsh_entry.md.md1_data.c4 = ntohl (mp->c4);
1290 else if (mp->md_type == 2)
1292 tlvs_len = mp->tlv_length;
1293 vec_validate_aligned (data, tlvs_len - 1, CLIB_CACHE_LINE_BYTES);
1295 clib_memcpy (data, mp->tlv, tlvs_len);
1296 a->nsh_entry.tlvs_data = data;
1297 a->nsh_entry.tlvs_len = tlvs_len;
1300 rv = nsh_add_del_entry (a, &entry_index);
1302 REPLY_MACRO2 (VL_API_NSH_ADD_DEL_ENTRY_REPLY, (
1305 htonl (entry_index);
1310 static void send_nsh_entry_details
1311 (nsh_entry_t * t, unix_shared_memory_queue_t * q, u32 context)
1313 vl_api_nsh_entry_details_t *rmp;
1314 nsh_main_t *nm = &nsh_main;
1316 rmp = vl_msg_api_alloc (sizeof (*rmp));
1317 memset (rmp, 0, sizeof (*rmp));
1319 rmp->_vl_msg_id = ntohs ((VL_API_NSH_ENTRY_DETAILS) + nm->msg_id_base);
1320 rmp->ver_o_c = t->nsh_base.ver_o_c;
1321 rmp->ttl = (t->nsh_base.ver_o_c & NSH_TTL_H4_MASK) << 2 |
1322 (t->nsh_base.length & NSH_TTL_L2_MASK) >> 6;
1323 rmp->length = t->nsh_base.length & NSH_LEN_MASK;
1324 rmp->md_type = t->nsh_base.md_type;
1325 rmp->next_protocol = t->nsh_base.next_protocol;
1326 rmp->nsp_nsi = htonl (t->nsh_base.nsp_nsi);
1328 if (t->nsh_base.md_type == 1)
1330 rmp->tlv_length = 4;
1331 rmp->c1 = htonl (t->md.md1_data.c1);
1332 rmp->c2 = htonl (t->md.md1_data.c2);
1333 rmp->c3 = htonl (t->md.md1_data.c3);
1334 rmp->c4 = htonl (t->md.md1_data.c4);
1336 else if (t->nsh_base.md_type == 2)
1338 rmp->tlv_length = t->tlvs_len;
1339 clib_memcpy (rmp->tlv, t->tlvs_data, t->tlvs_len);
1342 rmp->context = context;
1344 vl_msg_api_send_shmem (q, (u8 *) & rmp);
1348 vl_api_nsh_entry_dump_t_handler (vl_api_nsh_entry_dump_t * mp)
1350 unix_shared_memory_queue_t *q;
1351 nsh_main_t *nm = &nsh_main;
1355 q = vl_api_client_index_to_input_queue (mp->client_index);
1361 entry_index = ntohl (mp->entry_index);
1363 if (~0 == entry_index)
1365 pool_foreach (t, nm->nsh_entries, (
1367 send_nsh_entry_details (t, q,
1374 if (entry_index >= vec_len (nm->nsh_entries))
1378 t = &nm->nsh_entries[entry_index];
1379 send_nsh_entry_details (t, q, mp->context);
1383 static void send_nsh_map_details
1384 (nsh_map_t * t, unix_shared_memory_queue_t * q, u32 context)
1386 vl_api_nsh_map_details_t *rmp;
1387 nsh_main_t *nm = &nsh_main;
1389 rmp = vl_msg_api_alloc (sizeof (*rmp));
1390 memset (rmp, 0, sizeof (*rmp));
1392 rmp->_vl_msg_id = ntohs ((VL_API_NSH_MAP_DETAILS) + nm->msg_id_base);
1393 rmp->nsp_nsi = htonl (t->nsp_nsi);
1394 rmp->mapped_nsp_nsi = htonl (t->mapped_nsp_nsi);
1395 rmp->nsh_action = htonl (t->nsh_action);
1396 rmp->sw_if_index = htonl (t->sw_if_index);
1397 rmp->rx_sw_if_index = htonl (t->rx_sw_if_index);
1398 rmp->next_node = htonl (t->next_node);
1400 rmp->context = context;
1402 vl_msg_api_send_shmem (q, (u8 *) & rmp);
1406 vl_api_nsh_map_dump_t_handler (vl_api_nsh_map_dump_t * mp)
1408 unix_shared_memory_queue_t *q;
1409 nsh_main_t *nm = &nsh_main;
1413 q = vl_api_client_index_to_input_queue (mp->client_index);
1419 map_index = ntohl (mp->map_index);
1421 if (~0 == map_index)
1423 pool_foreach (t, nm->nsh_mappings, (
1425 send_nsh_map_details (t, q,
1432 if (map_index >= vec_len (nm->nsh_mappings))
1436 t = &nm->nsh_mappings[map_index];
1437 send_nsh_map_details (t, q, mp->context);
1441 static clib_error_t *
1442 show_nsh_entry_command_fn (vlib_main_t * vm,
1443 unformat_input_t * input, vlib_cli_command_t * cmd)
1445 nsh_main_t *nm = &nsh_main;
1446 nsh_entry_t *nsh_entry;
1448 if (pool_elts (nm->nsh_entries) == 0)
1449 vlib_cli_output (vm, "No nsh entries configured.");
1451 pool_foreach (nsh_entry, nm->nsh_entries, (
1453 vlib_cli_output (vm, "%U",
1455 nsh_entry->rewrite);
1456 vlib_cli_output (vm,
1457 " rewrite_size: %d bytes",
1458 nsh_entry->rewrite_size);
1465 VLIB_CLI_COMMAND (show_nsh_entry_command, static) =
1467 .path = "show nsh entry",.function = show_nsh_entry_command_fn,};
1470 /* Set up the API message handling tables */
1471 static clib_error_t *
1472 nsh_plugin_api_hookup (vlib_main_t * vm)
1474 nsh_main_t *nm __attribute__ ((unused)) = &nsh_main;
1476 vl_msg_api_set_handlers((VL_API_##N + nm->msg_id_base), \
1478 vl_api_##n##_t_handler, \
1480 vl_api_##n##_t_endian, \
1481 vl_api_##n##_t_print, \
1482 sizeof(vl_api_##n##_t), 1);
1483 foreach_nsh_plugin_api_msg;
1490 setup_message_id_table (nsh_main_t * nm, api_main_t * am)
1492 #define _(id,n,crc) \
1493 vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + nm->msg_id_base);
1494 foreach_vl_msg_name_crc_nsh;
1499 nsh_md2_encap (vlib_buffer_t * b, nsh_base_header_t * hdr,
1500 nsh_entry_t * nsh_entry)
1502 nsh_main_t *nm = &nsh_main;
1503 nsh_base_header_t *nsh_base;
1504 nsh_tlv_header_t *opt0;
1505 nsh_tlv_header_t *limit0;
1506 nsh_tlv_header_t *nsh_md2;
1507 nsh_option_map_t *nsh_option;
1508 u8 old_option_size = 0;
1509 u8 new_option_size = 0;
1511 /* Populate the NSH Header */
1512 opt0 = (nsh_tlv_header_t *) (nsh_entry->tlvs_data);
1513 limit0 = (nsh_tlv_header_t *) (nsh_entry->tlvs_data + nsh_entry->tlvs_len);
1515 nsh_md2 = (nsh_tlv_header_t *) ((u8 *) hdr /*nsh_entry->rewrite */ +
1516 sizeof (nsh_base_header_t));
1517 nsh_entry->rewrite_size = sizeof (nsh_base_header_t);
1519 /* Scan the set of variable metadata, process ones that we understand */
1520 while (opt0 < limit0)
1522 old_option_size = sizeof (nsh_tlv_header_t) + opt0->length;
1523 /* round to 4-byte */
1524 old_option_size = ((old_option_size + 3) >> 2) << 2;
1526 nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type);
1527 if (nsh_option == NULL)
1532 if (nm->options[nsh_option->option_id])
1534 if ((*nm->options[nsh_option->option_id]) (b, nsh_md2))
1539 /* option length may be varied */
1540 new_option_size = sizeof (nsh_tlv_header_t) + nsh_md2->length;
1541 /* round to 4-byte */
1542 new_option_size = ((new_option_size + 3) >> 2) << 2;
1543 nsh_entry->rewrite_size += new_option_size;
1545 nsh_md2 = (nsh_tlv_header_t *) (((u8 *) nsh_md2) + new_option_size);
1546 opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size);
1552 opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size);
1556 /* update nsh header's length */
1557 nsh_base = (nsh_base_header_t *) nsh_entry->rewrite;
1558 nsh_base->length = (nsh_base->length & NSH_TTL_L2_MASK) |
1559 ((nsh_entry->rewrite_size >> 2) & NSH_LEN_MASK);
1564 nsh_md2_swap (vlib_buffer_t * b,
1565 nsh_base_header_t * hdr,
1567 nsh_entry_t * nsh_entry, u32 * next, u32 drop_node_val)
1569 nsh_main_t *nm = &nsh_main;
1570 nsh_base_header_t *nsh_base;
1571 nsh_tlv_header_t *opt0;
1572 nsh_tlv_header_t *limit0;
1573 nsh_tlv_header_t *nsh_md2;
1574 nsh_option_map_t *nsh_option;
1575 u8 old_option_size = 0;
1576 u8 new_option_size = 0;
1578 /* Populate the NSH Header */
1579 opt0 = (nsh_md2_data_t *) (hdr + 1);
1580 limit0 = (nsh_md2_data_t *) ((u8 *) hdr + header_len);
1583 (nsh_tlv_header_t *) (nsh_entry->rewrite + sizeof (nsh_base_header_t));
1584 nsh_entry->rewrite_size = sizeof (nsh_base_header_t);
1586 /* Scan the set of variable metadata, process ones that we understand */
1587 while (opt0 < limit0)
1589 old_option_size = sizeof (nsh_tlv_header_t) + opt0->length;
1590 /* round to 4-byte */
1591 old_option_size = ((old_option_size + 3) >> 2) << 2;
1593 nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type);
1594 if (nsh_option == NULL)
1599 if (nm->swap_options[nsh_option->option_id])
1601 if ((*nm->swap_options[nsh_option->option_id]) (b, opt0, nsh_md2))
1606 /* option length may be varied */
1607 new_option_size = sizeof (nsh_tlv_header_t) + nsh_md2->length;
1608 /* round to 4-byte */
1609 new_option_size = ((new_option_size + 3) >> 2) << 2;
1610 nsh_entry->rewrite_size += new_option_size;
1611 nsh_md2 = (nsh_tlv_header_t *) (((u8 *) nsh_md2) + new_option_size);
1613 opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size);
1619 opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size);
1623 /* update nsh header's length */
1624 nsh_base = (nsh_base_header_t *) nsh_entry->rewrite;
1625 nsh_base->length = (nsh_base->length & NSH_TTL_L2_MASK) |
1626 ((nsh_entry->rewrite_size >> 2) & NSH_LEN_MASK);
1631 nsh_md2_decap (vlib_buffer_t * b,
1632 nsh_base_header_t * hdr,
1633 u32 * header_len, u32 * next, u32 drop_node_val)
1635 nsh_main_t *nm = &nsh_main;
1636 nsh_md2_data_t *opt0;
1637 nsh_md2_data_t *limit0;
1638 nsh_option_map_t *nsh_option;
1641 /* Populate the NSH Header */
1642 opt0 = (nsh_md2_data_t *) (hdr + 1);
1643 limit0 = (nsh_md2_data_t *) ((u8 *) hdr + *header_len);
1645 /* Scan the set of variable metadata, process ones that we understand */
1646 while (opt0 < limit0)
1648 nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type);
1649 if (nsh_option == NULL)
1651 *next = drop_node_val;
1655 if (nm->pop_options[nsh_option->option_id])
1657 if ((*nm->pop_options[nsh_option->option_id]) (b, opt0))
1659 *next = drop_node_val;
1663 /* round to 4-byte */
1664 option_len = ((opt0->length + 3) >> 2) << 2;
1666 (nsh_md2_data_t *) (((u8 *) opt0) + sizeof (nsh_md2_data_t) +
1669 (nm->decap_v4_next_override) ? (nm->decap_v4_next_override) : (*next);
1670 *header_len = (nm->decap_v4_next_override) ? 0 : (*header_len);
1677 nsh_input_map (vlib_main_t * vm,
1678 vlib_node_runtime_t * node,
1679 vlib_frame_t * from_frame, u32 node_type)
1681 u32 n_left_from, next_index, *from, *to_next;
1682 nsh_main_t *nm = &nsh_main;
1684 from = vlib_frame_vector_args (from_frame);
1685 n_left_from = from_frame->n_vectors;
1687 next_index = node->cached_next_index;
1689 while (n_left_from > 0)
1693 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1695 while (n_left_from >= 4 && n_left_to_next >= 2)
1698 vlib_buffer_t *b0, *b1;
1699 u32 next0 = NSH_NODE_NEXT_DROP, next1 = NSH_NODE_NEXT_DROP;
1700 uword *entry0, *entry1;
1701 nsh_base_header_t *hdr0 = 0, *hdr1 = 0;
1702 u32 header_len0 = 0, header_len1 = 0;
1703 u32 nsp_nsi0, nsp_nsi1;
1706 nsh_map_t *map0 = 0, *map1 = 0;
1707 nsh_entry_t *nsh_entry0 = 0, *nsh_entry1 = 0;
1708 nsh_base_header_t *encap_hdr0 = 0, *encap_hdr1 = 0;
1709 u32 encap_hdr_len0 = 0, encap_hdr_len1 = 0;
1710 nsh_proxy_session_by_key_t key0, key1;
1712 nsh_proxy_session_t *proxy0, *proxy1;
1713 u32 sw_if_index0 = 0, sw_if_index1 = 0;
1714 ethernet_header_t dummy_eth0, dummy_eth1;
1716 /* Prefetch next iteration. */
1718 vlib_buffer_t *p2, *p3;
1720 p2 = vlib_get_buffer (vm, from[2]);
1721 p3 = vlib_get_buffer (vm, from[3]);
1723 vlib_prefetch_buffer_header (p2, LOAD);
1724 vlib_prefetch_buffer_header (p3, LOAD);
1726 CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
1727 CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
1737 n_left_to_next -= 2;
1742 b0 = vlib_get_buffer (vm, bi0);
1743 b1 = vlib_get_buffer (vm, bi1);
1744 hdr0 = vlib_buffer_get_current (b0);
1745 if (node_type == NSH_INPUT_TYPE)
1747 nsp_nsi0 = hdr0->nsp_nsi;
1748 header_len0 = (hdr0->length & NSH_LEN_MASK) * 4;
1749 ttl0 = (hdr0->ver_o_c & NSH_TTL_H4_MASK) << 2 |
1750 (hdr0->length & NSH_TTL_L2_MASK) >> 6;
1752 if (PREDICT_FALSE (ttl0 == 0))
1754 error0 = NSH_NODE_ERROR_INVALID_TTL;
1758 else if (node_type == NSH_CLASSIFIER_TYPE)
1761 clib_host_to_net_u32 (vnet_buffer (b0)->
1762 l2_classify.opaque_index);
1764 else if (node_type == NSH_AWARE_VNF_PROXY_TYPE)
1766 /* Push dummy Eth header */
1767 memset (&dummy_eth0.dst_address[0], 0x11223344, 4);
1768 memset (&dummy_eth0.dst_address[4], 0x5566, 2);
1769 memset (&dummy_eth0.src_address[0], 0x778899aa, 4);
1770 memset (&dummy_eth0.src_address[4], 0xbbcc, 2);
1771 dummy_eth0.type = 0x0800;
1772 vlib_buffer_advance (b0, -(word) sizeof (ethernet_header_t));
1773 hdr0 = vlib_buffer_get_current (b0);
1774 clib_memcpy (hdr0, &dummy_eth0,
1775 (word) sizeof (ethernet_header_t));
1777 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
1778 nsp_nsi0 = nm->tunnel_index_by_sw_if_index[sw_if_index0];
1782 memset (&key0, 0, sizeof (key0));
1783 key0.transport_type = NSH_NODE_NEXT_ENCAP_VXLAN4;
1784 key0.transport_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1786 p0 = hash_get_mem (nm->nsh_proxy_session_by_key, &key0);
1787 if (PREDICT_FALSE (p0 == 0))
1789 error0 = NSH_NODE_ERROR_NO_PROXY;
1793 proxy0 = pool_elt_at_index (nm->nsh_proxy_sessions, p0[0]);
1794 if (PREDICT_FALSE (proxy0 == 0))
1796 error0 = NSH_NODE_ERROR_NO_PROXY;
1799 nsp_nsi0 = proxy0->nsp_nsi;
1802 hdr1 = vlib_buffer_get_current (b1);
1803 if (node_type == NSH_INPUT_TYPE)
1805 nsp_nsi1 = hdr1->nsp_nsi;
1806 header_len1 = (hdr1->length & NSH_LEN_MASK) * 4;
1807 ttl1 = (hdr1->ver_o_c & NSH_TTL_H4_MASK) << 2 |
1808 (hdr1->length & NSH_TTL_L2_MASK) >> 6;
1810 if (PREDICT_FALSE (ttl1 == 0))
1812 error1 = NSH_NODE_ERROR_INVALID_TTL;
1816 else if (node_type == NSH_CLASSIFIER_TYPE)
1819 clib_host_to_net_u32 (vnet_buffer (b1)->
1820 l2_classify.opaque_index);
1822 else if (node_type == NSH_AWARE_VNF_PROXY_TYPE)
1824 /* Push dummy Eth header */
1825 memset (&dummy_eth1.dst_address[0], 0x11223344, 4);
1826 memset (&dummy_eth1.dst_address[4], 0x5566, 2);
1827 memset (&dummy_eth1.src_address[0], 0x778899aa, 4);
1828 memset (&dummy_eth1.src_address[4], 0xbbcc, 2);
1829 dummy_eth1.type = 0x0800;
1830 vlib_buffer_advance (b1, -(word) sizeof (ethernet_header_t));
1831 hdr1 = vlib_buffer_get_current (b1);
1832 clib_memcpy (hdr1, &dummy_eth1,
1833 (word) sizeof (ethernet_header_t));
1835 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_TX];
1836 nsp_nsi1 = nm->tunnel_index_by_sw_if_index[sw_if_index1];
1840 memset (&key1, 0, sizeof (key1));
1841 key1.transport_type = NSH_NODE_NEXT_ENCAP_VXLAN4;
1842 key1.transport_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];
1844 p1 = hash_get_mem (nm->nsh_proxy_session_by_key, &key1);
1845 if (PREDICT_FALSE (p1 == 0))
1847 error1 = NSH_NODE_ERROR_NO_PROXY;
1851 proxy1 = pool_elt_at_index (nm->nsh_proxy_sessions, p1[0]);
1852 if (PREDICT_FALSE (proxy1 == 0))
1854 error1 = NSH_NODE_ERROR_NO_PROXY;
1857 nsp_nsi1 = proxy1->nsp_nsi;
1860 /* Process packet 0 */
1861 entry0 = hash_get_mem (nm->nsh_mapping_by_key, &nsp_nsi0);
1862 if (PREDICT_FALSE (entry0 == 0))
1864 error0 = NSH_NODE_ERROR_NO_MAPPING;
1868 /* Entry should point to a mapping ... */
1869 map0 = pool_elt_at_index (nm->nsh_mappings, entry0[0]);
1870 if (PREDICT_FALSE (map0 == 0))
1872 error0 = NSH_NODE_ERROR_NO_MAPPING;
1876 /* set up things for next node to transmit ie which node to handle it and where */
1877 next0 = map0->next_node;
1878 vnet_buffer (b0)->sw_if_index[VLIB_TX] = map0->sw_if_index;
1879 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = map0->adj_index;
1881 if (PREDICT_FALSE (map0->nsh_action == NSH_ACTION_POP))
1883 /* Manipulate MD2 */
1884 if (PREDICT_FALSE (hdr0->md_type == 2))
1886 nsh_md2_decap (b0, hdr0, &header_len0, &next0,
1887 NSH_NODE_NEXT_DROP);
1888 if (PREDICT_FALSE (next0 == NSH_NODE_NEXT_DROP))
1890 error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
1893 vnet_buffer (b0)->sw_if_index[VLIB_RX] =
1894 map0->rx_sw_if_index;
1897 /* Pop NSH header */
1898 vlib_buffer_advance (b0, (word) header_len0);
1902 entry0 = hash_get_mem (nm->nsh_entry_by_key, &map0->mapped_nsp_nsi);
1903 if (PREDICT_FALSE (entry0 == 0))
1905 error0 = NSH_NODE_ERROR_NO_ENTRY;
1910 (nsh_entry_t *) pool_elt_at_index (nm->nsh_entries, entry0[0]);
1911 encap_hdr0 = (nsh_base_header_t *) (nsh_entry0->rewrite);
1912 /* rewrite_size should equal to (encap_hdr0->length * 4) */
1913 encap_hdr_len0 = nsh_entry0->rewrite_size;
1915 if (PREDICT_TRUE (map0->nsh_action == NSH_ACTION_SWAP))
1917 /* Manipulate MD2 */
1918 if (PREDICT_FALSE (hdr0->md_type == 2))
1920 nsh_md2_swap (b0, hdr0, header_len0, nsh_entry0,
1921 &next0, NSH_NODE_NEXT_DROP);
1922 if (PREDICT_FALSE (next0 == NSH_NODE_NEXT_DROP))
1924 error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
1929 /* Pop old NSH header */
1930 vlib_buffer_advance (b0, (word) header_len0);
1932 /* After processing, md2's length may be varied */
1933 encap_hdr_len0 = nsh_entry0->rewrite_size;
1934 /* Push new NSH header */
1935 vlib_buffer_advance (b0, -(word) encap_hdr_len0);
1936 hdr0 = vlib_buffer_get_current (b0);
1937 clib_memcpy (hdr0, encap_hdr0, (word) encap_hdr_len0);
1942 if (PREDICT_TRUE (map0->nsh_action == NSH_ACTION_PUSH))
1944 /* After processing, md2's length may be varied */
1945 encap_hdr_len0 = nsh_entry0->rewrite_size;
1946 /* Push new NSH header */
1947 vlib_buffer_advance (b0, -(word) encap_hdr_len0);
1948 hdr0 = vlib_buffer_get_current (b0);
1949 clib_memcpy (hdr0, encap_hdr0, (word) encap_hdr_len0);
1951 /* Manipulate MD2 */
1952 if (PREDICT_FALSE (nsh_entry0->nsh_base.md_type == 2))
1954 nsh_md2_encap (b0, hdr0, nsh_entry0);
1959 trace0:b0->error = error0 ? node->errors[error0] : 0;
1961 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1963 nsh_input_trace_t *tr =
1964 vlib_add_trace (vm, node, b0, sizeof (*tr));
1965 clib_memcpy (&(tr->trace_data), hdr0,
1966 ((hdr0->length & NSH_LEN_MASK) * 4));
1969 /* Process packet 1 */
1970 entry1 = hash_get_mem (nm->nsh_mapping_by_key, &nsp_nsi1);
1971 if (PREDICT_FALSE (entry1 == 0))
1973 error1 = NSH_NODE_ERROR_NO_MAPPING;
1977 /* Entry should point to a mapping ... */
1978 map1 = pool_elt_at_index (nm->nsh_mappings, entry1[0]);
1979 if (PREDICT_FALSE (map1 == 0))
1981 error1 = NSH_NODE_ERROR_NO_MAPPING;
1985 /* set up things for next node to transmit ie which node to handle it and where */
1986 next1 = map1->next_node;
1987 vnet_buffer (b1)->sw_if_index[VLIB_TX] = map1->sw_if_index;
1988 vnet_buffer (b1)->ip.adj_index[VLIB_TX] = map1->adj_index;
1990 if (PREDICT_FALSE (map1->nsh_action == NSH_ACTION_POP))
1992 /* Manipulate MD2 */
1993 if (PREDICT_FALSE (hdr1->md_type == 2))
1995 nsh_md2_decap (b1, hdr1, &header_len1, &next1,
1996 NSH_NODE_NEXT_DROP);
1997 if (PREDICT_FALSE (next1 == NSH_NODE_NEXT_DROP))
1999 error1 = NSH_NODE_ERROR_INVALID_OPTIONS;
2002 vnet_buffer (b1)->sw_if_index[VLIB_RX] =
2003 map0->rx_sw_if_index;
2006 /* Pop NSH header */
2007 vlib_buffer_advance (b1, (word) header_len1);
2011 entry1 = hash_get_mem (nm->nsh_entry_by_key, &map1->mapped_nsp_nsi);
2012 if (PREDICT_FALSE (entry1 == 0))
2014 error1 = NSH_NODE_ERROR_NO_ENTRY;
2019 (nsh_entry_t *) pool_elt_at_index (nm->nsh_entries, entry1[0]);
2020 encap_hdr1 = (nsh_base_header_t *) (nsh_entry1->rewrite);
2021 /* rewrite_size should equal to (encap_hdr0->length * 4) */
2022 encap_hdr_len1 = nsh_entry1->rewrite_size;
2024 if (PREDICT_TRUE (map1->nsh_action == NSH_ACTION_SWAP))
2026 /* Manipulate MD2 */
2027 if (PREDICT_FALSE (hdr1->md_type == 2))
2029 nsh_md2_swap (b1, hdr1, header_len1, nsh_entry1,
2030 &next1, NSH_NODE_NEXT_DROP);
2031 if (PREDICT_FALSE (next1 == NSH_NODE_NEXT_DROP))
2033 error1 = NSH_NODE_ERROR_INVALID_OPTIONS;
2038 /* Pop old NSH header */
2039 vlib_buffer_advance (b1, (word) header_len1);
2041 /* After processing, md2's length may be varied */
2042 encap_hdr_len1 = nsh_entry1->rewrite_size;
2043 /* Push new NSH header */
2044 vlib_buffer_advance (b1, -(word) encap_hdr_len1);
2045 hdr1 = vlib_buffer_get_current (b1);
2046 clib_memcpy (hdr1, encap_hdr1, (word) encap_hdr_len1);
2051 if (PREDICT_FALSE (map1->nsh_action == NSH_ACTION_PUSH))
2053 /* After processing, md2's length may be varied */
2054 encap_hdr_len1 = nsh_entry1->rewrite_size;
2055 /* Push new NSH header */
2056 vlib_buffer_advance (b1, -(word) encap_hdr_len1);
2057 hdr1 = vlib_buffer_get_current (b1);
2058 clib_memcpy (hdr1, encap_hdr1, (word) encap_hdr_len1);
2060 /* Manipulate MD2 */
2061 if (PREDICT_FALSE (nsh_entry1->nsh_base.md_type == 2))
2063 nsh_md2_encap (b1, hdr1, nsh_entry1);
2068 trace1:b1->error = error1 ? node->errors[error1] : 0;
2070 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2072 nsh_input_trace_t *tr =
2073 vlib_add_trace (vm, node, b1, sizeof (*tr));
2074 clib_memcpy (&(tr->trace_data), hdr1,
2075 ((hdr1->length & NSH_LEN_MASK) * 4));
2078 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
2079 n_left_to_next, bi0, bi1, next0,
2084 while (n_left_from > 0 && n_left_to_next > 0)
2087 vlib_buffer_t *b0 = NULL;
2088 u32 next0 = NSH_NODE_NEXT_DROP;
2090 nsh_base_header_t *hdr0 = 0;
2091 u32 header_len0 = 0;
2095 nsh_map_t *map0 = 0;
2096 nsh_entry_t *nsh_entry0 = 0;
2097 nsh_base_header_t *encap_hdr0 = 0;
2098 u32 encap_hdr_len0 = 0;
2099 nsh_proxy_session_by_key_t key0;
2101 nsh_proxy_session_t *proxy0 = 0;
2102 u32 sw_if_index0 = 0;
2103 ethernet_header_t dummy_eth0;
2110 n_left_to_next -= 1;
2113 b0 = vlib_get_buffer (vm, bi0);
2114 hdr0 = vlib_buffer_get_current (b0);
2116 if (node_type == NSH_INPUT_TYPE)
2118 nsp_nsi0 = hdr0->nsp_nsi;
2119 header_len0 = (hdr0->length & NSH_LEN_MASK) * 4;
2120 ttl0 = (hdr0->ver_o_c & NSH_TTL_H4_MASK) << 2 |
2121 (hdr0->length & NSH_TTL_L2_MASK) >> 6;
2123 if (PREDICT_FALSE (ttl0 == 0))
2125 error0 = NSH_NODE_ERROR_INVALID_TTL;
2129 else if (node_type == NSH_CLASSIFIER_TYPE)
2132 clib_host_to_net_u32 (vnet_buffer (b0)->
2133 l2_classify.opaque_index);
2135 else if (node_type == NSH_AWARE_VNF_PROXY_TYPE)
2137 /* Push dummy Eth header */
2138 memset (&dummy_eth0.dst_address[0], 0x11223344, 4);
2139 memset (&dummy_eth0.dst_address[4], 0x5566, 2);
2140 memset (&dummy_eth0.src_address[0], 0x778899aa, 4);
2141 memset (&dummy_eth0.src_address[4], 0xbbcc, 2);
2142 dummy_eth0.type = 0x0800;
2143 vlib_buffer_advance (b0, -(word) sizeof (ethernet_header_t));
2144 hdr0 = vlib_buffer_get_current (b0);
2145 clib_memcpy (hdr0, &dummy_eth0,
2146 (word) sizeof (ethernet_header_t));
2148 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
2149 nsp_nsi0 = nm->tunnel_index_by_sw_if_index[sw_if_index0];
2153 memset (&key0, 0, sizeof (key0));
2154 key0.transport_type = NSH_NODE_NEXT_ENCAP_VXLAN4;
2155 key0.transport_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
2157 p0 = hash_get_mem (nm->nsh_proxy_session_by_key, &key0);
2158 if (PREDICT_FALSE (p0 == 0))
2160 error0 = NSH_NODE_ERROR_NO_PROXY;
2164 proxy0 = pool_elt_at_index (nm->nsh_proxy_sessions, p0[0]);
2165 if (PREDICT_FALSE (proxy0 == 0))
2167 error0 = NSH_NODE_ERROR_NO_PROXY;
2170 nsp_nsi0 = proxy0->nsp_nsi;
2173 entry0 = hash_get_mem (nm->nsh_mapping_by_key, &nsp_nsi0);
2175 if (PREDICT_FALSE (entry0 == 0))
2177 error0 = NSH_NODE_ERROR_NO_MAPPING;
2181 /* Entry should point to a mapping ... */
2182 map0 = pool_elt_at_index (nm->nsh_mappings, entry0[0]);
2184 if (PREDICT_FALSE (map0 == 0))
2186 error0 = NSH_NODE_ERROR_NO_MAPPING;
2190 /* set up things for next node to transmit ie which node to handle it and where */
2191 next0 = map0->next_node;
2192 vnet_buffer (b0)->sw_if_index[VLIB_TX] = map0->sw_if_index;
2193 vnet_buffer (b0)->ip.adj_index[VLIB_TX] = map0->adj_index;
2194 vnet_buffer (b0)->sw_if_index[VLIB_RX] = map0->nsh_sw_if;
2196 if (PREDICT_FALSE (map0->nsh_action == NSH_ACTION_POP))
2198 /* Manipulate MD2 */
2199 if (PREDICT_FALSE (hdr0->md_type == 2))
2201 nsh_md2_decap (b0, hdr0, &header_len0, &next0,
2202 NSH_NODE_NEXT_DROP);
2203 if (PREDICT_FALSE (next0 == NSH_NODE_NEXT_DROP))
2205 error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
2208 vnet_buffer (b0)->sw_if_index[VLIB_RX] =
2209 map0->rx_sw_if_index;
2212 /* Pop NSH header */
2213 vlib_buffer_advance (b0, (word) header_len0);
2217 entry0 = hash_get_mem (nm->nsh_entry_by_key, &map0->mapped_nsp_nsi);
2218 if (PREDICT_FALSE (entry0 == 0))
2220 error0 = NSH_NODE_ERROR_NO_ENTRY;
2225 (nsh_entry_t *) pool_elt_at_index (nm->nsh_entries, entry0[0]);
2226 encap_hdr0 = (nsh_base_header_t *) (nsh_entry0->rewrite);
2227 /* rewrite_size should equal to (encap_hdr0->length * 4) */
2228 encap_hdr_len0 = nsh_entry0->rewrite_size;
2230 if (PREDICT_TRUE (map0->nsh_action == NSH_ACTION_SWAP))
2232 /* Manipulate MD2 */
2233 if (PREDICT_FALSE (hdr0->md_type == 2))
2235 nsh_md2_swap (b0, hdr0, header_len0, nsh_entry0,
2236 &next0, NSH_NODE_NEXT_DROP);
2237 if (PREDICT_FALSE (next0 == NSH_NODE_NEXT_DROP))
2239 error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
2244 /* Pop old NSH header */
2245 vlib_buffer_advance (b0, (word) header_len0);
2247 /* After processing, md2's length may be varied */
2248 encap_hdr_len0 = nsh_entry0->rewrite_size;
2249 /* Push new NSH header */
2250 vlib_buffer_advance (b0, -(word) encap_hdr_len0);
2251 hdr0 = vlib_buffer_get_current (b0);
2252 clib_memcpy (hdr0, encap_hdr0, (word) encap_hdr_len0);
2257 if (PREDICT_TRUE (map0->nsh_action == NSH_ACTION_PUSH))
2259 /* After processing, md2's length may be varied */
2260 encap_hdr_len0 = nsh_entry0->rewrite_size;
2261 /* Push new NSH header */
2262 vlib_buffer_advance (b0, -(word) encap_hdr_len0);
2263 hdr0 = vlib_buffer_get_current (b0);
2264 clib_memcpy (hdr0, encap_hdr0, (word) encap_hdr_len0);
2265 /* Manipulate MD2 */
2266 if (PREDICT_FALSE (nsh_entry0->nsh_base.md_type == 2))
2268 nsh_md2_encap (b0, hdr0, nsh_entry0);
2273 trace00:b0->error = error0 ? node->errors[error0] : 0;
2275 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2277 nsh_input_trace_t *tr =
2278 vlib_add_trace (vm, node, b0, sizeof (*tr));
2279 clib_memcpy (&(tr->trace_data[0]), hdr0,
2280 ((hdr0->length & NSH_LEN_MASK) * 4));
2283 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2284 n_left_to_next, bi0, next0);
2287 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2291 return from_frame->n_vectors;
2295 * @brief Graph processing dispatch function for NSH Input
2300 * @param *from_frame
2302 * @return from_frame->n_vectors
2306 nsh_input (vlib_main_t * vm, vlib_node_runtime_t * node,
2307 vlib_frame_t * from_frame)
2309 return nsh_input_map (vm, node, from_frame, NSH_INPUT_TYPE);
2313 * @brief Graph processing dispatch function for NSH-Proxy
2318 * @param *from_frame
2320 * @return from_frame->n_vectors
2324 nsh_proxy (vlib_main_t * vm, vlib_node_runtime_t * node,
2325 vlib_frame_t * from_frame)
2327 return nsh_input_map (vm, node, from_frame, NSH_PROXY_TYPE);
2331 * @brief Graph processing dispatch function for NSH Classifier
2333 * @node nsh_classifier
2336 * @param *from_frame
2338 * @return from_frame->n_vectors
2342 nsh_classifier (vlib_main_t * vm, vlib_node_runtime_t * node,
2343 vlib_frame_t * from_frame)
2345 return nsh_input_map (vm, node, from_frame, NSH_CLASSIFIER_TYPE);
2349 * @brief Graph processing dispatch function for NSH-AWARE-VNF-PROXY
2351 * @node nsh_aware_vnf_proxy
2354 * @param *from_frame
2356 * @return from_frame->n_vectors
2360 nsh_aware_vnf_proxy (vlib_main_t * vm, vlib_node_runtime_t * node,
2361 vlib_frame_t * from_frame)
2363 return nsh_input_map (vm, node, from_frame, NSH_AWARE_VNF_PROXY_TYPE);
2366 static char *nsh_node_error_strings[] = {
2367 #define _(sym,string) string,
2368 foreach_nsh_node_error
2372 /* register nsh-input node */
2373 VLIB_REGISTER_NODE (nsh_input_node) =
2375 .function = nsh_input,.name = "nsh-input",.vector_size =
2376 sizeof (u32),.format_trace = format_nsh_node_map_trace,.format_buffer =
2377 format_nsh_header,.type = VLIB_NODE_TYPE_INTERNAL,.n_errors =
2378 ARRAY_LEN (nsh_node_error_strings),.error_strings =
2379 nsh_node_error_strings,.n_next_nodes = NSH_NODE_N_NEXT,.next_nodes =
2381 #define _(s,n) [NSH_NODE_NEXT_##s] = n,
2382 foreach_nsh_node_next
2387 VLIB_NODE_FUNCTION_MULTIARCH (nsh_input_node, nsh_input);
2389 /* register nsh-proxy node */
2390 VLIB_REGISTER_NODE (nsh_proxy_node) =
2392 .function = nsh_proxy,.name = "nsh-proxy",.vector_size =
2393 sizeof (u32),.format_trace = format_nsh_node_map_trace,.format_buffer =
2394 format_nsh_header,.type = VLIB_NODE_TYPE_INTERNAL,.n_errors =
2395 ARRAY_LEN (nsh_node_error_strings),.error_strings =
2396 nsh_node_error_strings,.n_next_nodes = NSH_NODE_N_NEXT,.next_nodes =
2398 #define _(s,n) [NSH_NODE_NEXT_##s] = n,
2399 foreach_nsh_node_next
2404 VLIB_NODE_FUNCTION_MULTIARCH (nsh_proxy_node, nsh_proxy);
2406 /* register nsh-classifier node */
2407 VLIB_REGISTER_NODE (nsh_classifier_node) =
2409 .function = nsh_classifier,.name = "nsh-classifier",.vector_size =
2410 sizeof (u32),.format_trace = format_nsh_node_map_trace,.format_buffer =
2411 format_nsh_header,.type = VLIB_NODE_TYPE_INTERNAL,.n_errors =
2412 ARRAY_LEN (nsh_node_error_strings),.error_strings =
2413 nsh_node_error_strings,.n_next_nodes = NSH_NODE_N_NEXT,.next_nodes =
2415 #define _(s,n) [NSH_NODE_NEXT_##s] = n,
2416 foreach_nsh_node_next
2421 VLIB_NODE_FUNCTION_MULTIARCH (nsh_classifier_node, nsh_classifier);
2423 /* register nsh-aware-vnf-proxy node */
2424 VLIB_REGISTER_NODE (nsh_aware_vnf_proxy_node) =
2426 .function = nsh_aware_vnf_proxy,.name = "nsh-aware-vnf-proxy",.vector_size =
2427 sizeof (u32),.format_trace = format_nsh_node_map_trace,.format_buffer =
2428 format_nsh_header,.type = VLIB_NODE_TYPE_INTERNAL,.n_errors =
2429 ARRAY_LEN (nsh_node_error_strings),.error_strings =
2430 nsh_node_error_strings,.n_next_nodes = NSH_NODE_N_NEXT,.next_nodes =
2432 #define _(s,n) [NSH_NODE_NEXT_##s] = n,
2433 foreach_nsh_node_next
2438 VLIB_NODE_FUNCTION_MULTIARCH (nsh_aware_vnf_proxy_node, nsh_aware_vnf_proxy);
2441 nsh_md2_set_next_ioam_export_override (uword next)
2443 nsh_main_t *hm = &nsh_main;
2444 hm->decap_v4_next_override = next;
2450 nsh_init (vlib_main_t * vm)
2452 nsh_main_t *nm = &nsh_main;
2453 clib_error_t *error = 0;
2457 /* Init the main structures from VPP */
2459 nm->vnet_main = vnet_get_main ();
2461 /* Various state maintenance mappings */
2462 nm->nsh_mapping_by_key = hash_create_mem (0, sizeof (u32), sizeof (uword));
2464 nm->nsh_mapping_by_mapped_key
2465 = hash_create_mem (0, sizeof (u32), sizeof (uword));
2467 nm->nsh_entry_by_key = hash_create_mem (0, sizeof (u32), sizeof (uword));
2469 nm->nsh_proxy_session_by_key
2471 hash_create_mem (0, sizeof (nsh_proxy_session_by_key_t), sizeof (uword));
2473 nm->nsh_option_map_by_key
2474 = hash_create_mem (0, sizeof (nsh_option_map_by_key_t), sizeof (uword));
2476 name = format (0, "nsh_%08x%c", api_version, 0);
2478 /* Set up the API */
2479 nm->msg_id_base = vl_msg_api_get_msg_ids
2480 ((char *) name, VL_MSG_FIRST_AVAILABLE);
2482 error = nsh_plugin_api_hookup (vm);
2484 /* Add our API messages to the global name_crc hash table */
2485 setup_message_id_table (nm, &api_main);
2487 /* Add dispositions to nodes that feed nsh-input */
2488 //alagalah - validate we don't really need to use the node value
2490 vlib_node_add_next (vm, vxlan4_gpe_input_node.index,
2491 nsh_input_node.index);
2492 vlib_node_add_next (vm, vxlan4_gpe_input_node.index, nsh_proxy_node.index);
2493 vlib_node_add_next (vm, vxlan4_gpe_input_node.index,
2494 nsh_aware_vnf_proxy_node.index);
2495 vxlan_gpe_register_decap_protocol (VXLAN_GPE_PROTOCOL_NSH, next_node);
2497 vlib_node_add_next (vm, vxlan6_gpe_input_node.index, nsh_input_node.index);
2498 vlib_node_add_next (vm, vxlan6_gpe_input_node.index, nsh_proxy_node.index);
2499 vlib_node_add_next (vm, vxlan6_gpe_input_node.index,
2500 nsh_aware_vnf_proxy_node.index);
2502 vlib_node_add_next (vm, gre4_input_node.index, nsh_input_node.index);
2503 vlib_node_add_next (vm, gre4_input_node.index, nsh_proxy_node.index);
2504 vlib_node_add_next (vm, gre4_input_node.index,
2505 nsh_aware_vnf_proxy_node.index);
2507 vlib_node_add_next (vm, gre6_input_node.index, nsh_input_node.index);
2508 vlib_node_add_next (vm, gre6_input_node.index, nsh_proxy_node.index);
2509 vlib_node_add_next (vm, gre6_input_node.index,
2510 nsh_aware_vnf_proxy_node.index);
2512 /* Add NSH-Proxy support */
2513 vlib_node_add_next (vm, vxlan4_input_node.index, nsh_proxy_node.index);
2514 vlib_node_add_next (vm, vxlan6_input_node.index, nsh_proxy_node.index);
2516 /* Add NSH-Classifier support */
2517 vlib_node_add_next (vm, ip4_classify_node.index, nsh_classifier_node.index);
2518 vlib_node_add_next (vm, ip6_classify_node.index, nsh_classifier_node.index);
2519 vlib_node_add_next (vm, l2_input_classify_node.index,
2520 nsh_classifier_node.index);
2522 /* Add Ethernet+NSH support */
2523 ethernet_register_input_type (vm, ETHERNET_TYPE_NSH, nsh_input_node.index);
2530 VLIB_INIT_FUNCTION (nsh_init);
2533 VLIB_PLUGIN_REGISTER () = {
2534 .version = VPP_BUILD_VER,
2535 .description = "Network Service Header",
2540 * fd.io coding-style-patch-verification: ON
2543 * eval: (c-set-style "gnu")