diff options
Diffstat (limited to 'hicn-plugin/src/route.c')
-rwxr-xr-x | hicn-plugin/src/route.c | 392 |
1 files changed, 392 insertions, 0 deletions
diff --git a/hicn-plugin/src/route.c b/hicn-plugin/src/route.c new file mode 100755 index 000000000..9202efbd4 --- /dev/null +++ b/hicn-plugin/src/route.c @@ -0,0 +1,392 @@ +/* + * 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/fib/fib_entry.h> +#include <vnet/fib/fib_table.h> +#include <vnet/ip/ip6_packet.h> +#include <vnet/dpo/dpo.h> +#include <vnet/dpo/load_balance.h> +#include <vlib/global_funcs.h> + +#include "strategy_dpo_ctx.h" +#include "strategy_dpo_manager.h" +#include "strategy.h" +#include "faces/face.h" +#include "error.h" +#include "strategies/dpo_mw.h" + +int +hicn_route_get_dpo (const ip46_address_t * prefix, u8 plen, + const dpo_id_t ** hicn_dpo, u32 * fib_index) +{ + fib_prefix_t fib_pfx; + const dpo_id_t *load_balance_dpo_id; + const dpo_id_t *former_dpo_id; + int found = 0, ret = HICN_ERROR_ROUTE_NOT_FOUND; + fib_node_index_t fib_entry_index; + + /* At this point the face exists in the face table */ + fib_prefix_from_ip46_addr (prefix, &fib_pfx); + fib_pfx.fp_len = plen; + + + /* Check if the route already exist in the fib */ + /* + * ASSUMPTION: we use table 0 which is the default table and it is + * already existing and locked + */ + *fib_index = fib_table_find_or_create_and_lock (fib_pfx.fp_proto, + HICN_FIB_TABLE, + FIB_SOURCE_PLUGIN_HI); + fib_entry_index = fib_table_lookup_exact_match (*fib_index, &fib_pfx); + + if (fib_entry_index != FIB_NODE_INDEX_INVALID) + { + /* Route already existing. We need to update the dpo. */ + load_balance_dpo_id = + fib_entry_contribute_ip_forwarding (fib_entry_index); + + /* The dpo is not a load balance dpo as expected */ + if (load_balance_dpo_id->dpoi_type != DPO_LOAD_BALANCE) + ret = HICN_ERROR_ROUTE_NO_LD; + else + { + /* former_dpo_id is a load_balance dpo */ + load_balance_t *lb = + load_balance_get (load_balance_dpo_id->dpoi_index); + + /* FIB entry exists but there is no hicn dpo. */ + ret = HICN_ERROR_ROUTE_DPO_NO_HICN; + for (int i = 0; i < lb->lb_n_buckets && !found; i++) + { + former_dpo_id = load_balance_get_bucket_i (lb, i); + + if (dpo_is_hicn (former_dpo_id)) + { + *hicn_dpo = former_dpo_id; + ret = HICN_ERROR_NONE; + found = 1; + } + } + } + } + /* + * Remove the lock from the table. We keep one lock per route, not + * per dpo + */ + fib_table_unlock (*fib_index, fib_pfx.fp_proto, FIB_SOURCE_PLUGIN_HI); + + return ret; +} + +/* Add a new route for a name prefix */ +int +hicn_route_add (hicn_face_id_t * face_id, u32 len, + const ip46_address_t * prefix, u8 plen) +{ + + fib_prefix_t fib_pfx; + dpo_id_t dpo = DPO_INVALID; + const dpo_id_t *hicn_dpo_id; + int ret = HICN_ERROR_NONE; + dpo_id_t face_dpo_tmp[HICN_PARAM_FIB_ENTRY_NHOPS_MAX]; + int n_face_dpo = 0; + index_t dpo_idx; + u32 fib_index; + vlib_main_t *vm = vlib_get_main (); + hicn_face_vft_t *face_vft = NULL; + + if (face_id == NULL) + { + return HICN_ERROR_ROUTE_INVAL; + } + /* + * Check is the faces are available, otherwise skip the face + * id_adjacency existance is not checked. It should be checked before + * sending a packet out + */ + for (int i = 0; i < clib_min (HICN_PARAM_FIB_ENTRY_NHOPS_MAX, len); i++) + { + hicn_face_t *face = hicn_dpoi_get_from_idx (face_id[i]); + face_vft = hicn_face_get_vft (face->shared.face_type); + dpo_id_t face_dpo = DPO_INVALID; + face_vft->hicn_face_get_dpo (face, &face_dpo); + + if (!dpo_id_is_valid (&face_dpo)) + { + vlib_cli_output (vm, "Face %d not found, skip...\n", face_id[i]); + return ret; + } + else + { + face_dpo_tmp[n_face_dpo++] = face_dpo; + } + } + + ret = hicn_route_get_dpo (prefix, plen, &hicn_dpo_id, &fib_index); + + if (ret == HICN_ERROR_ROUTE_NOT_FOUND) + { + /* The Fib entry does not exist */ + /* At this point the face exists in the face table */ + fib_prefix_from_ip46_addr (prefix, &fib_pfx); + fib_pfx.fp_len = plen; + + dpo_id_t nhops[HICN_PARAM_FIB_ENTRY_NHOPS_MAX]; + for (int i = 0; i < n_face_dpo; i++) + { + clib_memcpy (&nhops[i], &face_dpo_tmp[i], sizeof (dpo_id_t)); + } + + ret = + default_dpo.hicn_dpo_create (fib_pfx.fp_proto, nhops, n_face_dpo, + &dpo_idx); + + if (ret) + { + return ret; + } + /* the value we got when we registered */ + /* + * This should be taken from the name?!? the index of the + * object + */ + dpo_set (&dpo, + default_dpo.hicn_dpo_get_type (), + (ip46_address_is_ip4 (prefix) ? DPO_PROTO_IP4 : DPO_PROTO_IP6), + dpo_idx); + + /* Here is where we create the "via" like route */ + /* + * For the moment we use the global one the prefix you want + * to match Neale suggested -- FIB_SOURCE_HICN the client + * that is adding them -- no easy explanation at this time… + */ + fib_node_index_t new_fib_node_index = + fib_table_entry_special_dpo_add (fib_index, + &fib_pfx, + FIB_SOURCE_PLUGIN_HI, + FIB_ENTRY_FLAG_EXCLUSIVE, + &dpo); + + /* We added a route, therefore add one lock to the table */ + fib_table_lock (fib_index, fib_pfx.fp_proto, FIB_SOURCE_PLUGIN_HI); + + dpo_unlock (&dpo); + ret = + (new_fib_node_index != + FIB_NODE_INDEX_INVALID) ? HICN_ERROR_NONE : + HICN_ERROR_ROUTE_NO_INSERT; + + /* + * TODO: we might want to store the fib index in the face. + * This will help to update the fib entries when a face is + * deleted. Fib_index_t is returned from + * fib_table_entry_special_dpo_add. + */ + } + else if (ret == HICN_ERROR_NONE) + { + ret = HICN_ERROR_ROUTE_ALREADY_EXISTS; + } + return ret; +} + +int +hicn_route_add_nhops (hicn_face_id_t * face_id, u32 len, + const ip46_address_t * prefix, u8 plen) +{ + const dpo_id_t *hicn_dpo_id; + int ret = HICN_ERROR_NONE; + dpo_id_t faces_dpo_tmp[HICN_PARAM_FIB_ENTRY_NHOPS_MAX]; + int n_face_dpo = 0; + const hicn_dpo_vft_t *dpo_vft; + u32 fib_index; + vlib_main_t *vm = vlib_get_main (); + hicn_face_vft_t *face_vft = NULL; + + if (face_id == NULL) + { + return HICN_ERROR_ROUTE_INVAL; + } + /* + * Check is the faces are available, otherwise skip the face + * id_adjacency existance is not checked. It should be checked before + * sending a packet out + */ + for (int i = 0; i < clib_min (HICN_PARAM_FIB_ENTRY_NHOPS_MAX, len); i++) + { + hicn_face_t *face = hicn_dpoi_get_from_idx (face_id[i]); + face_vft = hicn_face_get_vft (face->shared.face_type); + dpo_id_t face_dpo = DPO_INVALID; + face_vft->hicn_face_get_dpo (face, &face_dpo); + + if (!dpo_id_is_valid (&face_dpo)) + { + vlib_cli_output (vm, "Face %d not found, skip...\n", face_id[i]); + return ret; + } + else + { + faces_dpo_tmp[n_face_dpo++] = face_dpo; + } + } + + ret = hicn_route_get_dpo (prefix, plen, &hicn_dpo_id, &fib_index); + + if (ret == HICN_ERROR_NONE) + { + for (int i = 0; i < n_face_dpo && (ret == HICN_ERROR_NONE); i++) + { + u32 vft_id = hicn_dpo_get_vft_id (hicn_dpo_id); + dpo_vft = hicn_dpo_get_vft (vft_id); + ret = dpo_vft->hicn_dpo_add_update_nh (&faces_dpo_tmp[i], + hicn_dpo_id->dpoi_index); + } + } + return ret; +} + +int +hicn_route_del (ip46_address_t * prefix, u8 plen) +{ + fib_prefix_t fib_pfx; + const dpo_id_t *hicn_dpo_id; + int ret = HICN_ERROR_NONE; + u32 fib_index; + + /* At this point the face exists in the face table */ + fib_prefix_from_ip46_addr (prefix, &fib_pfx); + fib_pfx.fp_len = plen; + + /* Remove the fib entry only if the dpo is of type hicn */ + ret = hicn_route_get_dpo (prefix, plen, &hicn_dpo_id, &fib_index); + + if (ret == HICN_ERROR_NONE) + { + fib_table_entry_special_remove (HICN_FIB_TABLE, &fib_pfx, + FIB_SOURCE_PLUGIN_HI); + + /* + * Remove the lock from the table. We keep one lock per route + */ + fib_table_unlock (fib_index, fib_pfx.fp_proto, FIB_SOURCE_PLUGIN_HI); + } + //Remember to remove the lock from the table when removing the entry + return ret; +} + +int +hicn_route_del_nhop (ip46_address_t * prefix, u8 plen, hicn_face_id_t face_id) +{ + + fib_prefix_t fib_pfx; + const dpo_id_t *hicn_dpo_id; + int ret; + u32 vft_id; + const hicn_dpo_vft_t *dpo_vft; + u32 fib_index; + + /* At this point the face exists in the face table */ + fib_prefix_from_ip46_addr (prefix, &fib_pfx); + fib_pfx.fp_len = plen; + + ret = hicn_route_get_dpo (prefix, plen, &hicn_dpo_id, &fib_index); + + /* Check if the dpo is an hicn_dpo_t */ + if (ret == HICN_ERROR_NONE) + { + vft_id = hicn_dpo_get_vft_id (hicn_dpo_id); + dpo_vft = hicn_dpo_get_vft (vft_id); + return dpo_vft->hicn_dpo_del_nh (face_id, hicn_dpo_id->dpoi_index, + &fib_pfx); + } + //Remember to remove the lock from the table when removing the entry + return ret; +} + +int +hicn_route_set_strategy (ip46_address_t * prefix, u8 plen, u8 strategy_id) +{ + fib_prefix_t fib_pfx; + const dpo_id_t *hicn_dpo_id; + dpo_id_t new_dpo_id = DPO_INVALID; + int ret; + hicn_dpo_ctx_t *old_hicn_dpo_ctx; + const hicn_dpo_vft_t *old_dpo_vft; + const hicn_dpo_vft_t *new_dpo_vft; + index_t new_hicn_dpo_idx; + u32 fib_index; + u32 old_vft_id; + + /* At this point the face exists in the face table */ + fib_prefix_from_ip46_addr (prefix, &fib_pfx); + fib_pfx.fp_len = plen; + + ret = hicn_route_get_dpo (prefix, plen, &hicn_dpo_id, &fib_index); + + if (ret == HICN_ERROR_NONE) + { + old_vft_id = hicn_dpo_get_vft_id (hicn_dpo_id); + old_dpo_vft = hicn_dpo_get_vft (old_vft_id); + old_hicn_dpo_ctx = + old_dpo_vft->hicn_dpo_get_ctx (hicn_dpo_id->dpoi_index); + + new_dpo_vft = hicn_dpo_get_vft_from_id (strategy_id); + + if (new_dpo_vft == NULL) + return HICN_ERROR_STRATEGY_NOT_FOUND; + + /* Create a new dpo for the new strategy */ + new_dpo_vft->hicn_dpo_create (hicn_dpo_id->dpoi_proto, + old_hicn_dpo_ctx->next_hops, + old_hicn_dpo_ctx->entry_count, + &new_hicn_dpo_idx); + + /* the value we got when we registered */ + dpo_set (&new_dpo_id, + new_dpo_vft->hicn_dpo_get_type (), + (ip46_address_is_ip4 (prefix) ? DPO_PROTO_IP4 : + DPO_PROTO_IP6), new_hicn_dpo_idx); + + /* Here is where we create the "via" like route */ + /* + * For the moment we use the global one the prefix you want + * to match Neale suggested -- FIB_SOURCE_HICN the client + * that is adding them -- no easy explanation at this time… + */ + fib_node_index_t new_fib_node_index = + fib_table_entry_special_dpo_update (fib_index, + &fib_pfx, + FIB_SOURCE_PLUGIN_HI, + FIB_ENTRY_FLAG_EXCLUSIVE, + &new_dpo_id); + + dpo_unlock (&new_dpo_id); + ret = + (new_fib_node_index != + FIB_NODE_INDEX_INVALID) ? HICN_ERROR_NONE : + HICN_ERROR_ROUTE_NOT_UPDATED; + } + //Remember to remove the lock from the table when removing the entry + return ret; + +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: eval: (c-set-style "gnu") End: + */ |