blob: ae7ceec1a6bf4123eb21931f8ed5994690da1e65 [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/fib/fib_entry_delegate.h>
19#include <vnet/fib/fib_entry.h>
20#include <vnet/fib/fib_table.h>
21#include <vnet/fib/fib_walk.h>
22
23static fib_bfd_state_t
24fib_bfd_bfd_state_to_fib (bfd_state_e bstate)
25{
26 switch (bstate)
27 {
28 case BFD_STATE_up:
29 return (FIB_BFD_STATE_UP);
30 case BFD_STATE_down:
31 case BFD_STATE_admin_down:
32 case BFD_STATE_init:
33 return (FIB_BFD_STATE_DOWN);
34 }
35 return (FIB_BFD_STATE_DOWN);
36}
37
38static void
39fib_bfd_update_walk (fib_node_index_t fei)
40{
41 /*
42 * initiate a backwalk of dependent children
43 * to notify of the state change of this entry.
44 */
45 fib_node_back_walk_ctx_t ctx = {
46 .fnbw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE,
47 };
48 fib_walk_sync(FIB_NODE_TYPE_ENTRY, fei, &ctx);
49}
50
51/**
52 * @brief Callback function registered with BFD module to receive notifications
53 * of the CRUD of BFD sessions
54 * would be static but for the fact it's called from the unit-tests
55 */
56void
57fib_bfd_notify (bfd_listen_event_e event,
58 const bfd_session_t *session)
59{
60 fib_entry_delegate_t *fed;
61 const bfd_udp_key_t *key;
62 fib_node_index_t fei;
63
64 if (BFD_HOP_TYPE_MULTI != session->hop_type)
65 {
66 /*
67 * multi-hop BFD sessions attach directly to the FIB entry
68 * single-hop adj to the associate adjacency.
69 */
70 return;
71 }
72
73 key = &session->udp.key;
74
75 fib_prefix_t pfx = {
76 .fp_addr = key->peer_addr,
77 .fp_proto = (ip46_address_is_ip4 (&key->peer_addr) ?
78 FIB_PROTOCOL_IP4:
79 FIB_PROTOCOL_IP6),
80 .fp_len = (ip46_address_is_ip4 (&key->peer_addr) ?
81 32:
82 128),
83 };
84
85 /*
86 * get the FIB entry
87 */
88 fei = fib_table_lookup_exact_match(key->fib_index, &pfx);
89
90 switch (event)
91 {
92 case BFD_LISTEN_EVENT_CREATE:
93 /*
94 * The creation of a new session
95 */
96 if ((FIB_NODE_INDEX_INVALID != fei) &&
97 (fed = fib_entry_delegate_get(fib_entry_get(fei),
98 FIB_ENTRY_DELEGATE_BFD)))
99 {
100 /*
101 * already got state for this entry
102 */
103 }
104 else
105 {
106 /*
107 * source and lock the entry. add the delegate
108 */
109 fei = fib_table_entry_special_add(key->fib_index,
110 &pfx,
111 FIB_SOURCE_RR,
Neale Rannsa0558302017-04-13 00:44:52 -0700112 FIB_ENTRY_FLAG_NONE);
Neale Ranns88fc83e2017-04-05 08:11:14 -0700113 fib_entry_lock(fei);
114
115 fed = fib_entry_delegate_find_or_add(fib_entry_get(fei),
116 FIB_ENTRY_DELEGATE_BFD);
117
118 /*
119 * pretend the session is up and skip the walk.
120 * If we set it down then we get traffic loss on new children.
121 * if we walk then we lose traffic for existing children. Wait
122 * for the first BFD UP/DOWN before we let the session's state
123 * influence forwarding.
124 */
125 fed->fd_bfd_state = FIB_BFD_STATE_UP;
126 }
127 break;
128
129 case BFD_LISTEN_EVENT_UPDATE:
130 /*
131 * state change up/dowm and
132 */
133 ASSERT(FIB_NODE_INDEX_INVALID != fei);
134
135 fed = fib_entry_delegate_get(fib_entry_get(fei),
136 FIB_ENTRY_DELEGATE_BFD);
137
138 if (NULL != fed)
139 {
140 fed->fd_bfd_state = fib_bfd_bfd_state_to_fib(session->local_state);
141 fib_bfd_update_walk(fei);
142 }
143 /*
144 * else
145 * no BFD state
146 */
147 break;
148
149 case BFD_LISTEN_EVENT_DELETE:
150 /*
151 * session has been removed.
152 */
153 if (FIB_NODE_INDEX_INVALID == fei)
154 {
155 /*
156 * no FIB entry
157 */
158 }
159 else if (fib_entry_delegate_get(fib_entry_get(fei),
160 FIB_ENTRY_DELEGATE_BFD))
161 {
162 /*
163 * has an associated BFD tracking delegate
Jim Thompsonf324dec2019-04-08 03:22:21 -0500164 * usource the entry and remove the BFD tracking delegate
Neale Ranns88fc83e2017-04-05 08:11:14 -0700165 */
166 fib_entry_delegate_remove(fib_entry_get(fei),
167 FIB_ENTRY_DELEGATE_BFD);
168 fib_bfd_update_walk(fei);
169
170 fib_table_entry_special_remove(key->fib_index,
171 &pfx,
172 FIB_SOURCE_RR);
173 fib_entry_unlock(fei);
174 }
175 /*
176 * else
177 * no BFD associated state
178 */
179 break;
180 }
181}
182
183static clib_error_t *
184fib_bfd_main_init (vlib_main_t * vm)
185{
186 clib_error_t * error = NULL;
187
188 if ((error = vlib_call_init_function (vm, bfd_main_init)))
189 return (error);
190
191 bfd_register_listener(fib_bfd_notify);
192
193 return (error);
194}
195
196VLIB_INIT_FUNCTION (fib_bfd_main_init);