ADJ: midchain delegate to performing stacking

this can be used by e.g. tunnels so it doesn't need to be
implemented for each tunnel type.

Change-Id: I0790f89aa49f83421612b35108cce67693285999
Signed-off-by: Neale Ranns <nranns@cisco.com>
This commit is contained in:
Neale Ranns
2019-03-26 07:02:58 +00:00
committed by Damjan Marion
parent af3f0783b0
commit 4c3ba81709
11 changed files with 267 additions and 211 deletions

View File

@ -1371,6 +1371,7 @@ list(APPEND VNET_SOURCES
adj/adj_nbr.c
adj/adj_glean.c
adj/adj_midchain.c
adj/adj_midchain_delegate.c
adj/adj_mcast.c
adj/adj_l2.c
adj/adj_nsh.c

View File

@ -537,10 +537,32 @@ static fib_node_back_walk_rc_t
adj_back_walk_notify (fib_node_t *node,
fib_node_back_walk_ctx_t *ctx)
{
/*
* Que pasa. yo soj en el final!
*/
ASSERT(0);
ip_adjacency_t *adj;
adj = ADJ_FROM_NODE(node);
switch (adj->lookup_next_index)
{
case IP_LOOKUP_NEXT_MIDCHAIN:
adj_midchain_delegate_restack(adj_get_index(adj));
break;
case IP_LOOKUP_NEXT_ARP:
case IP_LOOKUP_NEXT_REWRITE:
case IP_LOOKUP_NEXT_BCAST:
case IP_LOOKUP_NEXT_GLEAN:
case IP_LOOKUP_NEXT_MCAST:
case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
case IP_LOOKUP_NEXT_DROP:
case IP_LOOKUP_NEXT_PUNT:
case IP_LOOKUP_NEXT_LOCAL:
case IP_LOOKUP_NEXT_ICMP_ERROR:
case IP_LOOKUP_N_NEXT:
/*
* Que pasa. yo soj en el final!
*/
ASSERT(0);
break;
}
return (FIB_NODE_BACK_WALK_CONTINUE);
}

View File

@ -25,7 +25,7 @@ static adj_delegate_vft_t *ad_vfts;
/**
* The value of the last dynamically allocated delegeate value
*/
static adj_delegate_type_t ad_max_id = ADJ_DELEGATE_BFD;
static adj_delegate_type_t ad_max_id = ADJ_DELEGATE_LAST;
static adj_delegate_t *
adj_delegate_find_i (const ip_adjacency_t *adj,

View File

@ -36,8 +36,14 @@ typedef enum adj_delegate_type_t_ {
* BFD session state
*/
ADJ_DELEGATE_BFD,
/**
* Stacking of a midchain's nexthop
*/
ADJ_DELEGATE_MIDCHAIN,
} adj_delegate_type_t;
#define ADJ_DELEGATE_LAST (ADJ_DELEGATE_MIDCHAIN)
/**
* Adj delegate. This object is attached to the adjacency.
*/

View File

@ -118,4 +118,25 @@ extern void adj_midchain_module_init(void);
*/
extern u8* format_adj_midchain(u8* s, va_list *ap);
/**
* @brief
* create/attach a midchain delegate and stack it on the prefix passed
* @param ai - the index of the adjacency to stack
* @param fib_index - The FIB index of the prefix on which to stack
* @param pfx - The prefix on which to stack
*/
extern void adj_midchain_delegate_stack(adj_index_t ai,
u32 fib_index,
const fib_prefix_t *pfx);
/**
* @brief restack a midchain delegate
*/
extern void adj_midchain_delegate_restack(adj_index_t ai);
/**
* @brief unstack a midchain delegate (this stacks it on a drop)
*/
extern void adj_midchain_delegate_unstack(adj_index_t ai);
#endif

View File

@ -0,0 +1,183 @@
/*
* Copyright (c) 2016 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_delegate.h>
#include <vnet/adj/adj_midchain.h>
#include <vnet/fib/fib_table.h>
/**
* Midchain stacker delegate
*/
typedef struct adj_midchain_delegate_t_
{
/**
* the Fib Entry we are stacked on
*/
fib_node_index_t amd_fei;
/**
* The sibling entry on the FIB entry
*/
u32 amd_sibling;
} adj_midchain_delegate_t;
/**
* Pool of delegates
*/
static adj_midchain_delegate_t *amd_pool;
static inline const adj_midchain_delegate_t*
adj_midchain_from_const_base (const adj_delegate_t *ad)
{
if (NULL != ad)
{
return (pool_elt_at_index(amd_pool, ad->ad_index));
}
return (NULL);
}
static void
adj_midchain_delegate_restack_i (adj_index_t ai,
adj_midchain_delegate_t *amd)
{
if (vnet_sw_interface_is_admin_up (vnet_get_main (),
adj_get_sw_if_index(ai)) &&
(FIB_NODE_INDEX_INVALID != amd->amd_fei))
{
const fib_prefix_t *pfx;
pfx = fib_entry_get_prefix(amd->amd_fei);
adj_nbr_midchain_stack_on_fib_entry (
ai,
amd->amd_fei,
fib_forw_chain_type_from_fib_proto(pfx->fp_proto));
}
else
{
adj_nbr_midchain_unstack (ai);
}
}
void
adj_midchain_delegate_restack (adj_index_t ai)
{
adj_midchain_delegate_t *amd;
ip_adjacency_t *adj;
adj_delegate_t *ad;
/*
* if there's a delegate already use that
*/
adj = adj_get(ai);
ad = adj_delegate_get(adj, ADJ_DELEGATE_MIDCHAIN);
if (NULL != ad)
{
amd = pool_elt_at_index(amd_pool, ad->ad_index);
adj_midchain_delegate_restack_i(ai, amd);
}
/*
* else
* nothing to stack
*/
}
void
adj_midchain_delegate_stack (adj_index_t ai,
u32 fib_index,
const fib_prefix_t *pfx)
{
adj_midchain_delegate_t *amd;
ip_adjacency_t *adj;
adj_delegate_t *ad;
/*
* if there's a delegate already use that
*/
adj = adj_get(ai);
ad = adj_delegate_get(adj, ADJ_DELEGATE_MIDCHAIN);
if (NULL != ad)
{
amd = pool_elt_at_index(amd_pool, ad->ad_index);
}
else
{
pool_get(amd_pool, amd);
amd->amd_fei = FIB_NODE_INDEX_INVALID;
adj_delegate_add(adj, ADJ_DELEGATE_MIDCHAIN, amd - amd_pool);
amd->amd_fei = fib_table_entry_special_add(fib_index,
pfx,
FIB_SOURCE_RR,
FIB_ENTRY_FLAG_NONE);
amd->amd_sibling = fib_entry_child_add(amd->amd_fei,
FIB_NODE_TYPE_ADJ,
ai);
}
adj_midchain_delegate_restack_i(ai, amd);
}
void
adj_midchain_delegate_unstack (adj_index_t ai)
{
adj_nbr_midchain_unstack(ai);
}
static void
adj_midchain_delegate_adj_deleted (adj_delegate_t *ad)
{
adj_midchain_delegate_t *amd;
amd = pool_elt_at_index(amd_pool, ad->ad_index);
fib_entry_child_remove (amd->amd_fei, amd->amd_sibling);
fib_table_entry_delete_index (amd->amd_fei, FIB_SOURCE_RR);
pool_put(amd_pool, amd);
}
/**
* Print a delegate that represents MIDCHAIN tracking
*/
static u8 *
adj_midchain_delegate_fmt (const adj_delegate_t *aed, u8 *s)
{
const adj_midchain_delegate_t *amd = adj_midchain_from_const_base(aed);
s = format(s, "MIDCHAIN:[fib-entry:%d]", amd->amd_fei);
return (s);
}
const static adj_delegate_vft_t adj_delegate_vft = {
.adv_format = adj_midchain_delegate_fmt,
.adv_adj_deleted = adj_midchain_delegate_adj_deleted,
};
static clib_error_t *
adj_midchain_delegate_module_init (vlib_main_t * vm)
{
clib_error_t * error = NULL;
adj_delegate_register_type (ADJ_DELEGATE_MIDCHAIN, &adj_delegate_vft);
return (error);
}
VLIB_INIT_FUNCTION (adj_midchain_delegate_module_init);

View File

@ -39,7 +39,6 @@ typedef enum fib_node_type_t_ {
FIB_NODE_TYPE_MPLS_TUNNEL,
FIB_NODE_TYPE_LISP_GPE_FWD_ENTRY,
FIB_NODE_TYPE_LISP_ADJ,
FIB_NODE_TYPE_GRE_TUNNEL,
FIB_NODE_TYPE_VXLAN_TUNNEL,
FIB_NODE_TYPE_MAP_E,
FIB_NODE_TYPE_VXLAN_GPE_TUNNEL,
@ -69,7 +68,6 @@ typedef enum fib_node_type_t_ {
[FIB_NODE_TYPE_ADJ] = "adj", \
[FIB_NODE_TYPE_LISP_GPE_FWD_ENTRY] = "lisp-gpe-fwd-entry", \
[FIB_NODE_TYPE_LISP_ADJ] = "lisp-adj", \
[FIB_NODE_TYPE_GRE_TUNNEL] = "gre-tunnel", \
[FIB_NODE_TYPE_VXLAN_TUNNEL] = "vxlan-tunnel", \
[FIB_NODE_TYPE_MAP_E] = "map-e", \
[FIB_NODE_TYPE_VXLAN_GPE_TUNNEL] = "vxlan-gpe-tunnel", \

View File

@ -180,11 +180,6 @@ typedef struct
*/
CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
/**
* Linkage into the FIB object graph
*/
fib_node_t node;
/**
* The hash table's key stored in separate memory since the tunnel_t
* memory can realloc.
@ -207,19 +202,6 @@ typedef struct
u32 sw_if_index;
gre_tunnel_type_t type;
/**
* The FIB entry sourced by the tunnel for its destination prefix
*/
fib_node_index_t fib_entry_index;
/**
* The tunnel is a child of the FIB entry for its desintion. This is
* so it receives updates when the forwarding information for that entry
* changes.
* The tunnels sibling index on the FIB entry's dependency list.
*/
u32 sibling_index;
/**
* an L2 tunnel always rquires an L2 midchain. cache here for DP.
*/

View File

@ -112,14 +112,6 @@ gre_tunnel_db_remove (gre_tunnel_t * t)
t->key = NULL;
}
static gre_tunnel_t *
gre_tunnel_from_fib_node (fib_node_t * node)
{
ASSERT (FIB_NODE_TYPE_GRE_TUNNEL == node->fn_type);
return ((gre_tunnel_t *) (((char *) node) -
STRUCT_OFFSET_OF (gre_tunnel_t, node)));
}
/**
* gre_tunnel_stack
*
@ -146,14 +138,11 @@ gre_tunnel_stack (adj_index_t ai)
if ((vnet_hw_interface_get_flags (vnet_get_main (), gt->hw_if_index) &
VNET_HW_INTERFACE_FLAG_LINK_UP) == 0)
{
adj_nbr_midchain_unstack (ai);
adj_midchain_delegate_unstack (ai);
}
else
{
adj_nbr_midchain_stack_on_fib_entry (ai,
gt->fib_entry_index,
fib_forw_chain_type_from_fib_proto
(gt->tunnel_dst.fp_proto));
adj_midchain_delegate_stack (ai, gt->outer_fib_index, &gt->tunnel_dst);
}
}
@ -182,55 +171,6 @@ gre_tunnel_restack (gre_tunnel_t * gt)
}
}
/**
* Function definition to backwalk a FIB node
*/
static fib_node_back_walk_rc_t
gre_tunnel_back_walk (fib_node_t * node, fib_node_back_walk_ctx_t * ctx)
{
gre_tunnel_restack (gre_tunnel_from_fib_node (node));
return (FIB_NODE_BACK_WALK_CONTINUE);
}
/**
* Function definition to get a FIB node from its index
*/
static fib_node_t *
gre_tunnel_fib_node_get (fib_node_index_t index)
{
gre_tunnel_t *gt;
gre_main_t *gm;
gm = &gre_main;
gt = pool_elt_at_index (gm->tunnels, index);
return (&gt->node);
}
/**
* Function definition to inform the FIB node that its last lock has gone.
*/
static void
gre_tunnel_last_lock_gone (fib_node_t * node)
{
/*
* The MPLS GRE tunnel is a root of the graph. As such
* it never has children and thus is never locked.
*/
ASSERT (0);
}
/*
* Virtual function table registered by MPLS GRE tunnels
* for participation in the FIB object graph.
*/
const static fib_node_vft_t gre_vft = {
.fnv_get = gre_tunnel_fib_node_get,
.fnv_last_lock = gre_tunnel_last_lock_gone,
.fnv_back_walk = gre_tunnel_back_walk,
};
static int
vnet_gre_tunnel_add (vnet_gre_add_del_tunnel_args_t * a,
u32 outer_fib_index, u32 * sw_if_indexp)
@ -267,7 +207,6 @@ vnet_gre_tunnel_add (vnet_gre_add_del_tunnel_args_t * a,
t->dev_instance = t_idx; /* actual */
t->user_instance = u_idx; /* name */
fib_node_init (&t->node, FIB_NODE_TYPE_GRE_TUNNEL);
t->type = a->tunnel_type;
if (t->type == GRE_TUNNEL_TYPE_ERSPAN)
@ -357,11 +296,6 @@ vnet_gre_tunnel_add (vnet_gre_add_del_tunnel_args_t * a,
}
}
t->fib_entry_index = fib_table_entry_special_add
(outer_fib_index, &t->tunnel_dst, FIB_SOURCE_RR, FIB_ENTRY_FLAG_NONE);
t->sibling_index = fib_entry_child_add
(t->fib_entry_index, FIB_NODE_TYPE_GRE_TUNNEL, t_idx);
if (t->type != GRE_TUNNEL_TYPE_L3)
{
t->l2_adj_index = adj_nbr_add_or_lock
@ -403,10 +337,10 @@ vnet_gre_tunnel_delete (vnet_gre_add_del_tunnel_args_t * a,
ethernet_delete_interface (vnm, t->hw_if_index);
if (t->l2_adj_index != ADJ_INDEX_INVALID)
adj_unlock (t->l2_adj_index);
fib_entry_child_remove (t->fib_entry_index, t->sibling_index);
fib_table_entry_delete_index (t->fib_entry_index, FIB_SOURCE_RR);
{
adj_midchain_delegate_unstack (t->l2_adj_index);
adj_unlock (t->l2_adj_index);
}
ASSERT ((t->type != GRE_TUNNEL_TYPE_ERSPAN) || (t->gre_sn != NULL));
if ((t->type == GRE_TUNNEL_TYPE_ERSPAN) && (t->gre_sn->ref_count-- == 1))
@ -419,7 +353,6 @@ vnet_gre_tunnel_delete (vnet_gre_add_del_tunnel_args_t * a,
hash_unset (gm->instance_used, t->user_instance);
gre_tunnel_db_remove (t);
fib_node_deinit (&t->node);
pool_put (gm->tunnels, t);
if (sw_if_indexp)
@ -690,9 +623,7 @@ VLIB_CLI_COMMAND (show_gre_tunnel_command, static) = {
clib_error_t *
gre_interface_init (vlib_main_t * vm)
{
fib_node_register_type (FIB_NODE_TYPE_GRE_TUNNEL, &gre_vft);
return 0;
return (NULL);
}
VLIB_INIT_FUNCTION (gre_interface_init);

View File

@ -20,6 +20,7 @@
#include <vnet/ipip/ipip.h>
#include <vnet/vnet.h>
#include <vnet/adj/adj_nbr.h>
#include <vnet/adj/adj_midchain.h>
#include <vnet/fib/ip4_fib.h>
#include <vnet/fib/ip6_fib.h>
#include <vnet/ip/format.h>
@ -185,15 +186,21 @@ ipip_tunnel_stack (adj_index_t ai)
if ((vnet_hw_interface_get_flags (vnet_get_main (), t->hw_if_index) &
VNET_HW_INTERFACE_FLAG_LINK_UP) == 0)
{
adj_nbr_midchain_unstack (ai);
adj_midchain_delegate_unstack (ai);
}
else
{
adj_nbr_midchain_stack_on_fib_entry
(ai,
t->p2p.fib_entry_index,
(t->transport == IPIP_TRANSPORT_IP6) ?
FIB_FORW_CHAIN_TYPE_UNICAST_IP6 : FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
/* *INDENT-OFF* */
fib_prefix_t dst = {
.fp_len = t->transport == IPIP_TRANSPORT_IP6 ? 128 : 32,
.fp_proto = (t->transport == IPIP_TRANSPORT_IP6 ?
FIB_PROTOCOL_IP6 :
FIB_PROTOCOL_IP4),
.fp_addr = t->tunnel_dst
};
/* *INDENT-ON* */
adj_midchain_delegate_stack (ai, t->fib_index, &dst);
}
}
@ -356,82 +363,6 @@ ipip_tunnel_db_remove (ipip_tunnel_t * t)
t->key = NULL;
}
static ipip_tunnel_t *
ipip_tunnel_from_fib_node (fib_node_t * node)
{
ipip_main_t *gm = &ipip_main;
ASSERT (gm->fib_node_type == node->fn_type);
return ((ipip_tunnel_t *) (((char *) node) -
offsetof (ipip_tunnel_t, p2p.node)));
}
static fib_node_back_walk_rc_t
ipip_tunnel_back_walk (fib_node_t * node, fib_node_back_walk_ctx_t * ctx)
{
ipip_tunnel_restack (ipip_tunnel_from_fib_node (node));
return (FIB_NODE_BACK_WALK_CONTINUE);
}
static fib_node_t *
ipip_tunnel_fib_node_get (fib_node_index_t index)
{
ipip_tunnel_t *gt;
ipip_main_t *gm;
gm = &ipip_main;
gt = pool_elt_at_index (gm->tunnels, index);
return (&gt->p2p.node);
}
static void
ipip_tunnel_last_lock_gone (fib_node_t * node)
{
/*
* The MPLS IPIP tunnel is a root of the graph. As such
* it never has children and thus is never locked.
*/
ASSERT (0);
}
/*
* Virtual function table registered by IPIP tunnels
* for participation in the FIB object graph.
*/
const static fib_node_vft_t ipip_vft = {
.fnv_get = ipip_tunnel_fib_node_get,
.fnv_last_lock = ipip_tunnel_last_lock_gone,
.fnv_back_walk = ipip_tunnel_back_walk,
};
static void
ipip_fib_add (ipip_tunnel_t * t)
{
ipip_main_t *gm = &ipip_main;
fib_prefix_t dst = {.fp_len = t->transport == IPIP_TRANSPORT_IP6 ? 128 : 32,
.fp_proto =
t->transport ==
IPIP_TRANSPORT_IP6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4,
.fp_addr = t->tunnel_dst
};
t->p2p.fib_entry_index =
fib_table_entry_special_add (t->fib_index, &dst, FIB_SOURCE_RR,
FIB_ENTRY_FLAG_NONE);
t->p2p.sibling_index =
fib_entry_child_add (t->p2p.fib_entry_index, gm->fib_node_type,
t->dev_instance);
}
static void
ipip_fib_delete (ipip_tunnel_t * t)
{
fib_entry_child_remove (t->p2p.fib_entry_index, t->p2p.sibling_index);
fib_table_entry_delete_index (t->p2p.fib_entry_index, FIB_SOURCE_RR);
fib_node_deinit (&t->p2p.node);
}
int
ipip_add_tunnel (ipip_transport_t transport,
u32 instance, ip46_address_t * src, ip46_address_t * dst,
@ -470,7 +401,6 @@ ipip_add_tunnel (ipip_transport_t transport,
t->dev_instance = t_idx; /* actual */
t->user_instance = u_idx; /* name */
fib_node_init (&t->p2p.node, gm->fib_node_type);
hw_if_index = vnet_register_interface (vnm, ipip_device_class.index, t_idx,
ipip_hw_interface_class.index,
@ -507,12 +437,6 @@ ipip_add_tunnel (ipip_transport_t transport,
ipip_tunnel_db_add (t, &key);
/*
* Source the FIB entry for the tunnel's destination and become a
* child thereof. The tunnel will then get poked when the forwarding
* for the entry updates, and the tunnel can re-stack accordingly
*/
ipip_fib_add (t);
if (sw_if_indexp)
*sw_if_indexp = sw_if_index;
@ -546,7 +470,6 @@ ipip_del_tunnel (u32 sw_if_index)
vnet_sw_interface_set_flags (vnm, sw_if_index, 0 /* down */ );
gm->tunnel_index_by_sw_if_index[sw_if_index] = ~0;
vnet_delete_hw_interface (vnm, t->hw_if_index);
ipip_fib_delete (t);
hash_unset (gm->instance_used, t->user_instance);
ipip_tunnel_db_remove (t);
pool_put (gm->tunnels, t);
@ -564,7 +487,6 @@ ipip_init (vlib_main_t * vm)
gm->vnet_main = vnet_get_main ();
gm->tunnel_by_key =
hash_create_mem (0, sizeof (ipip_tunnel_key_t), sizeof (uword));
gm->fib_node_type = fib_node_register_new_type (&ipip_vft);
return 0;
}

View File

@ -84,25 +84,16 @@ typedef struct
u32 user_instance; /* Instance name being shown to user */
u8 tc_tos;
union
struct
{
struct
{
fib_node_t node;
fib_node_index_t fib_entry_index;
u32 sibling_index;
} p2p;
struct
{
ip6_address_t ip6_prefix;
ip4_address_t ip4_prefix;
u8 ip6_prefix_len;
u8 ip4_prefix_len;
u8 shift;
bool security_check;
u32 ip6_fib_index;
} sixrd;
};
ip6_address_t ip6_prefix;
ip4_address_t ip4_prefix;
u8 ip6_prefix_len;
u8 ip4_prefix_len;
u8 shift;
bool security_check;
u32 ip6_fib_index;
} sixrd;
} ipip_tunnel_t;
typedef struct
@ -110,7 +101,6 @@ typedef struct
ipip_tunnel_t *tunnels;
uword *tunnel_by_key;
u32 *tunnel_index_by_sw_if_index;
fib_node_type_t fib_node_type;
/* convenience */
vlib_main_t *vlib_main;