blob: b7ff64dcccf4337c56966770168635d454a86061 [file] [log] [blame]
Neale Ranns88fc83e2017-04-05 08:11:14 -07001/*
2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <vnet/bfd/bfd_main.h>
17
18#include <vnet/adj/adj_delegate.h>
19#include <vnet/adj/adj_nbr.h>
20#include <vnet/fib/fib_walk.h>
21
Neale Rannsd79a43c2018-02-19 02:36:19 -080022/**
23 * Distillation of the BFD session states into a go/no-go for using
24 * the associated tracked adjacency
25 */
26typedef enum adj_bfd_state_t_
27{
28 ADJ_BFD_STATE_DOWN,
29 ADJ_BFD_STATE_UP,
30} adj_bfd_state_t;
31
Neale Ranns4faab212018-07-16 06:12:33 -070032#define ADJ_BFD_STATES { \
33 [ADJ_BFD_STATE_DOWN] = "down", \
34 [ADJ_BFD_STATE_UP] = "up", \
35}
36
37static const char *adj_bfd_state_names[] = ADJ_BFD_STATES;
38
Neale Rannsd79a43c2018-02-19 02:36:19 -080039/**
40 * BFD delegate daa
41 */
42typedef struct adj_bfd_delegate_t_
43{
44 /**
Neale Rannsd79a43c2018-02-19 02:36:19 -080045 * BFD session state
46 */
47 adj_bfd_state_t abd_state;
48
49 /**
50 * BFD session index
51 */
52 u32 abd_index;
53} adj_bfd_delegate_t;
54
55/**
56 * Pool of delegates
57*/
58static adj_bfd_delegate_t *abd_pool;
59
60static inline adj_bfd_delegate_t*
61adj_bfd_from_base (adj_delegate_t *ad)
62{
Neale Ranns76447a72018-02-20 06:25:02 -080063 if (NULL != ad)
Neale Rannsd79a43c2018-02-19 02:36:19 -080064 {
Neale Ranns76447a72018-02-20 06:25:02 -080065 return (pool_elt_at_index(abd_pool, ad->ad_index));
Neale Rannsd79a43c2018-02-19 02:36:19 -080066 }
Neale Ranns76447a72018-02-20 06:25:02 -080067 return (NULL);
Neale Rannsd79a43c2018-02-19 02:36:19 -080068}
69
70static inline const adj_bfd_delegate_t*
71adj_bfd_from_const_base (const adj_delegate_t *ad)
72{
Neale Ranns76447a72018-02-20 06:25:02 -080073 if (NULL != ad)
Neale Rannsd79a43c2018-02-19 02:36:19 -080074 {
Neale Ranns76447a72018-02-20 06:25:02 -080075 return (pool_elt_at_index(abd_pool, ad->ad_index));
Neale Rannsd79a43c2018-02-19 02:36:19 -080076 }
Neale Ranns76447a72018-02-20 06:25:02 -080077 return (NULL);
Neale Rannsd79a43c2018-02-19 02:36:19 -080078}
79
Neale Ranns88fc83e2017-04-05 08:11:14 -070080static adj_bfd_state_t
81adj_bfd_bfd_state_to_fib (bfd_state_e bstate)
82{
83 switch (bstate)
84 {
85 case BFD_STATE_up:
86 return (ADJ_BFD_STATE_UP);
87 case BFD_STATE_down:
88 case BFD_STATE_admin_down:
89 case BFD_STATE_init:
90 return (ADJ_BFD_STATE_DOWN);
91 }
92 return (ADJ_BFD_STATE_DOWN);
93}
94
95static void
96adj_bfd_update_walk (adj_index_t ai)
97{
98 /*
99 * initiate a backwalk of dependent children
100 * to notify of the state change of this adj.
101 */
102 fib_node_back_walk_ctx_t ctx = {
103 .fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE,
104 };
105 fib_walk_sync(FIB_NODE_TYPE_ADJ, ai, &ctx);
106}
107
108/**
109 * @brief Callback function registered with BFD module to receive notifications
110 * of the CRUD of BFD sessions
111 * would be static but for the fact it's called from the unit-tests
112 */
113void
114adj_bfd_notify (bfd_listen_event_e event,
115 const bfd_session_t *session)
116{
117 const bfd_udp_key_t *key;
Neale Rannsd79a43c2018-02-19 02:36:19 -0800118 adj_bfd_delegate_t *abd;
Neale Ranns88fc83e2017-04-05 08:11:14 -0700119 fib_protocol_t fproto;
120 adj_delegate_t *aed;
121 adj_index_t ai;
122
123 if (BFD_HOP_TYPE_SINGLE != session->hop_type)
124 {
125 /*
126 * multi-hop BFD sessions attach directly to the FIB entry
127 * single-hop adj to the associate adjacency.
128 */
129 return;
130 }
131
132 key = &session->udp.key;
133
134 fproto = (ip46_address_is_ip4 (&key->peer_addr) ?
135 FIB_PROTOCOL_IP4:
136 FIB_PROTOCOL_IP6);
137
138 /*
139 * find the adj that corresponds to the BFD session.
140 */
141 ai = adj_nbr_add_or_lock(fproto,
142 fib_proto_to_link(fproto),
143 &key->peer_addr,
144 key->sw_if_index);
145
146 switch (event)
147 {
148 case BFD_LISTEN_EVENT_CREATE:
149 /*
150 * The creation of a new session
151 */
152 if ((ADJ_INDEX_INVALID != ai) &&
153 (aed = adj_delegate_get(adj_get(ai),
154 ADJ_DELEGATE_BFD)))
155 {
156 /*
157 * already got state for this adj
158 */
159 }
160 else
161 {
162 /*
163 * lock the adj. add the delegate.
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700164 * Locking the adj prevents it being removed and thus maintains
Neale Ranns88fc83e2017-04-05 08:11:14 -0700165 * the BFD derived states
166 */
167 adj_lock(ai);
168
Neale Rannsd79a43c2018-02-19 02:36:19 -0800169 /*
170 * allocate and init a new delegate struct
171 */
172 pool_get(abd_pool, abd);
Neale Ranns88fc83e2017-04-05 08:11:14 -0700173
174 /*
Neale Ranns4faab212018-07-16 06:12:33 -0700175 * it would be best here if we could ignore this create and just
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700176 * wait for the first update, but this is not possible because
Neale Ranns4faab212018-07-16 06:12:33 -0700177 * BFD sessions are created in the down state, and can remain this
178 * way without transitioning to another state if the peer is
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700179 * unresponsive. So we have to assume down and wait for up.
Neale Ranns88fc83e2017-04-05 08:11:14 -0700180 */
Neale Ranns4faab212018-07-16 06:12:33 -0700181 abd->abd_state = ADJ_BFD_STATE_DOWN;
Neale Rannsd79a43c2018-02-19 02:36:19 -0800182 abd->abd_index = session->bs_idx;
183
Neale Ranns76447a72018-02-20 06:25:02 -0800184 adj_delegate_add(adj_get(ai), ADJ_DELEGATE_BFD, abd - abd_pool);
Neale Ranns4faab212018-07-16 06:12:33 -0700185 adj_bfd_update_walk(ai);
Neale Ranns88fc83e2017-04-05 08:11:14 -0700186 }
187 break;
188
189 case BFD_LISTEN_EVENT_UPDATE:
190 /*
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700191 * state change up/down and
Neale Ranns88fc83e2017-04-05 08:11:14 -0700192 */
Neale Rannsd79a43c2018-02-19 02:36:19 -0800193 abd = adj_bfd_from_base(adj_delegate_get(adj_get(ai), ADJ_DELEGATE_BFD));
Neale Ranns88fc83e2017-04-05 08:11:14 -0700194
Neale Rannsd79a43c2018-02-19 02:36:19 -0800195 if (NULL != abd)
Neale Ranns88fc83e2017-04-05 08:11:14 -0700196 {
Neale Rannsd79a43c2018-02-19 02:36:19 -0800197 abd->abd_state = adj_bfd_bfd_state_to_fib(session->local_state);
Neale Ranns88fc83e2017-04-05 08:11:14 -0700198 adj_bfd_update_walk(ai);
199 }
200 /*
201 * else
202 * not an adj with BFD state
203 */
204 break;
205
206 case BFD_LISTEN_EVENT_DELETE:
207 /*
208 * session has been removed.
209 */
Neale Rannsd79a43c2018-02-19 02:36:19 -0800210 abd = adj_bfd_from_base(adj_delegate_get(adj_get(ai), ADJ_DELEGATE_BFD));
Neale Ranns88fc83e2017-04-05 08:11:14 -0700211
Neale Rannsd79a43c2018-02-19 02:36:19 -0800212 if (NULL != abd)
Neale Ranns88fc83e2017-04-05 08:11:14 -0700213 {
214 /*
215 * has an associated BFD tracking delegate
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700216 * remove the BFD tracking delegate, update children, then
Neale Ranns88fc83e2017-04-05 08:11:14 -0700217 * unlock the adj
218 */
Neale Rannsd79a43c2018-02-19 02:36:19 -0800219 adj_delegate_remove(ai, ADJ_DELEGATE_BFD);
220 pool_put(abd_pool, abd);
Neale Ranns88fc83e2017-04-05 08:11:14 -0700221
222 adj_bfd_update_walk(ai);
223 adj_unlock(ai);
224 }
225 /*
226 * else
227 * no BFD associated state
228 */
229 break;
230 }
231
232 /*
233 * unlock match of the add-or-lock at the start
234 */
235 adj_unlock(ai);
236}
237
Neale Rannsd79a43c2018-02-19 02:36:19 -0800238int
239adj_bfd_is_up (adj_index_t ai)
240{
241 const adj_bfd_delegate_t *abd;
242
243 abd = adj_bfd_from_base(adj_delegate_get(adj_get(ai), ADJ_DELEGATE_BFD));
244
245 if (NULL == abd)
246 {
247 /*
248 * no BFD tracking - resolved
249 */
250 return (!0);
251 }
252 else
253 {
254 /*
255 * defer to the state of the BFD tracking
256 */
257 return (ADJ_BFD_STATE_UP == abd->abd_state);
258 }
259}
260
Ole Troan793c7fe2018-02-15 16:14:56 +0100261/**
262 * Print a delegate that represents BFD tracking
263 */
264static u8 *
265adj_delegate_fmt_bfd (const adj_delegate_t *aed, u8 *s)
266{
Neale Rannsd79a43c2018-02-19 02:36:19 -0800267 const adj_bfd_delegate_t *abd = adj_bfd_from_const_base(aed);
268
Neale Ranns4faab212018-07-16 06:12:33 -0700269 s = format(s, "BFD:[state:%s index:%d]",
270 adj_bfd_state_names[abd->abd_state],
Neale Rannsd79a43c2018-02-19 02:36:19 -0800271 abd->abd_index);
Ole Troan793c7fe2018-02-15 16:14:56 +0100272
273 return (s);
274}
275
276const static adj_delegate_vft_t adj_delegate_vft = {
277 .adv_format = adj_delegate_fmt_bfd,
278};
279
Neale Ranns88fc83e2017-04-05 08:11:14 -0700280static clib_error_t *
281adj_bfd_main_init (vlib_main_t * vm)
282{
283 clib_error_t * error = NULL;
284
285 if ((error = vlib_call_init_function (vm, bfd_main_init)))
286 return (error);
287
288 bfd_register_listener(adj_bfd_notify);
289
Ole Troan793c7fe2018-02-15 16:14:56 +0100290 adj_delegate_register_type (ADJ_DELEGATE_BFD, &adj_delegate_vft);
291
Neale Ranns88fc83e2017-04-05 08:11:14 -0700292 return (error);
293}
294
295VLIB_INIT_FUNCTION (adj_bfd_main_init);