blob: de7abfe447079a4e2fc1f7a02d3ee1c01cd2668d [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
32/**
33 * BFD delegate daa
34 */
35typedef struct adj_bfd_delegate_t_
36{
37 /**
Neale Rannsd79a43c2018-02-19 02:36:19 -080038 * BFD session state
39 */
40 adj_bfd_state_t abd_state;
41
42 /**
43 * BFD session index
44 */
45 u32 abd_index;
46} adj_bfd_delegate_t;
47
48/**
49 * Pool of delegates
50*/
51static adj_bfd_delegate_t *abd_pool;
52
53static inline adj_bfd_delegate_t*
54adj_bfd_from_base (adj_delegate_t *ad)
55{
Neale Ranns76447a72018-02-20 06:25:02 -080056 if (NULL != ad)
Neale Rannsd79a43c2018-02-19 02:36:19 -080057 {
Neale Ranns76447a72018-02-20 06:25:02 -080058 return (pool_elt_at_index(abd_pool, ad->ad_index));
Neale Rannsd79a43c2018-02-19 02:36:19 -080059 }
Neale Ranns76447a72018-02-20 06:25:02 -080060 return (NULL);
Neale Rannsd79a43c2018-02-19 02:36:19 -080061}
62
63static inline const adj_bfd_delegate_t*
64adj_bfd_from_const_base (const adj_delegate_t *ad)
65{
Neale Ranns76447a72018-02-20 06:25:02 -080066 if (NULL != ad)
Neale Rannsd79a43c2018-02-19 02:36:19 -080067 {
Neale Ranns76447a72018-02-20 06:25:02 -080068 return (pool_elt_at_index(abd_pool, ad->ad_index));
Neale Rannsd79a43c2018-02-19 02:36:19 -080069 }
Neale Ranns76447a72018-02-20 06:25:02 -080070 return (NULL);
Neale Rannsd79a43c2018-02-19 02:36:19 -080071}
72
Neale Ranns88fc83e2017-04-05 08:11:14 -070073static adj_bfd_state_t
74adj_bfd_bfd_state_to_fib (bfd_state_e bstate)
75{
76 switch (bstate)
77 {
78 case BFD_STATE_up:
79 return (ADJ_BFD_STATE_UP);
80 case BFD_STATE_down:
81 case BFD_STATE_admin_down:
82 case BFD_STATE_init:
83 return (ADJ_BFD_STATE_DOWN);
84 }
85 return (ADJ_BFD_STATE_DOWN);
86}
87
88static void
89adj_bfd_update_walk (adj_index_t ai)
90{
91 /*
92 * initiate a backwalk of dependent children
93 * to notify of the state change of this adj.
94 */
95 fib_node_back_walk_ctx_t ctx = {
96 .fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE,
97 };
98 fib_walk_sync(FIB_NODE_TYPE_ADJ, ai, &ctx);
99}
100
101/**
102 * @brief Callback function registered with BFD module to receive notifications
103 * of the CRUD of BFD sessions
104 * would be static but for the fact it's called from the unit-tests
105 */
106void
107adj_bfd_notify (bfd_listen_event_e event,
108 const bfd_session_t *session)
109{
110 const bfd_udp_key_t *key;
Neale Rannsd79a43c2018-02-19 02:36:19 -0800111 adj_bfd_delegate_t *abd;
Neale Ranns88fc83e2017-04-05 08:11:14 -0700112 fib_protocol_t fproto;
113 adj_delegate_t *aed;
114 adj_index_t ai;
115
116 if (BFD_HOP_TYPE_SINGLE != session->hop_type)
117 {
118 /*
119 * multi-hop BFD sessions attach directly to the FIB entry
120 * single-hop adj to the associate adjacency.
121 */
122 return;
123 }
124
125 key = &session->udp.key;
126
127 fproto = (ip46_address_is_ip4 (&key->peer_addr) ?
128 FIB_PROTOCOL_IP4:
129 FIB_PROTOCOL_IP6);
130
131 /*
132 * find the adj that corresponds to the BFD session.
133 */
134 ai = adj_nbr_add_or_lock(fproto,
135 fib_proto_to_link(fproto),
136 &key->peer_addr,
137 key->sw_if_index);
138
139 switch (event)
140 {
141 case BFD_LISTEN_EVENT_CREATE:
142 /*
143 * The creation of a new session
144 */
145 if ((ADJ_INDEX_INVALID != ai) &&
146 (aed = adj_delegate_get(adj_get(ai),
147 ADJ_DELEGATE_BFD)))
148 {
149 /*
150 * already got state for this adj
151 */
152 }
153 else
154 {
155 /*
156 * lock the adj. add the delegate.
157 * Lockinging the adj prevents it being removed and thus maintains
158 * the BFD derived states
159 */
160 adj_lock(ai);
161
Neale Rannsd79a43c2018-02-19 02:36:19 -0800162 /*
163 * allocate and init a new delegate struct
164 */
165 pool_get(abd_pool, abd);
Neale Ranns88fc83e2017-04-05 08:11:14 -0700166
167 /*
168 * pretend the session is up and skip the walk.
169 * If we set it down then we get traffic loss on new children.
170 * if we walk then we lose traffic for existing children. Wait
171 * for the first BFD UP/DOWN before we let the session's state
172 * influence forwarding.
173 */
Neale Rannsd79a43c2018-02-19 02:36:19 -0800174 abd->abd_state = ADJ_BFD_STATE_UP;
175 abd->abd_index = session->bs_idx;
176
Neale Ranns76447a72018-02-20 06:25:02 -0800177 adj_delegate_add(adj_get(ai), ADJ_DELEGATE_BFD, abd - abd_pool);
Neale Ranns88fc83e2017-04-05 08:11:14 -0700178 }
179 break;
180
181 case BFD_LISTEN_EVENT_UPDATE:
182 /*
183 * state change up/dowm and
184 */
Neale Rannsd79a43c2018-02-19 02:36:19 -0800185 abd = adj_bfd_from_base(adj_delegate_get(adj_get(ai), ADJ_DELEGATE_BFD));
Neale Ranns88fc83e2017-04-05 08:11:14 -0700186
Neale Rannsd79a43c2018-02-19 02:36:19 -0800187 if (NULL != abd)
Neale Ranns88fc83e2017-04-05 08:11:14 -0700188 {
Neale Rannsd79a43c2018-02-19 02:36:19 -0800189 abd->abd_state = adj_bfd_bfd_state_to_fib(session->local_state);
Neale Ranns88fc83e2017-04-05 08:11:14 -0700190 adj_bfd_update_walk(ai);
191 }
192 /*
193 * else
194 * not an adj with BFD state
195 */
196 break;
197
198 case BFD_LISTEN_EVENT_DELETE:
199 /*
200 * session has been removed.
201 */
Neale Rannsd79a43c2018-02-19 02:36:19 -0800202 abd = adj_bfd_from_base(adj_delegate_get(adj_get(ai), ADJ_DELEGATE_BFD));
Neale Ranns88fc83e2017-04-05 08:11:14 -0700203
Neale Rannsd79a43c2018-02-19 02:36:19 -0800204 if (NULL != abd)
Neale Ranns88fc83e2017-04-05 08:11:14 -0700205 {
206 /*
207 * has an associated BFD tracking delegate
208 * remove the BFD tracking deletgate, update children, then
209 * unlock the adj
210 */
Neale Rannsd79a43c2018-02-19 02:36:19 -0800211 adj_delegate_remove(ai, ADJ_DELEGATE_BFD);
212 pool_put(abd_pool, abd);
Neale Ranns88fc83e2017-04-05 08:11:14 -0700213
214 adj_bfd_update_walk(ai);
215 adj_unlock(ai);
216 }
217 /*
218 * else
219 * no BFD associated state
220 */
221 break;
222 }
223
224 /*
225 * unlock match of the add-or-lock at the start
226 */
227 adj_unlock(ai);
228}
229
Neale Rannsd79a43c2018-02-19 02:36:19 -0800230int
231adj_bfd_is_up (adj_index_t ai)
232{
233 const adj_bfd_delegate_t *abd;
234
235 abd = adj_bfd_from_base(adj_delegate_get(adj_get(ai), ADJ_DELEGATE_BFD));
236
237 if (NULL == abd)
238 {
239 /*
240 * no BFD tracking - resolved
241 */
242 return (!0);
243 }
244 else
245 {
246 /*
247 * defer to the state of the BFD tracking
248 */
249 return (ADJ_BFD_STATE_UP == abd->abd_state);
250 }
251}
252
Ole Troan793c7fe2018-02-15 16:14:56 +0100253/**
254 * Print a delegate that represents BFD tracking
255 */
256static u8 *
257adj_delegate_fmt_bfd (const adj_delegate_t *aed, u8 *s)
258{
Neale Rannsd79a43c2018-02-19 02:36:19 -0800259 const adj_bfd_delegate_t *abd = adj_bfd_from_const_base(aed);
260
Ole Troan793c7fe2018-02-15 16:14:56 +0100261 s = format(s, "BFD:[state:%d index:%d]",
Neale Rannsd79a43c2018-02-19 02:36:19 -0800262 abd->abd_state,
263 abd->abd_index);
Ole Troan793c7fe2018-02-15 16:14:56 +0100264
265 return (s);
266}
267
268const static adj_delegate_vft_t adj_delegate_vft = {
269 .adv_format = adj_delegate_fmt_bfd,
270};
271
Neale Ranns88fc83e2017-04-05 08:11:14 -0700272static clib_error_t *
273adj_bfd_main_init (vlib_main_t * vm)
274{
275 clib_error_t * error = NULL;
276
277 if ((error = vlib_call_init_function (vm, bfd_main_init)))
278 return (error);
279
280 bfd_register_listener(adj_bfd_notify);
281
Ole Troan793c7fe2018-02-15 16:14:56 +0100282 adj_delegate_register_type (ADJ_DELEGATE_BFD, &adj_delegate_vft);
283
Neale Ranns88fc83e2017-04-05 08:11:14 -0700284 return (error);
285}
286
287VLIB_INIT_FUNCTION (adj_bfd_main_init);