diff options
Diffstat (limited to 'hicn-plugin/src/route.c')
-rw-r--r-- | hicn-plugin/src/route.c | 782 |
1 files changed, 572 insertions, 210 deletions
diff --git a/hicn-plugin/src/route.c b/hicn-plugin/src/route.c index c208dd4c1..6db52f2fd 100644 --- a/hicn-plugin/src/route.c +++ b/hicn-plugin/src/route.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Copyright (c) 2017-2020 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: @@ -15,9 +15,14 @@ #include <vnet/fib/fib_entry.h> #include <vnet/fib/fib_table.h> +#include <vnet/fib/fib_entry_track.h> #include <vnet/ip/ip6_packet.h> +#include <vnet/ip/ip.h> #include <vnet/dpo/dpo.h> +#include <vnet/dpo/drop_dpo.h> #include <vnet/dpo/load_balance.h> +#include <vnet/udp/udp.h> +#include <vnet/udp/udp_encap.h> #include <vlib/global_funcs.h> #include "strategy_dpo_ctx.h" @@ -26,11 +31,18 @@ #include "faces/face.h" #include "error.h" #include "strategies/dpo_mw.h" +#include "infra.h" +#include "udp_tunnels/udp_tunnel.h" #define FIB_SOURCE_HICN 0x04 //Right after the FIB_SOURCE_INTERFACE priority fib_source_t hicn_fib_src; +fib_node_type_t hicn_fib_node_type; + +ip4_address_t localhost4 = {0}; +ip6_address_t localhost6 = {0}; + int hicn_route_get_dpo (const fib_prefix_t * prefix, const dpo_id_t ** hicn_dpo, u32 * fib_index) @@ -91,134 +103,326 @@ hicn_route_get_dpo (const fib_prefix_t * prefix, } int -hicn_route_add_nhops (hicn_face_id_t * face_id, u32 len, - const fib_prefix_t * prefix) +hicn_route_set_strategy (fib_prefix_t * prefix, u8 strategy_id) { 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; + dpo_id_t new_dpo_id = DPO_INVALID; + int ret; + hicn_dpo_ctx_t *old_hicn_dpo_ctx; + const hicn_dpo_vft_t *new_dpo_vft; + index_t new_hicn_dpo_idx; u32 fib_index; - vlib_main_t *vm = vlib_get_main (); - hicn_face_vft_t *face_vft = NULL; - if (face_id == NULL) + ret = hicn_route_get_dpo (prefix, &hicn_dpo_id, &fib_index); + + if (ret == HICN_ERROR_NONE) { - return HICN_ERROR_ROUTE_INVAL; + old_hicn_dpo_ctx = hicn_strategy_dpo_ctx_get (hicn_dpo_id->dpoi_index); + + new_dpo_vft = hicn_dpo_get_vft_from_id (strategy_id); + + if (new_dpo_vft == NULL || old_hicn_dpo_ctx == 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->fp_addr) ? 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, + prefix, + hicn_fib_src, + 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; } - /* - * 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++) + //Remember to remove the lock from the table when removing the entry + return ret; + +} + +int +ip_nh_add_helper (fib_protocol_t fib_proto, const fib_prefix_t * rpfx, ip46_address_t * nh, u32 sw_if) +{ + fib_route_path_t *rpaths = NULL, rpath; + + u32 fib_index = fib_table_find(fib_proto, 0); + + clib_memset(&rpath, 0, sizeof(rpath)); + rpath.frp_weight = 1; + rpath.frp_sw_if_index = sw_if; + rpath.frp_addr = *nh; + rpath.frp_proto = ip46_address_is_ip4(nh) ? DPO_PROTO_IP4 : DPO_PROTO_IP6; + + vec_add1(rpaths, rpath); + + fib_table_entry_path_add2 (fib_index, + rpfx, + FIB_SOURCE_CLI, + FIB_ENTRY_FLAG_NONE, rpaths); + return 0; +} + +int +ip_nh_del_helper (fib_protocol_t fib_proto, const fib_prefix_t * rpfx, ip46_address_t * nh, u32 sw_if) +{ + fib_route_path_t *rpaths = NULL, rpath; + + u32 fib_index = fib_table_find(fib_proto, 0); + + clib_memset(&rpath, 0, sizeof(rpath)); + rpath.frp_weight = 1; + rpath.frp_sw_if_index = sw_if; + rpath.frp_addr = *nh; + rpath.frp_proto = ip46_address_is_ip4(nh) ? DPO_PROTO_IP4 : DPO_PROTO_IP6; + + vec_add1(rpaths, rpath); + + fib_table_entry_path_remove2 (fib_index, + rpfx, + FIB_SOURCE_CLI, + rpaths); + return 0; +} + + +static ip46_address_t * get_address(ip46_address_t * nh, u32 sw_if, fib_protocol_t proto) +{ + ip46_address_t * local_address = calloc(1, sizeof(ip46_address_t)); + + if (proto == FIB_PROTOCOL_IP4) { - 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); + ip_interface_address_t *interface_address; + ip4_address_t *addr = + ip4_interface_address_matching_destination (&ip4_main, + &nh->ip4, + sw_if, + &interface_address); + + if (addr == NULL) + addr = ip4_interface_first_address (&ip4_main, + sw_if, + &interface_address); + if (addr != NULL) + ip46_address_set_ip4 (local_address, addr); + } + else if (proto == FIB_PROTOCOL_IP6) + { + ip_interface_address_t *interface_address; + ip6_interface_address_matching_destination (&ip6_main, + &nh->ip6, + sw_if, + &interface_address); + + ip6_address_t *addr = NULL; + if (interface_address != NULL) + addr = + (ip6_address_t *) + ip_interface_address_get_address (&ip6_main.lookup_main, + interface_address); + + if (addr == NULL) + addr = ip6_interface_first_address (&ip6_main, sw_if); + + if (addr != NULL) + ip46_address_set_ip6 (local_address, addr); + } - if (!dpo_id_is_valid (&face_dpo)) - { - vlib_cli_output (vm, "Face %d not found, skip...\n", face_id[i]); - return ret; - } + return local_address; +} + +static void +sync_hicn_fib_entry(hicn_dpo_ctx_t *fib_entry) +{ + const dpo_id_t * dpo_loadbalance = fib_entry_contribute_ip_forwarding (fib_entry->fib_entry_index); + const load_balance_t *lb0 = load_balance_get(dpo_loadbalance->dpoi_index); + index_t hicn_fib_entry_index = hicn_strategy_dpo_ctx_get_index(fib_entry); + hicn_face_id_t * vec_faces = 0; + + dpo_id_t temp = DPO_INVALID; + const dpo_id_t *former_dpo = &temp; + int index = 0; + +#define ADD_FACE(nh) \ + do { \ + /* Careful, this adds a lock on the face if it exists */ \ + hicn_face_add(dpo, nh, sw_if, &face_id, 0); \ + vec_validate(vec_faces, index); \ + vec_faces[index] = face_id; \ + (index)++; \ + \ + /* Face creation can realloc load_balance_t? Seem the fib_tracking does so. */ \ + dpo_loadbalance = fib_entry_contribute_ip_forwarding (fib_entry->fib_entry_index); \ + lb0 = load_balance_get(dpo_loadbalance->dpoi_index); \ + } while (0) \ + + for (int j = 0; j < lb0->lb_n_buckets; j++) { + const dpo_id_t * dpo = load_balance_get_bucket_i(lb0,j); + + int dpo_comparison = dpo_cmp(former_dpo, dpo); + former_dpo = dpo; + /* + * Loadbalancing in ip replicate the dpo in multiple buckets + * in order to honor the assigned weights. + */ + if (dpo_comparison == 0) + continue; + + u32 sw_if = ~0; + ip46_address_t * nh = NULL; + hicn_face_id_t face_id = HICN_FACE_NULL; + + if (dpo_is_adj(dpo)) + { + ip_adjacency_t * adj = adj_get (dpo->dpoi_index); + sw_if = adj->rewrite_header.sw_if_index; + nh = get_address (&(adj->sub_type.nbr.next_hop), sw_if, fib_entry->proto); + ADD_FACE(nh); + } + else if (dpo->dpoi_type == dpo_type_udp_ip4 || dpo->dpoi_type == dpo_type_udp_ip6) + { + u8 proto = dpo->dpoi_type == dpo_type_udp_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6; + ip46_address_t _nh = {0}; + nh = &_nh; + switch (dpo->dpoi_proto) + { + case FIB_PROTOCOL_IP6: + case FIB_PROTOCOL_IP4: + /** + * Independently of the type of tunnel, encapsulated packet + * can be either v6 or v4, so we need to create 2 faces for each + * version. Tunneled hicn packet MUST have locator set to the loopback + * address, so ::1 for IPv6 and 127.0.0.1 for IPv4. + */ + ip46_address_set_ip6(nh, &localhost6); + ADD_FACE(nh); + ip46_address_set_ip4(nh, &localhost4); + ADD_FACE(nh); + break; + default: + continue; + } + udp_tunnel_add_existing (dpo->dpoi_index, proto); + } + } + + const hicn_dpo_vft_t * strategy_vft = hicn_dpo_get_vft(fib_entry->dpo_type); + int i = 0; + while (i < fib_entry->entry_count) + { + u32 idx_nh = vec_search(vec_faces, fib_entry->next_hops[i]); + if (idx_nh == ~0) + { + strategy_vft->hicn_dpo_del_nh(fib_entry->next_hops[i], hicn_fib_entry_index); + } else - { - faces_dpo_tmp[n_face_dpo++] = face_dpo; - } - } + { + vec_del1(vec_faces, idx_nh); - ret = hicn_route_get_dpo (prefix, &hicn_dpo_id, &fib_index); + /* Remove the lock added by hicn_face_add */ + hicn_face_unlock_with_id (fib_entry->next_hops[i]); + i++; + } + } - if (ret == HICN_ERROR_NONE) + hicn_face_id_t *face_id; + vec_foreach(face_id, vec_faces) { - 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); - - hicn_face_t *face = - hicn_dpoi_get_from_idx (faces_dpo_tmp[i].dpoi_index); - //Disable feature on the interface - if (prefix->fp_proto == FIB_PROTOCOL_IP4) - vnet_feature_enable_disable ("ip4-local", "hicn-data-input-ip4", - face->shared.sw_if, 1, 0, 0); - else if (prefix->fp_proto == FIB_PROTOCOL_IP6) - vnet_feature_enable_disable ("ip6-local", "hicn-data-input-ip6", - face->shared.sw_if, 1, 0, 0); - - ret = dpo_vft->hicn_dpo_add_update_nh (&faces_dpo_tmp[i], - hicn_dpo_id->dpoi_index); - } + strategy_vft->hicn_dpo_add_update_nh(*face_id, hicn_fib_entry_index); + + /* Remove the lock added by hicn_face_add */ + hicn_face_unlock_with_id (*face_id); + } - return ret; + vec_free(vec_faces); } -/* Add a new route for a name prefix */ -int -hicn_route_add (hicn_face_id_t * face_id, u32 len, - const fib_prefix_t * prefix) +static void +enable_disable_data_receiving (fib_protocol_t proto, u32 sw_if, u8 is_enable) { - 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 (proto == FIB_PROTOCOL_IP4 && sw_if != ~0) + vnet_feature_enable_disable ("ip4-local", "hicn-data-input-ip4", + sw_if, is_enable, 0, 0); + else if (proto == FIB_PROTOCOL_IP6 && sw_if != ~0) + vnet_feature_enable_disable ("ip6-local", "hicn-data-input-ip6", + sw_if, is_enable, 0, 0); - if (face_id == NULL || !hicn_dpoi_idx_is_valid (*face_id)) - { - return HICN_ERROR_ROUTE_INVAL; +} + +walk_rc_t enable_data_receiving_new_fib_entry (vnet_main_t * vnm, + vnet_sw_interface_t * si, + void *ctx) +{ + fib_protocol_t *proto = (fib_protocol_t *) ctx; + enable_disable_data_receiving(*proto, si->sw_if_index, 1); + + return (WALK_CONTINUE); +} + +walk_rc_t disable_data_receiving_rm_fib_entry (vnet_main_t * vnm, + vnet_sw_interface_t * si, + void *ctx) +{ + fib_protocol_t *proto = (fib_protocol_t *) ctx; + enable_disable_data_receiving(*proto, si->sw_if_index, 0); + + return (WALK_CONTINUE); } + +int +hicn_route_enable (fib_prefix_t *prefix) { + + int ret = HICN_ERROR_NONE; + fib_node_index_t fib_entry_index; + + /* Check if the route already exist in the fib */ /* - * 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 + * ASSUMPTION: we use table 0 which is the default table and it is + * already existing and locked */ - for (int i = 0; i < clib_min (HICN_PARAM_FIB_ENTRY_NHOPS_MAX, len); i++) + u32 fib_index = fib_table_find(prefix->fp_proto, 0); + + fib_entry_index = fib_table_lookup_exact_match (fib_index, prefix); + + if (fib_entry_index == FIB_NODE_INDEX_INVALID) { - 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); + fib_entry_index = fib_table_lookup (fib_index, prefix); - 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; - } + fib_route_path_t * paths = fib_entry_encode(fib_entry_index); + + fib_table_entry_path_add2(fib_index, prefix, FIB_SOURCE_CLI, FIB_ENTRY_FLAG_NONE, paths); } - ret = hicn_route_get_dpo (prefix, &hicn_dpo_id, &fib_index); + /* Check if the prefix is already enabled */ + u32 fib_hicn_index = fib_table_find(prefix->fp_proto, HICN_FIB_TABLE); - if (ret == HICN_ERROR_ROUTE_NOT_FOUND) - { - 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)); - hicn_face_t *face = - hicn_dpoi_get_from_idx (face_dpo_tmp[i].dpoi_index); - //Disable feature on the interface - if (prefix->fp_proto == FIB_PROTOCOL_IP4) - vnet_feature_enable_disable ("ip4-local", "hicn-data-input-ip4", - face->shared.sw_if, 1, 0, 0); - else if (prefix->fp_proto == FIB_PROTOCOL_IP6) - vnet_feature_enable_disable ("ip6-local", "hicn-data-input-ip6", - face->shared.sw_if, 1, 0, 0); - } + fib_node_index_t fib_hicn_entry_index = fib_table_lookup_exact_match (fib_hicn_index, prefix); - default_dpo.hicn_dpo_create (prefix->fp_proto, nhops, n_face_dpo, - &dpo_idx); + if (fib_hicn_entry_index == FIB_NODE_INDEX_INVALID) + { + dpo_id_t dpo = DPO_INVALID; + index_t dpo_idx; + default_dpo.hicn_dpo_create (prefix->fp_proto, 0, NEXT_HOP_INVALID, + &dpo_idx); /* the value we got when we registered */ /* @@ -226,9 +430,20 @@ hicn_route_add (hicn_face_id_t * face_id, u32 len, * object */ dpo_set (&dpo, - default_dpo.hicn_dpo_get_type (), - (ip46_address_is_ip4 (&prefix->fp_addr) ? DPO_PROTO_IP4 : - DPO_PROTO_IP6), dpo_idx); + default_dpo.hicn_dpo_get_type (), + (ip46_address_is_ip4 (&prefix->fp_addr) ? DPO_PROTO_IP4 : + DPO_PROTO_IP6), dpo_idx); + + hicn_dpo_ctx_t * fib_entry = hicn_strategy_dpo_ctx_get(dpo_idx); + + fib_node_init (&fib_entry->fib_node, hicn_fib_node_type); + fib_node_lock (&fib_entry->fib_node); + + fib_entry->fib_entry_index = fib_entry_track (fib_index, + prefix, + hicn_fib_node_type, + dpo_idx, &fib_entry->fib_sibling); + /* Here is where we create the "via" like route */ /* @@ -236,163 +451,310 @@ hicn_route_add (hicn_face_id_t * face_id, u32 len, * 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, - prefix, - hicn_fib_src, - (FIB_ENTRY_FLAG_EXCLUSIVE | - FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT), - &dpo); + CLIB_UNUSED (fib_node_index_t new_fib_node_index) = + fib_table_entry_special_dpo_add (fib_hicn_index, + prefix, + hicn_fib_src, + (FIB_ENTRY_FLAG_EXCLUSIVE | + FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT), + &dpo); + + sync_hicn_fib_entry(fib_entry); /* We added a route, therefore add one lock to the table */ fib_table_lock (fib_index, prefix->fp_proto, hicn_fib_src); - 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. + /* Enable the feature to punt data packet every time we enable a new hicn route + * For each enable there must be a disable to defenitely disable the feature + * + * We cannot enable only the interfaces on which we send out interest because + * Data packet might be coming on in different interfaces, as in che case of mpls + * tunnels (packets are received from the physical nic, not the mpls tunnel interface). */ + vnet_main_t * vnm = vnet_get_main (); + vnet_sw_interface_walk(vnm, enable_data_receiving_new_fib_entry, &(prefix->fp_proto)); + + dpo_unlock (&dpo); } - else if (ret == HICN_ERROR_NONE) + else { - ret = hicn_route_add_nhops (face_id, len, prefix); + const dpo_id_t *load_balance_dpo_id; + const dpo_id_t *strategy_dpo_id; + + /* Route already existing. We need to update the dpo. */ + load_balance_dpo_id = + fib_entry_contribute_ip_forwarding (fib_hicn_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; + goto done; + } + else + { + load_balance_t *lb = + load_balance_get (load_balance_dpo_id->dpoi_index); + + strategy_dpo_id = load_balance_get_bucket_i (lb, 0); + + if (!dpo_is_hicn (strategy_dpo_id)) + { + ret = HICN_ERROR_ROUTE_DPO_NO_HICN; + goto done; + } + + if (lb->lb_n_buckets > 1) + { + ret = HICN_ERROR_ROUTE_MLT_LD; + goto done; + } + + hicn_dpo_ctx_t * hicn_fib_entry = hicn_strategy_dpo_ctx_get(strategy_dpo_id->dpoi_index); + + sync_hicn_fib_entry(hicn_fib_entry); + } } + + done: return ret; } int -hicn_route_del (fib_prefix_t * prefix) -{ - const dpo_id_t *hicn_dpo_id; +hicn_route_disable (fib_prefix_t *prefix) { + int ret = HICN_ERROR_NONE; - u32 fib_index; - /* Remove the fib entry only if the dpo is of type hicn */ - ret = hicn_route_get_dpo (prefix, &hicn_dpo_id, &fib_index); + /* Check if the prefix is already enabled */ + u32 fib_hicn_index = fib_table_find(prefix->fp_proto, HICN_FIB_TABLE); - if (ret == HICN_ERROR_NONE) + fib_node_index_t fib_hicn_entry_index = fib_table_lookup_exact_match (fib_hicn_index, prefix); + + if (fib_hicn_entry_index == FIB_NODE_INDEX_INVALID) + { + return HICN_ERROR_ROUTE_NOT_FOUND; + } + else { - fib_table_entry_special_remove (HICN_FIB_TABLE, prefix, hicn_fib_src); + const dpo_id_t *load_balance_dpo_id; + const dpo_id_t *strategy_dpo_id; + hicn_dpo_ctx_t * hicn_fib_entry; - /* - * Remove the lock from the table. We keep one lock per route - */ - fib_table_unlock (fib_index, prefix->fp_proto, hicn_fib_src); + /* Route already existing. We need to update the dpo. */ + load_balance_dpo_id = + fib_entry_contribute_ip_forwarding (fib_hicn_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; + goto done; + } + else + { + load_balance_t *lb = + load_balance_get (load_balance_dpo_id->dpoi_index); + + strategy_dpo_id = load_balance_get_bucket_i (lb, 0); + + if (!dpo_is_hicn (strategy_dpo_id)) + { + ret = HICN_ERROR_ROUTE_DPO_NO_HICN; + goto done; + } + + if (lb->lb_n_buckets > 1) + { + ret = HICN_ERROR_ROUTE_MLT_LD; + goto done; + } + + hicn_fib_entry = hicn_strategy_dpo_ctx_get(strategy_dpo_id->dpoi_index); + + for (int i = 0; i < hicn_fib_entry->entry_count; i++) + { + hicn_strategy_dpo_ctx_del_nh(hicn_fib_entry->next_hops[i], hicn_fib_entry); + } + } + + fib_entry_untrack(hicn_fib_entry->fib_entry_index, hicn_fib_entry->fib_sibling); + + fib_table_entry_special_remove (fib_hicn_index, prefix, hicn_fib_src); + + /* Disable the feature to punt data packet every time we enable a new hicn route */ + vnet_main_t * vnm = vnet_get_main (); + vnet_sw_interface_walk(vnm, disable_data_receiving_rm_fib_entry, &(prefix->fp_proto)); } - //Remember to remove the lock from the table when removing the entry + + done: return ret; } -int -hicn_route_del_nhop (fib_prefix_t * prefix, hicn_face_id_t face_id) + +static fib_node_t * +hicn_ctx_node_get (fib_node_index_t index) { - const dpo_id_t *hicn_dpo_id; - int ret; - u32 vft_id; - const hicn_dpo_vft_t *dpo_vft; - u32 fib_index; + hicn_dpo_ctx_t * hicn_ctx; + hicn_ctx = hicn_strategy_dpo_ctx_get(index); - ret = hicn_route_get_dpo (prefix, &hicn_dpo_id, &fib_index); + return (&hicn_ctx->fib_node); +} - /* 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); +static void +hicn_fib_last_lock_gone (fib_node_t *node) +{ +} - hicn_face_t *face = hicn_dpoi_get_from_idx (face_id); - //Disable feature on the interface - if (prefix->fp_proto == FIB_PROTOCOL_IP4) - vnet_feature_enable_disable ("ip4-local", "hicn-data-input-ip4", - face->shared.sw_if, 0, 0, 0); - else if (prefix->fp_proto == FIB_PROTOCOL_IP6) - vnet_feature_enable_disable ("ip6-local", "hicn-data-input-ip6", - face->shared.sw_if, 0, 0, 0); +static hicn_dpo_ctx_t * +hicn_ctx_from_fib_node (fib_node_t * node) +{ + return ((hicn_dpo_ctx_t *) (((char *) node) - + STRUCT_OFFSET_OF (hicn_dpo_ctx_t, fib_node))); +} - ret = dpo_vft->hicn_dpo_del_nh (face_id, hicn_dpo_id->dpoi_index); +static fib_node_back_walk_rc_t +hicn_fib_back_walk_notify (fib_node_t *node, + fib_node_back_walk_ctx_t *ctx) +{ - hicn_dpo_ctx_t *dpo_ctx = - hicn_strategy_dpo_ctx_get (hicn_dpo_id->dpoi_index); + hicn_dpo_ctx_t *fib_entry = hicn_ctx_from_fib_node (node); + sync_hicn_fib_entry(fib_entry); - if (ret == HICN_ERROR_NONE && !dpo_ctx->entry_count) - ret = hicn_route_del (prefix); - } - //Remember to remove the lock from the table when removing the entry - return ret; + return (FIB_NODE_BACK_WALK_CONTINUE); } -int -hicn_route_set_strategy (fib_prefix_t * prefix, u8 strategy_id) +static void +hicn_fib_show_memory (void) { - 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 *new_dpo_vft; - index_t new_hicn_dpo_idx; - u32 fib_index; +} - ret = hicn_route_get_dpo (prefix, &hicn_dpo_id, &fib_index); - if (ret == HICN_ERROR_NONE) +static const fib_node_vft_t hicn_fib_vft = +{ + .fnv_get = hicn_ctx_node_get, + .fnv_last_lock = hicn_fib_last_lock_gone, + .fnv_back_walk = hicn_fib_back_walk_notify, + .fnv_mem_show = hicn_fib_show_memory, +}; + +fib_table_walk_rc_t enable_data_on_existing_hicn(fib_node_index_t fei, + void *ctx) +{ + u32 sw_if = *(u32 *)ctx; + const dpo_id_t *load_balance_dpo_id; + const dpo_id_t *strategy_dpo_id; + + /* Route already existing. We need to update the dpo. */ + load_balance_dpo_id = + fib_entry_contribute_ip_forwarding (fei); + + /* The dpo is not a load balance dpo as expected */ + if (load_balance_dpo_id->dpoi_type != DPO_LOAD_BALANCE) { - old_hicn_dpo_ctx = hicn_strategy_dpo_ctx_get (hicn_dpo_id->dpoi_index); + goto done; + } + else + { + load_balance_t *lb = + load_balance_get (load_balance_dpo_id->dpoi_index); - new_dpo_vft = hicn_dpo_get_vft_from_id (strategy_id); + strategy_dpo_id = load_balance_get_bucket_i (lb, 0); - if (new_dpo_vft == NULL || old_hicn_dpo_ctx == NULL) - return HICN_ERROR_STRATEGY_NOT_FOUND; + if (!dpo_is_hicn (strategy_dpo_id)) + { + goto done; + } - /* 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); + enable_disable_data_receiving (strategy_dpo_id->dpoi_proto, sw_if, 1); + } - /* the value we got when we registered */ - dpo_set (&new_dpo_id, - new_dpo_vft->hicn_dpo_get_type (), - (ip46_address_is_ip4 (&prefix->fp_addr) ? DPO_PROTO_IP4 : - DPO_PROTO_IP6), new_hicn_dpo_idx); + done: + return (FIB_TABLE_WALK_CONTINUE); +} - /* Here is where we create the "via" like route */ +static clib_error_t * +set_table_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add) +{ + + if (!is_add) + return HICN_ERROR_NONE; + + int rv = ip_table_bind (FIB_PROTOCOL_IP4, sw_if_index, HICN_FIB_TABLE, 1); + + if (!rv) + { + rv = ip_table_bind (FIB_PROTOCOL_IP6, sw_if_index, HICN_FIB_TABLE, 1); + + if (rv) + { + /* An error occurred. Bind the interface back to the default fib */ + ip_table_bind (FIB_PROTOCOL_IP4, sw_if_index, 0, 1); + } + } + + u32 fib_index = fib_table_find(FIB_PROTOCOL_IP4, + HICN_FIB_TABLE); + if (fib_index != ~0) + { /* - * 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… + * Walk the ip4 and ip6 fib tables to discover existing hicn fib entries. + * For each of them we need to enable the feature to punt data packets. */ - fib_node_index_t new_fib_node_index = - fib_table_entry_special_dpo_update (fib_index, - prefix, - hicn_fib_src, - FIB_ENTRY_FLAG_EXCLUSIVE, - &new_dpo_id); + fib_table_walk(fib_index, + FIB_PROTOCOL_IP4, + enable_data_on_existing_hicn, + &sw_if_index); + } - dpo_unlock (&new_dpo_id); - ret = - (new_fib_node_index != - FIB_NODE_INDEX_INVALID) ? HICN_ERROR_NONE : - HICN_ERROR_ROUTE_NOT_UPDATED; + fib_index = fib_table_find(FIB_PROTOCOL_IP6, + HICN_FIB_TABLE); + if (fib_index != ~0) + { + fib_table_walk(fib_index, + FIB_PROTOCOL_IP6, + enable_data_on_existing_hicn, + &sw_if_index); } - //Remember to remove the lock from the table when removing the entry - return ret; + return rv ? clib_error_return (0, "unable to add hicn table to interface") : 0; } +VNET_SW_INTERFACE_ADD_DEL_FUNCTION (set_table_interface_add_del); + void hicn_route_init () { + vnet_main_t * vnm = vnet_get_main (); + vlib_main_t * vm = vlib_get_main (); hicn_fib_src = fib_source_allocate ("hicn", FIB_SOURCE_HICN, FIB_SOURCE_BH_API); + + hicn_fib_node_type = fib_node_register_new_type(&hicn_fib_vft); + + ip_table_create(FIB_PROTOCOL_IP4, HICN_FIB_TABLE, 1, (const u8 *)"hicn4"); + ip_table_create(FIB_PROTOCOL_IP6, HICN_FIB_TABLE, 1, (const u8 *)"hicn6"); + + u32 sw_if_index; + u8 mac_address[6]; + u8 is_specified = 0; + u32 user_instance = 0; + + vnet_create_loopback_interface (&sw_if_index, mac_address, + is_specified, user_instance); + + localhost4.as_u8[0] = 127; + localhost4.as_u8[3] = 1; + u32 length4 = 32, length6 = 128, is_del = 0, flags = 0; + + localhost6.as_u8[15] = 1; + + ip4_add_del_interface_address (vm, sw_if_index, &localhost4, length4, is_del); + ip6_add_del_interface_address (vm, sw_if_index, &localhost6, length6, is_del); + + flags |= VNET_SW_INTERFACE_FLAG_ADMIN_UP; + vnet_sw_interface_set_flags (vnm, sw_if_index, flags); } /* |