X-Git-Url: https://gerrit.fd.io/r/gitweb?p=vpp.git;a=blobdiff_plain;f=src%2Fvnet%2Fadj%2Fadj_bfd.c;h=b7ff64dcccf4337c56966770168635d454a86061;hp=3d294c4646ed653b2ab5f46702c0db28938ceb47;hb=8feeaff56;hpb=909c26bda66313b86168dda31003f76410c1d746 diff --git a/src/vnet/adj/adj_bfd.c b/src/vnet/adj/adj_bfd.c index 3d294c4646e..b7ff64dcccf 100644 --- a/src/vnet/adj/adj_bfd.c +++ b/src/vnet/adj/adj_bfd.c @@ -19,6 +19,64 @@ #include #include +/** + * 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; + +#define ADJ_BFD_STATES { \ + [ADJ_BFD_STATE_DOWN] = "down", \ + [ADJ_BFD_STATE_UP] = "up", \ +} + +static const char *adj_bfd_state_names[] = ADJ_BFD_STATES; + +/** + * BFD delegate daa + */ +typedef struct adj_bfd_delegate_t_ +{ + /** + * 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 (pool_elt_at_index(abd_pool, ad->ad_index)); + } + return (NULL); +} + +static inline const adj_bfd_delegate_t* +adj_bfd_from_const_base (const adj_delegate_t *ad) +{ + if (NULL != ad) + { + return (pool_elt_at_index(abd_pool, ad->ad_index)); + } + return (NULL); +} + static adj_bfd_state_t adj_bfd_bfd_state_to_fib (bfd_state_e bstate) { @@ -57,6 +115,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; @@ -102,34 +161,40 @@ adj_bfd_notify (bfd_listen_event_e event, { /* * lock the adj. add the delegate. - * Lockinging the adj prevents it being removed and thus maintains + * Locking the adj prevents it being removed and thus maintains * the BFD derived states */ 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. - * If we set it down then we get traffic loss on new children. - * if we walk then we lose traffic for existing children. Wait - * for the first BFD UP/DOWN before we let the session's state - * influence forwarding. + * it would be best here if we could ignore this create and just + * wait for the first update, but this is not possible because + * BFD sessions are created in the down state, and can remain this + * way without transitioning to another state if the peer is + * unresponsive. So we have to assume down and wait for up. */ - aed->ad_bfd_state = ADJ_BFD_STATE_UP; - aed->ad_bfd_index = session->bs_idx; + abd->abd_state = ADJ_BFD_STATE_DOWN; + abd->abd_index = session->bs_idx; + + adj_delegate_add(adj_get(ai), ADJ_DELEGATE_BFD, abd - abd_pool); + adj_bfd_update_walk(ai); } break; case BFD_LISTEN_EVENT_UPDATE: /* - * state change up/dowm and + * state change up/down 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 +207,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 + * remove the BFD tracking delegate, 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,6 +235,48 @@ 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:%s index:%d]", + adj_bfd_state_names[abd->abd_state], + abd->abd_index); + + return (s); +} + +const static adj_delegate_vft_t adj_delegate_vft = { + .adv_format = adj_delegate_fmt_bfd, +}; + static clib_error_t * adj_bfd_main_init (vlib_main_t * vm) { @@ -178,6 +287,8 @@ adj_bfd_main_init (vlib_main_t * vm) bfd_register_listener(adj_bfd_notify); + adj_delegate_register_type (ADJ_DELEGATE_BFD, &adj_delegate_vft); + return (error); }