Typos. A bunch of typos I've been collecting.
[vpp.git] / src / vnet / fib / fib_entry_src_interpose.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 <vlib/vlib.h>
17 #include <vnet/ip/format.h>
18 #include <vnet/ip/lookup.h>
19 #include <vnet/adj/adj.h>
20 #include <vnet/dpo/drop_dpo.h>
21
22 #include "fib_entry_src.h"
23 #include "fib_entry_src_rr.h"
24 #include "fib_entry_cover.h"
25 #include "fib_entry.h"
26 #include "fib_table.h"
27
28 /*
29  * Source initialisation Function
30  */
31 static void
32 fib_entry_src_interpose_init (fib_entry_src_t *src)
33 {
34     src->u.interpose.fesi_cover = FIB_NODE_INDEX_INVALID;
35     src->u.interpose.fesi_sibling = FIB_NODE_INDEX_INVALID;
36 }
37
38 /*
39  * Source deinitialisation Function
40  */
41 static void
42 fib_entry_src_interpose_deinit (fib_entry_src_t *src)
43 {
44     ASSERT(src->u.interpose.fesi_cover == FIB_NODE_INDEX_INVALID);
45
46     src->u.interpose.fesi_cover = FIB_NODE_INDEX_INVALID;
47     src->u.interpose.fesi_sibling = FIB_NODE_INDEX_INVALID;
48
49     dpo_reset(&src->u.interpose.fesi_dpo);
50 }
51
52 static fib_entry_src_t *
53 fib_entry_src_rr_get_next_best (const fib_entry_src_t *src,
54                                 const fib_entry_t *fib_entry)
55 {
56     fib_entry_src_t *next_src, *best_src = NULL;
57     fib_source_t source;
58
59     FOR_EACH_SRC_ADDED(fib_entry, next_src, source,
60     ({
61         /*
62          * skip to the next best source after this one
63          */
64         if (source <= src->fes_src)
65         {
66             continue;
67         }
68         else
69         {
70             best_src = next_src;
71             break;
72         }
73     }));
74
75     return (best_src);
76 }
77
78 /*
79  * Source activation. Called when the source is the new best source on the entry
80  */
81 static int
82 fib_entry_src_interpose_activate (fib_entry_src_t *src,
83                                   const fib_entry_t *fib_entry)
84 {
85     fib_entry_src_t *best_src;
86     fib_node_index_t old_pl;
87     fib_entry_t *cover;
88
89     old_pl = src->fes_pl;
90     src->fes_pl = FIB_NODE_INDEX_INVALID;
91
92     /*
93      * The goal here is to find a path-list that will contribute forwarding
94      * for the entry.
95      * First check this entry for other sources that have a path-list
96      */
97     best_src = fib_entry_src_rr_get_next_best(src, fib_entry);
98
99     if (NULL != best_src)
100     {
101         const fib_entry_src_vft_t *vft;
102
103         best_src->fes_flags |= FIB_ENTRY_SRC_FLAG_CONTRIBUTING;
104         vft = fib_entry_src_get_vft(best_src);
105         /*
106          * there is another source for this entry. activate it so it
107          * can provide forwarding
108          */
109         if (NULL != vft->fesv_activate)
110         {
111             if (vft->fesv_activate(best_src, fib_entry))
112             {
113                 /*
114                  * next best source activated ok, use its path list
115                  */
116                 src->fes_pl = best_src->fes_pl;
117             }
118         }
119         else
120         {
121             /*
122              * next best source does not require activation, use its path list
123              */
124             src->fes_pl = best_src->fes_pl;
125         }
126     }
127     else
128     {
129         /*
130          * find the covering prefix. become a dependent thereof.
131          * for IP there should always be a cover, though it may be the default route.
132          * For MPLS there is never a cover.
133          */
134         if (FIB_PROTOCOL_MPLS == fib_entry->fe_prefix.fp_proto)
135         {
136             src->fes_pl = fib_path_list_create_special(DPO_PROTO_MPLS,
137                                                        FIB_PATH_LIST_FLAG_DROP,
138                                                        NULL);
139         }
140         else
141         {
142             src->u.interpose.fesi_cover =
143                 fib_table_get_less_specific(fib_entry->fe_fib_index,
144                                             &fib_entry->fe_prefix);
145
146             ASSERT(FIB_NODE_INDEX_INVALID != src->u.interpose.fesi_cover);
147
148             cover = fib_entry_get(src->u.interpose.fesi_cover);
149
150             src->u.interpose.fesi_sibling =
151                 fib_entry_cover_track(cover, fib_entry_get_index(fib_entry));
152
153             /*
154              * if the cover is attached then install an attached-host path
155              * (like an adj-fib). Otherwise inherit the forwarding from the cover
156              */
157             if (FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags_i(cover))
158             {
159                 fib_entry_src_rr_resolve_via_connected(src, fib_entry, cover);
160             }
161             else
162             {
163                 fib_entry_src_rr_use_covers_pl(src, fib_entry, cover);
164             }
165         }
166     }
167
168     fib_path_list_unlock(old_pl);
169     fib_path_list_lock(src->fes_pl);
170
171     /*
172      * return go for install
173      */
174     return (!0);
175 }
176
177 /**
178  * Source Deactivate.
179  * Called when the source is no longer best source on the entry
180  */
181 static void
182 fib_entry_src_interpose_deactivate (fib_entry_src_t *src,
183                                     const fib_entry_t *fib_entry)
184 {
185     fib_entry_t *cover;
186
187     if (FIB_NODE_INDEX_INVALID != src->u.interpose.fesi_cover)
188     {
189         /*
190          * remove the dependency on the covering entry, if that's
191          * what was contributing the path-list
192          */
193         cover = fib_entry_get(src->u.interpose.fesi_cover);
194         fib_entry_cover_untrack(cover, src->u.interpose.fesi_sibling);
195         src->u.interpose.fesi_cover = FIB_NODE_INDEX_INVALID;
196     }
197     else
198     {
199         fib_entry_src_t *best_src;
200
201         best_src = fib_entry_src_rr_get_next_best(src, fib_entry);
202
203         if (best_src)
204         {
205             best_src->fes_flags &= ~FIB_ENTRY_SRC_FLAG_CONTRIBUTING;
206             /*
207              * there is another source for this entry. activate it so it
208              * can provide forwarding
209              */
210             FIB_ENTRY_SRC_VFT_INVOKE(best_src, fesv_deactivate,
211                                      (best_src, fib_entry));
212         }
213     }
214
215     fib_path_list_unlock(src->fes_pl);
216     src->fes_pl = FIB_NODE_INDEX_INVALID;
217     src->fes_entry_flags &= ~FIB_ENTRY_FLAGS_RR_INHERITED;
218 }
219
220 static int
221 fib_entry_src_interpose_reactivate (fib_entry_src_t *src,
222                                     const fib_entry_t *fib_entry)
223 {
224     fib_entry_src_interpose_deactivate(src, fib_entry);
225     return (fib_entry_src_interpose_activate(src, fib_entry));
226 }
227
228 static fib_entry_src_cover_res_t
229 fib_entry_src_interpose_cover_change (fib_entry_src_t *src,
230                                       const fib_entry_t *fib_entry)
231 {
232     fib_entry_src_cover_res_t res = {
233        .install = !0,
234        .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
235     };
236
237     if (FIB_NODE_INDEX_INVALID == src->u.interpose.fesi_cover)
238     {
239        /*
240         * the source may be added, but it is not active
241         * if it is not tracking the cover.
242         */
243        return (res);
244     }
245
246     /*
247      * this function is called when this entry's cover has a more specific
248      * entry inserted beneath it. That does not necessarily mean that this
249      * entry is covered by the new prefix. check that
250      */
251     if (src->u.interpose.fesi_cover !=
252         fib_table_get_less_specific(fib_entry->fe_fib_index,
253                                     &fib_entry->fe_prefix))
254     {
255        fib_entry_src_interpose_deactivate(src, fib_entry);
256        fib_entry_src_interpose_activate(src, fib_entry);
257
258        /*
259         * dependent children need to re-resolve to the new forwarding info
260         */
261        res.bw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE;
262     }
263     return (res);
264 }
265
266 static void
267 fib_entry_src_interpose_add (fib_entry_src_t *src,
268                              const fib_entry_t *entry,
269                              fib_entry_flag_t flags,
270                              dpo_proto_t proto,
271                              const dpo_id_t *dpo)
272 {
273     dpo_copy(&src->u.interpose.fesi_dpo, dpo);
274 }
275
276 static void
277 fib_entry_src_interpose_remove (fib_entry_src_t *src)
278 {
279     dpo_reset(&src->u.interpose.fesi_dpo);
280 }
281
282 static void
283 fib_entry_src_interpose_set_data (fib_entry_src_t *src,
284                                   const fib_entry_t *fib_entry,
285                                   const void *data)
286 {
287     const dpo_id_t *dpo = data;
288
289     dpo_copy(&src->u.interpose.fesi_dpo, dpo);
290 }
291
292 /**
293  * Contribute forwarding to interpose in the chain
294  */
295 const dpo_id_t* fib_entry_src_interpose_contribute(const fib_entry_src_t *src,
296                                                    const fib_entry_t *fib_entry)
297 {
298     return (&src->u.interpose.fesi_dpo);
299 }
300
301 static void
302 fib_entry_src_interpose_copy (const fib_entry_src_t *orig_src,
303                               const fib_entry_t *fib_entry,
304                               fib_entry_src_t *copy_src)
305 {
306     copy_src->u.interpose.fesi_cover = orig_src->u.interpose.fesi_cover;
307
308     if (FIB_NODE_INDEX_INVALID != copy_src->u.interpose.fesi_cover)
309     {
310         fib_entry_t *cover;
311
312         cover = fib_entry_get(orig_src->u.interpose.fesi_cover);
313         copy_src->u.interpose.fesi_sibling =
314             fib_entry_cover_track(cover, fib_entry_get_index(fib_entry));
315     }
316
317     dpo_copy(&copy_src->u.interpose.fesi_dpo,
318              &orig_src->u.interpose.fesi_dpo);
319 }
320
321 static void
322 fib_entry_src_interpose_flag_change (fib_entry_src_t *src,
323                                      const fib_entry_t *fib_entry,
324                                      fib_entry_flag_t new_flags)
325 {
326     if (!(new_flags & FIB_ENTRY_FLAG_INTERPOSE))
327     {
328         /*
329          * stop tracking the source contributing forwarding
330          * and reset the interposer DPO
331          */
332         fib_entry_src_interpose_deactivate(src, fib_entry);
333         fib_entry_src_interpose_deinit(src);
334     }
335 }
336
337 static u8*
338 fib_entry_src_interpose_format (fib_entry_src_t *src,
339                                 u8* s)
340 {
341     s = format(s, " cover:%d interpose:\n%U%U",
342                src->u.interpose.fesi_cover,
343                format_white_space, 6,
344                format_dpo_id, &src->u.interpose.fesi_dpo, 8);
345
346     return (s);
347 }
348
349 const static fib_entry_src_vft_t interpose_src_vft = {
350     .fesv_init = fib_entry_src_interpose_init,
351     .fesv_deinit = fib_entry_src_interpose_deinit,
352     .fesv_activate = fib_entry_src_interpose_activate,
353     .fesv_reactivate = fib_entry_src_interpose_reactivate,
354     .fesv_deactivate = fib_entry_src_interpose_deactivate,
355     .fesv_cover_change = fib_entry_src_interpose_cover_change,
356     .fesv_cover_update = fib_entry_src_rr_cover_update,
357     .fesv_format = fib_entry_src_interpose_format,
358     .fesv_add = fib_entry_src_interpose_add,
359     .fesv_remove = fib_entry_src_interpose_remove,
360     .fesv_contribute_interpose = fib_entry_src_interpose_contribute,
361     .fesv_set_data = fib_entry_src_interpose_set_data,
362     .fesv_copy = fib_entry_src_interpose_copy,
363     .fesv_flags_change = fib_entry_src_interpose_flag_change,
364 };
365
366 void
367 fib_entry_src_interpose_register (void)
368 {
369     fib_entry_src_register(FIB_SOURCE_INTERPOSE, &interpose_src_vft);
370 }