VOM: mroutes
[vpp.git] / src / vnet / fib / fib_bfd.c
1 /*
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
23 static fib_bfd_state_t
24 fib_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
38 static void
39 fib_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  */
56 void
57 fib_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,
112                                               FIB_ENTRY_FLAG_NONE);
113             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
164              * usource the entry and remove the BFD tracking deletgate
165              */
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
183 static clib_error_t *
184 fib_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
196 VLIB_INIT_FUNCTION (fib_bfd_main_init);