diff options
Diffstat (limited to 'hicn-plugin/src/faces/ip')
-rwxr-xr-x | hicn-plugin/src/faces/ip/dpo_ip.c | 187 | ||||
-rwxr-xr-x | hicn-plugin/src/faces/ip/dpo_ip.h | 255 | ||||
-rwxr-xr-x | hicn-plugin/src/faces/ip/face_ip.c | 326 | ||||
-rwxr-xr-x | hicn-plugin/src/faces/ip/face_ip.h | 241 | ||||
-rwxr-xr-x | hicn-plugin/src/faces/ip/face_ip_cli.c | 158 | ||||
-rwxr-xr-x | hicn-plugin/src/faces/ip/face_ip_node.c | 761 | ||||
-rwxr-xr-x | hicn-plugin/src/faces/ip/face_ip_node.h | 40 | ||||
-rwxr-xr-x | hicn-plugin/src/faces/ip/iface_ip_node.c | 845 | ||||
-rwxr-xr-x | hicn-plugin/src/faces/ip/iface_ip_node.h | 35 |
9 files changed, 2848 insertions, 0 deletions
diff --git a/hicn-plugin/src/faces/ip/dpo_ip.c b/hicn-plugin/src/faces/ip/dpo_ip.c new file mode 100755 index 000000000..1b2dbcff9 --- /dev/null +++ b/hicn-plugin/src/faces/ip/dpo_ip.c @@ -0,0 +1,187 @@ +/* + * 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_ip.h" + +mhash_t hicn_face_ip_local_hashtb; +mhash_t hicn_face_ip_remote_hashtb; +dpo_type_t hicn_face_ip_type; + +const static char *const hicn_face_ip4dpoi_nodes[] = { + "hicn-face-ip4-input", + "hicn-face-ip4-output", + "hicn-iface-ip4-input", + "hicn-iface-ip4-output", + NULL, +}; + +const static char *const hicn_face_ip6dpoi_nodes[] = { + "hicn-face-ip6-input", + "hicn-face-ip6-output", + "hicn-iface-ip6-input", + "hicn-iface-ip6-output", + NULL, +}; + +const static char *const *const hicn_ip_nodes[DPO_PROTO_NUM] = { + [DPO_PROTO_IP4] = hicn_face_ip4dpoi_nodes, + [DPO_PROTO_IP6] = hicn_face_ip6dpoi_nodes +}; + +const static dpo_vft_t hicn_face_ip_vft = { + .dv_lock = hicn_face_lock, + .dv_unlock = hicn_face_unlock, + .dv_format = format_hicn_face_ip, +}; + +/* Must be executed after all the strategy nodes are created */ +void +hicn_dpo_ip_module_init (void) +{ + mhash_init (&hicn_face_ip_local_hashtb, + sizeof (hicn_face_id_t) /* value */ , + sizeof (hicn_face_ip_key_t) /* key */ ); + mhash_init (&hicn_face_ip_remote_hashtb, + sizeof (hicn_face_id_t) /* value */ , + sizeof (hicn_face_ip_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_ip_type = + dpo_register_new_type (&hicn_face_ip_vft, hicn_ip_nodes); +} + + +int +hicn_dpo_ip4_create (dpo_id_t * dpo, + const ip4_address_t * local_addr, + const ip4_address_t * remote_addr, + u32 sw_if, + adj_index_t adj, + u32 node_index, + hicn_face_flags_t flags, hicn_face_id_t * face_id) +{ + /* If local matches the dpoi is a face */ + hicn_face_t *face = + hicn_face_ip4_get (local_addr, sw_if, &hicn_face_ip_local_hashtb); + u8 is_appface; + + if (face != NULL) + return HICN_ERROR_FACE_ALREADY_CREATED; + + face = hicn_face_ip4_get (remote_addr, sw_if, &hicn_face_ip_remote_hashtb); + + if (face == NULL) + { + hicn_dpo_ip4_add_and_lock_from_remote (dpo, &is_appface, local_addr, + remote_addr, sw_if, node_index); + *face_id = (hicn_face_id_t) dpo->dpoi_index; + face = hicn_dpoi_get_from_idx (*face_id); + } + else + { + *face_id = hicn_dpoi_get_index (face); + dpo_set (dpo, hicn_face_ip_type, DPO_PROTO_IP4, *face_id); + dpo->dpoi_next_node = node_index; + } + + + hicn_face_ip_key_t key; + hicn_face_ip4_get_key (local_addr, sw_if, &key); + + mhash_set_mem (&hicn_face_ip_local_hashtb, &key, (uword *) face_id, 0); + + hicn_face_ip_t *ip_face = (hicn_face_ip_t *) face->data; + ip46_address_set_ip4 (&ip_face->local_addr, local_addr); + ip46_address_set_ip4 (&ip_face->remote_addr, remote_addr); + face->shared.flags = flags; + face->shared.adj = adj; + + return HICN_ERROR_NONE; +} + +int +hicn_dpo_ip6_create (dpo_id_t * dpo, + const ip6_address_t * local_addr, + const ip6_address_t * remote_addr, + u32 sw_if, + adj_index_t adj, + u32 node_index, + hicn_face_flags_t flags, hicn_face_id_t * face_id) +{ + /* If local matches the dpoi is a face */ + hicn_face_t *face = + hicn_face_ip6_get (local_addr, sw_if, &hicn_face_ip_local_hashtb); + + u8 is_appface; + + if (face != NULL) + return HICN_ERROR_FACE_ALREADY_CREATED; + + face = hicn_face_ip6_get (remote_addr, sw_if, &hicn_face_ip_remote_hashtb); + + /* If remote matches the dpoi is a iface */ + if (face == NULL) + { + hicn_dpo_ip6_add_and_lock_from_remote (dpo, &is_appface, local_addr, + remote_addr, sw_if, node_index); + *face_id = (hicn_face_id_t) dpo->dpoi_index; + face = hicn_dpoi_get_from_idx (*face_id); + } + else + { + *face_id = hicn_dpoi_get_index (face); + dpo_set (dpo, hicn_face_ip_type, DPO_PROTO_IP6, *face_id); + dpo->dpoi_next_node = node_index; + } + + hicn_face_ip_key_t key; + hicn_face_ip6_get_key (local_addr, sw_if, &key); + + mhash_set_mem (&hicn_face_ip_local_hashtb, &key, (uword *) face_id, 0); + + hicn_face_ip_t *ip_face = (hicn_face_ip_t *) face->data; + clib_memcpy (&ip_face->local_addr, local_addr, sizeof (ip6_address_t)); + clib_memcpy (&ip_face->remote_addr, remote_addr, sizeof (ip6_address_t)); + face->shared.sw_if = sw_if; + face->shared.flags = flags; + face->shared.adj = adj; + + + return HICN_ERROR_NONE; +} + +void +hicn_dpo_ip_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_ip_t *ip_face = (hicn_face_ip_t *) face->data; + dpo_set (dpo, face->shared.face_type, + ip46_address_is_ip4 (&ip_face-> + local_addr) ? 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/ip/dpo_ip.h b/hicn-plugin/src/faces/ip/dpo_ip.h new file mode 100755 index 000000000..675443277 --- /dev/null +++ b/hicn-plugin/src/faces/ip/dpo_ip.h @@ -0,0 +1,255 @@ +/* + * 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_IP_H__ +#define __HICN_DPO_IP_H__ + +#include <vnet/vnet.h> +#include <vnet/ip/ip4_packet.h> + +#include "face_ip.h" +#include "../face.h" + +/** + * @brief Initialize the internal structures of the dpo ip face module. + */ +void hicn_dpo_ip_module_init (void); + + +/** + * @brief Retrieve a face from the ip4 local address and returns its dpo. This + * method adds a lock on the face state. + * + * @param dpo: Result of the lookup. If the face doesn't exist dpo = NULL + * @param is_appface: Boolean that indicates whether the face is an application + * face or not + * @param local_addr: Ip v4 local address of the face + * @param sw_if: software interface id of the face + * + * @result HICN_ERROR_FACE_NOT_FOUND if the face does not exist, otherwise HICN_ERROR_NONE. + */ +always_inline int +hicn_dpo_ip4_lock_from_local (dpo_id_t * dpo, + u8 * is_appface, + const ip4_address_t * local_addr, u32 sw_if) +{ + hicn_face_t *face = + hicn_face_ip4_get (local_addr, sw_if, &hicn_face_ip_local_hashtb); + + if (PREDICT_FALSE (face == NULL)) + return HICN_ERROR_FACE_NOT_FOUND; + + *is_appface = face->shared.flags & HICN_FACE_FLAGS_APPFACE_PROD; + + hicn_face_id_t dpoi_index = hicn_dpoi_get_index (face); + dpo_set (dpo, hicn_face_ip_type, DPO_PROTO_IP4, dpoi_index); + dpo->dpoi_next_node = ~0; + dpo_lock (dpo); + + return HICN_ERROR_NONE; +} + +/** + * @brief Retrieve a face from the ip6 local address and returns its dpo. This + * method adds a lock on the face state. + * + * @param dpo: Result of the lookup. If the face doesn't exist dpo = NULL + * @param is_appface: Boolean that indicates whether the face is an application + * face or not + * @param local_addr: Ip v6 local address of the face + * @param sw_if: software interface id of the face + * + * @result HICN_ERROR_FACE_NOT_FOUND if the face does not exist, otherwise HICN_ERROR_NONE. + */ +always_inline int +hicn_dpo_ip6_lock_from_local (dpo_id_t * dpo, + u8 * is_appface, + const ip6_address_t * local_addr, u32 sw_if) +{ + hicn_face_t *face = + hicn_face_ip6_get (local_addr, sw_if, &hicn_face_ip_local_hashtb); + + if (PREDICT_FALSE (face == NULL)) + return HICN_ERROR_FACE_NOT_FOUND; + + *is_appface = face->shared.flags & HICN_FACE_FLAGS_APPFACE_PROD; + + hicn_face_id_t dpoi_index = hicn_dpoi_get_index (face); + dpo_set (dpo, hicn_face_ip_type, DPO_PROTO_IP6, dpoi_index); + dpo->dpoi_next_node = ~0; + dpo_lock (dpo); + + return HICN_ERROR_NONE; +} + + +/** + * @brief Retrieve, or create if it doesn't exist, a face from the ip6 local + * address and returns its dpo. This method adds a lock on the face state. + * + * @param dpo: Result of the lookup + * @param is_appface: Boolean that indicates whether the face is an application + * face or not + * @param local_addr: Ip v4 local address of the face + * @param remote_addr: Ip v4 remote address of the face + * @param sw_if: software interface id of the face + * @param node_index: vlib edge index to use in the packet processing + */ +always_inline void +hicn_dpo_ip4_add_and_lock_from_remote (dpo_id_t * dpo, + u8 * is_appface, + const ip4_address_t * local_addr, + const ip4_address_t * remote_addr, + u32 sw_if, u32 node_index) +{ + /*All (complete) faces are indexed by remote addess as well */ + hicn_face_t *face = + hicn_face_ip4_get (remote_addr, sw_if, &hicn_face_ip_remote_hashtb); + + if (face == NULL) + { + hicn_face_id_t dpoi_index; + ip46_address_t local_addr46 = to_ip46 (0, (u8 *) local_addr); + ip46_address_t remote_addr46 = to_ip46 (0, (u8 *) remote_addr); + hicn_iface_ip_add (&local_addr46, &remote_addr46, sw_if, &dpoi_index); + + *is_appface = 0; + + dpo_set (dpo, hicn_face_ip_type, DPO_PROTO_IP4, dpoi_index); + dpo->dpoi_next_node = node_index; + dpo_lock (dpo); + + return; + } + + /* Code replicated on purpose */ + *is_appface = face->shared.flags & HICN_FACE_FLAGS_APPFACE_PROD; + + hicn_face_id_t dpoi_index = hicn_dpoi_get_index (face); + dpo_set (dpo, hicn_face_ip_type, DPO_PROTO_IP4, dpoi_index); + dpo->dpoi_next_node = node_index; + dpo_lock (dpo); +} + +/** + * @brief Retrieve, or create if it doesn't exist, a face from the ip6 local + * address and returns its dpo. This method adds a lock on the face state. + * + * @param dpo: Result of the lookup + * @param is_appface: Boolean that indicates whether the face is an application + * face or not + * @param local_addr: Ip v6 local address of the face + * @param remote_addr: Ip v6 remote address of the face + * @param sw_if: software interface id of the face + * @param node_index: vlib edge index to use in the packet processing + */ +always_inline void +hicn_dpo_ip6_add_and_lock_from_remote (dpo_id_t * dpo, + u8 * is_appface, + const ip6_address_t * local_addr, + const ip6_address_t * remote_addr, + u32 sw_if, u32 node_index) +{ + /*All (complete) faces are indexed by remote addess as well */ + hicn_face_t *face = + hicn_face_ip6_get (remote_addr, sw_if, &hicn_face_ip_remote_hashtb); + + if (face == NULL) + { + hicn_face_id_t dpoi_index; + hicn_iface_ip_add ((ip46_address_t *) local_addr, + (ip46_address_t *) remote_addr, sw_if, &dpoi_index); + + *is_appface = 0; + + dpo_set (dpo, hicn_face_ip_type, DPO_PROTO_IP4, dpoi_index); + dpo->dpoi_next_node = node_index; + dpo_lock (dpo); + + return; + } + /* Code replicated on purpose */ + *is_appface = face->shared.flags & HICN_FACE_FLAGS_APPFACE_PROD; + + index_t dpoi_index = hicn_dpoi_get_index (face); + dpo_set (dpo, hicn_face_ip_type, DPO_PROTO_IP6, dpoi_index); + dpo->dpoi_next_node = node_index; + dpo_lock (dpo); +} + + +/** + * @brief Create an ip 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: Ip v4 local address of the face + * @param remote_addr: Ip v4 remote address of the face + * @param sw_if: software interface id of the face + * @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_ip4_create (dpo_id_t * dpo, + const ip4_address_t * local_addr, + const ip4_address_t * remote_addr, + u32 sw_if, + adj_index_t adj, + u32 node_index, + hicn_face_flags_t flags, hicn_face_id_t * face_id); + +/** + * @brief Create an ip 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: Ip v6 local address of the face + * @param remote_addr: Ip v6 remote address of the face + * @param sw_if: software interface id of the face + * @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_ip6_create (dpo_id_t * dpo, + const ip6_address_t * local_addr, + const ip6_address_t * remote_addr, + u32 sw_if, + adj_index_t adj, + u32 node_index, + hicn_face_flags_t flags, hicn_face_id_t * face_id); + +/** + * @brief Create a dpo from an ip face + * + * @param face Face from which to create the dpo + * @param dpoi_next_node Edge index that connects a node to the iface or face nodes + * @return the dpo + */ +void hicn_dpo_ip_create_from_face (hicn_face_t * face, dpo_id_t * dpo, + u16 dpoi_next_node); + +#endif // __HICN_DPO_IP_H__ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/hicn-plugin/src/faces/ip/face_ip.c b/hicn-plugin/src/faces/ip/face_ip.c new file mode 100755 index 000000000..c7f6a1ba1 --- /dev/null +++ b/hicn-plugin/src/faces/ip/face_ip.c @@ -0,0 +1,326 @@ +/* + * 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_ip.h" +#include "face_ip_node.h" +#include "dpo_ip.h" +#include "../../strategy_dpo_manager.h" +#include "../face.h" +#include "../../cache_policies/cs_lru.h" +#include "../../infra.h" +#include "../../hicn.h" +#include "../app/face_prod.h" +#include "../app/face_cons.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; + +u32 strategy_face_ip4_vlib_edge; +u32 strategy_face_ip6_vlib_edge; + +void +hicn_face_ip_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_ip4_vlib_edge = vlib_node_add_next (vm, + hicn_dpo_get_strategy_vft + (default_dpo. + hicn_dpo_get_type ())-> + get_strategy_node_index + (), + hicn_face_ip4_output_node. + index); + + strategy_face_ip6_vlib_edge = vlib_node_add_next (vm, + hicn_dpo_get_strategy_vft + (default_dpo. + hicn_dpo_get_type ())-> + get_strategy_node_index + (), + hicn_face_ip6_output_node. + index); + /* + * Create and edge between al the other strategy nodes + * and the ip_encap 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_ip4_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_ip6_output_node.index); + ASSERT (temp_index4 == strategy_face_ip4_vlib_edge); + ASSERT (temp_index6 == strategy_face_ip6_vlib_edge); + } + + hicn_dpo_ip_module_init (); + + register_face_type (hicn_face_ip_type, &ip_vft, "ip"); +} + +int +hicn_face_ip_del (hicn_face_id_t face_id) +{ + hicn_face_t *face = hicn_dpoi_get_from_idx (face_id); + hicn_face_ip_t *face_ip = (hicn_face_ip_t *) face->data; + hicn_face_ip_key_t key; + hicn_face_ip_key_t old_key; + + if (ip46_address_is_ip4 (&face_ip->local_addr)) + { + hicn_face_ip4_get_key (&(face_ip->local_addr.ip4), face->shared.sw_if, + &key); + mhash_unset (&hicn_face_ip_local_hashtb, &key, (uword *) & old_key); + hicn_face_ip4_get_key (&(face_ip->remote_addr.ip4), face->shared.sw_if, + &key); + mhash_unset (&hicn_face_ip_remote_hashtb, &key, (uword *) & old_key); + } + else + { + hicn_face_ip6_get_key (&(face_ip->local_addr.ip6), face->shared.sw_if, + &key); + mhash_unset (&hicn_face_ip_local_hashtb, &key, (uword *) & old_key); + hicn_face_ip6_get_key (&(face_ip->remote_addr.ip6), face->shared.sw_if, + &key); + mhash_unset (&hicn_face_ip_remote_hashtb, &key, (uword *) & old_key); + } + return hicn_face_del (face_id); +} + + +/* + * Utility that adds a new face cache entry. For the moment we assume that the + * ip_adjacency has already been set up. + */ +int +hicn_face_ip_add (const ip46_address_t * local_addr, + const ip46_address_t * remote_addr, + int sw_if, hicn_face_id_t * pfaceid) +{ + fib_protocol_t fib_type; + vnet_link_t link_type; + adj_index_t adj; + dpo_proto_t dpo_proto; + + /* Check if we found at least one ip address */ + if (ip46_address_is_zero (local_addr) || ip46_address_is_zero (remote_addr)) + return HICN_ERROR_FACE_NO_GLOBAL_IP; + + if (ip46_address_is_ip4 (local_addr) && ip46_address_is_ip4 (remote_addr)) + { + link_type = VNET_LINK_IP4; + fib_type = FIB_PROTOCOL_IP4; + } + else + { + link_type = VNET_LINK_IP6; + fib_type = FIB_PROTOCOL_IP6; + } + + + adj = adj_nbr_add_or_lock (fib_type, link_type, remote_addr, sw_if); + + hicn_face_flags_t flags = (hicn_face_flags_t) 0; + flags |= HICN_FACE_FLAGS_FACE; + + hicn_face_t *face; + if (ip46_address_is_ip4 (local_addr)) + { + face = + hicn_face_ip4_get (&(local_addr->ip4), sw_if, + &hicn_face_ip_local_hashtb); + + if (face != NULL) + return HICN_ERROR_FACE_ALREADY_CREATED; + + face = + hicn_face_ip4_get (&(remote_addr->ip4), sw_if, + &hicn_face_ip_remote_hashtb); + + /* If remote matches the face is a iface */ + if (face == NULL) + { + hicn_iface_ip_add (local_addr, remote_addr, sw_if, pfaceid); + face = hicn_dpoi_get_from_idx (*pfaceid); + } + else + { + *pfaceid = hicn_dpoi_get_index (face); + } + + hicn_face_ip_key_t key; + hicn_face_ip4_get_key (&(local_addr->ip4), sw_if, &key); + + mhash_set_mem (&hicn_face_ip_local_hashtb, &key, (uword *) pfaceid, 0); + + hicn_face_ip_t *ip_face = (hicn_face_ip_t *) face->data; + clib_memcpy (&ip_face->local_addr, local_addr, sizeof (ip4_address_t)); + clib_memcpy (&ip_face->remote_addr, remote_addr, + sizeof (ip4_address_t)); + face->shared.sw_if = sw_if; + face->shared.flags = flags; + face->shared.adj = adj; + + dpo_proto = DPO_PROTO_IP4; + } + else + { + face = + hicn_face_ip6_get (&(local_addr->ip6), sw_if, + &hicn_face_ip_local_hashtb); + + if (face != NULL) + return HICN_ERROR_FACE_ALREADY_CREATED; + + face = + hicn_face_ip6_get (&(remote_addr->ip6), sw_if, + &hicn_face_ip_remote_hashtb); + + /* If remote matches the face is a iface */ + if (face == NULL) + { + hicn_iface_ip_add (local_addr, remote_addr, sw_if, pfaceid); + face = hicn_dpoi_get_from_idx (*pfaceid); + } + else + { + *pfaceid = hicn_dpoi_get_index (face); + } + + hicn_face_ip_key_t key; + hicn_face_ip6_get_key (&(local_addr->ip6), sw_if, &key); + + mhash_set_mem (&hicn_face_ip_local_hashtb, &key, (uword *) pfaceid, 0); + + hicn_face_ip_t *ip_face = (hicn_face_ip_t *) face->data; + clib_memcpy (&ip_face->local_addr, local_addr, sizeof (ip6_address_t)); + clib_memcpy (&ip_face->remote_addr, remote_addr, + sizeof (ip6_address_t)); + face->shared.sw_if = sw_if; + face->shared.flags = flags; + face->shared.adj = adj; + + dpo_proto = DPO_PROTO_IP6; + } + + 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_ip_type,.dpoi_proto = dpo_proto,.dpoi_next_node = + 0,.dpoi_index = *pfaceid,} + }; + + return HICN_ERROR_NONE; +} + +u8 * +format_hicn_face_ip (u8 * s, va_list * args) +{ + index_t index = va_arg (*args, index_t); + CLIB_UNUSED (u32 indent) = va_arg (*args, u32); + hicn_face_t *face; + hicn_face_ip_t *ip_face; + ip_adjacency_t *adj; + vnet_main_t *vnm = vnet_get_main (); + + face = hicn_dpoi_get_from_idx (index); + ip_face = (hicn_face_ip_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); + + hicn_face_id_t face_id = hicn_dpoi_get_index (face); + s = format (s, "%U Face %d: ", format_white_space, indent, face_id); + s = format (s, "type IP local %U ", + format_ip46_address, &ip_face->local_addr, IP46_TYPE_ANY); + s = + format (s, "remote %U ", format_ip46_address, &ip_face->remote_addr, + IP46_TYPE_ANY); + 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_APPFACE_PROD)) + s = format (s, " %U", format_hicn_face_prod, face_id, 0); + else if ((face->shared.flags & HICN_FACE_FLAGS_APPFACE_CONS)) + s = format (s, " %U", format_hicn_face_cons, face_id, 0); + + if ((face->shared.flags & HICN_FACE_FLAGS_DELETED)) + s = format (s, " (deleted)"); + } + else + { + hicn_face_id_t face_id = hicn_dpoi_get_index (face); + s = format (s, "%U iFace %d: ", format_white_space, indent, face_id); + s = format (s, "type IP local %U remote %U", + format_ip46_address, &ip_face->local_addr, IP46_TYPE_ANY, + format_ip46_address, &ip_face->remote_addr, IP46_TYPE_ANY); + 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_APPFACE_PROD)) + s = format (s, " %U", format_hicn_face_prod, face_id, 0); + else if ((face->shared.flags & HICN_FACE_FLAGS_APPFACE_CONS)) + s = format (s, " %U", format_hicn_face_cons, face_id, 0); + + if ((face->shared.flags & HICN_FACE_FLAGS_DELETED)) + s = format (s, " (deleted)"); + } + + return s; +} + +void +hicn_face_ip_get_dpo (hicn_face_t * face, dpo_id_t * dpo) +{ + + hicn_face_ip_t *face_ip = (hicn_face_ip_t *) face->data; + return hicn_dpo_ip_create_from_face (face, dpo, + ip46_address_is_ip4 (&face_ip-> + remote_addr) ? + strategy_face_ip4_vlib_edge : + strategy_face_ip6_vlib_edge); +} + +hicn_face_vft_t ip_vft = { + .format_face = format_hicn_face_ip, + .hicn_face_del = hicn_face_ip_del, + .hicn_face_get_dpo = hicn_face_ip_get_dpo, +}; + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/hicn-plugin/src/faces/ip/face_ip.h b/hicn-plugin/src/faces/ip/face_ip.h new file mode 100755 index 000000000..8c31f6dd3 --- /dev/null +++ b/hicn-plugin/src/faces/ip/face_ip.h @@ -0,0 +1,241 @@ +/* + * 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_IP_H__ +#define __HICN_FACE_IP_H__ + +#include <vlib/vlib.h> +#include <vnet/vnet.h> +#include "../face.h" +#include "../../cache_policies/cs_policy.h" + +/** + * @file + * + * @brief IP face + * + * A face is carried through nodes as a dpo. The face state is the object + * pointed by the dpoi_index in the dpo_id_t (see + * https://docs.fd.io/vpp/18.07/d0/d37/dpo_8h_source.html) + */ +typedef struct hicn_ip_face_t_ +{ + /** + * The headers to paint, in packet painting order + */ + /* Local address of the interface sw_if */ + ip46_address_t local_addr; + + /* Remote address of neighbor */ + ip46_address_t remote_addr; + +} hicn_face_ip_t; + + +/** + * Hash tables that indexes a face by local address. For fast lookup when an + * data arrives. + */ +extern mhash_t hicn_face_ip_local_hashtb; + +/** + * Hash tables that indexes a face by remote address. For fast lookup when an + * interest arrives. + */ +extern mhash_t hicn_face_ip_remote_hashtb; + +/** + * Key definition for the mhash table. An ip face is uniquely identified by ip + * address and the interface id. The ip address can correspond to the remote ip + * address of the next hicn hop, or to the local address of the receiving + * interface. The former is used to retrieve the incoming face when an interest + * is received, the latter when the arring packet is a data. + */ +typedef struct hicn_face_ip_key_s +{ + ip46_address_t addr; + u32 sw_if; +} hicn_face_ip_key_t; + + +extern hicn_face_type_t hicn_face_ip_type; +extern hicn_face_vft_t ip_vft; + +/** + * @brief Create the key object for the mhash. Fill in the key object with the + * expected values. + * + * @param addr Local or remote ip v6 address of the face + * @param sw_if interface associated to the face + * @param key Pointer to an allocated hicn_face_ip_key_t object + */ +always_inline void +hicn_face_ip6_get_key (const ip6_address_t * addr, + u32 sw_if, hicn_face_ip_key_t * key) +{ + key->addr.ip6 = *addr; + key->sw_if = sw_if; +} + + +/** + * @brief Create the key object for the mhash. Fill in the key object with the + * expected values. + * + * @param addr Local or remote ip v4 address of the face + * @param sw_if interface associated to the face + * @param key Pointer to an allocated hicn_face_ip_key_t object + */ +always_inline void +hicn_face_ip4_get_key (const ip4_address_t * addr, + u32 sw_if, hicn_face_ip_key_t * key) +{ + ip46_address_set_ip4 (&(key->addr), addr); + key->sw_if = sw_if; +} + +/** + * @brief Get the dpoi from the ip v4 address. Does not add any lock. + * + * @param addr Ip v4 address used to create the key for the hash table. + * @param sw_if Software interface id used to create the key for the hash table. + * @param hashtb Hash table (remote or local) where to perform the lookup. + * + * @result Pointer to the face. + */ +always_inline hicn_face_t * +hicn_face_ip4_get (const ip4_address_t * addr, u32 sw_if, mhash_t * hashtb) +{ + hicn_face_ip_key_t key; + + hicn_face_ip4_get_key (addr, sw_if, &key); + + hicn_face_id_t *dpoi_index = (hicn_face_id_t *) mhash_get (hashtb, + &key); + + return dpoi_index == NULL ? NULL : hicn_dpoi_get_from_idx (*dpoi_index); +} + +/** + * @brief Get the dpoi from the ip v6 address. Does not add any lock. + * + * @param addr Ip v6 address used to create the key for the hash table. + * @param sw_if Software interface id used to create the key for the hash table. + * @param hashtb Hash table (remote or local) where to perform the lookup. + * + * @result Pointer to the face. + */ +always_inline hicn_face_t * +hicn_face_ip6_get (const ip6_address_t * addr, u32 sw_if, mhash_t * hashtb) +{ + hicn_face_ip_key_t key; + + hicn_face_ip6_get_key (addr, sw_if, &key); + + hicn_face_id_t *dpoi_index = (hicn_face_id_t *) mhash_get (hashtb, + &key); + + return dpoi_index == NULL ? NULL : hicn_dpoi_get_from_idx (*dpoi_index); +} + +/** + * @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 + * @param remote_addr Remote ip v4 or v6 address of the face + * @param sw_if interface associated to the face + * @param is_app_face Boolean to set the face as an application 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_ip_add (const ip46_address_t * local_addr, + const ip46_address_t * remote_addr, + int swif, hicn_face_id_t * pfaceid); + +/** + * @brief Create a new incomplete face ip. (Meant to be used by the data plane) + * + * @param local_addr Local ip v4 or v6 address of the face + * @param remote_addr Remote ip v4 or v6 address of the face + * @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 + */ +always_inline void +hicn_iface_ip_add (const ip46_address_t * local_addr, + const ip46_address_t * remote_addr, + int sw_if, hicn_face_id_t * pfaceid) +{ + hicn_face_t *face; + pool_get (hicn_dpoi_face_pool, face); + + hicn_face_ip_t *ip_face = (hicn_face_ip_t *) (face->data); + + clib_memcpy (&(ip_face->local_addr.ip6), local_addr, + sizeof (ip6_address_t)); + clib_memcpy (&(ip_face->remote_addr.ip6), remote_addr, + sizeof (ip6_address_t)); + face->shared.sw_if = sw_if; + + face->shared.adj = ADJ_INDEX_INVALID; + face->shared.pl_id = (u16) 0; + face->shared.face_type = hicn_face_ip_type; + face->shared.flags = HICN_FACE_FLAGS_IFACE; + face->shared.locks = 0; + + hicn_face_ip_key_t key; + hicn_face_ip6_get_key (&(remote_addr->ip6), sw_if, &key); + *pfaceid = hicn_dpoi_get_index (face); + + mhash_set_mem (&hicn_face_ip_remote_hashtb, &key, (uword *) pfaceid, 0); +} + +/** + * @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_ip_del (hicn_face_id_t face_id); + +/** + * @brief Format a IP face + * + * @param s Pointer to a previous string. If null it will be initialize + * @param args Array storing input values. Expected u32 face_id and u32 indent + * @return String with the formatted face + */ +u8 *format_hicn_face_ip (u8 * s, va_list * args); + +/** + * @brief Create a dpo from an ip face + * + * @param face Face from which to create the dpo + * @return the dpo + */ +void hicn_face_ip_get_dpo (hicn_face_t * face, dpo_id_t * dpo); + +#endif // __HICN_FACE_IP_H__ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/hicn-plugin/src/faces/ip/face_ip_cli.c b/hicn-plugin/src/faces/ip/face_ip_cli.c new file mode 100755 index 000000000..1558c82cb --- /dev/null +++ b/hicn-plugin/src/faces/ip/face_ip_cli.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 <vnet/vnet.h> +#include <vnet/dpo/dpo.h> +#include <vlib/vlib.h> + +#include "face_ip.h" +#include "dpo_ip.h" +#include "../face.h" + +#define HICN_FACE_NONE 0 +#define HICN_FACE_DELETE 1 +#define HICN_FACE_ADD 2 + +static clib_error_t * +hicn_face_ip_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 local_addr; + ip46_address_t remote_addr; + hicn_face_id_t face_id = HICN_FACE_NULL; + int app_face = 0; + u32 cs_reserved = HICN_PARAM_FACE_DFT_CS_RESERVED; + int ret = HICN_ERROR_NONE; + int sw_if; + int face_op = HICN_FACE_NONE; + + ip46_address_reset (&local_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, "local %U remote %U intfc %U", + unformat_ip46_address, &local_addr, IP46_TYPE_ANY, + unformat_ip46_address, &remote_addr, IP46_TYPE_ANY, + 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 if (unformat (line_input, "app_face %d", &app_face)) + { + if (unformat (line_input, "cs_size %d", &cs_reserved)); + } + 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 ((remote_addr.as_u64[0] == (u64) 0) + && (remote_addr.as_u64[1] == (u64) 0)) + { + return clib_error_return (0, "next hop address not specified"); + } + + rv = hicn_face_ip_add (&local_addr, &remote_addr, 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_ip_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_ip_cli_set_command, static) = +{ + .path = "hicn face ip", + .short_help = "hicn face ip {add local <local_address> remote <remote_address> intfc <sw_if>} {app_face <0/1>} {cs_size <size_in_packets>} | {del id <face_id>}", + .function = hicn_face_ip_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/ip/face_ip_node.c b/hicn-plugin/src/faces/ip/face_ip_node.c new file mode 100755 index 000000000..6081e4737 --- /dev/null +++ b/hicn-plugin/src/faces/ip/face_ip_node.c @@ -0,0 +1,761 @@ +/* + * 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 <vnet/adj/adj.h> + +#include "face_ip.h" +#include "face_ip_node.h" +#include "dpo_ip.h" +#include "../../strategy_dpo_manager.h" +#include "../face.h" +#include "../../cache_policies/cs_lru.h" +#include "../../infra.h" +#include "../../hicn.h" + +/** + * @File + * + * Definition of the nodes for ip incomplete faces. + */ + +vlib_node_registration_t hicn_face_ip4_input_node; +vlib_node_registration_t hicn_face_ip4_output_node; +vlib_node_registration_t hicn_face_ip6_input_node; +vlib_node_registration_t hicn_face_ip6_output_node; + +#define ip_v4 4 +#define ip_v6 6 + +static char *hicn_face_ip4_input_error_strings[] = { +#define _(sym, string) string, + foreach_hicnfwd_error +#undef _ +}; + +static char *hicn_face_ip6_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_ip4_input_trace_t; + +typedef enum +{ + HICN_FACE_IP4_INPUT_NEXT_DATA, + HICN_FACE_IP4_INPUT_NEXT_MAPME, + HICN_FACE_IP4_INPUT_NEXT_ERROR_DROP, + HICN_FACE_IP4_INPUT_N_NEXT, +} hicn_face_ip4_input_next_t; + +/* Trace context struct */ +typedef struct +{ + u32 next_index; + u32 sw_if_index; + u8 pkt_type; +} hicn_face_ip6_input_trace_t; + +typedef enum +{ + HICN_FACE_IP6_INPUT_NEXT_DATA, + HICN_FACE_IP6_INPUT_NEXT_MAPME, + HICN_FACE_IP6_INPUT_NEXT_ERROR_DROP, + HICN_FACE_IP6_INPUT_N_NEXT, +} hicn_face_ip6_input_next_t; + +#define NEXT_MAPME_IP4 HICN_FACE_IP4_INPUT_NEXT_MAPME +#define NEXT_MAPME_IP6 HICN_FACE_IP6_INPUT_NEXT_MAPME +#define NEXT_DATA_IP4 HICN_FACE_IP4_INPUT_NEXT_DATA +#define NEXT_DATA_IP6 HICN_FACE_IP6_INPUT_NEXT_DATA + +#define NEXT_ERROR_DROP_IP4 HICN_FACE_IP4_INPUT_NEXT_ERROR_DROP +#define NEXT_ERROR_DROP_IP6 HICN_FACE_IP6_INPUT_NEXT_ERROR_DROP + +#define IP_HEADER_4 ip4_header_t +#define IP_HEADER_6 ip6_header_t + +#define LOCK_FROM_LOCAL_IP4 hicn_dpo_ip4_lock_from_local +#define LOCK_FROM_LOCAL_IP6 hicn_dpo_ip6_lock_from_local + +#define TRACE_INPUT_PKT_IP4 hicn_face_ip4_input_trace_t +#define TRACE_INPUT_PKT_IP6 hicn_face_ip6_input_trace_t + +/* + * NOTE: Both hicn_face_ip4_input_node_fn and hicn_face_ip6_input_node_fn + * present a similar codebase. Macro are hard to debug, although the + * followind code is pretty straighforward and most of the complexity is in + * functions that can be easily debug. + */ +#define face_input_x1(ipv) \ + do{ \ + vlib_buffer_t *b0; \ + u32 bi0; \ + u32 next0 = NEXT_ERROR_DROP_IP##ipv; \ + IP_HEADER_##ipv * ip_hdr = NULL; \ + hicn_buffer_t * hicnb0; \ + int ret; \ + /* Prefetch for next iteration. */ \ + if (n_left_from > 1) \ + { \ + vlib_buffer_t *b1; \ + b1 = vlib_get_buffer (vm, from[1]); \ + CLIB_PREFETCH (b1, 2*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); \ + hicnb0 = hicn_get_buffer(b0); \ + ip_hdr = (IP_HEADER_##ipv *) vlib_buffer_get_current(b0); \ + \ + u8 is_icmp = ip_hdr->protocol == IPPROTO_ICMPV##ipv; \ + \ + next0 = is_icmp*NEXT_MAPME_IP##ipv + \ + (1-is_icmp)*NEXT_DATA_IP##ipv; \ + \ + ret = LOCK_FROM_LOCAL_IP##ipv \ + (&(hicnb0->face_dpo_id), \ + &hicnb0->is_appface, \ + &(ip_hdr->dst_address), \ + vnet_buffer (b0)->sw_if_index[VLIB_RX]); \ + \ + if ( PREDICT_FALSE(ret != HICN_ERROR_NONE) ) \ + next0 = NEXT_ERROR_DROP_IP##ipv; \ + else \ + stats.pkts_data_count += 1; \ + \ + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && \ + (b0->flags & VLIB_BUFFER_IS_TRACED))) \ + { \ + TRACE_INPUT_PKT_IP##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 face_input_x2(ipv) \ + do{ \ + vlib_buffer_t *b0, *b1; \ + u32 bi0, bi1; \ + u32 next0 = NEXT_ERROR_DROP_IP##ipv; \ + u32 next1 = NEXT_ERROR_DROP_IP##ipv; \ + IP_HEADER_##ipv * ip_hdr0 = NULL; \ + IP_HEADER_##ipv * ip_hdr1 = NULL; \ + hicn_buffer_t * hicnb0; \ + hicn_buffer_t * hicnb1; \ + int ret0, ret1; \ + /* 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, 2*CLIB_CACHE_LINE_BYTES, STORE); \ + CLIB_PREFETCH (b3, 2*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); \ + hicnb0 = hicn_get_buffer(b0); \ + hicnb1 = hicn_get_buffer(b1); \ + ip_hdr0 = (IP_HEADER_##ipv *) vlib_buffer_get_current(b0); \ + ip_hdr1 = (IP_HEADER_##ipv *) vlib_buffer_get_current(b1); \ + \ + u8 is_icmp0 = ip_hdr0->protocol == IPPROTO_ICMPV##ipv; \ + u8 is_icmp1 = ip_hdr1->protocol == IPPROTO_ICMPV##ipv; \ + \ + next0 = is_icmp0*NEXT_MAPME_IP##ipv + \ + (1-is_icmp0)*NEXT_DATA_IP##ipv; \ + \ + next1 = is_icmp1*NEXT_MAPME_IP##ipv + \ + (1-is_icmp1)*NEXT_DATA_IP##ipv; \ + \ + \ + ret0 = LOCK_FROM_LOCAL_IP##ipv \ + (&(hicnb0->face_dpo_id), \ + &hicnb0->is_appface, \ + &(ip_hdr0->dst_address), \ + vnet_buffer (b0)->sw_if_index[VLIB_RX]); \ + \ + ret1 = LOCK_FROM_LOCAL_IP##ipv \ + (&(hicnb1->face_dpo_id), \ + &hicnb1->is_appface, \ + &(ip_hdr1->dst_address), \ + vnet_buffer (b1)->sw_if_index[VLIB_RX]); \ + \ + if ( PREDICT_FALSE(ret0 != HICN_ERROR_NONE) ) \ + next0 = NEXT_ERROR_DROP_IP##ipv; \ + else \ + stats.pkts_data_count += 1; \ + \ + if ( PREDICT_FALSE(ret1 != HICN_ERROR_NONE) ) \ + next1 = NEXT_ERROR_DROP_IP##ipv; \ + else \ + stats.pkts_data_count += 1; \ + \ + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && \ + (b0->flags & VLIB_BUFFER_IS_TRACED))) \ + { \ + TRACE_INPUT_PKT_IP##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_IP##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_face_ip4_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_ip4_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_ip4_input_trace_t *t = + va_arg (*args, hicn_face_ip4_input_trace_t *); + + s = format (s, "FACE_IP4_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_ip4_input_node) = +{ + .function = hicn_face_ip4_input_node_fn, + .name = "hicn-face-ip4-input", + .vector_size = sizeof(u32), + .format_trace = hicn_face_ip4_input_format_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN(hicn_face_ip4_input_error_strings), + .error_strings = hicn_face_ip4_input_error_strings, + .n_next_nodes = HICN_FACE_IP4_INPUT_N_NEXT, + /* edit / add dispositions here */ + .next_nodes = + { + [HICN_FACE_IP4_INPUT_NEXT_DATA] = "hicn-data-pcslookup", + [HICN_FACE_IP4_INPUT_NEXT_MAPME] = "hicn-mapme-ack", + [HICN_FACE_IP4_INPUT_NEXT_ERROR_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + +/** + * @brief IPv6 face input node function + * @see hicn_face_ip4_input_node_fn + */ +static uword +hicn_face_ip6_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_DATAS, stats.pkts_data_count); + + return (frame->n_vectors); +} + +/* packet trace format function */ +static u8 * +hicn_face_ip6_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_ip6_input_trace_t *t = + va_arg (*args, hicn_face_ip6_input_trace_t *); + + s = format (s, "FACE_IP6_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_ip6_input_node) = +{ + .function = hicn_face_ip6_input_node_fn, + .name = "hicn-face-ip6-input", + .vector_size = sizeof(u32), + .format_trace = hicn_face_ip6_input_format_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN(hicn_face_ip6_input_error_strings), + .error_strings = hicn_face_ip6_input_error_strings, + .n_next_nodes = HICN_FACE_IP6_INPUT_N_NEXT, + /* edit / add dispositions here */ + .next_nodes = + { + [HICN_FACE_IP6_INPUT_NEXT_DATA] = "hicn-data-pcslookup", + [HICN_FACE_IP6_INPUT_NEXT_MAPME] = "hicn-mapme-ack", + [HICN_FACE_IP6_INPUT_NEXT_ERROR_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + +/**** FACE OUTPUT *****/ + +static inline void +hicn_face_rewrite_interest (vlib_main_t * vm, vlib_buffer_t * b0, + const hicn_face_t * face, u32 * next) +{ + ip_adjacency_t *adj = adj_get (face->shared.adj); + + /* We assume the ip adjacency has already the MAC/link layer address */ + vnet_buffer (b0)->ip.adj_index[VLIB_TX] = face->shared.adj; + hicn_header_t *hicn = vlib_buffer_get_current (b0); + + hicn_face_ip_t *ip_face = (hicn_face_ip_t *) face->data; + + ip46_address_t temp_addr; + ip46_address_reset (&temp_addr); + hicn_type_t type = hicn_get_buffer (b0)->type; + hicn_ops_vft[type.l1]->rewrite_interest (type, &hicn->protocol, + &ip_face->local_addr, &temp_addr); + + /* We rewrite the dst address to send an arp/neighbour discovert request */ + if (PREDICT_FALSE + (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP + || adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN)) + hicn_ops_vft[type.l1]->rewrite_data (type, &hicn->protocol, + &ip_face->remote_addr, &temp_addr, + 0); + + *next = adj->lookup_next_index; +} + +static char *hicn_face_ip4_output_error_strings[] = { +#define _(sym, string) string, + foreach_hicnfwd_error +#undef _ +}; + +static char *hicn_face_ip6_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_ip4_output_trace_t; + +/* Trace context struct */ +typedef struct +{ + u32 next_index; + u32 sw_if_index; + u8 pkt_type; +} hicn_face_ip6_output_trace_t; + +#define TRACE_OUTPUT_PKT_IP4 hicn_face_ip4_output_trace_t +#define TRACE_OUTPUT_PKT_IP6 hicn_face_ip6_output_trace_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 , STORE); \ + } \ + /* 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_rewrite_interest \ + (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_IP##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 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 , STORE); \ + CLIB_PREFETCH (b3->data, CLIB_CACHE_LINE_BYTES , STORE); \ + } \ + /* 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)) \ + { \ + hicn_face_rewrite_interest \ + (vm, b0, face0, &next0); \ + stats.pkts_interest_count += 1; \ + } \ + \ + if (PREDICT_TRUE(face1 != NULL)) \ + { \ + hicn_face_rewrite_interest \ + (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_IP##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_IP##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_face_ip4_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_ip4_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_ip4_output_trace_t *t = + va_arg (*args, hicn_face_ip4_output_trace_t *); + + s = format (s, "FACE_IP4_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_face_ip4_output_node) = +{ + .function = hicn_face_ip4_output_node_fn, + .name = "hicn-face-ip4-output", + .vector_size = sizeof(u32), + .format_trace = hicn_face_ip4_output_format_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN(hicn_face_ip4_output_error_strings), + .error_strings = hicn_face_ip4_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* */ + + +static uword +hicn_face_ip6_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); + } + + /* Dual loop, X1 */ + 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_ip6_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_ip6_output_trace_t *t = + va_arg (*args, hicn_face_ip6_output_trace_t *); + + s = format (s, "FACE_IP6_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_face_ip6_output_node) = +{ + .function = hicn_face_ip6_output_node_fn, + .name = "hicn-face-ip6-output", + .vector_size = sizeof(u32), + .format_trace = hicn_face_ip6_output_format_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN(hicn_face_ip6_output_error_strings), + .error_strings = hicn_face_ip6_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* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/hicn-plugin/src/faces/ip/face_ip_node.h b/hicn-plugin/src/faces/ip/face_ip_node.h new file mode 100755 index 000000000..000395a04 --- /dev/null +++ b/hicn-plugin/src/faces/ip/face_ip_node.h @@ -0,0 +1,40 @@ +/* + * 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_IP_NODE_H__ +#define __HICN_FACE_IP_NODE_H__ + +#include <vlib/vlib.h> +#include <vnet/vnet.h> + +extern vlib_node_registration_t hicn_face_ip4_input_node; +extern vlib_node_registration_t hicn_face_ip4_output_node; +extern vlib_node_registration_t hicn_face_ip6_input_node; +extern vlib_node_registration_t hicn_face_ip6_output_node; + +/** + * @brief Initialize the ip face module + */ +void hicn_face_ip_init (vlib_main_t * vm); + +#endif // __HICN_FACE_IP_NODE_H__ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/hicn-plugin/src/faces/ip/iface_ip_node.c b/hicn-plugin/src/faces/ip/iface_ip_node.c new file mode 100755 index 000000000..8df0467f0 --- /dev/null +++ b/hicn-plugin/src/faces/ip/iface_ip_node.c @@ -0,0 +1,845 @@ +/* + * 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 <hicn/hicn.h> +#include "face_ip.h" +#include "dpo_ip.h" +#include "../../strategy_dpo_manager.h" +#include "../face.h" +#include "../../infra.h" +#include "../../cache_policies/cs_lru.h" + +/** + * @File + * + * Definition of the nodes for ip incomplete faces. + */ + +vlib_node_registration_t hicn_iface_ip4_input_node; +vlib_node_registration_t hicn_iface_ip4_output_node; +vlib_node_registration_t hicn_iface_ip6_input_node; +vlib_node_registration_t hicn_iface_ip6_output_node; + +u32 data_fwd_iface_ip4_vlib_edge; +u32 data_fwd_iface_ip6_vlib_edge; + +void +hicn_iface_ip_init (vlib_main_t * vm) +{ + u32 temp_index4 = vlib_node_add_next (vm, + hicn_interest_hitcs_node.index, + hicn_iface_ip4_output_node.index); + u32 temp_index6 = vlib_node_add_next (vm, + hicn_interest_hitcs_node.index, + hicn_iface_ip6_output_node.index); + + data_fwd_iface_ip4_vlib_edge = vlib_node_add_next (vm, + hicn_data_fwd_node.index, + hicn_iface_ip4_output_node. + index); + + data_fwd_iface_ip6_vlib_edge = vlib_node_add_next (vm, + hicn_data_fwd_node.index, + hicn_iface_ip6_output_node. + index); + + ASSERT (temp_index4 == data_fwd_iface_ip4_vlib_edge); + ASSERT (temp_index6 == data_fwd_iface_ip6_vlib_edge); +} + +static char *hicn_iface_ip4_input_error_strings[] = { +#define _(sym, string) string, + foreach_hicnfwd_error +#undef _ +}; + +static char *hicn_iface_ip6_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_iface_ip4_input_trace_t; + +typedef enum +{ + HICN_IFACE_IP4_INPUT_NEXT_INTEREST, + HICN_IFACE_IP4_INPUT_NEXT_MAPME, + HICN_IFACE_IP4_INPUT_NEXT_ERROR_DROP, + HICN_IFACE_IP4_INPUT_N_NEXT, +} hicn_iface_ip4_input_next_t; + +/* Trace context struct */ +typedef struct +{ + u32 next_index; + u32 sw_if_index; + u8 pkt_type; +} hicn_iface_ip6_input_trace_t; + +typedef enum +{ + HICN_IFACE_IP6_INPUT_NEXT_INTEREST, + HICN_IFACE_IP6_INPUT_NEXT_MAPME, + HICN_IFACE_IP6_INPUT_NEXT_ERROR_DROP, + HICN_IFACE_IP6_INPUT_N_NEXT, +} hicn_iface_ip6_input_next_t; + +#define NEXT_MAPME_IP4 HICN_IFACE_IP4_INPUT_NEXT_MAPME +#define NEXT_MAPME_IP6 HICN_IFACE_IP6_INPUT_NEXT_MAPME + +#define NEXT_INTEREST_IP4 HICN_IFACE_IP6_INPUT_NEXT_INTEREST +#define NEXT_INTEREST_IP6 HICN_IFACE_IP6_INPUT_NEXT_INTEREST + +#define ADDRESS_IP4 ip_interface_address_t *ia = 0;ip4_address_t *local_address = ip4_interface_first_address(&ip4_main, swif, &ia) +#define ADDRESS_IP6 ip6_address_t *local_address = ip6_interface_first_address(&ip6_main, swif) + +#define ADDRESSX2_IP4 ip_interface_address_t *ia0, *ia1; ia0 = ia1 = 0; \ + ip4_address_t *local_address0 = ip4_interface_first_address(&ip4_main, swif0, &ia0); \ + ip4_address_t *local_address1 = ip4_interface_first_address(&ip4_main, swif1, &ia1); + +#define ADDRESSX2_IP6 ip6_address_t *local_address0 = ip6_interface_first_address(&ip6_main, swif0); \ + ip6_address_t *local_address1 = ip6_interface_first_address(&ip6_main, swif1); + +#define DPO_ADD_LOCK_IP4 hicn_dpo_ip4_add_and_lock_from_remote +#define DPO_ADD_LOCK_IP6 hicn_dpo_ip6_add_and_lock_from_remote + +#define VLIB_EDGE_IP4 data_fwd_iface_ip4_vlib_edge +#define VLIB_EDGE_IP6 data_fwd_iface_ip6_vlib_edge + +#define IP_HEADER_4 ip4_header_t +#define IP_HEADER_6 ip6_header_t + +#define TRACE_INPUT_PKT_IP4 hicn_iface_ip4_input_trace_t +#define TRACE_INPUT_PKT_IP6 hicn_iface_ip6_input_trace_t + +#define iface_input_x1(ipv) \ + do { \ + vlib_buffer_t *b0; \ + u32 bi0, next0; \ + IP_HEADER_##ipv * ip_hdr = NULL; \ + hicn_buffer_t * hicnb0; \ + u32 swif; \ + /* Prefetch for next iteration. */ \ + if (n_left_from > 1) \ + { \ + vlib_buffer_t *b1; \ + b1 = vlib_get_buffer (vm, from[1]); \ + CLIB_PREFETCH (b1, 2*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); \ + hicnb0 = hicn_get_buffer(b0); \ + ip_hdr = (IP_HEADER_##ipv *) vlib_buffer_get_current(b0); \ + \ + stats.pkts_interest_count += 1; \ + \ + u8 is_icmp = ip_hdr->protocol == IPPROTO_ICMPV##ipv; \ + \ + next0 = is_icmp*NEXT_MAPME_IP##ipv + \ + (1-is_icmp)*NEXT_INTEREST_IP##ipv; \ + \ + swif = vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ + \ + ADDRESS_IP##ipv; \ + \ + DPO_ADD_LOCK_IP##ipv \ + (&(hicnb0->face_dpo_id), \ + &hicnb0->is_appface, \ + local_address, \ + &(ip_hdr->src_address), \ + vnet_buffer(b0)->sw_if_index[VLIB_RX], \ + VLIB_EDGE_IP##ipv); \ + \ + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && \ + (b0->flags & VLIB_BUFFER_IS_TRACED))) \ + { \ + TRACE_INPUT_PKT_IP##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, next0, next1; \ + IP_HEADER_##ipv * ip_hdr0 = NULL; \ + IP_HEADER_##ipv * ip_hdr1 = NULL; \ + hicn_buffer_t *hicnb0, *hicnb1; \ + u32 swif0, swif1; \ + \ + /* 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, 2*CLIB_CACHE_LINE_BYTES, STORE); \ + CLIB_PREFETCH (b3, 2*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); \ + hicnb0 = hicn_get_buffer(b0); \ + hicnb1 = hicn_get_buffer(b1); \ + ip_hdr0 = (IP_HEADER_##ipv *) vlib_buffer_get_current(b0); \ + ip_hdr1 = (IP_HEADER_##ipv *) vlib_buffer_get_current(b1); \ + \ + stats.pkts_interest_count += 2; \ + \ + u8 is_icmp0 = ip_hdr0->protocol == IPPROTO_ICMPV##ipv; \ + u8 is_icmp1 = ip_hdr1->protocol == IPPROTO_ICMPV##ipv; \ + \ + next0 = is_icmp0*NEXT_MAPME_IP##ipv + \ + (1-is_icmp0)*NEXT_INTEREST_IP##ipv; \ + \ + next1 = is_icmp1*NEXT_MAPME_IP##ipv + \ + (1-is_icmp1)*NEXT_INTEREST_IP##ipv; \ + \ + swif0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; \ + swif1 = vnet_buffer (b1)->sw_if_index[VLIB_RX]; \ + \ + ADDRESSX2_IP##ipv; \ + \ + DPO_ADD_LOCK_IP##ipv \ + (&(hicnb0->face_dpo_id), \ + &hicnb0->is_appface, \ + local_address0, \ + &(ip_hdr0->src_address), \ + vnet_buffer(b0)->sw_if_index[VLIB_RX], \ + VLIB_EDGE_IP##ipv); \ + \ + DPO_ADD_LOCK_IP##ipv \ + (&(hicnb1->face_dpo_id), \ + &hicnb1->is_appface, \ + local_address1, \ + &(ip_hdr1->src_address), \ + vnet_buffer(b1)->sw_if_index[VLIB_RX], \ + VLIB_EDGE_IP##ipv); \ + \ + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && \ + (b0->flags & VLIB_BUFFER_IS_TRACED))) \ + { \ + TRACE_INPUT_PKT_IP##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_IP##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_ip4_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) + { + 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_ip4_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_ip4_input_trace_t *t = + va_arg (*args, hicn_iface_ip4_input_trace_t *); + + s = format (s, "IFACE_IP4_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_ip4_input_node) = +{ + .function = hicn_iface_ip4_input_node_fn, + .name = "hicn-iface-ip4-input", + .vector_size = sizeof (u32), + .format_trace = hicn_iface_ip4_input_format_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (hicn_iface_ip4_input_error_strings), + .error_strings = hicn_iface_ip4_input_error_strings, + .n_next_nodes = HICN_IFACE_IP4_INPUT_N_NEXT, + /* edit / add dispositions*/ + .next_nodes = + { + [HICN_IFACE_IP4_INPUT_NEXT_INTEREST] = "hicn-interest-pcslookup", + [HICN_IFACE_IP4_INPUT_NEXT_MAPME] = "hicn-mapme-ctrl", + [HICN_IFACE_IP4_INPUT_NEXT_ERROR_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + +static uword +hicn_iface_ip6_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) + { + 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_ip6_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_ip6_input_trace_t *t = + va_arg (*args, hicn_iface_ip6_input_trace_t *); + + s = format (s, "IFACE_IP6_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_ip6_input_node) = +{ + .function = hicn_iface_ip6_input_node_fn, + .name = "hicn-iface-ip6-input", + .vector_size = sizeof (u32), + .format_trace = hicn_iface_ip6_input_format_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (hicn_iface_ip6_input_error_strings), + .error_strings = hicn_iface_ip6_input_error_strings, + .n_next_nodes = HICN_IFACE_IP6_INPUT_N_NEXT, + /* edit / add dispositions*/ + .next_nodes = + { + [HICN_IFACE_IP6_INPUT_NEXT_INTEREST] = "hicn-interest-pcslookup", + [HICN_IFACE_IP6_INPUT_NEXT_MAPME] = "hicn-mapme-ctrl", + [HICN_IFACE_IP6_INPUT_NEXT_ERROR_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + + +/**** IFACE OUTPUT *****/ + +static inline void +hicn_rewrite_iface_data4 (vlib_main_t * vm, vlib_buffer_t * b0, + const hicn_face_t * iface) +{ + ip4_header_t *ip0; + + /* Get the pointer to the old ip and tcp header */ + ip0 = vlib_buffer_get_current (b0); + + /* Set up the ip6 header */ + /* IP4 lenght contains the size of the ip4 header too */ + u16 sval = (vlib_buffer_length_in_chain (vm, b0)); + ip0->length = clib_host_to_net_u16 (sval); + ip0->ttl = 254; // FIXME TTL + + vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ~0; + hicn_header_t *hicn = vlib_buffer_get_current (b0); + + ip46_address_t temp_addr; + ip46_address_reset (&temp_addr); + hicn_face_ip_t *iface_ip = (hicn_face_ip_t *) iface->data; + hicn_type_t type = hicn_get_buffer (b0)->type; + hicn_ops_vft[type.l1]->rewrite_data (type, &hicn->protocol, + &(iface_ip->remote_addr), &(temp_addr), + iface->shared.pl_id); +} + +static inline void +hicn_rewrite_iface_data6 (vlib_main_t * vm, vlib_buffer_t * b0, + const hicn_face_t * iface) +{ + ip6_header_t *ip0; + + /* Get the pointer to the old ip and tcp header */ + /* Copy the previous ip and tcp header to the new portion of memory */ + ip0 = vlib_buffer_get_current (b0); + + /* Set up the ip6 header */ + /* IP6 lenght does not include the size of the ip6 header */ + u16 sval = (vlib_buffer_length_in_chain (vm, b0) - (sizeof (ip6_header_t))); + ip0->payload_length = clib_host_to_net_u16 (sval); + ip0->hop_limit = HICN_IP6_HOP_LIMIT; + + vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ~0; + hicn_header_t *hicn = vlib_buffer_get_current (b0); + + ip46_address_t temp_addr; + ip46_address_reset (&temp_addr); + hicn_face_ip_t *iface_ip = (hicn_face_ip_t *) iface->data; + hicn_type_t type = hicn_get_buffer (b0)->type; + hicn_ops_vft[type.l1]->rewrite_data (type, &hicn->protocol, + &(iface_ip->remote_addr), &(temp_addr), + iface->shared.pl_id); +} + +static char *hicn_iface_ip4_output_error_strings[] = { +#define _(sym, string) string, + foreach_hicnfwd_error +#undef _ +}; + +static char *hicn_iface_ip6_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_ip4_output_trace_t; + +typedef enum +{ + HICN_IFACE_IP4_OUTPUT_NEXT_LOOKUP, + HICN_IFACE_IP4_OUTPUT_NEXT_ERROR_DROP, + HICN_IFACE_IP4_OUTPUT_N_NEXT, +} hicn_iface_ip4_output_next_t; + +/* Trace context struct */ +typedef struct +{ + u32 next_index; + u32 sw_if_index; + u8 pkt_type; +} hicn_iface_ip6_output_trace_t; + +typedef enum +{ + HICN_IFACE_IP6_OUTPUT_NEXT_LOOKUP, + HICN_IFACE_IP6_OUTPUT_NEXT_ERROR_DROP, + HICN_IFACE_IP6_OUTPUT_N_NEXT, +} hicn_iface_ip6_output_next_t; + +#define ERROR_OUTPUT_IP4 HICN_IFACE_IP4_OUTPUT_NEXT_ERROR_DROP +#define ERROR_OUTPUT_IP6 HICN_IFACE_IP6_OUTPUT_NEXT_ERROR_DROP + +#define NEXT_DATA_LOOKUP_IP4 HICN_IFACE_IP4_OUTPUT_NEXT_LOOKUP +#define NEXT_DATA_LOOKUP_IP6 HICN_IFACE_IP6_OUTPUT_NEXT_LOOKUP + +#define HICN_REWRITE_DATA_IP4 hicn_rewrite_iface_data4 +#define HICN_REWRITE_DATA_IP6 hicn_rewrite_iface_data6 + +#define TRACE_OUTPUT_PKT_IP4 hicn_iface_ip4_output_trace_t +#define TRACE_OUTPUT_PKT_IP6 hicn_iface_ip6_output_trace_t + +#define iface_output_x1(ipv) \ + do { \ + vlib_buffer_t *b0; \ + u32 bi0; \ + u32 next0 = ERROR_OUTPUT_IP##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 , STORE); \ + } \ + /* 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_REWRITE_DATA_IP##ipv \ + (vm, b0, face); \ + next0 = NEXT_DATA_LOOKUP_IP##ipv; \ + stats.pkts_data_count += 1; \ + } \ + \ + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && \ + (b0->flags & VLIB_BUFFER_IS_TRACED))) \ + { \ + TRACE_OUTPUT_PKT_IP##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_IP##ipv; \ + u32 next1 = ERROR_OUTPUT_IP##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 , STORE); \ + CLIB_PREFETCH (b3->data, CLIB_CACHE_LINE_BYTES , STORE); \ + } \ + \ + /* 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)) \ + { \ + HICN_REWRITE_DATA_IP##ipv \ + (vm, b0, face0); \ + next0 = NEXT_DATA_LOOKUP_IP##ipv; \ + stats.pkts_data_count += 1; \ + } \ + \ + if (PREDICT_TRUE(face1 != NULL)) \ + { \ + HICN_REWRITE_DATA_IP##ipv \ + (vm, b1, face1); \ + next1 = NEXT_DATA_LOOKUP_IP##ipv; \ + stats.pkts_data_count += 1; \ + } \ + \ + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && \ + (b0->flags & VLIB_BUFFER_IS_TRACED))) \ + { \ + TRACE_OUTPUT_PKT_IP##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_IP##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_ip4_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_ip4_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_ip4_output_trace_t *t = + va_arg (*args, hicn_iface_ip4_output_trace_t *); + + s = format (s, "IFACE_IP4_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_ip4_output_node) = +{ + .function = hicn_iface_ip4_output_node_fn, + .name = "hicn-iface-ip4-output", + .vector_size = sizeof (u32), + .format_trace = hicn_iface_ip4_output_format_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (hicn_iface_ip4_output_error_strings), + .error_strings = hicn_iface_ip4_output_error_strings, + .n_next_nodes = HICN_IFACE_IP4_OUTPUT_N_NEXT, + /* edit / add dispositions here */ + .next_nodes = + { + [HICN_IFACE_IP4_OUTPUT_NEXT_LOOKUP] = "ip4-lookup", + [HICN_IFACE_IP4_OUTPUT_NEXT_ERROR_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + + +static uword +hicn_iface_ip6_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_ip6_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_ip6_output_trace_t *t = + va_arg (*args, hicn_iface_ip6_output_trace_t *); + + s = format (s, "IFACE_IP6_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_ip6_output_node) = +{ + .function = hicn_iface_ip6_output_node_fn, + .name = "hicn-iface-ip6-output", + .vector_size = sizeof (u32), + .format_trace = hicn_iface_ip6_output_format_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN (hicn_iface_ip6_output_error_strings), + .error_strings = hicn_iface_ip6_output_error_strings, + .n_next_nodes = HICN_IFACE_IP6_OUTPUT_N_NEXT, + /* edit / add dispositions here */ + .next_nodes = + { + [HICN_IFACE_IP6_OUTPUT_NEXT_LOOKUP] = "ip6-lookup", + [HICN_IFACE_IP6_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/ip/iface_ip_node.h b/hicn-plugin/src/faces/ip/iface_ip_node.h new file mode 100755 index 000000000..36923f069 --- /dev/null +++ b/hicn-plugin/src/faces/ip/iface_ip_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_IFACE_IP_NODE_H__ +#define __HICN_IFACE_IP_NODE_H__ + +#include <vlib/vlib.h> +#include <vnet/vnet.h> + +/** + * @brief Initialize the ip iface module + */ +void hicn_iface_ip_init (vlib_main_t * vm); + +#endif // __HICN_IFACE_IP_NODE_H__ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ |