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
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 };
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
78 #define REPLY_MACRO(t) \
80 unix_shared_memory_queue_t * q = \
81 vl_api_client_index_to_input_queue (mp->client_index); \
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); \
90 vl_msg_api_send_shmem (q, (u8 *)&rmp); \
93 #define REPLY_MACRO2(t, body) \
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); \
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); \
111 vl_print (handle, (char *)s); \
115 /* List of message types that this plugin understands */
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)
123 /* Uses network order's class and type to register */
125 nsh_md2_register_option (u16 class,
128 int add_options (u8 * opt,
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))
139 nsh_main_t *nm = &nsh_main;
140 nsh_option_map_by_key_t key, *key_copy;
142 nsh_option_map_t *nsh_option;
148 p = hash_get_mem (nm->nsh_option_map_by_key, &key);
149 /* Already registered */
155 pool_get_aligned (nm->nsh_option_mappings, nsh_option,
156 CLIB_CACHE_LINE_BYTES);
157 clib_memset (nsh_option, 0, sizeof (*nsh_option));
158 nsh_option->option_id = nsh_option - nm->nsh_option_mappings;
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);
165 if (option_size > (MAX_NSH_OPTION_LEN + sizeof (nsh_tlv_header_t)))
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;
179 /* Uses network order's class and type to lookup */
181 nsh_md2_lookup_option (u16 class, u8 type)
183 nsh_main_t *nm = &nsh_main;
184 nsh_option_map_by_key_t key;
191 p = hash_get_mem (nm->nsh_option_map_by_key, &key);
198 return pool_elt_at_index (nm->nsh_option_mappings, p[0]);
202 /* Uses network order's class and type to unregister */
204 nsh_md2_unregister_option (u16 class,
206 int options (vlib_buffer_t * b,
207 nsh_tlv_header_t * opt),
208 u8 * trace (u8 * s, nsh_tlv_header_t * opt))
210 nsh_main_t *nm = &nsh_main;
211 nsh_option_map_by_key_t key, *key_copy;
214 nsh_option_map_t *nsh_option;
220 p = hash_get_mem (nm->nsh_option_map_by_key, &key);
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;
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);
238 pool_put (nm->nsh_option_mappings, nsh_option);
243 /* format from network order */
245 format_nsh_header (u8 * s, va_list * args)
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;
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)));
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 ");
266 if (nsh_base->ver_o_c & NSH_C_BIT)
267 s = format (s, "C-set ");
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);
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);
277 s = format (s, " service path %d service index %d\n",
278 (clib_net_to_host_u32 (nsh_base->nsp_nsi) >> NSH_NSP_SHIFT) &
280 clib_net_to_host_u32 (nsh_base->nsp_nsi) & NSH_NSI_MASK);
282 if (nsh_base->md_type == 1)
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));
290 else if (nsh_base->md_type == 2)
292 s = format (s, " Supported TLVs: \n");
294 /* Scan the set of variable metadata, network order */
295 while (opt0 < limit0)
297 nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type);
298 if (nsh_option != NULL)
300 if (nm->trace[nsh_option->option_id] != NULL)
302 s = (*nm->trace[nsh_option->option_id]) (s, opt0);
307 format (s, "\n untraced option %d length %d",
308 opt0->type, opt0->length);
314 format (s, "\n unrecognized option %d length %d",
315 opt0->type, opt0->length);
318 /* round to 4-byte */
319 option_len = ((opt0->length + 3) >> 2) << 2;
321 (nsh_md2_data_t *) (((u8 *) opt0) + sizeof (nsh_md2_data_t) +
330 format_nsh_action (u8 * s, va_list * args)
332 u32 nsh_action = va_arg (*args, u32);
336 case NSH_ACTION_SWAP:
337 return format (s, "swap");
338 case NSH_ACTION_PUSH:
339 return format (s, "push");
341 return format (s, "pop");
343 return format (s, "unknown %d", nsh_action);
349 format_nsh_map (u8 * s, va_list * args)
351 nsh_map_t *map = va_arg (*args, nsh_map_t *);
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,
358 map->mapped_nsp_nsi & NSH_NSI_MASK);
360 s = format (s, " nsh_action %U\n", format_nsh_action, map->nsh_action);
362 switch (map->next_node)
364 case NSH_NODE_NEXT_ENCAP_GRE4:
366 s = format (s, "encapped by GRE4 intf: %d", map->sw_if_index);
369 case NSH_NODE_NEXT_ENCAP_GRE6:
371 s = format (s, "encapped by GRE6 intf: %d", map->sw_if_index);
374 case NSH_NODE_NEXT_ENCAP_VXLANGPE:
376 s = format (s, "encapped by VXLAN GPE intf: %d", map->sw_if_index);
379 case NSH_NODE_NEXT_ENCAP_VXLAN4:
381 s = format (s, "encapped by VXLAN4 intf: %d", map->sw_if_index);
384 case NSH_NODE_NEXT_ENCAP_VXLAN6:
386 s = format (s, "encapped by VXLAN6 intf: %d", map->sw_if_index);
389 case NSH_NODE_NEXT_DECAP_ETH_INPUT:
391 s = format (s, "encap-none");
394 case NSH_NODE_NEXT_ENCAP_LISP_GPE:
396 s = format (s, "encapped by LISP GPE intf: %d", map->sw_if_index);
399 case NSH_NODE_NEXT_ENCAP_ETHERNET:
401 s = format (s, "encapped by Ethernet intf: %d", map->sw_if_index);
405 s = format (s, "only GRE and VXLANGPE support in this rev");
412 format_nsh_node_map_trace (u8 * s, va_list * args)
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 *);
418 s = format (s, "\n %U", format_nsh_header, &(t->trace_data));
424 * @brief Naming for NSH tunnel
426 * @param *s formatting string
429 * @return *s formatted string
433 format_nsh_name (u8 * s, va_list * args)
435 u32 dev_instance = va_arg (*args, u32);
436 return format (s, "nsh_tunnel%d", dev_instance);
440 * @brief CLI function for NSH admin up/down
449 static clib_error_t *
450 nsh_interface_admin_up_down (vnet_main_t * vnm, u32 nsh_hw_if, u32 flags)
452 if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
453 vnet_hw_interface_set_flags (vnm, nsh_hw_if,
454 VNET_HW_INTERFACE_FLAG_LINK_UP);
456 vnet_hw_interface_set_flags (vnm, nsh_hw_if, 0);
462 dummy_interface_tx (vlib_main_t * vm,
463 vlib_node_runtime_t * node, vlib_frame_t * frame)
465 clib_warning ("you shouldn't be here, leaking buffers...");
466 return frame->n_vectors;
469 VNET_DEVICE_CLASS (nsh_device_class, static) =
471 .name = "NSH",.format_device_name = format_nsh_name,.tx_function =
472 dummy_interface_tx,.admin_up_down_function =
473 nsh_interface_admin_up_down,};
476 * @brief Formatting function for tracing VXLAN GPE with length
485 format_nsh_tunnel_with_length (u8 * s, va_list * args)
487 u32 dev_instance = va_arg (*args, u32);
488 s = format (s, "unimplemented dev %u", dev_instance);
492 VNET_HW_INTERFACE_CLASS (nsh_hw_class) =
494 .name = "NSH",.format_header =
495 format_nsh_tunnel_with_length,.build_rewrite =
496 default_build_rewrite,.flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,};
500 * Action function to add or del an nsh map.
501 * Shared by both CLI and binary API
505 nsh_add_del_map (nsh_add_del_map_args_t * a, u32 * map_indexp)
507 nsh_main_t *nm = &nsh_main;
508 vnet_main_t *vnm = nm->vnet_main;
514 vnet_hw_interface_t *hi;
518 /* net order, so data plane could use nsh header to lookup directly */
519 key = clib_host_to_net_u32 (a->map.nsp_nsi);
521 entry = hash_get_mem (nm->nsh_mapping_by_key, &key);
525 /* adding an entry, must not already exist */
527 return -1; //TODO API_ERROR_INVALID_VALUE;
529 pool_get_aligned (nm->nsh_mappings, map, CLIB_CACHE_LINE_BYTES);
530 clib_memset (map, 0, sizeof (*map));
532 /* copy from arg structure */
533 map->nsp_nsi = a->map.nsp_nsi;
534 map->mapped_nsp_nsi = a->map.mapped_nsp_nsi;
535 map->nsh_action = a->map.nsh_action;
536 map->sw_if_index = a->map.sw_if_index;
537 map->rx_sw_if_index = a->map.rx_sw_if_index;
538 map->next_node = a->map.next_node;
539 map->adj_index = a->map.adj_index;
542 key_copy = clib_mem_alloc (sizeof (*key_copy));
543 clib_memcpy (key_copy, &key, sizeof (*key_copy));
545 hash_set_mem (nm->nsh_mapping_by_key, key_copy, map - nm->nsh_mappings);
546 map_index = map - nm->nsh_mappings;
548 if (vec_len (nm->free_nsh_tunnel_hw_if_indices) > 0)
550 nsh_hw_if = nm->free_nsh_tunnel_hw_if_indices
551 [vec_len (nm->free_nsh_tunnel_hw_if_indices) - 1];
552 _vec_len (nm->free_nsh_tunnel_hw_if_indices) -= 1;
554 hi = vnet_get_hw_interface (vnm, nsh_hw_if);
555 hi->dev_instance = map_index;
556 hi->hw_instance = hi->dev_instance;
560 nsh_hw_if = vnet_register_interface
561 (vnm, nsh_device_class.index, map_index, nsh_hw_class.index,
563 hi = vnet_get_hw_interface (vnm, nsh_hw_if);
564 hi->output_node_index = nsh_aware_vnf_proxy_node.index;
567 map->nsh_hw_if = nsh_hw_if;
568 map->nsh_sw_if = nsh_sw_if = hi->sw_if_index;
569 vec_validate_init_empty (nm->tunnel_index_by_sw_if_index, nsh_sw_if,
571 nm->tunnel_index_by_sw_if_index[nsh_sw_if] = key;
573 vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
574 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
579 return -2; //TODO API_ERROR_NO_SUCH_ENTRY;
581 map = pool_elt_at_index (nm->nsh_mappings, entry[0]);
583 vnet_sw_interface_set_flags (vnm, map->nsh_sw_if,
584 VNET_SW_INTERFACE_FLAG_ADMIN_DOWN);
585 vec_add1 (nm->free_nsh_tunnel_hw_if_indices, map->nsh_sw_if);
586 nm->tunnel_index_by_sw_if_index[map->nsh_sw_if] = ~0;
588 hp = hash_get_pair (nm->nsh_mapping_by_key, &key);
589 key_copy = (void *) (hp->key);
590 hash_unset_mem (nm->nsh_mapping_by_key, &key);
591 clib_mem_free (key_copy);
593 pool_put (nm->nsh_mappings, map);
597 *map_indexp = map_index;
603 * Action function to add or del an nsh-proxy-session.
604 * Shared by both CLI and binary API
608 nsh_add_del_proxy_session (nsh_add_del_map_args_t * a)
610 nsh_main_t *nm = &nsh_main;
611 nsh_proxy_session_t *proxy = 0;
612 nsh_proxy_session_by_key_t key, *key_copy;
615 u32 nsp = 0, nsi = 0;
617 clib_memset (&key, 0, sizeof (key));
618 key.transport_type = a->map.next_node;
619 key.transport_index = a->map.sw_if_index;
621 entry = hash_get_mem (nm->nsh_proxy_session_by_key, &key);
625 /* adding an entry, must not already exist */
627 return -1; //TODO API_ERROR_INVALID_VALUE;
629 pool_get_aligned (nm->nsh_proxy_sessions, proxy, CLIB_CACHE_LINE_BYTES);
630 clib_memset (proxy, 0, sizeof (*proxy));
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;
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);
642 key_copy = clib_mem_alloc (sizeof (*key_copy));
643 clib_memcpy (key_copy, &key, sizeof (*key_copy));
645 hash_set_mem (nm->nsh_proxy_session_by_key, key_copy,
646 proxy - nm->nsh_proxy_sessions);
651 return -2; //TODO API_ERROR_NO_SUCH_ENTRY;
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);
656 hash_unset_mem (nm->nsh_proxy_session_by_key, &key);
657 clib_mem_free (key_copy);
659 pool_put (nm->nsh_proxy_sessions, proxy);
666 * CLI command for NSH map
670 unformat_nsh_action (unformat_input_t * input, va_list * args)
672 u32 *result = va_arg (*args, u32 *);
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))
690 nsh_get_adj_by_sw_if_index (u32 sw_if_index)
695 pool_foreach_index(ai, adj_pool,
697 if (sw_if_index == adj_get_sw_if_index(ai))
707 static clib_error_t *
708 nsh_add_del_map_command_fn (vlib_main_t * vm,
709 unformat_input_t * input,
710 vlib_cli_command_t * cmd)
712 unformat_input_t _line_input, *line_input = &_line_input;
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;
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;
725 /* Get a line of input. */
726 if (!unformat_user (input, unformat_line_input, line_input))
729 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
731 if (unformat (line_input, "del"))
733 else if (unformat (line_input, "nsp %d", &nsp))
735 else if (unformat (line_input, "nsi %d", &nsi))
737 else if (unformat (line_input, "mapped-nsp %d", &mapped_nsp))
739 else if (unformat (line_input, "mapped-nsi %d", &mapped_nsi))
741 else if (unformat (line_input, "nsh_action %U", unformat_nsh_action,
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))
758 next_node = NSH_NODE_NEXT_ENCAP_ETHERNET;
759 adj_index = nsh_get_adj_by_sw_if_index (sw_if_index);
763 (line_input, "encap-none %d %d", &sw_if_index, &rx_sw_if_index))
764 next_node = NSH_NODE_NEXT_DECAP_ETH_INPUT;
766 return clib_error_return (0, "parse error: '%U'",
767 format_unformat_error, line_input);
770 unformat_free (line_input);
772 if (nsp_set == 0 || nsi_set == 0)
773 return clib_error_return (0, "nsp nsi pair required. Key: for NSH entry");
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");
779 if (nsh_action_set == 0)
780 return clib_error_return (0, "nsh_action required: swap|push|pop.");
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>]");
786 clib_memset (a, 0, sizeof (*a));
788 /* set args structure */
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;
793 a->map.sw_if_index = sw_if_index;
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;
798 rv = nsh_add_del_map (a, &map_index);
804 case -1: //TODO API_ERROR_INVALID_VALUE:
805 return clib_error_return (0,
806 "mapping already exists. Remove it first.");
808 case -2: // TODO API_ERROR_NO_SUCH_ENTRY:
809 return clib_error_return (0, "mapping does not exist.");
812 return clib_error_return (0, "nsh_add_del_map returned %d", rv);
815 if ((a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN4)
816 | (a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN6))
818 rv = nsh_add_del_proxy_session (a);
824 case -1: //TODO API_ERROR_INVALID_VALUE:
825 return clib_error_return (0,
826 "nsh-proxy-session already exists. Remove it first.");
828 case -2: // TODO API_ERROR_NO_SUCH_ENTRY:
829 return clib_error_return (0, "nsh-proxy-session does not exist.");
832 return clib_error_return
833 (0, "nsh_add_del_proxy_session() returned %d", rv);
840 VLIB_CLI_COMMAND (create_nsh_map_command, static) =
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
846 = nsh_add_del_map_command_fn,};
848 /** API message handler */
850 vl_api_nsh_add_del_map_t_handler (vl_api_nsh_add_del_map_t * mp)
852 vl_api_nsh_add_del_map_reply_t *rmp;
853 nsh_main_t *nm = &nsh_main;
855 nsh_add_del_map_args_t _a, *a = &_a;
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);
866 rv = nsh_add_del_map (a, &map_index);
868 if ((a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN4)
869 | (a->map.next_node == NSH_NODE_NEXT_ENCAP_VXLAN6))
871 rv = nsh_add_del_proxy_session (a);
874 REPLY_MACRO2 (VL_API_NSH_ADD_DEL_MAP_REPLY, (
883 * CLI command for showing the mapping between NSH entries
885 static clib_error_t *
886 show_nsh_map_command_fn (vlib_main_t * vm,
887 unformat_input_t * input, vlib_cli_command_t * cmd)
889 nsh_main_t *nm = &nsh_main;
892 if (pool_elts (nm->nsh_mappings) == 0)
893 vlib_cli_output (vm, "No nsh maps configured.");
895 pool_foreach (map, nm->nsh_mappings, (
897 vlib_cli_output (vm, "%U",
906 VLIB_CLI_COMMAND (show_nsh_map_command, static) =
908 .path = "show nsh map",.function = show_nsh_map_command_fn,};
911 nsh_header_rewrite (nsh_entry_t * nsh_entry)
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;
925 vec_free (nsh_entry->rewrite);
926 if (nsh_entry->nsh_base.md_type == 1)
928 len = sizeof (nsh_base_header_t) + sizeof (nsh_md1_data_t);
930 else if (nsh_entry->nsh_base.md_type == 2)
932 /* set to maxim, maybe dataplane will add more TLVs */
933 len = MAX_NSH_HEADER_LEN;
935 vec_validate_aligned (rw, len - 1, CLIB_CACHE_LINE_BYTES);
936 clib_memset (rw, 0, len);
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);
945 if (nsh_base->md_type == 1)
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;
954 else if (nsh_base->md_type == 2)
956 opt0 = (nsh_md2_data_t *) (nsh_entry->tlvs_data);
957 limit0 = (nsh_md2_data_t *) ((u8 *) opt0 + nsh_entry->tlvs_len);
959 nsh_md2 = (nsh_md2_data_t *) (rw + sizeof (nsh_base_header_t));
960 nsh_entry->rewrite_size = sizeof (nsh_base_header_t);
962 while (opt0 < limit0)
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;
968 nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type);
969 if (nsh_option == NULL)
974 if (nm->add_options[nsh_option->option_id] != NULL)
976 if (0 != nm->add_options[nsh_option->option_id] ((u8 *) nsh_md2,
982 /* round to 4-byte */
983 new_option_size = ((new_option_size + 3) >> 2) << 2;
985 nsh_entry->rewrite_size += new_option_size;
987 (nsh_md2_data_t *) (((u8 *) nsh_md2) + new_option_size);
988 opt0 = (nsh_md2_data_t *) (((u8 *) opt0) + old_option_size);
993 opt0 = (nsh_md2_data_t *) (((u8 *) opt0) + old_option_size);
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);
1008 * Action function for adding an NSH entry
1009 * nsh_add_del_entry_args_t *a: host order
1013 nsh_add_del_entry (nsh_add_del_entry_args_t * a, u32 * entry_indexp)
1015 nsh_main_t *nm = &nsh_main;
1016 nsh_entry_t *nsh_entry = 0;
1020 u32 entry_index = ~0;
1024 /* host order, because nsh map table stores nsp_nsi in host order */
1025 key = a->nsh_entry.nsh_base.nsp_nsi;
1027 entry_id = hash_get_mem (nm->nsh_entry_by_key, &key);
1031 /* adding an entry, must not already exist */
1033 return -1; // TODO VNET_API_ERROR_INVALID_VALUE;
1035 pool_get_aligned (nm->nsh_entries, nsh_entry, CLIB_CACHE_LINE_BYTES);
1036 clib_memset (nsh_entry, 0, sizeof (*nsh_entry));
1038 /* copy from arg structure */
1039 #define _(x) nsh_entry->nsh_base.x = a->nsh_entry.nsh_base.x;
1040 foreach_copy_nsh_base_hdr_field;
1043 if (a->nsh_entry.nsh_base.md_type == 1)
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;
1050 else if (a->nsh_entry.nsh_base.md_type == 2)
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);
1056 clib_memcpy (data, a->nsh_entry.tlvs_data, tlvs_len);
1057 nsh_entry->tlvs_data = data;
1058 nsh_entry->tlvs_len = tlvs_len;
1059 vec_free (a->nsh_entry.tlvs_data);
1062 nsh_header_rewrite (nsh_entry);
1064 key_copy = clib_mem_alloc (sizeof (*key_copy));
1065 clib_memcpy (key_copy, &key, sizeof (*key_copy));
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;
1074 return -2; //TODO API_ERROR_NO_SUCH_ENTRY;
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);
1082 vec_free (nsh_entry->tlvs_data);
1083 vec_free (nsh_entry->rewrite);
1084 pool_put (nm->nsh_entries, nsh_entry);
1088 *entry_indexp = entry_index;
1095 * CLI command for adding NSH entry
1098 static clib_error_t *
1099 nsh_add_del_entry_command_fn (vlib_main_t * vm,
1100 unformat_input_t * input,
1101 vlib_cli_command_t * cmd)
1103 unformat_input_t _line_input, *line_input = &_line_input;
1109 u8 next_protocol = 1; /* default: ip4 */
1120 nsh_tlv_header_t tlv_header;
1121 u8 cur_len = 0, tlvs_len = 0;
1123 nsh_main_t *nm = &nsh_main;
1124 nsh_option_map_t _nsh_option, *nsh_option = &_nsh_option;
1129 nsh_add_del_entry_args_t _a, *a = &_a;
1130 u8 has_ioam_trace_option = 0;
1132 /* Get a line of input. */
1133 if (!unformat_user (input, unformat_line_input, line_input))
1136 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1138 if (unformat (line_input, "del"))
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))
1150 else if (unformat (line_input, "next-ip4"))
1152 else if (unformat (line_input, "next-ip6"))
1154 else if (unformat (line_input, "next-ethernet"))
1156 else if (unformat (line_input, "c1 %d", &c1))
1158 else if (unformat (line_input, "c2 %d", &c2))
1160 else if (unformat (line_input, "c3 %d", &c3))
1162 else if (unformat (line_input, "c4 %d", &c4))
1164 else if (unformat (line_input, "nsp %d", &nsp))
1166 else if (unformat (line_input, "nsi %d", &nsi))
1168 else if (unformat (line_input, "tlv-ioam-trace"))
1169 has_ioam_trace_option = 1;
1171 return clib_error_return (0, "parse error: '%U'",
1172 format_unformat_error, line_input);
1175 unformat_free (line_input);
1178 return clib_error_return (0, "nsp not specified");
1181 return clib_error_return (0, "nsi not specified");
1183 if (md_type == 1 && has_ioam_trace_option == 1)
1184 return clib_error_return (0, "Invalid MD Type");
1186 nsp_nsi = (nsp << 8) | nsi;
1188 clib_memset (a, 0, sizeof (*a));
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;
1199 else if (md_type == 2)
1201 length = sizeof (nsh_base_header_t) >> 2;
1203 vec_free (a->nsh_entry.tlvs_data);
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;
1209 if (has_ioam_trace_option)
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 */
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");
1219 if (nm->add_options[nsh_option->option_id] != NULL)
1221 if (0 != nm->add_options[nsh_option->option_id] ((u8 *) current,
1224 return clib_error_return (0, "Invalid MD Type");
1228 nm->options_size[nsh_option->option_id] = option_size;
1229 /* round to 4-byte */
1230 option_size = (((option_size + 3) >> 2) << 2);
1232 cur_len += option_size;
1233 current = data + option_size;
1236 /* Add more options' parsing */
1238 a->nsh_entry.tlvs_len = cur_len;
1239 length += (cur_len >> 2);
1241 length = (length & NSH_LEN_MASK) | ((ttl & 0x3) << 6);
1243 #define _(x) a->nsh_entry.nsh_base.x = x;
1244 foreach_copy_nsh_base_hdr_field;
1247 rv = nsh_add_del_entry (a, &entry_index);
1254 return clib_error_return (0, "nsh_add_del_entry returned %d", rv);
1260 VLIB_CLI_COMMAND (create_nsh_entry_command, static) =
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
1265 = nsh_add_del_entry_command_fn,};
1267 /** API message handler */
1268 static void vl_api_nsh_add_del_entry_t_handler
1269 (vl_api_nsh_add_del_entry_t * mp)
1271 vl_api_nsh_add_del_entry_reply_t *rmp;
1272 nsh_main_t *nm = &nsh_main;
1274 nsh_add_del_entry_args_t _a, *a = &_a;
1275 u32 entry_index = ~0;
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)
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);
1294 else if (mp->md_type == 2)
1296 tlvs_len = mp->tlv_length;
1297 vec_validate_aligned (data, tlvs_len - 1, CLIB_CACHE_LINE_BYTES);
1299 clib_memcpy (data, mp->tlv, tlvs_len);
1300 a->nsh_entry.tlvs_data = data;
1301 a->nsh_entry.tlvs_len = tlvs_len;
1304 rv = nsh_add_del_entry (a, &entry_index);
1306 REPLY_MACRO2 (VL_API_NSH_ADD_DEL_ENTRY_REPLY, (
1309 htonl (entry_index);
1314 static void send_nsh_entry_details
1315 (nsh_entry_t * t, unix_shared_memory_queue_t * q, u32 context)
1317 vl_api_nsh_entry_details_t *rmp;
1318 nsh_main_t *nm = &nsh_main;
1320 rmp = vl_msg_api_alloc (sizeof (*rmp));
1321 clib_memset (rmp, 0, sizeof (*rmp));
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);
1332 if (t->nsh_base.md_type == 1)
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);
1340 else if (t->nsh_base.md_type == 2)
1342 rmp->tlv_length = t->tlvs_len;
1343 clib_memcpy (rmp->tlv, t->tlvs_data, t->tlvs_len);
1346 rmp->context = context;
1348 vl_msg_api_send_shmem (q, (u8 *) & rmp);
1352 vl_api_nsh_entry_dump_t_handler (vl_api_nsh_entry_dump_t * mp)
1354 unix_shared_memory_queue_t *q;
1355 nsh_main_t *nm = &nsh_main;
1359 q = vl_api_client_index_to_input_queue (mp->client_index);
1365 entry_index = ntohl (mp->entry_index);
1367 if (~0 == entry_index)
1369 pool_foreach (t, nm->nsh_entries, (
1371 send_nsh_entry_details (t, q,
1378 if (entry_index >= vec_len (nm->nsh_entries))
1382 t = &nm->nsh_entries[entry_index];
1383 send_nsh_entry_details (t, q, mp->context);
1387 static void send_nsh_map_details
1388 (nsh_map_t * t, unix_shared_memory_queue_t * q, u32 context)
1390 vl_api_nsh_map_details_t *rmp;
1391 nsh_main_t *nm = &nsh_main;
1393 rmp = vl_msg_api_alloc (sizeof (*rmp));
1394 clib_memset (rmp, 0, sizeof (*rmp));
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);
1404 rmp->context = context;
1406 vl_msg_api_send_shmem (q, (u8 *) & rmp);
1410 vl_api_nsh_map_dump_t_handler (vl_api_nsh_map_dump_t * mp)
1412 unix_shared_memory_queue_t *q;
1413 nsh_main_t *nm = &nsh_main;
1417 q = vl_api_client_index_to_input_queue (mp->client_index);
1423 map_index = ntohl (mp->map_index);
1425 if (~0 == map_index)
1427 pool_foreach (t, nm->nsh_mappings, (
1429 send_nsh_map_details (t, q,
1436 if (map_index >= vec_len (nm->nsh_mappings))
1440 t = &nm->nsh_mappings[map_index];
1441 send_nsh_map_details (t, q, mp->context);
1445 static clib_error_t *
1446 show_nsh_entry_command_fn (vlib_main_t * vm,
1447 unformat_input_t * input, vlib_cli_command_t * cmd)
1449 nsh_main_t *nm = &nsh_main;
1450 nsh_entry_t *nsh_entry;
1452 if (pool_elts (nm->nsh_entries) == 0)
1453 vlib_cli_output (vm, "No nsh entries configured.");
1455 pool_foreach (nsh_entry, nm->nsh_entries, (
1457 vlib_cli_output (vm, "%U",
1459 nsh_entry->rewrite);
1460 vlib_cli_output (vm,
1461 " rewrite_size: %d bytes",
1462 nsh_entry->rewrite_size);
1469 VLIB_CLI_COMMAND (show_nsh_entry_command, static) =
1471 .path = "show nsh entry",.function = show_nsh_entry_command_fn,};
1474 /* Set up the API message handling tables */
1475 static clib_error_t *
1476 nsh_plugin_api_hookup (vlib_main_t * vm)
1478 nsh_main_t *nm __attribute__ ((unused)) = &nsh_main;
1480 vl_msg_api_set_handlers((VL_API_##N + nm->msg_id_base), \
1482 vl_api_##n##_t_handler, \
1484 vl_api_##n##_t_endian, \
1485 vl_api_##n##_t_print, \
1486 sizeof(vl_api_##n##_t), 1);
1487 foreach_nsh_plugin_api_msg;
1494 setup_message_id_table (nsh_main_t * nm, api_main_t * am)
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;
1503 nsh_md2_encap (vlib_buffer_t * b, nsh_base_header_t * hdr,
1504 nsh_entry_t * nsh_entry)
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;
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);
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);
1523 /* Scan the set of variable metadata, process ones that we understand */
1524 while (opt0 < limit0)
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;
1530 nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type);
1531 if (nsh_option == NULL)
1536 if (nm->options[nsh_option->option_id])
1538 if ((*nm->options[nsh_option->option_id]) (b, nsh_md2))
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;
1549 nsh_md2 = (nsh_tlv_header_t *) (((u8 *) nsh_md2) + new_option_size);
1550 opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size);
1556 opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size);
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);
1568 nsh_md2_swap (vlib_buffer_t * b,
1569 nsh_base_header_t * hdr,
1571 nsh_entry_t * nsh_entry, u32 * next, u32 drop_node_val)
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;
1582 /* Populate the NSH Header */
1583 opt0 = (nsh_md2_data_t *) (hdr + 1);
1584 limit0 = (nsh_md2_data_t *) ((u8 *) hdr + header_len);
1587 (nsh_tlv_header_t *) (nsh_entry->rewrite + sizeof (nsh_base_header_t));
1588 nsh_entry->rewrite_size = sizeof (nsh_base_header_t);
1590 /* Scan the set of variable metadata, process ones that we understand */
1591 while (opt0 < limit0)
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;
1597 nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type);
1598 if (nsh_option == NULL)
1603 if (nm->swap_options[nsh_option->option_id])
1605 if ((*nm->swap_options[nsh_option->option_id]) (b, opt0, nsh_md2))
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);
1617 opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size);
1623 opt0 = (nsh_tlv_header_t *) (((u8 *) opt0) + old_option_size);
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);
1635 nsh_md2_decap (vlib_buffer_t * b,
1636 nsh_base_header_t * hdr,
1637 u32 * header_len, u32 * next, u32 drop_node_val)
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;
1645 /* Populate the NSH Header */
1646 opt0 = (nsh_md2_data_t *) (hdr + 1);
1647 limit0 = (nsh_md2_data_t *) ((u8 *) hdr + *header_len);
1649 /* Scan the set of variable metadata, process ones that we understand */
1650 while (opt0 < limit0)
1652 nsh_option = nsh_md2_lookup_option (opt0->class, opt0->type);
1653 if (nsh_option == NULL)
1655 *next = drop_node_val;
1659 if (nm->pop_options[nsh_option->option_id])
1661 if ((*nm->pop_options[nsh_option->option_id]) (b, opt0))
1663 *next = drop_node_val;
1667 /* round to 4-byte */
1668 option_len = ((opt0->length + 3) >> 2) << 2;
1670 (nsh_md2_data_t *) (((u8 *) opt0) + sizeof (nsh_md2_data_t) +
1673 (nm->decap_v4_next_override) ? (nm->decap_v4_next_override) : (*next);
1674 *header_len = (nm->decap_v4_next_override) ? 0 : (*header_len);
1681 nsh_input_map (vlib_main_t * vm,
1682 vlib_node_runtime_t * node,
1683 vlib_frame_t * from_frame, u32 node_type)
1685 u32 n_left_from, next_index, *from, *to_next;
1686 nsh_main_t *nm = &nsh_main;
1688 from = vlib_frame_vector_args (from_frame);
1689 n_left_from = from_frame->n_vectors;
1691 next_index = node->cached_next_index;
1693 while (n_left_from > 0)
1697 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1699 while (n_left_from >= 4 && n_left_to_next >= 2)
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;
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;
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;
1720 /* Prefetch next iteration. */
1722 vlib_buffer_t *p2, *p3;
1724 p2 = vlib_get_buffer (vm, from[2]);
1725 p3 = vlib_get_buffer (vm, from[3]);
1727 vlib_prefetch_buffer_header (p2, LOAD);
1728 vlib_prefetch_buffer_header (p3, LOAD);
1730 CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
1731 CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
1741 n_left_to_next -= 2;
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);
1751 /* Process packet 0 */
1752 if (node_type == NSH_INPUT_TYPE)
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;
1759 if (PREDICT_FALSE (ttl0 == 0))
1761 error0 = NSH_NODE_ERROR_INVALID_TTL;
1765 else if (node_type == NSH_CLASSIFIER_TYPE)
1768 clib_host_to_net_u32 (vnet_buffer (b0)->
1769 l2_classify.opaque_index);
1771 else if (node_type == NSH_AWARE_VNF_PROXY_TYPE)
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));
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];
1787 clib_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];
1791 p0 = hash_get_mem (nm->nsh_proxy_session_by_key, &key0);
1792 if (PREDICT_FALSE (p0 == 0))
1794 error0 = NSH_NODE_ERROR_NO_PROXY;
1798 proxy0 = pool_elt_at_index (nm->nsh_proxy_sessions, p0[0]);
1799 if (PREDICT_FALSE (proxy0 == 0))
1801 error0 = NSH_NODE_ERROR_NO_PROXY;
1804 nsp_nsi0 = proxy0->nsp_nsi;
1807 entry0 = hash_get_mem (nm->nsh_mapping_by_key, &nsp_nsi0);
1808 if (PREDICT_FALSE (entry0 == 0))
1810 error0 = NSH_NODE_ERROR_NO_MAPPING;
1814 /* Entry should point to a mapping ... */
1815 map0 = pool_elt_at_index (nm->nsh_mappings, entry0[0]);
1816 if (PREDICT_FALSE (map0 == 0))
1818 error0 = NSH_NODE_ERROR_NO_MAPPING;
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;
1827 if (PREDICT_FALSE (map0->nsh_action == NSH_ACTION_POP))
1829 /* Manipulate MD2 */
1830 if (PREDICT_FALSE (hdr0->md_type == 2))
1832 nsh_md2_decap (b0, hdr0, &header_len0, &next0,
1833 NSH_NODE_NEXT_DROP);
1834 if (PREDICT_FALSE (next0 == NSH_NODE_NEXT_DROP))
1836 error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
1839 vnet_buffer (b0)->sw_if_index[VLIB_RX] =
1840 map0->rx_sw_if_index;
1843 /* Pop NSH header */
1844 vlib_buffer_advance (b0, (word) header_len0);
1848 entry0 = hash_get_mem (nm->nsh_entry_by_key, &map0->mapped_nsp_nsi);
1849 if (PREDICT_FALSE (entry0 == 0))
1851 error0 = NSH_NODE_ERROR_NO_ENTRY;
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;
1861 if (PREDICT_TRUE (map0->nsh_action == NSH_ACTION_SWAP))
1863 /* Manipulate MD2 */
1864 if (PREDICT_FALSE (hdr0->md_type == 2))
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))
1870 error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
1875 /* Pop old NSH header */
1876 vlib_buffer_advance (b0, (word) header_len0);
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);
1888 if (PREDICT_TRUE (map0->nsh_action == NSH_ACTION_PUSH))
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);
1897 /* Manipulate MD2 */
1898 if (PREDICT_FALSE (nsh_entry0->nsh_base.md_type == 2))
1900 nsh_md2_encap (b0, hdr0, nsh_entry0);
1906 b0->error = error0 ? node->errors[error0] : 0;
1908 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
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));
1916 /* Process packet 1 */
1917 if (node_type == NSH_INPUT_TYPE)
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;
1924 if (PREDICT_FALSE (ttl1 == 0))
1926 error1 = NSH_NODE_ERROR_INVALID_TTL;
1930 else if (node_type == NSH_CLASSIFIER_TYPE)
1933 clib_host_to_net_u32 (vnet_buffer (b1)->
1934 l2_classify.opaque_index);
1936 else if (node_type == NSH_AWARE_VNF_PROXY_TYPE)
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));
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];
1952 clib_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];
1956 p1 = hash_get_mem (nm->nsh_proxy_session_by_key, &key1);
1957 if (PREDICT_FALSE (p1 == 0))
1959 error1 = NSH_NODE_ERROR_NO_PROXY;
1963 proxy1 = pool_elt_at_index (nm->nsh_proxy_sessions, p1[0]);
1964 if (PREDICT_FALSE (proxy1 == 0))
1966 error1 = NSH_NODE_ERROR_NO_PROXY;
1969 nsp_nsi1 = proxy1->nsp_nsi;
1972 entry1 = hash_get_mem (nm->nsh_mapping_by_key, &nsp_nsi1);
1973 if (PREDICT_FALSE (entry1 == 0))
1975 error1 = NSH_NODE_ERROR_NO_MAPPING;
1979 /* Entry should point to a mapping ... */
1980 map1 = pool_elt_at_index (nm->nsh_mappings, entry1[0]);
1981 if (PREDICT_FALSE (map1 == 0))
1983 error1 = NSH_NODE_ERROR_NO_MAPPING;
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;
1992 if (PREDICT_FALSE (map1->nsh_action == NSH_ACTION_POP))
1994 /* Manipulate MD2 */
1995 if (PREDICT_FALSE (hdr1->md_type == 2))
1997 nsh_md2_decap (b1, hdr1, &header_len1, &next1,
1998 NSH_NODE_NEXT_DROP);
1999 if (PREDICT_FALSE (next1 == NSH_NODE_NEXT_DROP))
2001 error1 = NSH_NODE_ERROR_INVALID_OPTIONS;
2004 vnet_buffer (b1)->sw_if_index[VLIB_RX] =
2005 map1->rx_sw_if_index;
2008 /* Pop NSH header */
2009 vlib_buffer_advance (b1, (word) header_len1);
2013 entry1 = hash_get_mem (nm->nsh_entry_by_key, &map1->mapped_nsp_nsi);
2014 if (PREDICT_FALSE (entry1 == 0))
2016 error1 = NSH_NODE_ERROR_NO_ENTRY;
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;
2026 if (PREDICT_TRUE (map1->nsh_action == NSH_ACTION_SWAP))
2028 /* Manipulate MD2 */
2029 if (PREDICT_FALSE (hdr1->md_type == 2))
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))
2035 error1 = NSH_NODE_ERROR_INVALID_OPTIONS;
2040 /* Pop old NSH header */
2041 vlib_buffer_advance (b1, (word) header_len1);
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);
2053 if (PREDICT_FALSE (map1->nsh_action == NSH_ACTION_PUSH))
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);
2062 /* Manipulate MD2 */
2063 if (PREDICT_FALSE (nsh_entry1->nsh_base.md_type == 2))
2065 nsh_md2_encap (b1, hdr1, nsh_entry1);
2071 b1->error = error1 ? node->errors[error1] : 0;
2073 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
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));
2081 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
2082 n_left_to_next, bi0, bi1, next0,
2087 while (n_left_from > 0 && n_left_to_next > 0)
2090 vlib_buffer_t *b0 = NULL;
2091 u32 next0 = NSH_NODE_NEXT_DROP;
2093 nsh_base_header_t *hdr0 = 0;
2094 u32 header_len0 = 0;
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;
2102 nsh_proxy_session_by_key_t key0;
2104 nsh_proxy_session_t *proxy0 = 0;
2105 u32 sw_if_index0 = 0;
2106 ethernet_header_t dummy_eth0;
2113 n_left_to_next -= 1;
2116 b0 = vlib_get_buffer (vm, bi0);
2117 hdr0 = vlib_buffer_get_current (b0);
2119 if (node_type == NSH_INPUT_TYPE)
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;
2126 if (PREDICT_FALSE (ttl0 == 0))
2128 error0 = NSH_NODE_ERROR_INVALID_TTL;
2132 else if (node_type == NSH_CLASSIFIER_TYPE)
2135 clib_host_to_net_u32 (vnet_buffer (b0)->
2136 l2_classify.opaque_index);
2138 else if (node_type == NSH_AWARE_VNF_PROXY_TYPE)
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));
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];
2154 clib_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];
2158 p0 = hash_get_mem (nm->nsh_proxy_session_by_key, &key0);
2159 if (PREDICT_FALSE (p0 == 0))
2161 error0 = NSH_NODE_ERROR_NO_PROXY;
2165 proxy0 = pool_elt_at_index (nm->nsh_proxy_sessions, p0[0]);
2166 if (PREDICT_FALSE (proxy0 == 0))
2168 error0 = NSH_NODE_ERROR_NO_PROXY;
2171 nsp_nsi0 = proxy0->nsp_nsi;
2174 entry0 = hash_get_mem (nm->nsh_mapping_by_key, &nsp_nsi0);
2176 if (PREDICT_FALSE (entry0 == 0))
2178 error0 = NSH_NODE_ERROR_NO_MAPPING;
2182 /* Entry should point to a mapping ... */
2183 map0 = pool_elt_at_index (nm->nsh_mappings, entry0[0]);
2185 if (PREDICT_FALSE (map0 == 0))
2187 error0 = NSH_NODE_ERROR_NO_MAPPING;
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;
2197 if (PREDICT_FALSE (map0->nsh_action == NSH_ACTION_POP))
2199 /* Manipulate MD2 */
2200 if (PREDICT_FALSE (hdr0->md_type == 2))
2202 nsh_md2_decap (b0, hdr0, &header_len0, &next0,
2203 NSH_NODE_NEXT_DROP);
2204 if (PREDICT_FALSE (next0 == NSH_NODE_NEXT_DROP))
2206 error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
2209 vnet_buffer (b0)->sw_if_index[VLIB_RX] =
2210 map0->rx_sw_if_index;
2213 /* Pop NSH header */
2214 vlib_buffer_advance (b0, (word) header_len0);
2218 entry0 = hash_get_mem (nm->nsh_entry_by_key, &map0->mapped_nsp_nsi);
2219 if (PREDICT_FALSE (entry0 == 0))
2221 error0 = NSH_NODE_ERROR_NO_ENTRY;
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;
2231 if (PREDICT_TRUE (map0->nsh_action == NSH_ACTION_SWAP))
2233 /* Manipulate MD2 */
2234 if (PREDICT_FALSE (hdr0->md_type == 2))
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))
2240 error0 = NSH_NODE_ERROR_INVALID_OPTIONS;
2245 /* Pop old NSH header */
2246 vlib_buffer_advance (b0, (word) header_len0);
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);
2258 if (PREDICT_TRUE (map0->nsh_action == NSH_ACTION_PUSH))
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))
2269 nsh_md2_encap (b0, hdr0, nsh_entry0);
2274 trace00:b0->error = error0 ? node->errors[error0] : 0;
2276 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
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));
2284 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2285 n_left_to_next, bi0, next0);
2288 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2292 return from_frame->n_vectors;
2296 * @brief Graph processing dispatch function for NSH Input
2301 * @param *from_frame
2303 * @return from_frame->n_vectors
2307 nsh_input (vlib_main_t * vm, vlib_node_runtime_t * node,
2308 vlib_frame_t * from_frame)
2310 return nsh_input_map (vm, node, from_frame, NSH_INPUT_TYPE);
2314 * @brief Graph processing dispatch function for NSH-Proxy
2319 * @param *from_frame
2321 * @return from_frame->n_vectors
2325 nsh_proxy (vlib_main_t * vm, vlib_node_runtime_t * node,
2326 vlib_frame_t * from_frame)
2328 return nsh_input_map (vm, node, from_frame, NSH_PROXY_TYPE);
2332 * @brief Graph processing dispatch function for NSH Classifier
2334 * @node nsh_classifier
2337 * @param *from_frame
2339 * @return from_frame->n_vectors
2343 nsh_classifier (vlib_main_t * vm, vlib_node_runtime_t * node,
2344 vlib_frame_t * from_frame)
2346 return nsh_input_map (vm, node, from_frame, NSH_CLASSIFIER_TYPE);
2350 * @brief Graph processing dispatch function for NSH-AWARE-VNF-PROXY
2352 * @node nsh_aware_vnf_proxy
2355 * @param *from_frame
2357 * @return from_frame->n_vectors
2361 nsh_aware_vnf_proxy (vlib_main_t * vm, vlib_node_runtime_t * node,
2362 vlib_frame_t * from_frame)
2364 return nsh_input_map (vm, node, from_frame, NSH_AWARE_VNF_PROXY_TYPE);
2367 static char *nsh_node_error_strings[] = {
2368 #define _(sym,string) string,
2369 foreach_nsh_node_error
2373 /* register nsh-input node */
2374 VLIB_REGISTER_NODE (nsh_input_node) =
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 =
2382 #define _(s,n) [NSH_NODE_NEXT_##s] = n,
2383 foreach_nsh_node_next
2388 VLIB_NODE_FUNCTION_MULTIARCH (nsh_input_node, nsh_input);
2390 /* register nsh-proxy node */
2391 VLIB_REGISTER_NODE (nsh_proxy_node) =
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 =
2399 #define _(s,n) [NSH_NODE_NEXT_##s] = n,
2400 foreach_nsh_node_next
2405 VLIB_NODE_FUNCTION_MULTIARCH (nsh_proxy_node, nsh_proxy);
2407 /* register nsh-classifier node */
2408 VLIB_REGISTER_NODE (nsh_classifier_node) =
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 =
2416 #define _(s,n) [NSH_NODE_NEXT_##s] = n,
2417 foreach_nsh_node_next
2422 VLIB_NODE_FUNCTION_MULTIARCH (nsh_classifier_node, nsh_classifier);
2424 /* register nsh-aware-vnf-proxy node */
2425 VLIB_REGISTER_NODE (nsh_aware_vnf_proxy_node) =
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 =
2433 #define _(s,n) [NSH_NODE_NEXT_##s] = n,
2434 foreach_nsh_node_next
2439 VLIB_NODE_FUNCTION_MULTIARCH (nsh_aware_vnf_proxy_node, nsh_aware_vnf_proxy);
2442 nsh_md2_set_next_ioam_export_override (uword next)
2444 nsh_main_t *hm = &nsh_main;
2445 hm->decap_v4_next_override = next;
2451 nsh_init (vlib_main_t * vm)
2453 nsh_main_t *nm = &nsh_main;
2454 clib_error_t *error = 0;
2458 /* Init the main structures from VPP */
2460 nm->vnet_main = vnet_get_main ();
2462 /* Various state maintenance mappings */
2463 nm->nsh_mapping_by_key = hash_create_mem (0, sizeof (u32), sizeof (uword));
2465 nm->nsh_mapping_by_mapped_key
2466 = hash_create_mem (0, sizeof (u32), sizeof (uword));
2468 nm->nsh_entry_by_key = hash_create_mem (0, sizeof (u32), sizeof (uword));
2470 nm->nsh_proxy_session_by_key
2472 hash_create_mem (0, sizeof (nsh_proxy_session_by_key_t), sizeof (uword));
2474 nm->nsh_option_map_by_key
2475 = hash_create_mem (0, sizeof (nsh_option_map_by_key_t), sizeof (uword));
2477 name = format (0, "nsh_%08x%c", api_version, 0);
2479 /* Set up the API */
2480 nm->msg_id_base = vl_msg_api_get_msg_ids
2481 ((char *) name, VL_MSG_FIRST_AVAILABLE);
2483 error = nsh_plugin_api_hookup (vm);
2485 /* Add our API messages to the global name_crc hash table */
2486 setup_message_id_table (nm, &api_main);
2488 /* Add dispositions to nodes that feed nsh-input */
2489 //alagalah - validate we don't really need to use the node value
2491 vlib_node_add_next (vm, vxlan4_gpe_input_node.index,
2492 nsh_input_node.index);
2493 vlib_node_add_next (vm, vxlan4_gpe_input_node.index, nsh_proxy_node.index);
2494 vlib_node_add_next (vm, vxlan4_gpe_input_node.index,
2495 nsh_aware_vnf_proxy_node.index);
2496 vxlan_gpe_register_decap_protocol (VXLAN_GPE_PROTOCOL_NSH, next_node);
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);
2500 vlib_node_add_next (vm, vxlan6_gpe_input_node.index,
2501 nsh_aware_vnf_proxy_node.index);
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);
2505 vlib_node_add_next (vm, gre4_input_node.index,
2506 nsh_aware_vnf_proxy_node.index);
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);
2510 vlib_node_add_next (vm, gre6_input_node.index,
2511 nsh_aware_vnf_proxy_node.index);
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);
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);
2520 vlib_node_add_next (vm, l2_input_classify_node.index,
2521 nsh_classifier_node.index);
2523 /* Add Ethernet+NSH support */
2524 ethernet_register_input_type (vm, ETHERNET_TYPE_NSH, nsh_input_node.index);
2531 VLIB_INIT_FUNCTION (nsh_init);
2534 VLIB_PLUGIN_REGISTER () = {
2535 .version = VPP_BUILD_VER,
2536 .description = "Network Service Header",
2541 * fd.io coding-style-patch-verification: ON
2544 * eval: (c-set-style "gnu")