diff options
author | Luca Muscariello <lumuscar+fdio@cisco.com> | 2019-01-17 13:47:57 +0100 |
---|---|---|
committer | Luca Muscariello <lumuscar+fdio@cisco.com> | 2019-01-17 16:32:51 +0100 |
commit | bac3da61644515f05663789b122554dc77549286 (patch) | |
tree | 898210bc8e70371d77de7d446a26c5dd4fd1165a /hicn-plugin/src/faces/udp | |
parent | d5165246787301d0f13b646fda5e8a8567aef5ac (diff) |
This is the first commit of the hicn projectv19.01
Change-Id: I6f2544ad9b9f8891c88cc4bcce3cf19bd3cc863f
Signed-off-by: Luca Muscariello <lumuscar+fdio@cisco.com>
Diffstat (limited to 'hicn-plugin/src/faces/udp')
-rwxr-xr-x | hicn-plugin/src/faces/udp/dpo_udp.c | 158 | ||||
-rwxr-xr-x | hicn-plugin/src/faces/udp/dpo_udp.h | 312 | ||||
-rwxr-xr-x | hicn-plugin/src/faces/udp/face_udp.c | 371 | ||||
-rwxr-xr-x | hicn-plugin/src/faces/udp/face_udp.h | 248 | ||||
-rwxr-xr-x | hicn-plugin/src/faces/udp/face_udp_cli.c | 164 | ||||
-rwxr-xr-x | hicn-plugin/src/faces/udp/face_udp_node.c | 864 | ||||
-rwxr-xr-x | hicn-plugin/src/faces/udp/face_udp_node.h | 35 | ||||
-rwxr-xr-x | hicn-plugin/src/faces/udp/iface_udp_node.c | 894 | ||||
-rwxr-xr-x | hicn-plugin/src/faces/udp/iface_udp_node.h | 36 |
9 files changed, 3082 insertions, 0 deletions
diff --git a/hicn-plugin/src/faces/udp/dpo_udp.c b/hicn-plugin/src/faces/udp/dpo_udp.c new file mode 100755 index 000000000..e58fc9788 --- /dev/null +++ b/hicn-plugin/src/faces/udp/dpo_udp.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "dpo_udp.h" + +#include <vnet/ip/format.h> +#include <vnet/adj/adj.h> +#include <vnet/vnet.h> +#include <vlib/vlib.h> + +const static char *const hicn_face_ip4udp_nodes[] = { + "hicn-face-encap-udp4", + "hicn-face-decap-udp4", + "hicn-iface-decap-udp4", + "hicn-iface-encap-udp4", + NULL, +}; + +const static char *const hicn_face_ip6udp_nodes[] = { + "hicn-face-encap-udp6", + "hicn-face-decap-udp6", + "hicn-iface-decap-udp6", + "hicn-iface-encap-udp6", + NULL, +}; + +const static char *const *const hicn_ipudp_nodes[DPO_PROTO_NUM] = { + [DPO_PROTO_IP4] = hicn_face_ip4udp_nodes, + [DPO_PROTO_IP6] = hicn_face_ip6udp_nodes +}; + + +const static dpo_vft_t hicn_dpoi_udp_vft = { + .dv_lock = hicn_face_lock, + .dv_unlock = hicn_face_unlock, + .dv_format = format_hicn_face_udp, +}; + +/* Must be executed after all the strategy nodes are created */ +void +hicn_dpo_udp_module_init (void) +{ + mhash_init (&hicn_face_udp_hashtb, sizeof (hicn_face_id_t) /* value */ , + sizeof (hicn_face_udp_key_t) /* key */ ); + + /* + * How much useful is the following registration? + * So far it seems that we need it only for setting the dpo_type. + */ + hicn_face_udp_type = + dpo_register_new_type (&hicn_dpoi_udp_vft, hicn_ipudp_nodes); +} + + +/* Here udp ports are in host order, move them to network order to do the lookup */ +int +hicn_dpo_udp4_create (dpo_id_t * dpo, + const ip4_address_t * src_ip, + const ip4_address_t * dst_ip, + u16 src_port, u16 dst_port, + u32 sw_if, + adj_index_t ip_adj, + u32 node_index, + hicn_face_flags_t flags, hicn_face_id_t * face_id) +{ + u16 net_src_port = clib_host_to_net_u16 (src_port); + u16 net_dst_port = clib_host_to_net_u16 (dst_port); + hicn_face_t *face = hicn_face_udp4_get (src_ip, dst_ip, src_port, dst_port); + + u8 is_appface; + /* ip_csum_t sum0; */ + + if (face != NULL) + return HICN_ERROR_FACE_ALREADY_CREATED; + + hicn_dpo_udp4_add_and_lock (dpo, src_ip, dst_ip, net_src_port, net_dst_port, + node_index, &is_appface); + + face = hicn_dpoi_get_from_idx (dpo->dpoi_index); + + hicn_face_udp_t *udp_face = (hicn_face_udp_t *) face->data; + + udp_face->hdrs.ip4.ip.checksum = + ip4_header_checksum (&(udp_face->hdrs.ip4.ip)); + + face->shared.flags = flags; + face->shared.adj = ip_adj; + face->shared.sw_if = sw_if; + *face_id = hicn_dpoi_get_index (face); + + return HICN_ERROR_NONE; +} + + +int +hicn_dpo_udp6_create (dpo_id_t * dpo, + const ip6_address_t * src_ip, + const ip6_address_t * dst_ip, + u16 src_port, u16 dst_port, + u32 sw_if, + adj_index_t ip_adj, + u32 node_index, + hicn_face_flags_t flags, hicn_face_id_t * face_id) +{ + u16 net_src_port = clib_host_to_net_u16 (src_port); + u16 net_dst_port = clib_host_to_net_u16 (dst_port); + hicn_face_t *face = + hicn_face_udp6_get (src_ip, dst_ip, net_src_port, net_dst_port); + u8 is_appface; + + if (face != NULL) + return HICN_ERROR_FACE_ALREADY_CREATED; + + hicn_dpo_udp6_add_and_lock (dpo, src_ip, dst_ip, net_src_port, net_dst_port, + node_index, &is_appface); + + face = hicn_dpoi_get_from_idx (dpo->dpoi_index); + + face->shared.flags = flags; + face->shared.adj = ip_adj; + face->shared.sw_if = sw_if; + *face_id = hicn_dpoi_get_index (face); + + return HICN_ERROR_NONE; +} + +void +hicn_dpo_udp_create_from_face (hicn_face_t * face, dpo_id_t * dpo, + u16 dpoi_next_node) +{ + hicn_face_id_t face_dpoi_id = hicn_dpoi_get_index (face); + hicn_face_udp_t *face_udp = (hicn_face_udp_t *) face->data; + u8 version = + (face_udp->hdrs.ip4.ip.ip_version_and_header_length & 0xf0) >> 4; + dpo_set (dpo, face->shared.face_type, + version == 4 ? DPO_PROTO_IP4 : DPO_PROTO_IP6, face_dpoi_id); + dpo->dpoi_next_node = dpoi_next_node; +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/hicn-plugin/src/faces/udp/dpo_udp.h b/hicn-plugin/src/faces/udp/dpo_udp.h new file mode 100755 index 000000000..fdde4192b --- /dev/null +++ b/hicn-plugin/src/faces/udp/dpo_udp.h @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __HICN_DPO_UDP_H__ +#define __HICN_DPO_UDP_H__ + +#include <vnet/adj/adj_types.h> +#include <vnet/ip/ip4_packet.h> +#include <vnet/ip/ip6_packet.h> + +#include "face_udp.h" +#include "../face.h" +#include "../../error.h" + + +/** + * @brief Initialize the internal structures of the dpo udp face module. + */ +void hicn_dpo_udp_module_init (void); + +/** + * @brief Create a udp face and its corresponding dpo. Meant to be used for the + * control plane. + * + * @param dpo: Data plane object that point to the face created. + * @param local_addr: Local address of the UDP tunnel + * @param remote_addr: Remote address of the UDP tunnel + * @param local_port: Local port of the UDP tunnel + * @param remote_port: Remote port of the UDP tunnel + * @param adj: Ip adjacency corresponding to the remote address in the face + * @param node_index: vlib edge index to use in the packet processing + * @param flags: Flags of the face + * @param face_id: Identifier for the face (dpoi_index) + * @return HICN_ERROR_FACE_ALREADY_CREATED if the face exists, otherwise HICN_ERROR_NONE + */ +int +hicn_dpo_udp4_create (dpo_id_t * dpo, + const ip4_address_t * local_addr, + const ip4_address_t * remote_addr, + u16 local_port, u16 remote_port, + u32 sw_if, + adj_index_t adj, + u32 node_index, + hicn_face_flags_t flags, hicn_face_id_t * face_id); + +/** + * @brief Retrieve a face using the face identifier, i.e., the quadruplet (local_addr, remote_addr, + * local_port, remote_port). This method adds a lock on the face state. + * + * @param dpo: Result of the lookup. If the face doesn't exist dpo = NULL + * @param local_addr: Local address of the UDP tunnel + * @param remote_addr: Remote address of the UDP tunnel + * @param local_port: Local port of the UDP tunnel + * @param remote_port: Remote port of the UDP tunnel + * @param is_appface: Boolean that indicates whether the face is an application + * face or not. (Currently only IP faces can be appface) + * + * @result HICN_ERROR_FACE_NOT_FOUND if the face does not exist, otherwise HICN_ERROR_NONE. + */ +always_inline int +hicn_dpo_udp4_lock (dpo_id_t * dpo, + const ip4_address_t * local_addr, + const ip4_address_t * remote_addr, + u16 local_port, u16 remote_port, u8 * is_appface) +{ + hicn_face_t *face = + hicn_face_udp4_get (local_addr, remote_addr, local_port, remote_port); + + if (PREDICT_FALSE (face == NULL)) + return HICN_ERROR_FACE_NOT_FOUND; + + index_t dpoi_index = hicn_dpoi_get_index (face); + dpo_set (dpo, hicn_face_udp_type, DPO_PROTO_IP4, dpoi_index); + dpo->dpoi_next_node = ~0; + dpo_lock (dpo); + + *is_appface = 0; + + return HICN_ERROR_NONE; +} + +/** + * @brief Retrieve, or create if it doesn't exist, a face from the face + * identifier (local_addr, remote_addr, local_port, remote_port) and returns its + * dpo. This method adds a lock on the face state. + * + * @param dpo: Result of the lookup + * @param local_addr: Local address of the UDP tunnel + * @param remote_addr: Remote address of the UDP tunnel + * @param local_port: Local port of the UDP tunnel + * @param remote_port: Remote port of the UDP tunnel + * @param is_appface: Boolean that indicates whether the face is an application + * face or not. (Currently only IP faces can be appface) + * @param node_index: vlib edge index to use in the packet processing + */ +always_inline void +hicn_dpo_udp4_add_and_lock (dpo_id_t * dpo, + const ip4_address_t * local_addr, + const ip4_address_t * remote_addr, + u16 local_port, u16 remote_port, + u32 node_index, u8 * is_appface) +{ + hicn_face_t *face = + hicn_face_udp4_get (local_addr, remote_addr, local_port, remote_port); + + if (face == NULL) + { + pool_get (hicn_dpoi_face_pool, face); + + hicn_face_udp_t *udp_face = (hicn_face_udp_t *) face->data; + + clib_memcpy (&(udp_face->hdrs.ip4.ip), &ip4_header_skl, + sizeof (ip4_header_t)); + clib_memcpy (&(udp_face->hdrs.ip4.ip.src_address), local_addr, + sizeof (ip4_address_t)); + clib_memcpy (&(udp_face->hdrs.ip4.ip.dst_address), remote_addr, + sizeof (ip4_address_t)); + + udp_face->hdrs.ip4.udp.src_port = local_port; + udp_face->hdrs.ip4.udp.dst_port = remote_port; + + face->shared.adj = ADJ_INDEX_INVALID; + face->shared.pl_id = (u16) 0; + face->shared.face_type = hicn_face_udp_type; + face->shared.flags = HICN_FACE_FLAGS_IFACE; + face->shared.locks = 0; + + hicn_face_udp_key_t key; + hicn_face_udp4_get_key (local_addr, remote_addr, local_port, + remote_port, &key); + hicn_face_id_t dpoi_index = hicn_dpoi_get_index (face); + + mhash_set_mem (&hicn_face_udp_hashtb, &key, (uword *) & dpoi_index, 0); + face = face; + + *is_appface = 0; + dpo_set (dpo, hicn_face_udp_type, DPO_PROTO_IP4, dpoi_index); + dpo->dpoi_next_node = node_index; + dpo_lock (dpo); + + return; + } + + *is_appface = 0; + + hicn_face_id_t dpoi_index = hicn_dpoi_get_index (face); + dpo_set (dpo, hicn_face_udp_type, DPO_PROTO_IP4, dpoi_index); + dpo->dpoi_next_node = node_index; + dpo_lock (dpo); +} + +/** + * @brief Create a udp face and its corresponding dpo. Meant to be used for the + * control plane. + * + * @param dpo: Data plane object that point to the face created. + * @param local_addr: Local address of the UDP tunnel + * @param remote_addr: Remote address of the UDP tunnel + * @param local_port: Local port of the UDP tunnel + * @param remote_port: Remote port of the UDP tunnel + * @param adj: Ip adjacency corresponding to the remote address in the face + * @param node_index: vlib edge index to use in the packet processing + * @param flags: Flags of the face + * @param face_id: Identifier for the face (dpoi_index) + * @return HICN_ERROR_FACE_ALREADY_CREATED if the face exists, otherwise HICN_ERROR_NONE + */ +int +hicn_dpo_udp6_create (dpo_id_t * dpo, + const ip6_address_t * local_addr, + const ip6_address_t * remote_addr, + u16 local_port, u16 remote_port, + u32 sw_if, + adj_index_t adj, + u32 node_index, + hicn_face_flags_t flags, hicn_face_id_t * face_id); + + +/** + * @brief Retrieve a face using the face identifier, i.e., the quadruplet (local_addr, remote_addr, + * local_port, remote_port). This method adds a lock on the face state. + * + * @param dpo: Result of the lookup. If the face doesn't exist dpo = NULL + * @param local_addr: Local address of the UDP tunnel + * @param remote_addr: Remote address of the UDP tunnel + * @param local_port: Local port of the UDP tunnel + * @param remote_port: Remote port of the UDP tunnel + * @param is_appface: Boolean that indicates whether the face is an application + * face or not. (Currently only IP faces can be appface) + * + * @result HICN_ERROR_FACE_NOT_FOUND if the face does not exist, otherwise HICN_ERROR_NONE. + */ +always_inline int +hicn_dpo_udp6_lock (dpo_id_t * dpo, + const ip6_address_t * local_addr, + const ip6_address_t * remote_addr, + u16 local_port, u16 remote_port, u8 * is_appface) +{ + hicn_face_t *face = + hicn_face_udp6_get (local_addr, remote_addr, local_port, remote_port); + + + if (PREDICT_FALSE (face == NULL)) + return HICN_ERROR_FACE_NOT_FOUND; + + hicn_face_id_t dpoi_index = hicn_dpoi_get_index (face); + dpo_set (dpo, hicn_face_udp_type, DPO_PROTO_IP4, dpoi_index); + dpo->dpoi_next_node = ~0; + dpo_lock (dpo); + *is_appface = 0; + + return HICN_ERROR_NONE; +} + +/** + * @brief Retrieve, or create if it doesn't exist, a face from the face + * identifier (local_addr, remote_addr, local_port, remote_port) and returns its + * dpo. This method adds a lock on the face state. + * + * @param dpo: Result of the lookup + * @param local_addr: Local address of the UDP tunnel + * @param remote_addr: Remote address of the UDP tunnel + * @param local_port: Local port of the UDP tunnel + * @param remote_port: Remote port of the UDP tunnel + * @param is_appface: Boolean that indicates whether the face is an application + * face or not. (Currently only IP faces can be appface) + * @param node_index: vlib edge index to use in the packet processing + */ +always_inline void +hicn_dpo_udp6_add_and_lock (dpo_id_t * dpo, + const ip6_address_t * local_addr, + const ip6_address_t * remote_addr, + u16 local_port, u16 remote_port, + u32 node_index, u8 * is_appface) +{ + hicn_face_t *face = + hicn_face_udp6_get (local_addr, remote_addr, local_port, remote_port); + + if (face == NULL) + { + pool_get (hicn_dpoi_face_pool, face); + + hicn_face_udp_t *udp_face = (hicn_face_udp_t *) face->data; + + clib_memcpy (&(udp_face->hdrs.ip6.ip), &ip6_header_skl, + sizeof (ip6_header_t)); + clib_memcpy (&(udp_face->hdrs.ip6.ip.src_address), local_addr, + sizeof (ip6_address_t)); + clib_memcpy (&(udp_face->hdrs.ip6.ip.dst_address), remote_addr, + sizeof (ip6_address_t)); + + udp_face->hdrs.ip6.udp.src_port = local_port; + udp_face->hdrs.ip6.udp.dst_port = remote_port; + + face->shared.adj = ADJ_INDEX_INVALID; + face->shared.pl_id = (u16) 0; + face->shared.face_type = hicn_face_udp_type; + face->shared.flags = HICN_FACE_FLAGS_IFACE; + face->shared.locks = 0; + + hicn_face_udp_key_t key; + hicn_face_udp6_get_key (local_addr, remote_addr, local_port, + remote_port, &key); + hicn_face_id_t dpoi_index = hicn_dpoi_get_index (face); + + mhash_set_mem (&hicn_face_udp_hashtb, &key, (uword *) & dpoi_index, 0); + + *is_appface = 0; + dpo_set (dpo, hicn_face_udp_type, DPO_PROTO_IP6, dpoi_index); + dpo->dpoi_next_node = node_index; + dpo_lock (dpo); + + return; + } + + *is_appface = 0; + + hicn_face_id_t dpoi_index = hicn_dpoi_get_index (face); + dpo_set (dpo, hicn_face_udp_type, DPO_PROTO_IP6, dpoi_index); + dpo->dpoi_next_node = node_index; + dpo_lock (dpo); +} + +/** + * @brief Create a dpo from a udp face + * + * @param face Face from which to create the dpo + * @return the dpo + */ +void hicn_dpo_udp_create_from_face (hicn_face_t * face, dpo_id_t * dpo, + u16 dpoi_next_node); + +#endif // __HICN_DPO_UDP_H__ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/hicn-plugin/src/faces/udp/face_udp.c b/hicn-plugin/src/faces/udp/face_udp.c new file mode 100755 index 000000000..92335273a --- /dev/null +++ b/hicn-plugin/src/faces/udp/face_udp.c @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <vlib/vlib.h> +#include <vnet/vnet.h> + +#include "face_udp.h" +#include "face_udp_node.h" +#include "dpo_udp.h" +#include "../face.h" +#include "../../strategy.h" +#include "../../strategy_dpo_manager.h" +#include "../../hicn.h" + +#include "../../mapme.h" // HICN_MAPME_EVENT_* +#include "../../mapme_eventmgr.h" // hicn_mapme_eventmgr_process_node +extern vlib_node_registration_t hicn_mapme_eventmgr_process_node; + +mhash_t hicn_face_udp_hashtb; + +dpo_type_t hicn_face_udp_type; + +ip4_header_t ip4_header_skl = { + .ip_version_and_header_length = 0x45, + .tos = 0x00, + .length = (u16) 0, + .fragment_id = (u16) 0, + .flags_and_fragment_offset = (u16) 0, + .ttl = 254, + .protocol = IP_PROTOCOL_UDP, + .checksum = 0, + .src_address = {{0}}, + .dst_address = {{0}}, +}; + +ip6_header_t ip6_header_skl = { +#if CLIB_ARCH_IS_BIG_ENDIAN + .ip_version_traffic_class_and_flow_label = 0x60000000, +#else + .ip_version_traffic_class_and_flow_label = 0x00000060, +#endif + .payload_length = (u16) 0, + .protocol = IP_PROTOCOL_UDP, + .hop_limit = 254, + .src_address = {{0}}, + .dst_address = {{0}} +}; + +u32 strategy_face_udp4_vlib_edge; +u32 strategy_face_udp6_vlib_edge; + +/* Separated from the hicn_face_udp_init because it cannot be called by the + init macro due to dependencies with other modules not yet initialied */ +void +hicn_face_udp_init_internal () +{ + ip4_header_t *ip4_hdr = &ip4_header_skl; + ip4_header_skl.checksum = ip4_header_checksum (ip4_hdr); +} + +void +hicn_face_udp_init (vlib_main_t * vm) +{ + int strategy_nodes_n = hicn_strategy_get_all_available (); + + /* Default Strategy has index 0 and it always exists */ + strategy_face_udp4_vlib_edge = vlib_node_add_next (vm, + hicn_dpo_get_strategy_vft + (default_dpo. + hicn_dpo_get_type ())-> + get_strategy_node_index + (), + hicn_face_udp4_output_node. + index); + strategy_face_udp6_vlib_edge = + vlib_node_add_next (vm, + hicn_dpo_get_strategy_vft (default_dpo. + hicn_dpo_get_type ())-> + get_strategy_node_index (), + hicn_face_udp6_output_node.index); + + /* + * Create and edge between al the other strategy nodes + * and the udp_output nodes. + */ + for (int i = 1; i < strategy_nodes_n; i++) + { + u32 temp_index4 = vlib_node_add_next (vm, + hicn_dpo_get_strategy_vft_from_id + (i)->get_strategy_node_index (), + hicn_face_udp4_output_node.index); + u32 temp_index6 = vlib_node_add_next (vm, + hicn_dpo_get_strategy_vft_from_id + (i)->get_strategy_node_index (), + hicn_face_udp6_output_node.index); + ASSERT (temp_index4 == strategy_face_udp4_vlib_edge); + ASSERT (temp_index6 == strategy_face_udp6_vlib_edge); + } + + hicn_dpo_udp_module_init (); + + register_face_type (hicn_face_udp_type, &udp_vft, "udp");; +} + +int +hicn_face_udp_add (const ip46_address_t * local_addr, + const ip46_address_t * remote_addr, u16 local_port, + u16 remote_port, u32 swif, hicn_face_id_t * pfaceid) +{ + fib_protocol_t fib_type; + vnet_link_t link_type; + adj_index_t ip_adj; + int ret = HICN_ERROR_NONE; + dpo_proto_t dpo_proto; + + hicn_face_flags_t flags = (hicn_face_flags_t) 0; + flags |= HICN_FACE_FLAGS_FACE; + + + if (ip46_address_is_ip4 (local_addr) && ip46_address_is_ip4 (remote_addr)) + { + link_type = VNET_LINK_IP4; + fib_type = FIB_PROTOCOL_IP4; + ip_adj = adj_nbr_add_or_lock (fib_type, link_type, remote_addr, swif); + + hicn_face_t *face = + hicn_face_udp4_get (&local_addr->ip4, &remote_addr->ip4, local_port, + remote_port); + + if (face != NULL) + return HICN_ERROR_FACE_ALREADY_CREATED; + + pool_get (hicn_dpoi_face_pool, face); + + hicn_face_udp_t *udp_face = (hicn_face_udp_t *) face->data; + + clib_memcpy (&(udp_face->hdrs.ip4.ip), &ip4_header_skl, + sizeof (ip4_header_t)); + clib_memcpy (&(udp_face->hdrs.ip4.ip.src_address), &(local_addr->ip4), + sizeof (ip4_address_t)); + clib_memcpy (&(udp_face->hdrs.ip4.ip.dst_address), &(remote_addr->ip4), + sizeof (ip4_address_t)); + + udp_face->hdrs.ip4.udp.src_port = local_port; + udp_face->hdrs.ip4.udp.dst_port = remote_port; + + ip_csum_t csum = udp_face->hdrs.ip4.ip.checksum; + csum = ip_csum_sub_even (csum, ip4_header_skl.src_address.as_u32); + csum = ip_csum_sub_even (csum, ip4_header_skl.dst_address.as_u32); + csum = + ip_csum_add_even (csum, udp_face->hdrs.ip4.ip.src_address.as_u32); + csum = + ip_csum_add_even (csum, udp_face->hdrs.ip4.ip.dst_address.as_u32); + udp_face->hdrs.ip4.ip.checksum = ip_csum_fold (csum); + + face->shared.adj = ip_adj; + face->shared.sw_if = swif; + face->shared.pl_id = (u16) 0; + face->shared.face_type = hicn_face_udp_type; + face->shared.flags = flags; + face->shared.locks = 0; + + hicn_face_udp_key_t key; + hicn_face_udp4_get_key (&local_addr->ip4, &remote_addr->ip4, local_port, + remote_port, &key); + hicn_face_id_t dpoi_index = hicn_dpoi_get_index (face); + + mhash_set_mem (&hicn_face_udp_hashtb, &key, (uword *) & dpoi_index, 0); + + *pfaceid = hicn_dpoi_get_index (face); + dpo_proto = DPO_PROTO_IP4; + } + else if (!ip46_address_is_ip4 (local_addr) + && !ip46_address_is_ip4 (remote_addr)) + { + link_type = VNET_LINK_IP6; + fib_type = FIB_PROTOCOL_IP6; + ip_adj = adj_nbr_add_or_lock (fib_type, link_type, remote_addr, swif); + + hicn_face_t *face = + hicn_face_udp6_get (&local_addr->ip6, &remote_addr->ip6, local_port, + remote_port); + + if (face != NULL) + return HICN_ERROR_FACE_ALREADY_CREATED; + + pool_get (hicn_dpoi_face_pool, face); + + hicn_face_udp_t *udp_face = (hicn_face_udp_t *) face->data; + + clib_memcpy (&(udp_face->hdrs.ip6.ip), &ip6_header_skl, + sizeof (ip6_header_t)); + clib_memcpy (&(udp_face->hdrs.ip6.ip.src_address), local_addr, + sizeof (ip6_address_t)); + clib_memcpy (&(udp_face->hdrs.ip6.ip.dst_address), remote_addr, + sizeof (ip6_address_t)); + + udp_face->hdrs.ip6.udp.src_port = local_port; + udp_face->hdrs.ip6.udp.dst_port = remote_port; + + face->shared.adj = ip_adj; + face->shared.sw_if = swif; + face->shared.pl_id = (u16) 0; + face->shared.face_type = hicn_face_udp_type; + face->shared.flags = flags; + face->shared.locks = 0; + + hicn_face_udp_key_t key; + hicn_face_udp6_get_key (&local_addr->ip6, &remote_addr->ip6, local_port, + remote_port, &key); + hicn_face_id_t dpoi_index = hicn_dpoi_get_index (face); + + mhash_set_mem (&hicn_face_udp_hashtb, &key, (uword *) & dpoi_index, 0); + + *pfaceid = hicn_dpoi_get_index (face); + dpo_proto = DPO_PROTO_IP6; + } + else + { + return HICN_ERROR_IPS_ADDR_TYPE_NONUNIFORM; + } + + retx_t *retx = vlib_process_signal_event_data (vlib_get_main (), + hicn_mapme_eventmgr_process_node. + index, + HICN_MAPME_EVENT_FACE_ADD, 1, + sizeof (retx_t)); + *retx = (retx_t) + { + .prefix = 0,.dpo = (dpo_id_t) + { + .dpoi_type = hicn_face_udp_type,.dpoi_proto = + dpo_proto,.dpoi_next_node = 0,.dpoi_index = *pfaceid,} + }; + + return ret; +} + +int +hicn_face_udp_del (u32 faceid) +{ + return hicn_face_del (faceid); +} + +u8 * +format_hicn_face_udp (u8 * s, va_list * args) +{ + hicn_face_id_t face_id = va_arg (*args, index_t); + CLIB_UNUSED (u32 indent) = va_arg (*args, u32); + hicn_face_t *face; + hicn_face_udp_t *udp_face; + ip_adjacency_t *adj; + u8 ipv = 0x40; + vnet_main_t *vnm = vnet_get_main (); + + + face = hicn_dpoi_get_from_idx (face_id); + udp_face = (hicn_face_udp_t *) (face->data); + + if (face->shared.flags & HICN_FACE_FLAGS_FACE) + { + ASSERT (face->shared.adj != (adj_index_t) ~ 0); + adj = adj_get (face->shared.adj); + + s = format (s, "%U Face %d: ", format_white_space, indent, face_id); + if (udp_face->hdrs.ip4.ip.ip_version_and_header_length == ipv) + { + s = format (s, "type UDP local %U|%u ", + format_ip4_address, &udp_face->hdrs.ip4.ip.src_address, + clib_net_to_host_u16 (udp_face->hdrs.ip4.udp.src_port)); + s = + format (s, "remote %U|%u ", format_ip4_address, + &udp_face->hdrs.ip4.ip.dst_address, + clib_net_to_host_u16 (udp_face->hdrs.ip4.udp.dst_port)); + s = format (s, "%U", format_vnet_link, adj->ia_link); + s = format (s, " dev %U", format_vnet_sw_interface_name, vnm, + vnet_get_sw_interface (vnm, face->shared.sw_if)); + if ((face->shared.flags & HICN_FACE_FLAGS_DELETED)) + s = format (s, " (deleted)"); + } + else + { + s = format (s, "type UDP local %U|%u ", + format_ip6_address, &udp_face->hdrs.ip6.ip.src_address, + clib_net_to_host_u16 (udp_face->hdrs.ip6.udp.src_port)); + s = + format (s, "remote %U|%u", format_ip6_address, + &udp_face->hdrs.ip6.ip.dst_address, + clib_net_to_host_u16 (udp_face->hdrs.ip6.udp.dst_port)); + s = format (s, "%U", format_vnet_link, adj->ia_link); + s = format (s, " dev %U", format_vnet_sw_interface_name, vnm, + vnet_get_sw_interface (vnm, face->shared.sw_if)); + if ((face->shared.flags & HICN_FACE_FLAGS_DELETED)) + s = format (s, " (deleted)"); + } + } + else + { + s = format (s, "IFace %d: ", format_white_space, indent, face_id); + if (udp_face->hdrs.ip4.ip.ip_version_and_header_length == ipv) + { + s = format (s, "type UDP local %U|%u", + format_ip4_address, &udp_face->hdrs.ip4.ip.src_address, + clib_net_to_host_u16 (udp_face->hdrs.ip4.udp.src_port)); + s = + format (s, " local %U|%u", format_ip4_address, + &udp_face->hdrs.ip4.ip.dst_address, + clib_net_to_host_u16 (udp_face->hdrs.ip4.udp.dst_port)); + s = + format (s, " dev %U", format_vnet_sw_interface_name, vnm, + vnet_get_sw_interface (vnm, face->shared.sw_if)); + if ((face->shared.flags & HICN_FACE_FLAGS_DELETED)) + s = format (s, " (deleted)"); + } + else + { + s = format (s, "type UDP local %U|%u", + format_ip6_address, &udp_face->hdrs.ip6.ip.src_address, + clib_net_to_host_u16 (udp_face->hdrs.ip6.udp.src_port)); + s = + format (s, " remote %U|%u", format_ip6_address, + &udp_face->hdrs.ip6.ip.dst_address, + clib_net_to_host_u16 (udp_face->hdrs.ip6.udp.dst_port)); + s = + format (s, " dev %U", format_vnet_sw_interface_name, vnm, + vnet_get_sw_interface (vnm, face->shared.sw_if)); + if ((face->shared.flags & HICN_FACE_FLAGS_DELETED)) + s = format (s, " (deleted)"); + } + } + + return s; +} + +void +hicn_face_udp_get_dpo (hicn_face_t * face, dpo_id_t * dpo) +{ + hicn_face_udp_t *face_udp = (hicn_face_udp_t *) face->data; + u8 version = + (face_udp->hdrs.ip4.ip.ip_version_and_header_length & 0xf0) >> 4; + return hicn_dpo_udp_create_from_face (face, dpo, + version == + (u8) 4 ? strategy_face_udp4_vlib_edge + : strategy_face_udp6_vlib_edge); +} + +hicn_face_vft_t udp_vft = { + .format_face = format_hicn_face_udp, + .hicn_face_del = hicn_face_udp_del, + .hicn_face_get_dpo = hicn_face_udp_get_dpo, +}; + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/hicn-plugin/src/faces/udp/face_udp.h b/hicn-plugin/src/faces/udp/face_udp.h new file mode 100755 index 000000000..8694bad5c --- /dev/null +++ b/hicn-plugin/src/faces/udp/face_udp.h @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __HICN_FACE_UDP_H__ +#define __HICN_FACE_UDP_H__ + +#include <vlib/vlib.h> +#include <vnet/vnet.h> +#include <vnet/ip/ip6_packet.h> +#include <vnet/udp/udp_packet.h> + +#include "../face.h" + +/** + * @file + * @brief UDP face + * + * This file containes the definition of UDP faces. + * UDP faces encap and decap an hicn packet into a UDP tunnel. + * Src and dst address in interest and data packets are not considered and + * should be set to 0 (not checked in the forwarder). + */ + +/* Pre-instantiated ip header to fast fill an newly encapsulated packet */ +extern ip4_header_t ip4_header_skl; +extern ip6_header_t ip6_header_skl; + +#define INVALID_UDP_DPO_INDEX ~0 + +/** + * @brief UDP face representation. The following is stored in the data field of + * an hicn_face_t object (see hicn_face.h). A UDP face is identifies by the + * quadruplet (src addr, dst addr, src port, dst port). + */ +typedef struct hicn_face_udp_t_ +{ + /** + * The headers to paint, in packet painting order + */ + union + { + struct + { + ip4_header_t ip; + udp_header_t udp; + } __attribute__ ((packed)) ip4; + struct + { + ip6_header_t ip; + udp_header_t udp; + } __attribute__ ((packed)) ip6; + } __attribute__ ((packed)) hdrs; +} hicn_face_udp_t; + +/* Hast table mapping the udp key with the face id (dpoi_index pointing to and + element in the face pool defined in hicn_face.h)*/ +extern mhash_t hicn_face_udp_hashtb; + +/** + * @brief Hash table key. + */ +typedef struct hicn_face_udp_key_s +{ + ip46_address_t local_addr; + ip46_address_t remote_addr; + u16 local_port; + u16 remote_port; +} hicn_face_udp_key_t; + +/* DPO type for the udp face */ +extern dpo_type_t hicn_face_udp_type; + +/* VFT table for the udp face. Mainly used to format the face in the right way */ +extern hicn_face_vft_t udp_vft; + +/** + * @brief Create the key object for the mhash. Fill in the key object with the + * expected values. + * + * @param local_addr Local address of the UDP tunnel + * @param remote_addr Remote address of the UDP tunnel + * @param local_port Local port of the UDP tunnel + * @param remote_port Remote port of the UDP tunnel + * @param key Pointer to an allocated hicn_face_udp_key_t object + */ +always_inline void +hicn_face_udp4_get_key (const ip4_address_t * local_addr, + const ip4_address_t * remote_addr, + u16 local_port, u16 remote_port, + hicn_face_udp_key_t * key) +{ + + ip46_address_set_ip4 (&(key->local_addr), local_addr); + ip46_address_set_ip4 (&(key->remote_addr), remote_addr); + key->local_port = local_port; + key->remote_port = remote_port; +} + +/** + * @brief Create the key object for the mhash. Fill in the key object with the + * expected values. + * + * @param local_addr Local address of the UDP tunnel + * @param remote_addr Remote address of the UDP tunnel + * @param local_port Local port of the UDP tunnel + * @param remote_port Remote port of the UDP tunnel + * @param key Pointer to an allocated hicn_face_udp_key_t object + */ +always_inline void +hicn_face_udp6_get_key (const ip6_address_t * local_addr, + const ip6_address_t * remote_addr, + u16 local_port, u16 remote_port, + hicn_face_udp_key_t * key) +{ + key->local_addr.ip6 = *local_addr; + key->remote_addr.ip6 = *remote_addr; + key->local_port = local_port; + key->remote_port = remote_port; +} + +/** + * @brief Get the dpoi from the quadruplet that identifies the face. Does not add any lock. + * + * @param local_addr Local address of the UDP tunnel + * @param remote_addr Remote address of the UDP tunnel + * @param local_port Local port of the UDP tunnel + * @param remote_port Remote port of the UDP tunnel + * + * @result Pointer to the face. + */ +always_inline hicn_face_t * +hicn_face_udp4_get (const ip4_address_t * local_addr, + const ip4_address_t * remote_addr, + u16 local_port, u16 remote_port) +{ + hicn_face_udp_key_t key; + + hicn_face_udp4_get_key (local_addr, remote_addr, local_port, remote_port, + &key); + + hicn_face_id_t *dpoi_index = + (hicn_face_id_t *) mhash_get (&hicn_face_udp_hashtb, + &key); + + return dpoi_index == NULL ? NULL : hicn_dpoi_get_from_idx (*dpoi_index); +} + +/** + * @brief Get the dpoi from the quadruplet that identifies the face. Does not add any lock. + * + * @param local_addr Local address of the UDP tunnel (network order) + * @param remote_addr Remote address of the UDP tunnel (network order) + * @param local_port Local port of the UDP tunnel (network order) + * @param remote_port Remote port of the UDP tunnel (network order) + * + * @result Pointer to the face. + */ +always_inline hicn_face_t * +hicn_face_udp6_get (const ip6_address_t * local_addr, + const ip6_address_t * remote_addr, + u16 local_port, u16 remote_port) +{ + hicn_face_udp_key_t key; + + hicn_face_udp6_get_key (local_addr, remote_addr, local_port, remote_port, + &key); + + hicn_face_id_t *dpoi_index = + (hicn_face_id_t *) mhash_get (&hicn_face_udp_hashtb, + &key); + + return dpoi_index == NULL ? NULL : hicn_dpoi_get_from_idx (*dpoi_index); +} + + +/** + * @brief Initialize the udp face module + */ +void hicn_face_udp_init (vlib_main_t * vm); + +/** + * @brief Create a new face ip. API for other modules (e.g., routing) + * + * @param local_addr Local ip v4 or v6 address of the face (network order) + * @param remote_addr Remote ip v4 or v6 address of the face (network order) + * @param local_port Local udp port of the face (network order) + * @param remote_port Remote udp port of the face (network order) + * @param sw_if interface associated to the face + * @param pfaceid Pointer to return the face id + * @return HICN_ERROR_FACE_NO_GLOBAL_IP if the face does not have a globally + * reachable ip address, otherwise HICN_ERROR_NONE + */ +int hicn_face_udp_add (const ip46_address_t * local_addr, + const ip46_address_t * remote_addr, u16 local_port, + u16 remote_port, u32 swif, hicn_face_id_t * pfaceid); + +/** + * @brief Delete an ip face + * + * @param face_id Id of the face to delete + * @return HICN_ERROR_FACE_NOT_FOUND if the face does not exist, otherwise + * HICN_ERROR_NONE + */ +int hicn_face_udp_del (hicn_face_id_t faceid); + +/** + * @brief Format a UDP face + * + * @param s Pointer to a previous string. If null it will be initialize + * @param args Array storing input values. Expected u32 indent and u32 face_id + * @return String with the formatted face + */ +u8 *format_hicn_face_udp (u8 * s, va_list * args); + +/** + * @brief Create a dpo from a udp face + * + * @param face Face from which to create the dpo + * @return the dpo + */ +void hicn_face_udp_get_dpo (hicn_face_t * face, dpo_id_t * dpo); + +/** + * @brief Init some internal structures + */ +void hicn_face_udp_init_internal (void); + +#endif // __HICN_FACE_UDP_H__ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/hicn-plugin/src/faces/udp/face_udp_cli.c b/hicn-plugin/src/faces/udp/face_udp_cli.c new file mode 100755 index 000000000..7bb172ce8 --- /dev/null +++ b/hicn-plugin/src/faces/udp/face_udp_cli.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "face_udp.h" +#include "dpo_udp.h" + +#include <vnet/vnet.h> +#include <vnet/dpo/dpo.h> +#include <vlib/vlib.h> +#include <vnet/ip/format.h> + +#define HICN_FACE_NONE 0 +#define HICN_FACE_DELETE 1 +#define HICN_FACE_ADD 2 + + +static clib_error_t * +hicn_face_udp_cli_set_command_fn (vlib_main_t * vm, + unformat_input_t * main_input, + vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + ip46_address_t src_addr; + u32 src_port = 0; + ip46_address_t dst_addr; + u32 dst_port = 0; + hicn_face_id_t face_id = HICN_FACE_NULL; + int ret = HICN_ERROR_NONE; + int sw_if; + int face_op = HICN_FACE_NONE; + + ip46_address_reset (&src_addr); + ip46_address_reset (&dst_addr); + /* Get a line of input. */ + unformat_input_t _line_input, *line_input = &_line_input; + if (!unformat_user (main_input, unformat_line_input, line_input)) + { + return (0); + } + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "del")) + { + if (unformat (line_input, "id %d", &face_id)) + face_op = HICN_FACE_DELETE; + else + { + return clib_error_return (0, "missing face id"); + } + } + else if (unformat (line_input, "add")) + { + face_op = HICN_FACE_ADD; + if (unformat + (line_input, "src_addr %U port %u dst_addr %U port %u intfc %U", + unformat_ip46_address, &src_addr, IP46_TYPE_ANY, &src_port, + unformat_ip46_address, &dst_addr, IP46_TYPE_ANY, &dst_port, + unformat_vnet_sw_interface, vnm, &sw_if)); + else + { + return clib_error_return (0, "%s '%U'", + get_error_string + (HICN_ERROR_CLI_INVAL), + format_unformat_error, line_input); + } + } + else + { + return clib_error_return (0, "%s '%U'", + get_error_string (HICN_ERROR_CLI_INVAL), + format_unformat_error, line_input); + } + } + + if (face_id != HICN_FACE_NULL) + { + if (!hicn_dpoi_idx_is_valid (face_id)) + { + return clib_error_return (0, "%s, face_id %d not valid", + get_error_string (ret), face_id); + } + } + + int rv; + switch (face_op) + { + case HICN_FACE_ADD: + + /* Check for presence of next hop address */ + if (((dst_addr.as_u64[0] == (u64) 0) && (dst_addr.as_u64[1] == (u64) 0)) + || dst_port == 0) + { + return clib_error_return (0, "dst address and port not specified"); + } + + if (((src_addr.as_u64[0] == (u64) 0) && (src_addr.as_u64[1] == (u64) 0)) + || src_port == 0) + { + return clib_error_return (0, "src address not specified"); + } + + rv = + hicn_face_udp_add (&src_addr, &dst_addr, + clib_host_to_net_u16 (src_port), + clib_host_to_net_u16 (dst_port), sw_if, &face_id); + if (rv == HICN_ERROR_NONE) + { + vlib_cli_output (vm, "Face id: %d", face_id); + } + else + { + return clib_error_return (0, get_error_string (rv)); + } + break; + case HICN_FACE_DELETE: + rv = hicn_face_udp_del (face_id); + if (rv == HICN_ERROR_NONE) + { + vlib_cli_output (vm, "Face %d deleted", face_id); + } + else + { + return clib_error_return (0, get_error_string (rv)); + } + break; + default: + return clib_error_return (0, "Operation (%d) not implemented", face_op); + break; + } + return (rv == HICN_ERROR_NONE) ? 0 : clib_error_return (0, "%s\n", + get_error_string + (rv)); +} + +/* cli declaration for 'cfg face' */ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (hicn_face_udp_cli_set_command, static) = +{ + .path = "hicn face udp", + .short_help = "hicn face udp {add src_addr <src_address> port <src_port > dst_addr <dst_address> port <dst_port>} intfc <interface> | {del id <face_id>}", + .function = hicn_face_udp_cli_set_command_fn, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/hicn-plugin/src/faces/udp/face_udp_node.c b/hicn-plugin/src/faces/udp/face_udp_node.c new file mode 100755 index 000000000..74d0b1864 --- /dev/null +++ b/hicn-plugin/src/faces/udp/face_udp_node.c @@ -0,0 +1,864 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <vlib/vlib.h> +#include <vnet/vnet.h> +#include <vnet/ip/ip_packet.h> + +#include "face_udp.h" +#include "face_udp_node.h" +#include "dpo_udp.h" +#include "../face.h" +#include "../../strategy.h" +#include "../../strategy_dpo_manager.h" +#include "../../hicn.h" + +/** + * @File + * + * Definition of the nodes for udp faces. + */ + +vlib_node_registration_t hicn_face_udp4_input_node; +vlib_node_registration_t hicn_face_udp6_input_node; +vlib_node_registration_t hicn_face_udp4_output_node; +vlib_node_registration_t hicn_face_udp6_output_node; + +static char *hicn_face_udp4_input_error_strings[] = { +#define _(sym, string) string, + foreach_hicnfwd_error +#undef _ +}; + +static char *hicn_face_udp6_input_error_strings[] = { +#define _(sym, string) string, + foreach_hicnfwd_error +#undef _ +}; + +/* Trace context struct */ +typedef struct +{ + u32 next_index; + u32 sw_if_index; + u8 pkt_type; +} hicn_face_udp4_input_trace_t; + +typedef enum +{ + HICN_FACE_UDP4_INPUT_NEXT_DATA, + HICN_FACE_UDP4_INPUT_NEXT_MAPME, + HICN_FACE_UDP4_INPUT_NEXT_ERROR_DROP, + HICN_FACE_UDP4_INPUT_N_NEXT, +} hicn_face_udp4_input_next_t; + +/* Trace context struct */ +typedef struct +{ + u32 next_index; + u32 sw_if_index; + u8 pkt_type; +} hicn_face_udp6_input_trace_t; + +typedef enum +{ + HICN_FACE_UDP6_INPUT_NEXT_DATA, + HICN_FACE_UDP6_INPUT_NEXT_MAPME, + HICN_FACE_UDP6_INPUT_NEXT_ERROR_DROP, + HICN_FACE_UDP6_INPUT_N_NEXT, +} hicn_face_udp6_input_next_t; + +#define ERROR_INPUT_UDP4 HICN_FACE_UDP4_INPUT_NEXT_ERROR_DROP +#define ERROR_INPUT_UDP6 HICN_FACE_UDP6_INPUT_NEXT_ERROR_DROP + +#define NEXT_MAPME_UDP4 HICN_FACE_UDP4_INPUT_NEXT_MAPME +#define NEXT_MAPME_UDP6 HICN_FACE_UDP6_INPUT_NEXT_MAPME +#define NEXT_DATA_UDP4 HICN_FACE_UDP4_INPUT_NEXT_DATA +#define NEXT_DATA_UDP6 HICN_FACE_UDP6_INPUT_NEXT_DATA + +#define IP_HEADER_4 ip4_header_t +#define IP_HEADER_6 ip6_header_t + +#define HICN_DPO_UDP_LOCK_IP4 hicn_dpo_udp4_lock +#define HICN_DPO_UDP_LOCK_IP6 hicn_dpo_udp6_lock + +#define TRACE_INPUT_PKT_UDP4 hicn_face_udp4_input_trace_t +#define TRACE_INPUT_PKT_UDP6 hicn_face_udp6_input_trace_t + +#define face_input_x1(ipv) \ + do { \ + int ret; \ + vlib_buffer_t *b0; \ + u32 bi0; \ + u32 next0 = ERROR_INPUT_UDP##ipv; \ + IP_HEADER_##ipv * ip_hdr = NULL; \ + u8 * inner_ip_hdr = NULL; \ + udp_header_t * udp_hdr = NULL; \ + hicn_buffer_t * hicnb0; \ + /* Prefetch for next iteration. */ \ + if (n_left_from > 1) \ + { \ + vlib_buffer_t *b1; \ + b1 = vlib_get_buffer (vm, from[1]); \ + CLIB_PREFETCH (b1, CLIB_CACHE_LINE_BYTES, STORE); \ + CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES , LOAD); \ + } \ + /* Dequeue a packet buffer */ \ + bi0 = from[0]; \ + from += 1; \ + n_left_from -= 1; \ + to_next[0] = bi0; \ + to_next += 1; \ + n_left_to_next -= 1; \ + \ + b0 = vlib_get_buffer (vm, bi0); \ + ip_hdr = (IP_HEADER_##ipv *) vlib_buffer_get_current(b0); \ + udp_hdr = (udp_header_t *) (ip_hdr + 1); \ + hicnb0 = hicn_get_buffer(b0); \ + \ + inner_ip_hdr = (u8 *)(udp_hdr + 1); \ + u8 is_v6 = ((inner_ip_hdr[0] & 2) >> 1); \ + u8 is_icmp = is_v6*(inner_ip_hdr[7] == IPPROTO_ICMPV6) + \ + (1 - is_v6)*(inner_ip_hdr[10] == IPPROTO_ICMPV4); \ + \ + ret = HICN_DPO_UDP_LOCK_IP##ipv \ + (&(hicnb0->face_dpo_id), \ + &(ip_hdr->dst_address), \ + &(ip_hdr->src_address), \ + (udp_hdr->dst_port), \ + (udp_hdr->src_port), \ + &hicnb0->is_appface); \ + \ + if ( PREDICT_FALSE(ret != HICN_ERROR_NONE) ) \ + { \ + next0 = ERROR_INPUT_UDP##ipv; \ + } \ + else \ + { \ + next0 = is_icmp*NEXT_MAPME_UDP##ipv + \ + (1-is_icmp)*NEXT_DATA_UDP##ipv; \ + stats.pkts_data_count += 1; \ + \ + vlib_buffer_advance(b0, sizeof(IP_HEADER_##ipv) + \ + sizeof(udp_header_t)); \ + } \ + \ + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && \ + (b0->flags & VLIB_BUFFER_IS_TRACED))) \ + { \ + TRACE_INPUT_PKT_UDP##ipv *t = \ + vlib_add_trace (vm, node, b0, sizeof (*t)); \ + t->pkt_type = HICN_PKT_TYPE_CONTENT; \ + t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ + t->next_index = next0; \ + } \ + \ + \ + /* Verify speculative enqueue, maybe switch current next frame */ \ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, \ + to_next, n_left_to_next, \ + bi0, next0); \ + }while(0) \ + +#define face_input_x2(ipv) \ + do { \ + int ret0, ret1; \ + vlib_buffer_t *b0, *b1; \ + u32 bi0, bi1; \ + u32 next0 = ERROR_INPUT_UDP##ipv; \ + u32 next1 = ERROR_INPUT_UDP##ipv; \ + IP_HEADER_##ipv * ip_hdr0 = NULL; \ + IP_HEADER_##ipv * ip_hdr1 = NULL; \ + u8 * inner_ip_hdr0 = NULL; \ + u8 * inner_ip_hdr1 = NULL; \ + udp_header_t * udp_hdr0 = NULL; \ + udp_header_t * udp_hdr1 = NULL; \ + hicn_buffer_t *hicnb0, *hicnb1; \ + \ + /* Prefetch for next iteration. */ \ + { \ + vlib_buffer_t *b2, *b3; \ + b2 = vlib_get_buffer (vm, from[2]); \ + b3 = vlib_get_buffer (vm, from[3]); \ + CLIB_PREFETCH (b2, CLIB_CACHE_LINE_BYTES, STORE); \ + CLIB_PREFETCH (b3, CLIB_CACHE_LINE_BYTES, STORE); \ + CLIB_PREFETCH (b2->data, CLIB_CACHE_LINE_BYTES , LOAD); \ + CLIB_PREFETCH (b3->data, CLIB_CACHE_LINE_BYTES , LOAD); \ + } \ + \ + /* Dequeue a packet buffer */ \ + bi0 = from[0]; \ + bi1 = from[1]; \ + from += 2; \ + n_left_from -= 2; \ + to_next[0] = bi0; \ + to_next[1] = bi1; \ + to_next += 2; \ + n_left_to_next -= 2; \ + \ + b0 = vlib_get_buffer (vm, bi0); \ + b1 = vlib_get_buffer (vm, bi1); \ + ip_hdr0 = (IP_HEADER_##ipv *) vlib_buffer_get_current(b0); \ + ip_hdr1 = (IP_HEADER_##ipv *) vlib_buffer_get_current(b1); \ + udp_hdr0 = (udp_header_t *) (ip_hdr0 + 1); \ + udp_hdr1 = (udp_header_t *) (ip_hdr1 + 1); \ + hicnb0 = hicn_get_buffer(b0); \ + hicnb1 = hicn_get_buffer(b1); \ + \ + inner_ip_hdr0 = (u8 *)(udp_hdr0 + 1); \ + u8 is_v6_0 = ((inner_ip_hdr0[0] & 2) >> 1); \ + u8 is_icmp0 = is_v6_0*(inner_ip_hdr0[7] == IPPROTO_ICMPV6) + \ + (1 - is_v6_0)*(inner_ip_hdr0[10] == IPPROTO_ICMPV4); \ + \ + inner_ip_hdr1 = (u8 *)(udp_hdr1 + 1); \ + u8 is_v6_1 = ((inner_ip_hdr1[0] & 2) >> 1); \ + u8 is_icmp1 = is_v6_1*(inner_ip_hdr1[7] == IPPROTO_ICMPV6) + \ + (1 - is_v6_1)*(inner_ip_hdr1[10] == IPPROTO_ICMPV4); \ + \ + ret0 = HICN_DPO_UDP_LOCK_IP##ipv \ + (&(hicnb0->face_dpo_id), \ + &(ip_hdr0->dst_address), \ + &(ip_hdr0->src_address), \ + (udp_hdr0->dst_port), \ + (udp_hdr0->src_port), \ + &hicnb0->is_appface); \ + \ + ret1 = HICN_DPO_UDP_LOCK_IP##ipv \ + (&(hicnb1->face_dpo_id), \ + &(ip_hdr1->dst_address), \ + &(ip_hdr1->src_address), \ + (udp_hdr1->dst_port), \ + (udp_hdr1->src_port), \ + &hicnb1->is_appface); \ + \ + if ( PREDICT_FALSE(ret0 != HICN_ERROR_NONE) ) \ + { \ + next0 = ERROR_INPUT_UDP##ipv; \ + } \ + else \ + { \ + stats.pkts_data_count += 1; \ + next0 = is_icmp0*NEXT_MAPME_UDP##ipv + \ + (1-is_icmp0)*NEXT_DATA_UDP##ipv; \ + \ + vlib_buffer_advance(b0, sizeof(IP_HEADER_##ipv) + \ + sizeof(udp_header_t)); \ + } \ + \ + if ( PREDICT_FALSE(ret1 != HICN_ERROR_NONE) ) \ + { \ + next1 = ERROR_INPUT_UDP##ipv; \ + } \ + else \ + { \ + stats.pkts_data_count += 1; \ + next1 = is_icmp1*NEXT_MAPME_UDP##ipv + \ + (1-is_icmp1)*NEXT_DATA_UDP##ipv; \ + \ + vlib_buffer_advance(b1, sizeof(IP_HEADER_##ipv) + \ + sizeof(udp_header_t)); \ + } \ + \ + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && \ + (b0->flags & VLIB_BUFFER_IS_TRACED))) \ + { \ + TRACE_INPUT_PKT_UDP##ipv *t = \ + vlib_add_trace (vm, node, b0, sizeof (*t)); \ + t->pkt_type = HICN_PKT_TYPE_CONTENT; \ + t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ + t->next_index = next0; \ + } \ + \ + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && \ + (b1->flags & VLIB_BUFFER_IS_TRACED))) \ + { \ + TRACE_INPUT_PKT_UDP##ipv *t = \ + vlib_add_trace (vm, node, b1, sizeof (*t)); \ + t->pkt_type = HICN_PKT_TYPE_CONTENT; \ + t->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX]; \ + t->next_index = next1; \ + } \ + \ + \ + /* Verify speculative enqueue, maybe switch current next frame */ \ + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, \ + to_next, n_left_to_next, \ + bi0, bi1, next0, next1); \ + }while(0) \ + +static uword +hicn_face_udp4_input_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next, next_index; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + vl_api_hicn_api_node_stats_get_reply_t stats = { 0 }; + + while (n_left_from > 0) + { + u32 n_left_to_next; + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + /* Dual loop, X2 */ + while (n_left_from >= 4 && n_left_to_next >= 2) + { + face_input_x2 (4); + } + + /* Dual loop, X1 */ + while (n_left_from > 0 && n_left_to_next > 0) + { + face_input_x1 (4); + } + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + vlib_node_increment_counter (vm, node->node_index, + HICNFWD_ERROR_DATAS, stats.pkts_data_count); + + return (frame->n_vectors); +} + +/* packet trace format function */ +static u8 * +hicn_face_udp4_input_format_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + hicn_face_udp4_input_trace_t *t = + va_arg (*args, hicn_face_udp4_input_trace_t *); + + s = format (s, "FACE_UDP4_INPUT: pkt: %d, sw_if_index %d, next index %d", + (int) t->pkt_type, t->sw_if_index, t->next_index); + return (s); +} + +/* + * Node registration for the interest forwarder node + */ +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (hicn_face_udp4_input_node) = +{ + .function = hicn_face_udp4_input_node_fn, + .name = "hicn-face-udp4-input", + .vector_size = sizeof (u32), + .format_trace = hicn_face_udp4_input_format_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (hicn_face_udp4_input_error_strings), + .error_strings = hicn_face_udp4_input_error_strings, + .n_next_nodes = HICN_FACE_UDP4_INPUT_N_NEXT, + /* edit / add dispositions here */ + .next_nodes = + { + [HICN_FACE_UDP4_INPUT_NEXT_DATA] = "hicn-data-pcslookup", + [HICN_FACE_UDP4_INPUT_NEXT_MAPME] = "hicn-mapme-ack", + [HICN_FACE_UDP4_INPUT_NEXT_ERROR_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + + +static uword +hicn_face_udp6_input_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next, next_index; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + vl_api_hicn_api_node_stats_get_reply_t stats = { 0 }; + + while (n_left_from > 0) + { + u32 n_left_to_next; + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + /* Dual loop, X2 */ + while (n_left_from >= 4 && n_left_to_next >= 2) + { + face_input_x2 (6); + } + + /* Dual loop, X1 */ + while (n_left_from > 0 && n_left_to_next > 0) + { + face_input_x1 (6); + } + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + vlib_node_increment_counter (vm, node->node_index, + HICNFWD_ERROR_PROCESSED, stats.pkts_processed); + + vlib_node_increment_counter (vm, node->node_index, + HICNFWD_ERROR_DATAS, stats.pkts_data_count); + + return (frame->n_vectors); +} + +/* packet trace format function */ +static u8 * +hicn_face_udp6_input_format_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + hicn_face_udp6_input_trace_t *t = + va_arg (*args, hicn_face_udp6_input_trace_t *); + + s = format (s, "FACE_UDP6_INPUT: pkt: %d, sw_if_index %d, next index %d", + (int) t->pkt_type, t->sw_if_index, t->next_index); + return (s); +} + +/* + * Node registration for the interest forwarder node + */ +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (hicn_face_udp6_input_node) = +{ + .function = hicn_face_udp6_input_node_fn, + .name = "hicn-face-udp6-input", + .vector_size = sizeof (u32), + .format_trace = hicn_face_udp6_input_format_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (hicn_face_udp6_input_error_strings), + .error_strings = hicn_face_udp6_input_error_strings, + .n_next_nodes = HICN_FACE_UDP6_INPUT_N_NEXT, + /* edit / add dispositions here */ + .next_nodes = + { + [HICN_FACE_UDP6_INPUT_NEXT_DATA] = "hicn-data-pcslookup", + [HICN_FACE_UDP6_INPUT_NEXT_MAPME] = "hicn-mapme-ack", + [HICN_FACE_UDP6_INPUT_NEXT_ERROR_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + +/******* Face Output *******/ + +always_inline void +hicn_face_udp4_encap (vlib_main_t * vm, + vlib_buffer_t * outer_b0, + hicn_face_t * face, u32 * next) +{ + u16 old_l0 = 0, new_l0; + ip_csum_t sum0; + ip4_header_t *ip0; + udp_header_t *udp0; + hicn_face_udp_t *face_udp = (hicn_face_udp_t *) face->data; + ip_adjacency_t *adj = adj_get (face->shared.adj); + + /* ip */ + ip0 = vlib_buffer_get_current (outer_b0); + clib_memcpy (ip0, &(face_udp->hdrs.ip4.ip), sizeof (ip4_header_t) + + sizeof (udp_header_t)); + + /* Fix UDP length */ + udp0 = (udp_header_t *) (ip0 + 1); + + new_l0 = + clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, outer_b0) - + sizeof (*ip0)); + udp0->length = new_l0; + + old_l0 = ip0->length; + ip0->length = + clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, outer_b0)); + + sum0 = ip0->checksum; + + //old_l0 always 0, see the rewrite setup + new_l0 = ip0->length; + + sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t, + length /* changed member */ ); + ip0->checksum = sum0; + + vnet_buffer (outer_b0)->ip.adj_index[VLIB_TX] = face->shared.adj; + + *next = adj->lookup_next_index; +} + +always_inline void +hicn_face_udp6_encap (vlib_main_t * vm, + vlib_buffer_t * outer_b0, + hicn_face_t * face, u32 * next) +{ + int bogus0; + u16 new_l0; + ip6_header_t *ip0; + udp_header_t *udp0; + hicn_face_udp_t *face_udp = (hicn_face_udp_t *) face->data; + ip_adjacency_t *adj = adj_get (face->shared.adj); + + /* ip */ + ip0 = vlib_buffer_get_current (outer_b0); + clib_memcpy (ip0, &(face_udp->hdrs.ip6.ip), sizeof (ip6_header_t) + + sizeof (udp_header_t)); + new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, outer_b0) + - sizeof (*ip0)); + ip0->payload_length = new_l0; + + /* Fix UDP length */ + udp0 = (udp_header_t *) (ip0 + 1); + udp0->length = new_l0; + + udp0->checksum = + ip6_tcp_udp_icmp_compute_checksum (vm, outer_b0, ip0, &bogus0); + + ASSERT (bogus0 == 0); + + if (udp0->checksum == 0) + udp0->checksum = 0xffff; + + vnet_buffer (outer_b0)->ip.adj_index[VLIB_TX] = face->shared.adj; + + *next = adj->lookup_next_index; +} + +static char *hicn_face_udp4_output_error_strings[] = { +#define _(sym, string) string, + foreach_hicnfwd_error +#undef _ +}; + +static char *hicn_face_udp6_output_error_strings[] = { +#define _(sym, string) string, + foreach_hicnfwd_error +#undef _ +}; + + +/* Trace context struct */ +typedef struct +{ + u32 next_index; + u32 sw_if_index; + u8 pkt_type; +} hicn_face_udp4_output_trace_t; + +/* Trace context struct */ +typedef struct +{ + u32 next_index; + u32 sw_if_index; + u8 pkt_type; +} hicn_face_udp6_output_trace_t; + +#define HICN_FACE_UDP_ENCAP_IP4 hicn_face_udp4_encap +#define HICN_FACE_UDP_ENCAP_IP6 hicn_face_udp6_encap + +#define TRACE_OUTPUT_PKT_UDP4 hicn_face_udp4_output_trace_t +#define TRACE_OUTPUT_PKT_UDP6 hicn_face_udp6_output_trace_t + +#define IP_HEADER_4 ip4_header_t +#define IP_HEADER_6 ip6_header_t + +#define face_output_x1(ipv) \ + do { \ + vlib_buffer_t *b0; \ + u32 bi0; \ + u32 next0 = IP_LOOKUP_NEXT_DROP; \ + hicn_face_t * face; \ + \ + /* Prefetch for next iteration. */ \ + if (n_left_from > 1) \ + { \ + vlib_buffer_t *b1; \ + b1 = vlib_get_buffer (vm, from[1]); \ + CLIB_PREFETCH (b1, CLIB_CACHE_LINE_BYTES, STORE); \ + CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES , LOAD); \ + } \ + /* Dequeue a packet buffer */ \ + bi0 = from[0]; \ + from += 1; \ + n_left_from -= 1; \ + \ + b0 = vlib_get_buffer (vm, bi0); \ + face = \ + hicn_dpoi_get_from_idx(vnet_buffer (b0)->ip.adj_index[VLIB_TX]); \ + \ + if (PREDICT_TRUE(face != NULL)) \ + { \ + /* Adjust vlib buffer. Create space for the udp tunnel. */ \ + vlib_buffer_advance(b0, -(sizeof (IP_HEADER_##ipv) + \ + sizeof (udp_header_t))); \ + \ + \ + HICN_FACE_UDP_ENCAP_IP##ipv \ + (vm, b0, face, &next0); \ + stats.pkts_interest_count += 1; \ + } \ + \ + \ + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && \ + (b0->flags & VLIB_BUFFER_IS_TRACED))) \ + { \ + TRACE_OUTPUT_PKT_UDP##ipv *t = \ + vlib_add_trace (vm, node, b0, sizeof (*t)); \ + t->pkt_type = HICN_PKT_TYPE_INTEREST; \ + t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ + t->next_index = next0; \ + } \ + \ + to_next[0] = bi0; \ + to_next += 1; \ + n_left_to_next -= 1; \ + \ + \ + /* Verify speculative enqueue, maybe switch current next frame */ \ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, \ + to_next, n_left_to_next, \ + bi0, next0); \ + } while(0) \ + + +#define face_output_x2(ipv) \ + do { \ + vlib_buffer_t *b0, *b1; \ + u32 bi0, bi1; \ + u32 next0 = IP_LOOKUP_NEXT_DROP; \ + u32 next1 = IP_LOOKUP_NEXT_DROP; \ + hicn_face_t *face0, *face1; \ + \ + /* Prefetch for next iteration. */ \ + { \ + vlib_buffer_t *b2, *b3; \ + b2 = vlib_get_buffer (vm, from[2]); \ + b3 = vlib_get_buffer (vm, from[3]); \ + CLIB_PREFETCH (b2, CLIB_CACHE_LINE_BYTES, STORE); \ + CLIB_PREFETCH (b3, CLIB_CACHE_LINE_BYTES, STORE); \ + CLIB_PREFETCH (b2->data, CLIB_CACHE_LINE_BYTES , LOAD); \ + CLIB_PREFETCH (b3->data, CLIB_CACHE_LINE_BYTES , LOAD); \ + } \ + \ + /* Dequeue a packet buffer */ \ + bi0 = from[0]; \ + bi1 = from[1]; \ + from += 2; \ + n_left_from -= 2; \ + to_next[0] = bi0; \ + to_next[1] = bi1; \ + to_next += 2; \ + n_left_to_next -= 2; \ + \ + b0 = vlib_get_buffer (vm, bi0); \ + b1 = vlib_get_buffer (vm, bi1); \ + \ + face0 = \ + hicn_dpoi_get_from_idx(vnet_buffer (b0)->ip.adj_index[VLIB_TX]); \ + face1 = \ + hicn_dpoi_get_from_idx(vnet_buffer (b1)->ip.adj_index[VLIB_TX]); \ + \ + if (PREDICT_TRUE(face0 != NULL)) \ + { \ + /* Adjust vlib buffer. Create space for the udp tunnel. */ \ + vlib_buffer_advance(b0, -(sizeof (IP_HEADER_##ipv) + \ + sizeof (udp_header_t))); \ + \ + \ + HICN_FACE_UDP_ENCAP_IP##ipv \ + (vm, b0, face0, &next0); \ + stats.pkts_interest_count += 1; \ + } \ + \ + if (PREDICT_TRUE(face1 != NULL)) \ + { \ + /* Adjust vlib buffer. Create space for the udp tunnel. */ \ + vlib_buffer_advance(b1, -(sizeof (IP_HEADER_##ipv) + \ + sizeof (udp_header_t))); \ + \ + \ + HICN_FACE_UDP_ENCAP_IP##ipv \ + (vm, b1, face1, &next1); \ + stats.pkts_interest_count += 1; \ + } \ + \ + \ + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && \ + (b0->flags & VLIB_BUFFER_IS_TRACED))) \ + { \ + TRACE_OUTPUT_PKT_UDP##ipv *t = \ + vlib_add_trace (vm, node, b0, sizeof (*t)); \ + t->pkt_type = HICN_PKT_TYPE_INTEREST; \ + t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ + t->next_index = next0; \ + } \ + \ + /* Verify speculative enqueue, maybe switch current next frame */ \ + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, \ + to_next, n_left_to_next, \ + bi0, bi1, next0, next1); \ + } while(0) \ + + +static uword +hicn_face_udp4_output_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next, next_index; + vl_api_hicn_api_node_stats_get_reply_t stats = { 0 }; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + /* Dual loop, X2 */ + while (n_left_from >= 4 && n_left_to_next >= 2) + { + face_output_x2 (4); + } + + /* Dual loop, X1 */ + while (n_left_from > 0 && n_left_to_next > 0) + { + face_output_x1 (4); + } + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + vlib_node_increment_counter (vm, node->node_index, + HICNFWD_ERROR_INTERESTS, + stats.pkts_interest_count); + + return (frame->n_vectors); +} + +/* packet trace format function */ +static u8 * +hicn_face_udp4_output_format_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + hicn_face_udp4_output_trace_t *t = + va_arg (*args, hicn_face_udp4_output_trace_t *); + + s = format (s, "FACE_UDP4_OUTPUT: pkt: %d, sw_if_index %d, next index %d", + (int) t->pkt_type, t->sw_if_index, t->next_index); + return (s); +} + +/* *INDENT-OFF* */ +/* + * Node registration for the interest forwarder node + */ +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (hicn_face_udp4_output_node) = +{ + .function = hicn_face_udp4_output_node_fn, + .name = "hicn-face-udp4-output", + .vector_size = sizeof (u32), + .format_trace = hicn_face_udp4_output_format_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (hicn_face_udp4_output_error_strings), + .error_strings = hicn_face_udp4_output_error_strings, + .n_next_nodes = IP4_LOOKUP_N_NEXT, + /* Reusing the list of nodes from lookup to be compatible with arp */ + .next_nodes = IP4_LOOKUP_NEXT_NODES, +}; +/* *INDENT-ON* */ + +/* *INDENT-ON* */ + +static uword +hicn_face_udp6_output_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next, next_index; + vl_api_hicn_api_node_stats_get_reply_t stats = { 0 }; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + /* Dual loop, X2 */ + while (n_left_from >= 4 && n_left_to_next >= 2) + { + face_output_x2 (6); + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + face_output_x1 (6); + } + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + vlib_node_increment_counter (vm, node->node_index, + HICNFWD_ERROR_INTERESTS, + stats.pkts_interest_count); + + return (frame->n_vectors); +} + +/* packet trace format function */ +static u8 * +hicn_face_udp6_output_format_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + hicn_face_udp6_output_trace_t *t = + va_arg (*args, hicn_face_udp6_output_trace_t *); + + s = format (s, "FACE_UDP6_OUTPUT: pkt: %d, sw_if_index %d, next index %d", + (int) t->pkt_type, t->sw_if_index, t->next_index); + return (s); +} + +/* *INDENT-OFF* */ +/* + * Node registration for the interest forwarder node + */ +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (hicn_face_udp6_output_node) = +{ + .function = hicn_face_udp6_output_node_fn, + .name = "hicn-face-udp6-output", + .vector_size = sizeof (u32), + .format_trace = hicn_face_udp6_output_format_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (hicn_face_udp6_output_error_strings), + .error_strings = hicn_face_udp6_output_error_strings, + .n_next_nodes = IP6_LOOKUP_N_NEXT, + /* Reusing the list of nodes from lookup to be compatible with neighbour discovery */ + .next_nodes = IP6_LOOKUP_NEXT_NODES, +}; +/* *INDENT-ON* */ + +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/hicn-plugin/src/faces/udp/face_udp_node.h b/hicn-plugin/src/faces/udp/face_udp_node.h new file mode 100755 index 000000000..c759312c8 --- /dev/null +++ b/hicn-plugin/src/faces/udp/face_udp_node.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __HICN_FACE_UDP_NODE_H__ +#define __HICN_FACE_UDP_NODE_H__ + +#include <vlib/vlib.h> +#include <vnet/vnet.h> + +extern vlib_node_registration_t hicn_face_udp4_input_node; +extern vlib_node_registration_t hicn_face_udp6_input_node; +extern vlib_node_registration_t hicn_face_udp4_output_node; +extern vlib_node_registration_t hicn_face_udp6_output_node; + +#endif // __HICN_FACE_UDP_NODE_H__ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/hicn-plugin/src/faces/udp/iface_udp_node.c b/hicn-plugin/src/faces/udp/iface_udp_node.c new file mode 100755 index 000000000..ddea31b4c --- /dev/null +++ b/hicn-plugin/src/faces/udp/iface_udp_node.c @@ -0,0 +1,894 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "iface_udp_node.h" +#include "dpo_udp.h" +#include "../face.h" + +#include "../../infra.h" +#include "../../hicn.h" + +/** + * @File + * + * Definition of the nodes for udp incomplete faces. + */ + +vlib_node_registration_t hicn_iface_udp4_input_node; +vlib_node_registration_t hicn_iface_udp6_input_node; +vlib_node_registration_t hicn_iface_udp4_output_node; +vlib_node_registration_t hicn_iface_udp6_output_node; + +u32 data_fwd_face_udp4_vlib_edge; +u32 data_fwd_face_udp6_vlib_edge; + +void +hicn_iface_udp_init (vlib_main_t * vm) +{ + data_fwd_face_udp4_vlib_edge = vlib_node_add_next (vm, + hicn_data_fwd_node.index, + hicn_iface_udp4_output_node. + index); + + data_fwd_face_udp6_vlib_edge = vlib_node_add_next (vm, + hicn_data_fwd_node.index, + hicn_iface_udp6_output_node. + index); + + u32 temp_index4 = vlib_node_add_next (vm, + hicn_interest_hitcs_node.index, + hicn_iface_udp4_output_node.index); + u32 temp_index6 = vlib_node_add_next (vm, + hicn_interest_hitcs_node.index, + hicn_iface_udp6_output_node.index); + + ASSERT (temp_index4 == data_fwd_face_udp4_vlib_edge); + ASSERT (temp_index6 == data_fwd_face_udp6_vlib_edge); +} + +static char *hicn_iface_udp4_input_error_strings[] = { +#define _(sym, string) string, + foreach_hicnfwd_error +#undef _ +}; + +static char *hicn_iface_udp6_input_error_strings[] = { +#define _(sym, string) string, + foreach_hicnfwd_error +#undef _ +}; + +u32 +get_face_udp4_output_node (void) +{ + return data_fwd_face_udp4_vlib_edge; +} + +u32 +get_face_udp6_output_node (void) +{ + return data_fwd_face_udp6_vlib_edge; +} + +/* Trace context struct */ +typedef struct +{ + u32 next_index; + u32 sw_if_index; + u8 pkt_type; +} hicn_iface_udp4_input_trace_t; + +typedef enum +{ + HICN_IFACE_UDP4_INPUT_NEXT_INTEREST, + HICN_IFACE_UDP4_INPUT_NEXT_MAPME, + HICN_IFACE_UDP4_INPUT_NEXT_ERROR_DROP, + HICN_IFACE_UDP4_INPUT_N_NEXT, +} hicn_iface_udp4_input_next_t; + +/* Trace context struct */ +typedef struct +{ + u32 next_index; + u32 sw_if_index; + u8 pkt_type; +} hicn_iface_udp6_input_trace_t; + +typedef enum +{ + HICN_IFACE_UDP6_INPUT_NEXT_INTEREST, + HICN_IFACE_UDP6_INPUT_NEXT_MAPME, + HICN_IFACE_UDP6_INPUT_NEXT_ERROR_DROP, + HICN_IFACE_UDP6_INPUT_N_NEXT, +} hicn_iface_udp6_input_next_t; + +#define ERROR_INPUT_UDP4 HICN_IFACE_UDP4_INPUT_NEXT_ERROR_DROP +#define ERROR_INPUT_UDP6 HICN_IFACE_UDP6_INPUT_NEXT_ERROR_DROP + +#define IP_HEADER_4 ip4_header_t +#define IP_HEADER_6 ip6_header_t + +#define NEXT_MAPME_UDP4 HICN_IFACE_UDP4_INPUT_NEXT_MAPME +#define NEXT_MAPME_UDP6 HICN_IFACE_UDP6_INPUT_NEXT_MAPME + +#define NEXT_INTEREST_UDP4 HICN_IFACE_UDP4_INPUT_NEXT_INTEREST +#define NEXT_INTEREST_UDP6 HICN_IFACE_UDP6_INPUT_NEXT_INTEREST + +#define HICN_IFACE_UDP_ADD_LOCK_IP4 hicn_dpo_udp4_add_and_lock +#define HICN_IFACE_UDP_ADD_LOCK_IP6 hicn_dpo_udp6_add_and_lock + +#define GET_FACE_UDP4 get_face_udp4_output_node +#define GET_FACE_UDP6 get_face_udp6_output_node + +#define TRACE_INPUT_PKT_UDP4 hicn_iface_udp4_input_trace_t +#define TRACE_INPUT_PKT_UDP6 hicn_iface_udp6_input_trace_t + +#define iface_input_x1(ipv) \ + do { \ + vlib_buffer_t *b0; \ + u32 bi0; \ + u32 next0 = ERROR_INPUT_UDP##ipv; \ + IP_HEADER_##ipv * ip_hdr = NULL; \ + u8 * inner_ip_hdr = NULL; \ + udp_header_t * udp_hdr = NULL; \ + hicn_buffer_t * hicnb0; \ + /* Prefetch for next iteration. */ \ + if (n_left_from > 1) \ + { \ + vlib_buffer_t *b1; \ + b1 = vlib_get_buffer (vm, from[1]); \ + CLIB_PREFETCH (b1, CLIB_CACHE_LINE_BYTES, STORE); \ + CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES , LOAD); \ + } \ + /* Dequeue a packet buffer */ \ + bi0 = from[0]; \ + from += 1; \ + n_left_from -= 1; \ + to_next[0] = bi0; \ + to_next += 1; \ + n_left_to_next -= 1; \ + \ + b0 = vlib_get_buffer (vm, bi0); \ + ip_hdr = (IP_HEADER_##ipv *) vlib_buffer_get_current(b0); \ + udp_hdr = (udp_header_t *) (ip_hdr + 1); \ + hicnb0 = hicn_get_buffer(b0); \ + \ + stats.pkts_interest_count += 1; \ + \ + inner_ip_hdr = (u8 *)(udp_hdr + 1); \ + u8 is_v6 = ((inner_ip_hdr[0] & 2) >> 1); \ + u8 is_icmp = is_v6*(inner_ip_hdr[7] == IPPROTO_ICMPV6) + \ + (1 - is_v6)*(inner_ip_hdr[10] == IPPROTO_ICMPV4); \ + \ + next0 = is_icmp*NEXT_MAPME_UDP##ipv + \ + (1-is_icmp)*NEXT_INTEREST_UDP##ipv; \ + \ + HICN_IFACE_UDP_ADD_LOCK_IP##ipv \ + (&(hicnb0->face_dpo_id), \ + &(ip_hdr->dst_address), \ + &(ip_hdr->src_address), \ + udp_hdr->dst_port, \ + udp_hdr->src_port, \ + GET_FACE_UDP##ipv \ + (), \ + &hicnb0->is_appface); \ + \ + vlib_buffer_advance(b0, sizeof(IP_HEADER_##ipv) + \ + sizeof(udp_header_t)); \ + \ + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && \ + (b0->flags & VLIB_BUFFER_IS_TRACED))) \ + { \ + TRACE_INPUT_PKT_UDP##ipv *t = \ + vlib_add_trace (vm, node, b0, sizeof (*t)); \ + t->pkt_type = HICN_PKT_TYPE_INTEREST; \ + t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ + t->next_index = next0; \ + } \ + \ + \ + /* Verify speculative enqueue, maybe switch current next frame */ \ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, \ + to_next, n_left_to_next, \ + bi0, next0); \ + }while(0) + + +#define iface_input_x2(ipv) \ + do { \ + vlib_buffer_t *b0, *b1; \ + u32 bi0, bi1; \ + u32 next0, next1 = ERROR_INPUT_UDP##ipv; \ + IP_HEADER_##ipv * ip_hdr0 = NULL, *ip_hdr1 = NULL; \ + u8 * inner_ip_hdr0 = NULL, *inner_ip_hdr1 = NULL; \ + udp_header_t * udp_hdr0 = NULL, *udp_hdr1 = NULL; \ + hicn_buffer_t * hicnb0, *hicnb1; \ + \ + /* Prefetch for next iteration. */ \ + { \ + vlib_buffer_t *b2, *b3; \ + b2 = vlib_get_buffer (vm, from[2]); \ + b3 = vlib_get_buffer (vm, from[3]); \ + CLIB_PREFETCH (b2, CLIB_CACHE_LINE_BYTES, STORE); \ + CLIB_PREFETCH (b3, CLIB_CACHE_LINE_BYTES, STORE); \ + CLIB_PREFETCH (b2->data, CLIB_CACHE_LINE_BYTES , LOAD); \ + CLIB_PREFETCH (b3->data, CLIB_CACHE_LINE_BYTES , LOAD); \ + } \ + \ + /* Dequeue a packet buffer */ \ + bi0 = from[0]; \ + bi1 = from[1]; \ + from += 2; \ + n_left_from -= 2; \ + to_next[0] = bi0; \ + to_next[1] = bi1; \ + to_next += 2; \ + n_left_to_next -= 2; \ + \ + b0 = vlib_get_buffer (vm, bi0); \ + b1 = vlib_get_buffer (vm, bi1); \ + ip_hdr0 = (IP_HEADER_##ipv *) vlib_buffer_get_current(b0); \ + ip_hdr1 = (IP_HEADER_##ipv *) vlib_buffer_get_current(b1); \ + udp_hdr0 = (udp_header_t *) (ip_hdr0 + 1); \ + udp_hdr1 = (udp_header_t *) (ip_hdr1 + 1); \ + hicnb0 = hicn_get_buffer(b0); \ + hicnb1 = hicn_get_buffer(b1); \ + \ + stats.pkts_interest_count += 2; \ + \ + inner_ip_hdr0 = (u8 *)(udp_hdr0 + 1); \ + inner_ip_hdr1 = (u8 *)(udp_hdr1 + 1); \ + u8 is_v6_0 = ((inner_ip_hdr0[0] & 2) >> 1); \ + u8 is_v6_1 = ((inner_ip_hdr1[0] & 2) >> 1); \ + u8 is_icmp0 = is_v6_0*(inner_ip_hdr0[7] == IPPROTO_ICMPV6) + \ + (1 - is_v6_0)*(inner_ip_hdr0[10] == IPPROTO_ICMPV4); \ + u8 is_icmp1 = is_v6_1*(inner_ip_hdr1[7] == IPPROTO_ICMPV6) + \ + (1 - is_v6_1)*(inner_ip_hdr1[10] == IPPROTO_ICMPV4); \ + \ + next0 = is_icmp0*NEXT_MAPME_UDP##ipv + \ + (1-is_icmp0)*NEXT_INTEREST_UDP##ipv; \ + next1 = is_icmp1*NEXT_MAPME_UDP##ipv + \ + (1-is_icmp1)*NEXT_INTEREST_UDP##ipv; \ + \ + HICN_IFACE_UDP_ADD_LOCK_IP##ipv \ + (&(hicnb0->face_dpo_id), \ + &(ip_hdr0->dst_address), \ + &(ip_hdr0->src_address), \ + udp_hdr0->dst_port, \ + udp_hdr0->src_port, \ + GET_FACE_UDP##ipv \ + (), \ + &hicnb0->is_appface); \ + \ + \ + HICN_IFACE_UDP_ADD_LOCK_IP##ipv \ + (&(hicnb1->face_dpo_id), \ + &(ip_hdr1->dst_address), \ + &(ip_hdr1->src_address), \ + udp_hdr1->dst_port, \ + udp_hdr1->src_port, \ + GET_FACE_UDP##ipv \ + (), \ + &hicnb1->is_appface); \ + \ + vlib_buffer_advance(b0, sizeof(IP_HEADER_##ipv) + \ + sizeof(udp_header_t)); \ + \ + vlib_buffer_advance(b1, sizeof(IP_HEADER_##ipv) + \ + sizeof(udp_header_t)); \ + \ + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && \ + (b0->flags & VLIB_BUFFER_IS_TRACED))) \ + { \ + TRACE_INPUT_PKT_UDP##ipv *t = \ + vlib_add_trace (vm, node, b0, sizeof (*t)); \ + t->pkt_type = HICN_PKT_TYPE_INTEREST; \ + t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ + t->next_index = next0; \ + } \ + \ + \ + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && \ + (b1->flags & VLIB_BUFFER_IS_TRACED))) \ + { \ + TRACE_INPUT_PKT_UDP##ipv *t = \ + vlib_add_trace (vm, node, b1, sizeof (*t)); \ + t->pkt_type = HICN_PKT_TYPE_INTEREST; \ + t->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX]; \ + t->next_index = next1; \ + } \ + \ + \ + /* Verify speculative enqueue, maybe switch current next frame */ \ + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, \ + to_next, n_left_to_next, \ + bi0, bi1, next0, next1); \ + }while(0) + + +static uword +hicn_iface_udp4_input_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next, next_index; + vl_api_hicn_api_node_stats_get_reply_t stats = { 0 }; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + /* Dual loop, X2 */ + while (n_left_from >= 4 && n_left_to_next >= 2) + { + iface_input_x2 (4); + } + + /* Dual loop, X1 */ + while (n_left_from > 0 && n_left_to_next > 0) + { + iface_input_x1 (4); + } + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + vlib_node_increment_counter (vm, node->node_index, + HICNFWD_ERROR_INTERESTS, + stats.pkts_interest_count); + + return (frame->n_vectors); +} + +/* packet trace format function */ +static u8 * +hicn_iface_udp4_input_format_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + hicn_iface_udp4_input_trace_t *t = + va_arg (*args, hicn_iface_udp4_input_trace_t *); + + s = format (s, "IFACE_UDP4_INPUT: pkt: %d, sw_if_index %d, next index %d", + (int) t->pkt_type, t->sw_if_index, t->next_index); + return (s); +} + +/* + * Node registration for the interest forwarder node + */ +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (hicn_iface_udp4_input_node) = + +{ + .function = hicn_iface_udp4_input_node_fn, + .name = "hicn-iface-udp4-input", + .vector_size = sizeof (u32), + .format_trace = hicn_iface_udp4_input_format_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (hicn_iface_udp4_input_error_strings), + .error_strings = hicn_iface_udp4_input_error_strings, + .n_next_nodes = HICN_IFACE_UDP4_INPUT_N_NEXT, + .next_nodes = + { + [HICN_IFACE_UDP4_INPUT_NEXT_INTEREST] = "hicn-interest-pcslookup", + [HICN_IFACE_UDP4_INPUT_NEXT_MAPME] = "hicn-mapme-ctrl", + [HICN_IFACE_UDP4_INPUT_NEXT_ERROR_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + + +static uword +hicn_iface_udp6_input_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next, next_index; + vl_api_hicn_api_node_stats_get_reply_t stats = { 0 }; + + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + /* Dual loop, X2 */ + while (n_left_from >= 4 && n_left_to_next >= 2) + { + iface_input_x2 (6); + } + + /* Dual loop, X1 */ + while (n_left_from > 0 && n_left_to_next > 0) + { + iface_input_x1 (6); + } + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + vlib_node_increment_counter (vm, node->node_index, + HICNFWD_ERROR_INTERESTS, + stats.pkts_interest_count); + + return (frame->n_vectors); +} + +/* packet trace format function */ +static u8 * +hicn_iface_udp6_input_format_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + hicn_iface_udp6_input_trace_t *t = + va_arg (*args, hicn_iface_udp6_input_trace_t *); + + s = format (s, "IFACE_UDP6_INPUT: pkt: %d, sw_if_index %d, next index %d", + (int) t->pkt_type, t->sw_if_index, t->next_index); + return (s); +} + +/* + * Node registration for the interest forwarder node + */ +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (hicn_iface_udp6_input_node) = +{ + .function = hicn_iface_udp6_input_node_fn, + .name = "hicn-iface-udp6-input", + .vector_size = sizeof (u32), + .format_trace = hicn_iface_udp6_input_format_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (hicn_iface_udp6_input_error_strings), + .error_strings = hicn_iface_udp6_input_error_strings, + .n_next_nodes = HICN_IFACE_UDP6_INPUT_N_NEXT, + .next_nodes = + { + [HICN_IFACE_UDP6_INPUT_NEXT_INTEREST] = "hicn-interest-pcslookup", + [HICN_IFACE_UDP6_INPUT_NEXT_MAPME] = "hicn-mapme-ctrl", + [HICN_IFACE_UDP6_INPUT_NEXT_ERROR_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + +/******* Iface Output *******/ + +always_inline void +hicn_iface_udp4_encap (vlib_main_t * vm, + vlib_buffer_t * b0, hicn_face_t * face) +{ + u16 new_l0 = 0; + ip4_header_t *ip0; + udp_header_t *udp0; + hicn_face_udp_t *face_udp = (hicn_face_udp_t *) face->data; + + /* Adjust vlib buffers */ + /* Set the right length on the header buffer */ + /* Move the next buffer current data pointer back to the ip+tcp header (hicn header) */ + int offset = sizeof (ip4_header_t) + sizeof (udp_header_t); + b0->current_data -= offset; + b0->current_length += offset; + + /* ip */ + ip0 = vlib_buffer_get_current (b0); + clib_memcpy (ip0, &(face_udp->hdrs.ip4.ip), sizeof (ip4_header_t) + + sizeof (udp_header_t)); + + /* Fix UDP length */ + udp0 = (udp_header_t *) (ip0 + 1); + + new_l0 = + clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0) - + sizeof (*ip0)); + udp0->length = new_l0; + + ip0->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)); + ip0->checksum = ip4_header_checksum (ip0); +} + +always_inline void +hicn_iface_udp6_encap (vlib_main_t * vm, + vlib_buffer_t * b0, hicn_face_t * face) +{ + int bogus0; + u16 new_l0; + ip6_header_t *ip0; + udp_header_t *udp0; + hicn_face_udp_t *face_udp = (hicn_face_udp_t *) face->data; + + /* Adjust vlib buffer */ + int offset = sizeof (ip6_header_t) + sizeof (udp_header_t); + b0->current_data -= offset; + b0->current_length += offset; + + /* ip */ + ip0 = vlib_buffer_get_current (b0); + clib_memcpy (ip0, &(face_udp->hdrs.ip6.ip), sizeof (ip6_header_t) + + sizeof (udp_header_t)); + + new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0) + - sizeof (*ip0)); + + ip0->payload_length = new_l0; + + /* Fix UDP length */ + udp0 = (udp_header_t *) (ip0 + 1); + udp0->length = new_l0; + + udp0->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0, &bogus0); + + ASSERT (bogus0 == 0); + + if (udp0->checksum == 0) + udp0->checksum = 0xffff; +} + +static char *hicn_iface_udp4_output_error_strings[] = { +#define _(sym, string) string, + foreach_hicnfwd_error +#undef _ +}; + +static char *hicn_iface_udp6_output_error_strings[] = { +#define _(sym, string) string, + foreach_hicnfwd_error +#undef _ +}; + +/* Trace context struct */ +typedef struct +{ + u32 next_index; + u32 sw_if_index; + u8 pkt_type; +} hicn_iface_udp4_output_trace_t; + +typedef enum +{ + HICN_IFACE_UDP4_OUTPUT_NEXT_LOOKUP, + HICN_IFACE_UDP4_OUTPUT_NEXT_ERROR_DROP, + HICN_IFACE_UDP4_OUTPUT_N_NEXT, +} hicn_iface_udp4_output_next_t; + +/* Trace context struct */ +typedef struct +{ + u32 next_index; + u32 sw_if_index; + u8 pkt_type; +} hicn_iface_udp6_output_trace_t; + +typedef enum +{ + HICN_IFACE_UDP6_OUTPUT_NEXT_LOOKUP, + HICN_IFACE_UDP6_OUTPUT_NEXT_ERROR_DROP, + HICN_IFACE_UDP6_OUTPUT_N_NEXT, +} hicn_iface_udp6_output_next_t; + +#define ERROR_OUTPUT_UDP4 HICN_IFACE_UDP4_OUTPUT_NEXT_ERROR_DROP +#define ERROR_OUTPUT_UDP6 HICN_IFACE_UDP6_OUTPUT_NEXT_ERROR_DROP + +#define IP_HEADER_4 ip4_header_t +#define IP_HEADER_6 ip6_header_t + +#define NEXT_LOOKUP_UDP4 HICN_IFACE_UDP4_OUTPUT_NEXT_LOOKUP +#define NEXT_LOOKUP_UDP6 HICN_IFACE_UDP6_OUTPUT_NEXT_LOOKUP + +#define HICN_IFACE_UDP_ADD_LOCK_IP4 hicn_dpo_udp4_add_and_lock +#define HICN_IFACE_UDP_ADD_LOCK_IP6 hicn_dpo_udp6_add_and_lock + +#define HICN_FACE_UDP_ENCAP_IP4 hicn_iface_udp4_encap +#define HICN_FACE_UDP_ENCAP_IP6 hicn_iface_udp6_encap + +#define TRACE_OUTPUT_PKT_UDP4 hicn_iface_udp4_output_trace_t +#define TRACE_OUTPUT_PKT_UDP6 hicn_iface_udp6_output_trace_t + +#define iface_output_x1(ipv) \ + do { \ + vlib_buffer_t *b0; \ + u32 bi0; \ + u32 next0 = ERROR_OUTPUT_UDP##ipv; \ + hicn_face_t * face; \ + \ + /* Prefetch for next iteration. */ \ + if (n_left_from > 1) \ + { \ + vlib_buffer_t *b1; \ + b1 = vlib_get_buffer (vm, from[1]); \ + CLIB_PREFETCH (b1, CLIB_CACHE_LINE_BYTES, STORE); \ + CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES , LOAD); \ + } \ + /* Dequeue a packet buffer */ \ + bi0 = from[0]; \ + from += 1; \ + n_left_from -= 1; \ + to_next[0] = bi0; \ + to_next += 1; \ + n_left_to_next -= 1; \ + \ + b0 = vlib_get_buffer (vm, bi0); \ + \ + face = \ + hicn_dpoi_get_from_idx(vnet_buffer (b0)->ip.adj_index[VLIB_TX]); \ + \ + if (PREDICT_TRUE(face != NULL)) \ + { \ + HICN_FACE_UDP_ENCAP_IP##ipv \ + (vm, b0, face); \ + next0 = NEXT_LOOKUP_UDP##ipv; \ + stats.pkts_data_count += 1; \ + } \ + \ + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && \ + (b0->flags & VLIB_BUFFER_IS_TRACED))) \ + { \ + TRACE_OUTPUT_PKT_UDP##ipv *t = \ + vlib_add_trace (vm, node, b0, sizeof (*t)); \ + t->pkt_type = HICN_PKT_TYPE_INTEREST; \ + t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ + t->next_index = next0; \ + } \ + \ + \ + /* Verify speculative enqueue, maybe switch current next frame */ \ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, \ + to_next, n_left_to_next, \ + bi0, next0); \ + } while(0) + +#define iface_output_x2(ipv) \ + do { \ + vlib_buffer_t *b0, *b1; \ + u32 bi0, bi1; \ + u32 next0 = ERROR_OUTPUT_UDP##ipv, next1 = ERROR_OUTPUT_UDP##ipv; \ + hicn_face_t *face0, *face1; \ + \ + /* Prefetch for next iteration. */ \ + { \ + vlib_buffer_t *b2, *b3; \ + b2 = vlib_get_buffer (vm, from[2]); \ + b3 = vlib_get_buffer (vm, from[3]); \ + CLIB_PREFETCH (b2, CLIB_CACHE_LINE_BYTES, STORE); \ + CLIB_PREFETCH (b3, CLIB_CACHE_LINE_BYTES, STORE); \ + CLIB_PREFETCH (b2->data, CLIB_CACHE_LINE_BYTES , LOAD); \ + CLIB_PREFETCH (b3->data, CLIB_CACHE_LINE_BYTES , LOAD); \ + } \ + \ + /* Dequeue packets buffers */ \ + bi0 = from[0]; \ + bi1 = from[1]; \ + from += 2; \ + n_left_from -= 2; \ + to_next[0] = bi0; \ + to_next[1] = bi1; \ + to_next += 2; \ + n_left_to_next -= 2; \ + \ + b0 = vlib_get_buffer (vm, bi0); \ + b1 = vlib_get_buffer (vm, bi1); \ + \ + face0 = \ + hicn_dpoi_get_from_idx(vnet_buffer (b0)->ip.adj_index[VLIB_TX]); \ + face1 = \ + hicn_dpoi_get_from_idx(vnet_buffer (b0)->ip.adj_index[VLIB_TX]); \ + \ + if (PREDICT_TRUE(face0 != NULL)) \ + { \ + HICN_FACE_UDP_ENCAP_IP##ipv \ + (vm, b0, face0); \ + next0 = NEXT_LOOKUP_UDP##ipv; \ + stats.pkts_data_count += 1; \ + } \ + \ + if (PREDICT_TRUE(face1 != NULL)) \ + { \ + HICN_FACE_UDP_ENCAP_IP##ipv \ + (vm, b1, face1); \ + next0 = NEXT_LOOKUP_UDP##ipv; \ + stats.pkts_data_count += 1; \ + } \ + \ + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && \ + (b0->flags & VLIB_BUFFER_IS_TRACED))) \ + { \ + TRACE_OUTPUT_PKT_UDP##ipv *t = \ + vlib_add_trace (vm, node, b0, sizeof (*t)); \ + t->pkt_type = HICN_PKT_TYPE_INTEREST; \ + t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ + t->next_index = next0; \ + } \ + \ + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && \ + (b1->flags & VLIB_BUFFER_IS_TRACED))) \ + { \ + TRACE_OUTPUT_PKT_UDP##ipv *t = \ + vlib_add_trace (vm, node, b1, sizeof (*t)); \ + t->pkt_type = HICN_PKT_TYPE_INTEREST; \ + t->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX]; \ + t->next_index = next1; \ + } \ + \ + \ + /* Verify speculative enqueue, maybe switch current next frame */ \ + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, \ + to_next, n_left_to_next, \ + bi0, bi1, next0, next1); \ + } while(0) + + +static uword +hicn_iface_udp4_output_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next, next_index; + vl_api_hicn_api_node_stats_get_reply_t stats = { 0 }; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from >= 4 && n_left_to_next >= 2) + { + iface_output_x2 (4); + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + iface_output_x1 (4); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + vlib_node_increment_counter (vm, node->node_index, + HICNFWD_ERROR_DATAS, stats.pkts_data_count); + + return (frame->n_vectors); +} + +/* packet trace format function */ +static u8 * +hicn_iface_udp4_output_format_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + hicn_iface_udp4_output_trace_t *t = + va_arg (*args, hicn_iface_udp4_output_trace_t *); + + s = format (s, "IFACE_UDP4_OUTPUT: pkt: %d, sw_if_index %d, next index %d", + (int) t->pkt_type, t->sw_if_index, t->next_index); + return (s); +} + + +/* + * Node registration for the interest forwarder node + */ +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (hicn_iface_udp4_output_node) = +{ + .function = hicn_iface_udp4_output_node_fn, + .name = "hicn-iface-udp4-output", + .vector_size = sizeof (u32), + .format_trace = hicn_iface_udp4_output_format_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (hicn_iface_udp4_output_error_strings), + .error_strings = hicn_iface_udp4_output_error_strings, + .n_next_nodes = HICN_IFACE_UDP4_OUTPUT_N_NEXT, + /* edit / add dispositions here */ + .next_nodes = + { + [HICN_IFACE_UDP4_OUTPUT_NEXT_LOOKUP] = "ip4-lookup", + [HICN_IFACE_UDP4_OUTPUT_NEXT_ERROR_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + + +static uword +hicn_iface_udp6_output_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next, next_index; + vl_api_hicn_api_node_stats_get_reply_t stats = { 0 }; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from >= 4 && n_left_to_next >= 2) + { + iface_output_x2 (6); + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + iface_output_x1 (6); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + vlib_node_increment_counter (vm, node->node_index, + HICNFWD_ERROR_DATAS, stats.pkts_data_count); + + return (frame->n_vectors); + +} + +/* packet trace format function */ +static u8 * +hicn_iface_udp6_output_format_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + hicn_iface_udp6_output_trace_t *t = + va_arg (*args, hicn_iface_udp6_output_trace_t *); + + s = format (s, "IFACE_UDP6_OUTPUT: pkt: %d, sw_if_index %d, next index %d", + (int) t->pkt_type, t->sw_if_index, t->next_index); + return (s); +} + +/* + * Node registration for the interest forwarder node + */ +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (hicn_iface_udp6_output_node) = +{ + .function = hicn_iface_udp6_output_node_fn, + .name = "hicn-iface-udp6-output", + .vector_size = sizeof (u32), + .format_trace = hicn_iface_udp6_output_format_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (hicn_iface_udp6_output_error_strings), + .error_strings = hicn_iface_udp6_output_error_strings, + .n_next_nodes = HICN_IFACE_UDP6_OUTPUT_N_NEXT, + /* edit / add dispositions here */ + .next_nodes = + { + [HICN_IFACE_UDP6_OUTPUT_NEXT_LOOKUP] = "ip6-lookup", + [HICN_IFACE_UDP6_OUTPUT_NEXT_ERROR_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/hicn-plugin/src/faces/udp/iface_udp_node.h b/hicn-plugin/src/faces/udp/iface_udp_node.h new file mode 100755 index 000000000..957d19217 --- /dev/null +++ b/hicn-plugin/src/faces/udp/iface_udp_node.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __HICN_IFACE_UDP_H__ +#define __HICN_IFACE_UDP_H__ + +#include <vlib/vlib.h> + +extern vlib_node_registration_t hicn_iface_udp4_input_node; +extern vlib_node_registration_t hicn_iface_udp6_input_node; +extern vlib_node_registration_t hicn_iface_udp4_output_node; +extern vlib_node_registration_t hicn_iface_udp6_output_node; + +void hicn_iface_udp_init (vlib_main_t * vm); + +#endif // __HICN_FACE_UDP_H__ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ |