diff options
author | Neale Ranns <nranns@cisco.com> | 2016-08-25 15:29:12 +0100 |
---|---|---|
committer | Damjan Marion <dmarion.lists@gmail.com> | 2016-09-21 17:37:39 +0000 |
commit | 0bfe5d8c792abcdbcf27bfcc7b7b353fba04aee2 (patch) | |
tree | d600b0e2e693e766e722936744930d3bebac493c /vnet/vnet/lisp-gpe/lisp_gpe.c | |
parent | 60537f3d83e83d0ce10a620ca99aad4eddf85f5e (diff) |
A Protocol Independent Hierarchical FIB (VPP-352)
Main Enhancements:
- Protocol Independent FIB API
- Hierarchical FIB entries. Dynamic recursive route resolution.
- Extranet Support.
- Integration of IP and MPLS forwarding.
- Separation of FIB and Adjacency databases.
- Data-Plane Object forwarding model.
Change-Id: I52dc815c0d0aa8b493e3cf6b978568f3cc82296c
Signed-off-by: Neale Ranns <nranns@cisco.com>
Diffstat (limited to 'vnet/vnet/lisp-gpe/lisp_gpe.c')
-rw-r--r-- | vnet/vnet/lisp-gpe/lisp_gpe.c | 855 |
1 files changed, 300 insertions, 555 deletions
diff --git a/vnet/vnet/lisp-gpe/lisp_gpe.c b/vnet/vnet/lisp-gpe/lisp_gpe.c index 579422b4..f05c6a20 100644 --- a/vnet/vnet/lisp-gpe/lisp_gpe.c +++ b/vnet/vnet/lisp-gpe/lisp_gpe.c @@ -19,435 +19,230 @@ */ #include <vnet/lisp-gpe/lisp_gpe.h> -#include <vppinfra/math.h> +#include <vnet/lisp-gpe/lisp_gpe_adjacency.h> +#include <vnet/adj/adj_midchain.h> +#include <vnet/fib/fib_table.h> +#include <vnet/fib/fib_entry.h> +#include <vnet/fib/fib_path_list.h> +#include <vnet/dpo/drop_dpo.h> +#include <vnet/dpo/load_balance.h> /** LISP-GPE global state */ lisp_gpe_main_t lisp_gpe_main; /** - * @brief Compute IP-UDP-GPE sub-tunnel encap/rewrite header. - * - * @param[in] t Parent of the sub-tunnel. - * @param[in] st Sub-tunnel. - * @param[in] lp Local and remote locators used in the encap header. - * - * @return 0 on success. + * @brief A Pool of all LISP forwarding entries */ -static int -lisp_gpe_rewrite (lisp_gpe_tunnel_t * t, lisp_gpe_sub_tunnel_t * st, - locator_pair_t * lp) -{ - u8 *rw = 0; - lisp_gpe_header_t *lisp0; - int len; - - if (ip_addr_version (&lp->lcl_loc) == IP4) - { - ip4_header_t *ip0; - ip4_udp_lisp_gpe_header_t *h0; - len = sizeof (*h0); +static lisp_fwd_entry_t *lisp_fwd_entry_pool; - vec_validate_aligned (rw, len - 1, CLIB_CACHE_LINE_BYTES); +/** + * DB of all forwarding entries. The Key is:{l-EID,r-EID,vni} + * where the EID encodes L2 or L3 + */ +static uword *lisp_gpe_fwd_entries; - h0 = (ip4_udp_lisp_gpe_header_t *) rw; +static void +create_fib_entries (lisp_fwd_entry_t * lfe) +{ + dpo_proto_t dproto; - /* Fixed portion of the (outer) ip4 header */ - ip0 = &h0->ip4; - ip0->ip_version_and_header_length = 0x45; - ip0->ttl = 254; - ip0->protocol = IP_PROTOCOL_UDP; + dproto = (ip_prefix_version (&lfe->key->rmt.ippref) == IP4 ? + FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6); - /* we fix up the ip4 header length and checksum after-the-fact */ - ip_address_copy_addr (&ip0->src_address, &lp->lcl_loc); - ip_address_copy_addr (&ip0->dst_address, &lp->rmt_loc); - ip0->checksum = ip4_header_checksum (ip0); + lfe->src_fib_index = ip_dst_fib_add_route (lfe->eid_fib_index, + &lfe->key->rmt.ippref); - /* UDP header, randomize src port on something, maybe? */ - h0->udp.src_port = clib_host_to_net_u16 (4341); - h0->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_lisp_gpe); + if (LISP_FWD_ENTRY_TYPE_NEGATIVE == lfe->type) + { + dpo_id_t dpo = DPO_NULL; - /* LISP-gpe header */ - lisp0 = &h0->lisp; + switch (lfe->action) + { + case LISP_NO_ACTION: + /* TODO update timers? */ + case LISP_FORWARD_NATIVE: + /* TODO check if route/next-hop for eid exists in fib and add + * more specific for the eid with the next-hop found */ + case LISP_SEND_MAP_REQUEST: + /* insert tunnel that always sends map-request */ + dpo_set (&dpo, DPO_LISP_CP, 0, dproto); + break; + case LISP_DROP: + /* for drop fwd entries, just add route, no need to add encap tunnel */ + dpo_copy (&dpo, drop_dpo_get (dproto)); + break; + } + ip_src_fib_add_route_w_dpo (lfe->src_fib_index, + &lfe->key->lcl.ippref, &dpo); + dpo_reset (&dpo); } else { - ip6_header_t *ip0; - ip6_udp_lisp_gpe_header_t *h0; - len = sizeof (*h0); - - vec_validate_aligned (rw, len - 1, CLIB_CACHE_LINE_BYTES); - - h0 = (ip6_udp_lisp_gpe_header_t *) rw; - - /* Fixed portion of the (outer) ip6 header */ - ip0 = &h0->ip6; - ip0->ip_version_traffic_class_and_flow_label = - clib_host_to_net_u32 (0x6 << 28); - ip0->hop_limit = 254; - ip0->protocol = IP_PROTOCOL_UDP; - - /* we fix up the ip6 header length after-the-fact */ - ip_address_copy_addr (&ip0->src_address, &lp->lcl_loc); - ip_address_copy_addr (&ip0->dst_address, &lp->rmt_loc); - - /* UDP header, randomize src port on something, maybe? */ - h0->udp.src_port = clib_host_to_net_u16 (4341); - h0->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_lisp_gpe); - - /* LISP-gpe header */ - lisp0 = &h0->lisp; + ip_src_fib_add_route (lfe->src_fib_index, + &lfe->key->lcl.ippref, lfe->paths); } - - lisp0->flags = t->flags; - lisp0->ver_res = t->ver_res; - lisp0->res = t->res; - lisp0->next_protocol = t->next_protocol; - lisp0->iid = clib_host_to_net_u32 (t->vni); - - st->is_ip4 = ip_addr_version (&lp->lcl_loc) == IP4; - st->rewrite = rw; - return 0; } -static int -weight_cmp (normalized_sub_tunnel_weights_t * a, - normalized_sub_tunnel_weights_t * b) +static void +delete_fib_entries (lisp_fwd_entry_t * lfe) { - int cmp = a->weight - b->weight; - return (cmp == 0 - ? a->sub_tunnel_index - b->sub_tunnel_index : (cmp > 0 ? -1 : 1)); + ip_src_dst_fib_del_route (lfe->src_fib_index, + &lfe->key->lcl.ippref, + lfe->eid_fib_index, &lfe->key->rmt.ippref); } -/** - * @brief Computes sub-tunnel load balancing vector. - * - * Algorithm is identical to that used for building unequal-cost multipath - * adjacencies. Saves normalized sub-tunnel weights and builds load-balancing - * vector consisting of list of sub-tunnel indexes replicated according to - * weight. - * - * @param[in] t Tunnel for which load balancing vector is computed. - */ static void -compute_sub_tunnels_balancing_vector (lisp_gpe_tunnel_t * t) +gid_to_dp_address (gid_address_t * g, dp_address_t * d) { - uword n_sts, i, n_nsts, n_nsts_left; - f64 sum_weight, norm, error, tolerance; - normalized_sub_tunnel_weights_t *nsts = 0, *stp; - lisp_gpe_sub_tunnel_t *sts = t->sub_tunnels; - u32 *st_lbv = 0; - - /* Accept 1% error */ - tolerance = .01; - - n_sts = vec_len (sts); - vec_validate (nsts, 2 * n_sts - 1); - - sum_weight = 0; - for (i = 0; i < n_sts; i++) + switch (gid_address_type (g)) { - /* Find total weight to normalize weights. */ - sum_weight += sts[i].weight; - - /* build normalized sub tunnels vector */ - nsts[i].weight = sts[i].weight; - nsts[i].sub_tunnel_index = i; - } - - n_nsts = n_sts; - if (n_sts == 1) - { - nsts[0].weight = 1; - _vec_len (nsts) = 1; - goto build_lbv; + case GID_ADDR_IP_PREFIX: + case GID_ADDR_SRC_DST: + ip_prefix_copy (&d->ippref, &gid_address_ippref (g)); + d->type = FID_ADDR_IP_PREF; + break; + case GID_ADDR_MAC: + default: + mac_copy (&d->mac, &gid_address_mac (g)); + d->type = FID_ADDR_MAC; + break; } +} - /* Sort sub-tunnels by weight */ - qsort (nsts, n_nsts, sizeof (u32), (void *) weight_cmp); +static lisp_fwd_entry_t * +find_fwd_entry (lisp_gpe_main_t * lgm, + vnet_lisp_gpe_add_del_fwd_entry_args_t * a, + lisp_gpe_fwd_entry_key_t * key) +{ + uword *p; - /* Save copies of all next hop weights to avoid being overwritten in loop below. */ - for (i = 0; i < n_nsts; i++) - nsts[n_nsts + i].weight = nsts[i].weight; + memset (key, 0, sizeof (*key)); - /* Try larger and larger power of 2 sized blocks until we - find one where traffic flows to within 1% of specified weights. */ - for (n_nsts = max_pow2 (n_sts);; n_nsts *= 2) + if (GID_ADDR_IP_PREFIX == gid_address_type (&a->rmt_eid)) { - error = 0; - - norm = n_nsts / sum_weight; - n_nsts_left = n_nsts; - for (i = 0; i < n_sts; i++) - { - f64 nf = nsts[n_sts + i].weight * norm; - word n = flt_round_nearest (nf); - - n = n > n_nsts_left ? n_nsts_left : n; - n_nsts_left -= n; - error += fabs (nf - n); - nsts[i].weight = n; - } - - nsts[0].weight += n_nsts_left; - - /* Less than 5% average error per adjacency with this size adjacency block? */ - if (error <= tolerance * n_nsts) - { - /* Truncate any next hops with zero weight. */ - _vec_len (nsts) = i; - break; - } + /* + * the ip version of the source is not set to ip6 when the + * source is all zeros. force it. + */ + ip_prefix_version (&gid_address_ippref (&a->lcl_eid)) = + ip_prefix_version (&gid_address_ippref (&a->rmt_eid)); } -build_lbv: + gid_to_dp_address (&a->rmt_eid, &key->rmt); + gid_to_dp_address (&a->lcl_eid, &key->lcl); + key->vni = a->vni; - /* build load balancing vector */ - vec_foreach (stp, nsts) - { - for (i = 0; i < stp[0].weight; i++) - vec_add1 (st_lbv, stp[0].sub_tunnel_index); - } + p = hash_get_mem (lisp_gpe_fwd_entries, key); - t->sub_tunnels_lbv = st_lbv; - t->sub_tunnels_lbv_count = n_nsts; - t->norm_sub_tunnel_weights = nsts; + if (NULL != p) + { + return (pool_elt_at_index (lisp_fwd_entry_pool, p[0])); + } + return (NULL); } -/** Create sub-tunnels and load-balancing vector for all locator pairs - * associated to a tunnel.*/ -static void -create_sub_tunnels (lisp_gpe_main_t * lgm, lisp_gpe_tunnel_t * t) +static int +lisp_gpe_fwd_entry_path_sort (void *a1, void *a2) { - lisp_gpe_sub_tunnel_t st; - locator_pair_t *lp = 0; - int i; - - /* create sub-tunnels for all locator pairs */ - for (i = 0; i < vec_len (t->locator_pairs); i++) - { - lp = &t->locator_pairs[i]; - st.locator_pair_index = i; - st.parent_index = t - lgm->tunnels; - st.weight = lp->weight; - - /* compute rewrite for sub-tunnel */ - lisp_gpe_rewrite (t, &st, lp); - vec_add1 (t->sub_tunnels, st); - } + lisp_fwd_path_t *p1 = a1, *p2 = a2; - /* normalize weights and compute sub-tunnel load balancing vector */ - compute_sub_tunnels_balancing_vector (t); + return (p1->priority - p2->priority); } -#define foreach_copy_field \ -_(encap_fib_index) \ -_(decap_fib_index) \ -_(decap_next_index) \ -_(vni) \ -_(action) - /** - * @brief Create/delete IP encapsulated tunnel. + * @brief Add/Delete LISP IP forwarding entry. * - * Builds GPE tunnel for L2 or L3 packets and populates tunnel pool - * @ref lisp_gpe_tunnel_by_key in @ref lisp_gpe_main_t. + * creation of forwarding entries for IP LISP overlay: * - * @param[in] a Tunnel parameters. - * @param[in] is_l2 Flag indicating if encapsulated content is l2. - * @param[out] tun_index_res Tunnel index. + * @param[in] lgm Reference to @ref lisp_gpe_main_t. + * @param[in] a Parameters for building the forwarding entry. * * @return 0 on success. */ static int -add_del_ip_tunnel (vnet_lisp_gpe_add_del_fwd_entry_args_t * a, u8 is_l2, - u32 * tun_index_res) +add_ip_fwd_entry (lisp_gpe_main_t * lgm, + vnet_lisp_gpe_add_del_fwd_entry_args_t * a) { - lisp_gpe_main_t *lgm = &lisp_gpe_main; - lisp_gpe_tunnel_t *t = 0; - lisp_gpe_tunnel_key_t key; - lisp_gpe_sub_tunnel_t *stp = 0; - uword *p; - - /* prepare tunnel key */ - memset (&key, 0, sizeof (key)); - - /* fill in the key's remote eid */ - if (!is_l2) - ip_prefix_copy (&key.rmt.ippref, &gid_address_ippref (&a->rmt_eid)); - else - mac_copy (&key.rmt.mac, &gid_address_mac (&a->rmt_eid)); - - key.vni = clib_host_to_net_u32 (a->vni); - - p = mhash_get (&lgm->lisp_gpe_tunnel_by_key, &key); - - if (a->is_add) - { - /* adding a tunnel: tunnel must not already exist */ - if (p) - return VNET_API_ERROR_INVALID_VALUE; - - if (a->decap_next_index >= LISP_GPE_INPUT_N_NEXT) - return VNET_API_ERROR_INVALID_DECAP_NEXT; + lisp_gpe_fwd_entry_key_t key; + lisp_fwd_entry_t *lfe; + fib_protocol_t fproto; - pool_get_aligned (lgm->tunnels, t, CLIB_CACHE_LINE_BYTES); - memset (t, 0, sizeof (*t)); + lfe = find_fwd_entry (lgm, a, &key); - /* copy from arg structure */ -#define _(x) t->x = a->x; - foreach_copy_field; -#undef _ + if (NULL != lfe) + /* don't support updates */ + return VNET_API_ERROR_INVALID_VALUE; - t->locator_pairs = vec_dup (a->locator_pairs); + pool_get (lisp_fwd_entry_pool, lfe); + memset (lfe, 0, sizeof (*lfe)); + lfe->key = clib_mem_alloc (sizeof (key)); + memcpy (lfe->key, &key, sizeof (key)); - /* if vni is non-default */ - if (a->vni) - t->flags = LISP_GPE_FLAGS_I; + hash_set_mem (lisp_gpe_fwd_entries, lfe->key, lfe - lisp_fwd_entry_pool); - /* work in lisp-gpe not legacy mode */ - t->flags |= LISP_GPE_FLAGS_P; + fproto = (IP4 == ip_prefix_version (&fid_addr_ippref (&lfe->key->rmt)) ? + FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6); - /* next proto */ - if (!is_l2) - t->next_protocol = ip_prefix_version (&key.rmt.ippref) == IP4 ? - LISP_GPE_NEXT_PROTO_IP4 : LISP_GPE_NEXT_PROTO_IP6; - else - t->next_protocol = LISP_GPE_NEXT_PROTO_ETHERNET; - - /* build sub-tunnels for lowest priority locator-pairs */ - if (!a->is_negative) - create_sub_tunnels (lgm, t); - - mhash_set (&lgm->lisp_gpe_tunnel_by_key, &key, t - lgm->tunnels, 0); + lfe->type = (a->is_negative ? + LISP_FWD_ENTRY_TYPE_NEGATIVE : LISP_FWD_ENTRY_TYPE_NORMAL); + lfe->eid_table_id = a->table_id; + lfe->eid_fib_index = fib_table_find_or_create_and_lock (fproto, + lfe->eid_table_id); - /* return tunnel index */ - if (tun_index_res) - tun_index_res[0] = t - lgm->tunnels; - } - else + if (LISP_FWD_ENTRY_TYPE_NEGATIVE != lfe->type) { - /* deleting a tunnel: tunnel must exist */ - if (!p) - { - clib_warning ("Tunnel for eid %U doesn't exist!", - format_gid_address, &a->rmt_eid); - return VNET_API_ERROR_NO_SUCH_ENTRY; - } - - t = pool_elt_at_index (lgm->tunnels, p[0]); + lisp_fwd_path_t *path; + u32 index; - mhash_unset (&lgm->lisp_gpe_tunnel_by_key, &key, 0); + vec_validate (lfe->paths, vec_len (a->locator_pairs) - 1); - vec_foreach (stp, t->sub_tunnels) + vec_foreach_index (index, a->locator_pairs) { - vec_free (stp->rewrite); + path = &lfe->paths[index]; + + path->priority = a->locator_pairs[index].priority; + path->weight = a->locator_pairs[index].weight; + + path->lisp_adj = + lisp_gpe_adjacency_find_or_create_and_lock (&a->locator_pairs + [index], + lfe->eid_table_id, + lfe->key->vni); } - vec_free (t->sub_tunnels); - vec_free (t->sub_tunnels_lbv); - vec_free (t->locator_pairs); - pool_put (lgm->tunnels, t); + vec_sort_with_function (lfe->paths, lisp_gpe_fwd_entry_path_sort); } - return 0; + create_fib_entries (lfe); + + return (0); } -/** - * @brief Build IP adjacency for LISP Source/Dest FIB. - * - * Because LISP forwarding does not follow typical IP forwarding path, the - * adjacency's fields are overloaded (i.e., hijacked) to carry LISP specific - * data concerning the lisp-gpe interface the packets hitting the adjacency - * should be sent to and the tunnel that should be used. - * - * @param[in] lgm Reference to @ref lisp_gpe_main_t. - * @param[out] adj Adjacency to be populated. - * @param[in] table_id VRF for adjacency. - * @param[in] vni Virtual Network identifier (tenant id). - * @param[in] tun_index Tunnel index. - * @param[in] n_sub_tun Number of sub-tunnels. - * @param[in] is_negative Flag to indicate if the adjacency is for a - * negative mapping. - * @param[in] action Action to be taken for negative mapping. - * @param[in] ip_ver IP version for the adjacency. - * - * @return 0 on success. - */ -static int -build_ip_adjacency (lisp_gpe_main_t * lgm, ip_adjacency_t * adj, u32 table_id, - u32 vni, u32 tun_index, u32 n_sub_tun, u8 is_negative, - u8 action, u8 ip_ver) +static void +del_ip_fwd_entry_i (lisp_fwd_entry_t * lfe) { - uword *lookup_next_index, *lgpe_sw_if_index, *lnip; + lisp_fwd_path_t *path; + fib_protocol_t fproto; - memset (adj, 0, sizeof (adj[0])); - adj->n_adj = 1; - /* fill in lookup_next_index with a 'legal' value to avoid problems */ - adj->lookup_next_index = (ip_ver == IP4) ? - lgm->ip4_lookup_next_lgpe_ip4_lookup : - lgm->ip6_lookup_next_lgpe_ip6_lookup; + vec_foreach (path, lfe->paths) + { + lisp_gpe_adjacency_unlock (path->lisp_adj); + } - /* positive mapping */ - if (!is_negative) - { - /* send packets that hit this adj to lisp-gpe interface output node in - * requested vrf. */ - lnip = (ip_ver == IP4) ? - lgm->lgpe_ip4_lookup_next_index_by_table_id : - lgm->lgpe_ip6_lookup_next_index_by_table_id; - lookup_next_index = hash_get (lnip, table_id); - lgpe_sw_if_index = hash_get (lgm->l3_ifaces.sw_if_index_by_vni, vni); - - /* the assumption is that the interface must've been created before - * programming the dp */ - ASSERT (lookup_next_index != 0 && lgpe_sw_if_index != 0); - - /* hijack explicit fib index to store lisp interface node index, - * if_address_index for the tunnel index and saved lookup next index - * for the number of sub tunnels */ - adj->explicit_fib_index = lookup_next_index[0]; - adj->if_address_index = tun_index; - adj->rewrite_header.sw_if_index = lgpe_sw_if_index[0]; - adj->saved_lookup_next_index = n_sub_tun; - } - /* negative mapping */ - else - { - adj->rewrite_header.sw_if_index = ~0; - adj->rewrite_header.next_index = ~0; - adj->if_address_index = tun_index; + delete_fib_entries (lfe); - switch (action) - { - case LISP_NO_ACTION: - /* TODO update timers? */ - case LISP_FORWARD_NATIVE: - /* TODO check if route/next-hop for eid exists in fib and add - * more specific for the eid with the next-hop found */ - case LISP_SEND_MAP_REQUEST: - /* insert tunnel that always sends map-request */ - adj->explicit_fib_index = (ip_ver == IP4) ? - LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP : - LGPE_IP6_LOOKUP_NEXT_LISP_CP_LOOKUP; - break; - case LISP_DROP: - /* for drop fwd entries, just add route, no need to add encap tunnel */ - adj->explicit_fib_index = (ip_ver == IP4 ? - LGPE_IP4_LOOKUP_NEXT_DROP : - LGPE_IP6_LOOKUP_NEXT_DROP); - break; - default: - return -1; - } - } - return 0; + fproto = (IP4 == ip_prefix_version (&fid_addr_ippref (&lfe->key->rmt)) ? + FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6); + fib_table_unlock (lfe->eid_fib_index, fproto); + + hash_unset_mem (lisp_gpe_fwd_entries, lfe->key); + clib_mem_free (lfe->key); + pool_put (lisp_fwd_entry_pool, lfe); } /** * @brief Add/Delete LISP IP forwarding entry. * - * Coordinates the creation/removal of forwarding entries for IP LISP overlay: - * creates lisp-gpe tunnel, builds tunnel customized forwarding entry and - * injects new route in Source/Dest FIB. + * removal of forwarding entries for IP LISP overlay: * * @param[in] lgm Reference to @ref lisp_gpe_main_t. * @param[in] a Parameters for building the forwarding entry. @@ -455,63 +250,21 @@ build_ip_adjacency (lisp_gpe_main_t * lgm, ip_adjacency_t * adj, u32 table_id, * @return 0 on success. */ static int -add_del_ip_fwd_entry (lisp_gpe_main_t * lgm, - vnet_lisp_gpe_add_del_fwd_entry_args_t * a) +del_ip_fwd_entry (lisp_gpe_main_t * lgm, + vnet_lisp_gpe_add_del_fwd_entry_args_t * a) { - ip_adjacency_t adj, *adjp; - lisp_gpe_tunnel_t *t; - u32 rv, tun_index = ~0, n_sub_tuns = 0; - ip_prefix_t *rmt_pref, *lcl_pref; - u8 ip_ver; - - rmt_pref = &gid_address_ippref (&a->rmt_eid); - lcl_pref = &gid_address_ippref (&a->lcl_eid); - ip_ver = ip_prefix_version (rmt_pref); - - /* add/del tunnel to tunnels pool and prepares rewrite */ - if (0 != a->locator_pairs) - { - rv = add_del_ip_tunnel (a, 0 /* is_l2 */ , &tun_index); - if (rv) - { - clib_warning ("failed to build tunnel!"); - return rv; - } - if (a->is_add) - { - t = pool_elt_at_index (lgm->tunnels, tun_index); - n_sub_tuns = t->sub_tunnels_lbv_count; - } - } - - /* setup adjacency for eid */ - rv = build_ip_adjacency (lgm, &adj, a->table_id, a->vni, tun_index, - n_sub_tuns, a->is_negative, a->action, ip_ver); - - /* add/delete route for eid */ - rv |= ip_sd_fib_add_del_route (lgm, rmt_pref, lcl_pref, a->table_id, &adj, - a->is_add); - - if (rv) - { - clib_warning ("failed to insert route for tunnel!"); - return rv; - } + lisp_gpe_fwd_entry_key_t key; + lisp_fwd_entry_t *lfe; - /* check that everything worked */ - if (CLIB_DEBUG && a->is_add) - { - u32 adj_index; - adj_index = ip_sd_fib_get_route (lgm, rmt_pref, lcl_pref, a->table_id); - ASSERT (adj_index != 0); + lfe = find_fwd_entry (lgm, a, &key); - adjp = ip_get_adjacency ((ip_ver == IP4) ? lgm->lm4 : lgm->lm6, - adj_index); + if (NULL == lfe) + /* no such entry */ + return VNET_API_ERROR_INVALID_VALUE; - ASSERT (adjp != 0 && adjp->if_address_index == tun_index); - } + del_ip_fwd_entry_i (lfe); - return rv; + return (0); } static void @@ -536,7 +289,7 @@ make_mac_fib_key (BVT (clib_bihash_kv) * kv, u16 bd_index, u8 src_mac[6], * * @return index of mapping matching the lookup key. */ -u32 +index_t lisp_l2_fib_lookup (lisp_gpe_main_t * lgm, u16 bd_index, u8 src_mac[6], u8 dst_mac[6]) { @@ -555,7 +308,7 @@ lisp_l2_fib_lookup (lisp_gpe_main_t * lgm, u16 bd_index, u8 src_mac[6], return value.value; } - return ~0; + return lisp_gpe_main.l2_lb_miss; } /** @@ -601,6 +354,12 @@ l2_fib_init (lisp_gpe_main_t * lgm) BV (clib_bihash_init) (&lgm->l2_fib, "l2 fib", 1 << max_log2 (L2_FIB_DEFAULT_HASH_NUM_BUCKETS), L2_FIB_DEFAULT_HASH_MEMORY_SIZE); + + /* + * the result from a 'miss' in a L2 Table + */ + lgm->l2_lb_miss = load_balance_create (1, DPO_PROTO_IP4, 0); + load_balance_set_bucket (lgm->l2_lb_miss, 0, drop_dpo_get (DPO_PROTO_IP4)); } /** @@ -618,27 +377,75 @@ static int add_del_l2_fwd_entry (lisp_gpe_main_t * lgm, vnet_lisp_gpe_add_del_fwd_entry_args_t * a) { - int rv; - u32 tun_index; - bd_main_t *bdm = &bd_main; - uword *bd_indexp; - - /* create tunnel */ - rv = add_del_ip_tunnel (a, 1 /* is_l2 */ , &tun_index); - if (rv) - return rv; - - bd_indexp = hash_get (bdm->bd_index_by_bd_id, a->bd_id); - if (!bd_indexp) - { - clib_warning ("bridge domain %d doesn't exist", a->bd_id); - return -1; - } - - /* add entry to l2 lisp fib */ - lisp_l2_fib_add_del_entry (lgm, bd_indexp[0], gid_address_mac (&a->lcl_eid), - gid_address_mac (&a->rmt_eid), tun_index, - a->is_add); + /* lisp_gpe_fwd_entry_key_t key; */ + /* lisp_fwd_entry_t *lfe; */ + /* fib_protocol_t fproto; */ + /* uword *bd_indexp; */ + + /* bd_indexp = hash_get (bdm->bd_index_by_bd_id, a->bd_id); */ + /* if (!bd_indexp) */ + /* { */ + /* clib_warning ("bridge domain %d doesn't exist", a->bd_id); */ + /* return -1; */ + /* } */ + + /* lfe = find_fwd_entry(lgm, a, &key); */ + + /* if (NULL != lfe) */ + /* /\* don't support updates *\/ */ + /* return VNET_API_ERROR_INVALID_VALUE; */ + + /* int rv; */ + /* u32 tun_index; */ + /* fib_node_index_t old_path_list; */ + /* bd_main_t *bdm = &bd_main; */ + /* fib_route_path_t *rpaths; */ + /* lisp_gpe_tunnel_t *t; */ + /* const dpo_id_t *dpo; */ + /* index_t lbi; */ + + /* /\* create tunnel *\/ */ + /* rv = add_del_ip_tunnel (a, 1 /\* is_l2 *\/ , &tun_index, NULL); */ + /* if (rv) */ + /* return rv; */ + + /* bd_indexp = hash_get (bdm->bd_index_by_bd_id, a->bd_id); */ + /* if (!bd_indexp) */ + /* { */ + /* clib_warning ("bridge domain %d doesn't exist", a->bd_id); */ + /* return -1; */ + /* } */ + + /* t = pool_elt_at_index (lgm->tunnels, tun_index); */ + /* old_path_list = t->l2_path_list; */ + + /* if (LISP_NO_ACTION == t->action) */ + /* { */ + /* rpaths = lisp_gpe_mk_paths_for_sub_tunnels (t); */ + + /* t->l2_path_list = fib_path_list_create (FIB_PATH_LIST_FLAG_NONE, */ + /* rpaths); */ + + /* vec_free (rpaths); */ + /* fib_path_list_lock (t->l2_path_list); */ + + /* dpo = fib_path_list_contribute_forwarding (t->l2_path_list, */ + /* FIB_FORW_CHAIN_TYPE_UNICAST_IP); */ + /* lbi = dpo->dpoi_index; */ + /* } */ + /* else if (LISP_SEND_MAP_REQUEST == t->action) */ + /* { */ + /* lbi = lgm->l2_lb_cp_lkup; */ + /* } */ + /* else */ + /* { */ + /* lbi = lgm->l2_lb_miss; */ + /* } */ + /* fib_path_list_unlock (old_path_list); */ + + /* /\* add entry to l2 lisp fib *\/ */ + /* lisp_l2_fib_add_del_entry (lgm, bd_indexp[0], gid_address_mac (&a->lcl_eid), */ + /* gid_address_mac (&a->rmt_eid), lbi, a->is_add); */ return 0; } @@ -669,7 +476,11 @@ vnet_lisp_gpe_add_del_fwd_entry (vnet_lisp_gpe_add_del_fwd_entry_args_t * a, switch (type) { case GID_ADDR_IP_PREFIX: - return add_del_ip_fwd_entry (lgm, a); + if (a->is_add) + return add_ip_fwd_entry (lgm, a); + else + return del_ip_fwd_entry (lgm, a); + break; case GID_ADDR_MAC: return add_del_l2_fwd_entry (lgm, a); default: @@ -807,103 +618,77 @@ done: /* *INDENT-OFF* */ VLIB_CLI_COMMAND (lisp_gpe_add_del_fwd_entry_command, static) = { - .path = "lisp gpe tunnel", - .short_help = "lisp gpe tunnel add/del vni <vni> vrf <vrf> [leid <leid>]" + .path = "lisp gpe entry", + .short_help = "lisp gpe entry add/del vni <vni> vrf <vrf> [leid <leid>]" "reid <reid> [loc-pair <lloc> <rloc> p <priority> w <weight>] " "[negative action <action>]", .function = lisp_gpe_add_del_fwd_entry_command_fn, }; /* *INDENT-ON* */ -/** Format LISP-GPE next indexes. */ static u8 * -format_decap_next (u8 * s, va_list * args) +format_lisp_fwd_path (u8 * s, va_list ap) { - u32 next_index = va_arg (*args, u32); + lisp_fwd_path_t *lfp = va_arg (ap, lisp_fwd_path_t *); - switch (next_index) - { - case LISP_GPE_INPUT_NEXT_DROP: - return format (s, "drop"); - case LISP_GPE_INPUT_NEXT_IP4_INPUT: - return format (s, "ip4"); - case LISP_GPE_INPUT_NEXT_IP6_INPUT: - return format (s, "ip6"); - default: - return format (s, "unknown %d", next_index); - } - return s; + s = format (s, "pirority:%d weight:%d ", lfp->priority, lfp->weight); + s = format (s, "adj:[%U]\n", + format_lisp_gpe_adjacency, + lisp_gpe_adjacency_get (lfp->lisp_adj), + LISP_GPE_ADJ_FORMAT_FLAG_NONE); + + return (s); } -/** Format LISP-GPE tunnel. */ -u8 * -format_lisp_gpe_tunnel (u8 * s, va_list * args) +static u8 * +format_lisp_gpe_fwd_entry (u8 * s, va_list ap) { - lisp_gpe_tunnel_t *t = va_arg (*args, lisp_gpe_tunnel_t *); - lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main (); - locator_pair_t *lp = 0; - normalized_sub_tunnel_weights_t *nstw; - - s = - format (s, "tunnel %d vni %d (0x%x)\n", t - lgm->tunnels, t->vni, t->vni); - s = - format (s, " fibs: encap %d, decap %d decap next %U\n", - t->encap_fib_index, t->decap_fib_index, format_decap_next, - t->decap_next_index); - s = format (s, " lisp ver %d ", (t->ver_res >> 6)); - -#define _(n,v) if (t->flags & v) s = format (s, "%s-bit ", #n); - foreach_lisp_gpe_flag_bit; -#undef _ - - s = format (s, "next_protocol %d ver_res %x res %x\n", - t->next_protocol, t->ver_res, t->res); - - s = format (s, " locator-pairs:\n"); - vec_foreach (lp, t->locator_pairs) - { - s = format (s, " local: %U remote: %U weight %d\n", - format_ip_address, &lp->lcl_loc, format_ip_address, - &lp->rmt_loc, lp->weight); - } + lisp_fwd_entry_t *lfe = va_arg (ap, lisp_fwd_entry_t *); - s = format (s, " active sub-tunnels:\n"); - vec_foreach (nstw, t->norm_sub_tunnel_weights) - { - lp = vec_elt_at_index (t->locator_pairs, nstw->sub_tunnel_index); - s = format (s, " local: %U remote: %U weight %d\n", format_ip_address, - &lp->lcl_loc, format_ip_address, &lp->rmt_loc, nstw->weight); - } - return s; + s = format (s, "VNI:%d VRF:%d EID: %U -> %U", + lfe->key->vni, lfe->eid_table_id, + format_fid_address, &lfe->key->lcl, + format_fid_address, &lfe->key->rmt); + if (LISP_FWD_ENTRY_TYPE_NEGATIVE == lfe->type) + { + s = format (s, "\n Negative - action:%U", + format_negative_mapping_action, lfe->action); + } + else + { + lisp_fwd_path_t *path; + + s = format (s, "\n via:"); + vec_foreach (path, lfe->paths) + { + s = format (s, "\n %U", format_lisp_fwd_path, path); + } + } + + return (s); } -/** CLI command to show LISP-GPE tunnels. */ static clib_error_t * -show_lisp_gpe_tunnel_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) +lisp_gpe_fwd_entry_show (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) { - lisp_gpe_main_t *lgm = &lisp_gpe_main; - lisp_gpe_tunnel_t *t; - - if (pool_elts (lgm->tunnels) == 0) - vlib_cli_output (vm, "No lisp-gpe tunnels configured..."); + lisp_fwd_entry_t *lfe; - /* *INDENT-OFF* */ - pool_foreach (t, lgm->tunnels, +/* *INDENT-OFF* */ + pool_foreach (lfe, lisp_fwd_entry_pool, ({ - vlib_cli_output (vm, "%U", format_lisp_gpe_tunnel, t); + vlib_cli_output (vm, "%U", format_lisp_gpe_fwd_entry, lfe); })); - /* *INDENT-ON* */ +/* *INDENT-ON* */ - return 0; + return (NULL); } /* *INDENT-OFF* */ -VLIB_CLI_COMMAND (show_lisp_gpe_tunnel_command, static) = -{ - .path = "show lisp gpe tunnel", - .function = show_lisp_gpe_tunnel_command_fn, +VLIB_CLI_COMMAND (lisp_gpe_fwd_entry_show_command, static) = { + .path = "show lisp gpe entry", + .short_help = "show lisp gpe entry vni <vni> vrf <vrf> [leid <leid>] reid <reid>", + .function = lisp_gpe_fwd_entry_show, }; /* *INDENT-ON* */ @@ -921,29 +706,9 @@ clib_error_t * vnet_lisp_gpe_enable_disable (vnet_lisp_gpe_enable_disable_args_t * a) { lisp_gpe_main_t *lgm = &lisp_gpe_main; - vnet_main_t *vnm = lgm->vnet_main; if (a->is_en) { - /* add lgpe_ip4_lookup as possible next_node for ip4 lookup */ - if (lgm->ip4_lookup_next_lgpe_ip4_lookup == ~0) - { - lgm->ip4_lookup_next_lgpe_ip4_lookup = - vlib_node_add_next (vnm->vlib_main, ip4_lookup_node.index, - lgpe_ip4_lookup_node.index); - } - /* add lgpe_ip6_lookup as possible next_node for ip6 lookup */ - if (lgm->ip6_lookup_next_lgpe_ip6_lookup == ~0) - { - lgm->ip6_lookup_next_lgpe_ip6_lookup = - vlib_node_add_next (vnm->vlib_main, ip6_lookup_node.index, - lgpe_ip6_lookup_node.index); - } - else - { - /* ask cp to re-add ifaces and defaults */ - } - lgm->is_en = 1; } else @@ -951,37 +716,17 @@ vnet_lisp_gpe_enable_disable (vnet_lisp_gpe_enable_disable_args_t * a) CLIB_UNUSED (uword * val); hash_pair_t *p; u32 *dp_tables = 0, *dp_table; - lisp_gpe_tunnel_key_t *tunnels = 0, *tunnel; - vnet_lisp_gpe_add_del_fwd_entry_args_t _at, *at = &_at; vnet_lisp_gpe_add_del_iface_args_t _ai, *ai = &_ai; + lisp_fwd_entry_t *lfe; - /* remove all tunnels */ - + /* remove all entries */ /* *INDENT-OFF* */ - mhash_foreach(tunnel, val, &lgm->lisp_gpe_tunnel_by_key, ({ - vec_add1(tunnels, tunnel[0]); + pool_foreach (lfe, lisp_fwd_entry_pool, + ({ + del_ip_fwd_entry_i (lfe); })); /* *INDENT-ON* */ - vec_foreach (tunnel, tunnels) - { - memset (at, 0, sizeof (at[0])); - at->is_add = 0; - if (tunnel->rmt.type == GID_ADDR_IP_PREFIX) - { - gid_address_type (&at->rmt_eid) = GID_ADDR_IP_PREFIX; - ip_prefix_copy (&gid_address_ippref (&at->rmt_eid), - &tunnel->rmt.ippref); - } - else - { - gid_address_type (&at->rmt_eid) = GID_ADDR_MAC; - mac_copy (&gid_address_mac (&at->rmt_eid), &tunnel->rmt.mac); - } - vnet_lisp_gpe_add_del_fwd_entry (at, 0); - } - vec_free (tunnels); - /* disable all l3 ifaces */ /* *INDENT-OFF* */ @@ -1109,6 +854,7 @@ format_vnet_lisp_gpe_status (u8 * s, va_list * args) return format (s, "%s", lgm->is_en ? "enabled" : "disabled"); } + /** LISP-GPE init function. */ clib_error_t * lisp_gpe_init (vlib_main_t * vm) @@ -1128,11 +874,10 @@ lisp_gpe_init (vlib_main_t * vm) lgm->im6 = &ip6_main; lgm->lm4 = &ip4_main.lookup_main; lgm->lm6 = &ip6_main.lookup_main; - lgm->ip4_lookup_next_lgpe_ip4_lookup = ~0; - lgm->ip6_lookup_next_lgpe_ip6_lookup = ~0; - mhash_init (&lgm->lisp_gpe_tunnel_by_key, sizeof (uword), - sizeof (lisp_gpe_tunnel_key_t)); + lisp_gpe_fwd_entries = hash_create_mem (0, + sizeof (lisp_gpe_fwd_entry_key_t), + sizeof (uword)); l2_fib_init (lgm); |