diff options
-rw-r--r-- | src/vnet/adj/adj.c | 28 | ||||
-rw-r--r-- | src/vnet/adj/adj.h | 2 | ||||
-rw-r--r-- | src/vnet/adj/adj_bfd.c | 113 | ||||
-rw-r--r-- | src/vnet/adj/adj_delegate.c | 122 | ||||
-rw-r--r-- | src/vnet/adj/adj_delegate.h | 125 | ||||
-rw-r--r-- | src/vnet/adj/adj_internal.h | 12 | ||||
-rw-r--r-- | src/vnet/fib/fib_node.h | 42 |
7 files changed, 287 insertions, 157 deletions
diff --git a/src/vnet/adj/adj.c b/src/vnet/adj/adj.c index e1d7821fd39..386070ed3f8 100644 --- a/src/vnet/adj/adj.c +++ b/src/vnet/adj/adj.c @@ -129,18 +129,13 @@ format_ip_adjacency (u8 * s, va_list * args) if (fiaf & FORMAT_IP_ADJACENCY_DETAIL) { - adj_delegate_type_t adt; - adj_delegate_t *aed; vlib_counter_t counts; vlib_get_combined_counter(&adjacency_counters, adj_index, &counts); s = format (s, "\n counts:[%Ld:%Ld]", counts.packets, counts.bytes); s = format (s, "\n locks:%d", adj->ia_node.fn_locks); s = format(s, "\n delegates:\n "); - FOR_EACH_ADJ_DELEGATE(adj, adt, aed, - { - s = format(s, " %U\n", format_adj_delegate, aed); - }); + adj_delegate_format(s, adj); s = format(s, "\n children:\n "); s = fib_node_children_format(adj->ia_node.fn_children, s); @@ -162,7 +157,7 @@ adj_last_lock_gone (ip_adjacency_t *adj) ASSERT(0 == fib_node_list_get_size(adj->ia_node.fn_children)); ADJ_DBG(adj, "last-lock-gone"); - adj_delegate_vft_lock_gone(adj); + adj_delegate_adj_deleted(adj); vlib_worker_thread_barrier_sync (vm); @@ -430,24 +425,7 @@ adj_get_sw_if_index (adj_index_t ai) int adj_is_up (adj_index_t ai) { - const adj_delegate_t *aed; - - aed = adj_delegate_get(adj_get(ai), ADJ_DELEGATE_BFD); - - if (NULL == aed) - { - /* - * no BFD tracking - resolved - */ - return (!0); - } - else - { - /* - * defer to the state of the BFD tracking - */ - return (ADJ_BFD_STATE_UP == aed->ad_bfd_state); - } + return (adj_bfd_is_up(ai)); } /** diff --git a/src/vnet/adj/adj.h b/src/vnet/adj/adj.h index bcf6c041209..0434d7c89e5 100644 --- a/src/vnet/adj/adj.h +++ b/src/vnet/adj/adj.h @@ -273,7 +273,7 @@ typedef struct ip_adjacency_t_ /** * A sorted vector of delegates */ - struct adj_delegate_t_ *ia_delegates; + struct adj_delegate_t_ **ia_delegates; } ip_adjacency_t; diff --git a/src/vnet/adj/adj_bfd.c b/src/vnet/adj/adj_bfd.c index 2d845ffcfd8..a4e7e277298 100644 --- a/src/vnet/adj/adj_bfd.c +++ b/src/vnet/adj/adj_bfd.c @@ -19,6 +19,66 @@ #include <vnet/adj/adj_nbr.h> #include <vnet/fib/fib_walk.h> +/** + * Distillation of the BFD session states into a go/no-go for using + * the associated tracked adjacency + */ +typedef enum adj_bfd_state_t_ +{ + ADJ_BFD_STATE_DOWN, + ADJ_BFD_STATE_UP, +} adj_bfd_state_t; + +/** + * BFD delegate daa + */ +typedef struct adj_bfd_delegate_t_ +{ + /** + * Base class,linkage to the adjacency + */ + adj_delegate_t abd_link; + + /** + * BFD session state + */ + adj_bfd_state_t abd_state; + + /** + * BFD session index + */ + u32 abd_index; +} adj_bfd_delegate_t; + +/** + * Pool of delegates +*/ +static adj_bfd_delegate_t *abd_pool; + +static inline adj_bfd_delegate_t* +adj_bfd_from_base (adj_delegate_t *ad) +{ + if (NULL == ad) + { + return (NULL); + } + return ((adj_bfd_delegate_t*)((char*)ad - + STRUCT_OFFSET_OF(adj_bfd_delegate_t, + abd_link))); +} + +static inline const adj_bfd_delegate_t* +adj_bfd_from_const_base (const adj_delegate_t *ad) +{ + if (NULL == ad) + { + return (NULL); + } + return ((adj_bfd_delegate_t*)((char*)ad - + STRUCT_OFFSET_OF(adj_bfd_delegate_t, + abd_link))); +} + static adj_bfd_state_t adj_bfd_bfd_state_to_fib (bfd_state_e bstate) { @@ -57,6 +117,7 @@ adj_bfd_notify (bfd_listen_event_e event, const bfd_session_t *session) { const bfd_udp_key_t *key; + adj_bfd_delegate_t *abd; fib_protocol_t fproto; adj_delegate_t *aed; adj_index_t ai; @@ -107,7 +168,10 @@ adj_bfd_notify (bfd_listen_event_e event, */ adj_lock(ai); - aed = adj_delegate_find_or_add(adj_get(ai), ADJ_DELEGATE_BFD); + /* + * allocate and init a new delegate struct + */ + pool_get(abd_pool, abd); /* * pretend the session is up and skip the walk. @@ -116,8 +180,10 @@ adj_bfd_notify (bfd_listen_event_e event, * for the first BFD UP/DOWN before we let the session's state * influence forwarding. */ - aed->ad_bfd_state = ADJ_BFD_STATE_UP; - aed->ad_bfd_index = session->bs_idx; + abd->abd_state = ADJ_BFD_STATE_UP; + abd->abd_index = session->bs_idx; + + adj_delegate_add(adj_get(ai), ADJ_DELEGATE_BFD, &abd->abd_link); } break; @@ -125,11 +191,11 @@ adj_bfd_notify (bfd_listen_event_e event, /* * state change up/dowm and */ - aed = adj_delegate_get(adj_get(ai), ADJ_DELEGATE_BFD); + abd = adj_bfd_from_base(adj_delegate_get(adj_get(ai), ADJ_DELEGATE_BFD)); - if (NULL != aed) + if (NULL != abd) { - aed->ad_bfd_state = adj_bfd_bfd_state_to_fib(session->local_state); + abd->abd_state = adj_bfd_bfd_state_to_fib(session->local_state); adj_bfd_update_walk(ai); } /* @@ -142,15 +208,17 @@ adj_bfd_notify (bfd_listen_event_e event, /* * session has been removed. */ + abd = adj_bfd_from_base(adj_delegate_get(adj_get(ai), ADJ_DELEGATE_BFD)); - if (adj_delegate_get(adj_get(ai), ADJ_DELEGATE_BFD)) + if (NULL != abd) { /* * has an associated BFD tracking delegate * remove the BFD tracking deletgate, update children, then * unlock the adj */ - adj_delegate_remove(adj_get(ai), ADJ_DELEGATE_BFD); + adj_delegate_remove(ai, ADJ_DELEGATE_BFD); + pool_put(abd_pool, abd); adj_bfd_update_walk(ai); adj_unlock(ai); @@ -168,15 +236,40 @@ adj_bfd_notify (bfd_listen_event_e event, adj_unlock(ai); } +int +adj_bfd_is_up (adj_index_t ai) +{ + const adj_bfd_delegate_t *abd; + + abd = adj_bfd_from_base(adj_delegate_get(adj_get(ai), ADJ_DELEGATE_BFD)); + + if (NULL == abd) + { + /* + * no BFD tracking - resolved + */ + return (!0); + } + else + { + /* + * defer to the state of the BFD tracking + */ + return (ADJ_BFD_STATE_UP == abd->abd_state); + } +} + /** * Print a delegate that represents BFD tracking */ static u8 * adj_delegate_fmt_bfd (const adj_delegate_t *aed, u8 *s) { + const adj_bfd_delegate_t *abd = adj_bfd_from_const_base(aed); + s = format(s, "BFD:[state:%d index:%d]", - aed->ad_bfd_state, - aed->ad_bfd_index); + abd->abd_state, + abd->abd_index); return (s); } diff --git a/src/vnet/adj/adj_delegate.c b/src/vnet/adj/adj_delegate.c index 0125c89f5fb..1cc7c4b94bd 100644 --- a/src/vnet/adj/adj_delegate.c +++ b/src/vnet/adj/adj_delegate.c @@ -22,23 +22,28 @@ */ 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_t * adj_delegate_find_i (const ip_adjacency_t *adj, adj_delegate_type_t type, u32 *index) { - adj_delegate_t *delegate; + adj_delegate_t **delegate; int ii; ii = 0; vec_foreach(delegate, adj->ia_delegates) { - if (delegate->ad_type == type) + if ((*delegate)->ad_type == type) { if (NULL != index) *index = ii; - return (delegate); + return (*delegate); } else { @@ -57,12 +62,14 @@ adj_delegate_get (const ip_adjacency_t *adj, } void -adj_delegate_remove (ip_adjacency_t *adj, +adj_delegate_remove (adj_index_t ai, adj_delegate_type_t type) { + ip_adjacency_t *adj; adj_delegate_t *aed; u32 index = ~0; + adj = adj_get(ai); aed = adj_delegate_find_i(adj, type, &index); ASSERT(NULL != aed); @@ -74,29 +81,29 @@ static int adj_delegate_cmp_for_sort (void * v1, void * v2) { - adj_delegate_t *delegate1 = v1, *delegate2 = v2; + adj_delegate_t **delegate1 = v1, **delegate2 = v2; - return (delegate1->ad_type - delegate2->ad_type); + return ((*delegate1)->ad_type - (*delegate2)->ad_type); } static void adj_delegate_init (ip_adjacency_t *adj, - adj_delegate_type_t type) + adj_delegate_type_t adt, + adj_delegate_t *aed) { - adj_delegate_t delegate = { - .ad_adj_index = adj_get_index(adj), - .ad_type = type, - }; + aed->ad_adj_index = adj_get_index(adj); + aed->ad_type = adt; - vec_add1(adj->ia_delegates, delegate); + vec_add1(adj->ia_delegates, aed); vec_sort_with_function(adj->ia_delegates, adj_delegate_cmp_for_sort); } -adj_delegate_t * -adj_delegate_find_or_add (ip_adjacency_t *adj, - adj_delegate_type_t adt) +int +adj_delegate_add (ip_adjacency_t *adj, + adj_delegate_type_t adt, + adj_delegate_t *ad) { adj_delegate_t *delegate; @@ -104,30 +111,52 @@ adj_delegate_find_or_add (ip_adjacency_t *adj, if (NULL == delegate) { - adj_delegate_init(adj, adt); + adj_delegate_init(adj, adt, ad); + } + else + { + return (-1); } - return (adj_delegate_get(adj, adt)); + return (0); } -void adj_delegate_vft_lock_gone (ip_adjacency_t *adj) +void +adj_delegate_adj_deleted (ip_adjacency_t *adj) { - adj_delegate_t *delegate; - vec_foreach(delegate, adj->ia_delegates) { - if (ad_vfts[delegate->ad_type].adv_last_lock) - ad_vfts[delegate->ad_type].adv_last_lock(adj, delegate); + adj_delegate_t **delegate; + + vec_foreach(delegate, adj->ia_delegates) + { + if (ad_vfts[(*delegate)->ad_type].adv_adj_deleted) + { + ad_vfts[(*delegate)->ad_type].adv_adj_deleted(*delegate); + } } + + vec_reset_length(adj->ia_delegates); } -u8 * -format_adj_delegate (u8 * s, va_list * args) +u8* +adj_delegate_format (u8* s, ip_adjacency_t *adj) { - adj_delegate_t *aed; + adj_delegate_t **aed; - aed = va_arg (*args, adj_delegate_t *); - if (ad_vfts[aed->ad_type].adv_format) - return ad_vfts[aed->ad_type].adv_format(aed, s); - return format(s, "unknown delegate"); + vec_foreach(aed, adj->ia_delegates) + { + if (ad_vfts[(*aed)->ad_type].adv_format) + { + s = format(s, "{"); + s = ad_vfts[(*aed)->ad_type].adv_format(*aed, s); + s = format(s, "}"); + } + else + { + s = format(s, "{unknown delegate}"); + } + } + + return (s); } /** @@ -135,17 +164,34 @@ format_adj_delegate (u8 * s, va_list * args) * * Register the function table for a given type */ - void adj_delegate_register_type (adj_delegate_type_t type, const adj_delegate_vft_t *vft) { - /* - * assert that one only registration is made per-node type - */ - if (vec_len(ad_vfts) > type) - ASSERT(NULL == ad_vfts[type].adv_last_lock); - - vec_validate(ad_vfts, type); - ad_vfts[type] = *vft; + /* + * assert that one only registration is made per-node type + */ + if (vec_len(ad_vfts) > type) + ASSERT(NULL == ad_vfts[type].adv_adj_deleted); + + vec_validate(ad_vfts, type); + ad_vfts[type] = *vft; +} + +/** + * adj_delegate_register_new_type + * + * Register the function table for a new type + */ +adj_delegate_type_t +adj_delegate_register_new_type (const adj_delegate_vft_t *vft) +{ + adj_delegate_type_t type; + + type = ++ad_max_id; + + vec_validate(ad_vfts, type); + ad_vfts[type] = *vft; + + return (type); } diff --git a/src/vnet/adj/adj_delegate.h b/src/vnet/adj/adj_delegate.h index 9f7d8c64afc..b57900bf595 100644 --- a/src/vnet/adj/adj_delegate.h +++ b/src/vnet/adj/adj_delegate.h @@ -12,6 +12,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +/** + * A Delagate is a means to implement the Delagation design pattern; + * the extension of an object's functionality through the composition of, + * and delgation to, other objects. + * These 'other' objects are delegates. Delagates are thus attached to + * ADJ objects to extend their functionality. + */ #ifndef __ADJ_DELEGATE_T__ #define __ADJ_DELEGATE_T__ @@ -19,7 +26,10 @@ #include <vnet/adj/adj.h> /** - * Delegate types + * Built-in delegate types. + * When adding new types, if your code is within the vnet subsystem, then add a + * new type here. If not then use the adj_delegate_register_new_type API to + * register a new type. */ typedef enum adj_delegate_type_t_ { /** @@ -28,35 +38,12 @@ typedef enum adj_delegate_type_t_ { ADJ_DELEGATE_BFD, } adj_delegate_type_t; -#define FOR_EACH_ADJ_DELEGATE(_adj, _adt, _aed, _body) \ -{ \ - for (_adt = ADJ_DELEGATE_BFD; \ - _adt <= ADJ_DELEGATE_BFD; \ - _adt++) \ - { \ - _aed = adj_delegate_get(_adj, _adt); \ - if (NULL != _aed) { \ - _body; \ - } \ - } \ -} - -/** - * Distillation of the BFD session states into a go/no-go for using - * the associated tracked adjacency - */ -typedef enum adj_bfd_state_t_ -{ - ADJ_BFD_STATE_DOWN, - ADJ_BFD_STATE_UP, -} adj_bfd_state_t; - /** - * A Delagate is a means to implement the Delagation design pattern; - * the extension of an object's functionality through the composition of, - * and delgation to, other objects. - * These 'other' objects are delegates. Delagates are thus attached to - * ADJ objects to extend their functionality. + * Adj delegate. This object should be contained within all type specific + * delegates. i.e. this is the base class to all type specific derived classes. + * With this model the delegate provider is free to manage the memory of the + * delegate in the way it chooses. Specifically it can assign them from its own + * pools and thus, for example, add the delegates to the FIB node graph. */ typedef struct adj_delegate_t_ { @@ -69,47 +56,69 @@ typedef struct adj_delegate_t_ * The delagate type */ adj_delegate_type_t ad_type; - - /** - * A union of data for the different delegate types - */ - union - { - /** - * BFD delegate daa - */ - struct { - /** - * BFD session state - */ - adj_bfd_state_t ad_bfd_state; - /** - * BFD session index - */ - u32 ad_bfd_index; - }; - }; } adj_delegate_t; /** - * An ADJ delegate virtual function table + * Indication that the adjacency has been deleted. The delegate provider should free + * the delegate. + */ +typedef void (*adj_delegate_adj_deleted_t)(adj_delegate_t *aed); + +/** + * Format function for the delegate */ -typedef void (*adj_delegate_last_lock_gone_t)(ip_adjacency_t *adj, adj_delegate_t *aed); typedef u8 * (*adj_delegate_format_t)(const adj_delegate_t *aed, u8 *s); + +/** + * An ADJ delegate virtual function table + */ typedef struct adj_delegate_vft_t_ { - adj_delegate_format_t adv_format; - adj_delegate_last_lock_gone_t adv_last_lock; + adj_delegate_format_t adv_format; + adj_delegate_adj_deleted_t adv_adj_deleted; } adj_delegate_vft_t; -extern void adj_delegate_remove(ip_adjacency_t *adj, +/** + * @brief Remove a delegate from an adjacency + * + * @param ai The adjacency to remove the delegate from + * @param type The type of delegate being removed + */ +extern void adj_delegate_remove(adj_index_t ai, adj_delegate_type_t type); -extern adj_delegate_t *adj_delegate_find_or_add(ip_adjacency_t *adj, - adj_delegate_type_t fdt); +/** + * @brief Add a delegate to an adjacency + * + * @param ai The adjacency to add the delegate to + * @param type The type of delegate being added + * @param ad The delegate. The provider should allocate memory for this object + * Typically this is a 'derived' class with the + * adj_delegate_t struct embedded within. + */ +extern int adj_delegate_add(ip_adjacency_t *adj, + adj_delegate_type_t fdt, + adj_delegate_t *ad); + + +/** + * @brief Get a delegate from an adjacency + * + * @param ai The adjacency to get the delegate from + * @param type The type of delegate being sought + */ extern adj_delegate_t *adj_delegate_get(const ip_adjacency_t *adj, adj_delegate_type_t type); -extern u8 *format_adj_delegate(u8 * s, va_list * args); -extern void adj_delegate_register_type(adj_delegate_type_t type, const adj_delegate_vft_t *vft); +/** + * @brief Register a VFT for one of the built-in types + */ +extern void adj_delegate_register_type(adj_delegate_type_t type, + const adj_delegate_vft_t *vft); + +/** + * @brief create a new delegate type and register a new VFT + */ +extern adj_delegate_type_t adj_delegate_register_new_type( + const adj_delegate_vft_t *vft); #endif diff --git a/src/vnet/adj/adj_internal.h b/src/vnet/adj/adj_internal.h index 55afe55fa79..efaa11d5346 100644 --- a/src/vnet/adj/adj_internal.h +++ b/src/vnet/adj/adj_internal.h @@ -126,6 +126,16 @@ extern void adj_mcast_remove(fib_protocol_t proto, u32 sw_if_index); extern u32 adj_dpo_get_urpf(const dpo_id_t *dpo); -extern void adj_delegate_vft_lock_gone(ip_adjacency_t *adj); + +/* + * Adj BFD + */ +extern int adj_bfd_is_up (adj_index_t ai); + +/* + * Adj delegates + */ +extern void adj_delegate_adj_deleted(ip_adjacency_t *adj); +extern u8* adj_delegate_format(u8* s, ip_adjacency_t *adj); #endif diff --git a/src/vnet/fib/fib_node.h b/src/vnet/fib/fib_node.h index 532efd54dee..ec3b542b019 100644 --- a/src/vnet/fib/fib_node.h +++ b/src/vnet/fib/fib_node.h @@ -56,24 +56,24 @@ typedef enum fib_node_type_t_ { #define FIB_NODE_TYPE_MAX (FIB_NODE_TYPE_LAST + 1) -#define FIB_NODE_TYPES { \ - [FIB_NODE_TYPE_ENTRY] = "entry", \ - [FIB_NODE_TYPE_MFIB_ENTRY] = "mfib-entry", \ - [FIB_NODE_TYPE_WALK] = "walk", \ - [FIB_NODE_TYPE_PATH_LIST] = "path-list", \ - [FIB_NODE_TYPE_PATH] = "path", \ - [FIB_NODE_TYPE_MPLS_ENTRY] = "mpls-entry", \ - [FIB_NODE_TYPE_MPLS_TUNNEL] = "mpls-tunnel", \ - [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", \ - [FIB_NODE_TYPE_UDP_ENCAP] = "udp-encap", \ - [FIB_NODE_TYPE_BIER_FMASK] = "bier-fmask", \ - [FIB_NODE_TYPE_BIER_ENTRY] = "bier-entry", \ +#define FIB_NODE_TYPES { \ + [FIB_NODE_TYPE_ENTRY] = "entry", \ + [FIB_NODE_TYPE_MFIB_ENTRY] = "mfib-entry", \ + [FIB_NODE_TYPE_WALK] = "walk", \ + [FIB_NODE_TYPE_PATH_LIST] = "path-list", \ + [FIB_NODE_TYPE_PATH] = "path", \ + [FIB_NODE_TYPE_MPLS_ENTRY] = "mpls-entry", \ + [FIB_NODE_TYPE_MPLS_TUNNEL] = "mpls-tunnel", \ + [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", \ + [FIB_NODE_TYPE_UDP_ENCAP] = "udp-encap", \ + [FIB_NODE_TYPE_BIER_FMASK] = "bier-fmask", \ + [FIB_NODE_TYPE_BIER_ENTRY] = "bier-entry", \ } /** @@ -293,12 +293,6 @@ typedef struct fib_node_t_ { * Some pad space the concrete/derived type is free to use */ u16 fn_pad; - /** - * The node's VFT. - * we could store the type here instead, and lookup the VFT using that. But - * I like this better, - */ -// const fib_node_vft_t *fn_vft; /** * Vector of nodes that depend upon/use/share this node |