Typos. A bunch of typos I've been collecting.
[vpp.git] / src / vnet / fib / fib_entry_src_adj.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 "fib_entry.h"
17 #include "fib_entry_src.h"
18 #include "fib_path_list.h"
19 #include "fib_table.h"
20 #include "fib_entry_cover.h"
21 #include "fib_attached_export.h"
22 #include "fib_path_ext.h"
23
24 /**
25  * Source initialisation Function
26  */
27 static void
28 fib_entry_src_adj_init (fib_entry_src_t *src)
29 {
30     src->u.adj.fesa_cover = FIB_NODE_INDEX_INVALID;
31     src->u.adj.fesa_sibling = FIB_NODE_INDEX_INVALID;
32 }
33
34 static void
35 fib_entry_src_adj_path_add (fib_entry_src_t *src,
36                             const fib_entry_t *entry,
37                             fib_path_list_flags_t pl_flags,
38                             const fib_route_path_t *paths)
39 {
40     const fib_route_path_t *rpath;
41
42     if (FIB_NODE_INDEX_INVALID == src->fes_pl)
43     {
44         src->fes_pl = fib_path_list_create(pl_flags, paths);
45     }
46     else
47     {
48         src->fes_pl = fib_path_list_copy_and_path_add(src->fes_pl,
49                                                       pl_flags,
50                                                       paths);
51     }
52
53     /*
54      * resolve the existing extensions
55      */
56     fib_path_ext_list_resolve(&src->fes_path_exts, src->fes_pl);
57
58     /*
59      * and new extensions
60      */
61     vec_foreach(rpath, paths)
62     {
63         fib_path_ext_list_insert(&src->fes_path_exts,
64                                  src->fes_pl,
65                                  FIB_PATH_EXT_ADJ,
66                                  rpath);
67     }
68 }
69
70 static void
71 fib_entry_src_adj_path_remove (fib_entry_src_t *src,
72                                fib_path_list_flags_t pl_flags,
73                                const fib_route_path_t *rpaths)
74 {
75     const fib_route_path_t *rpath;
76
77     if (FIB_NODE_INDEX_INVALID != src->fes_pl)
78     {
79         src->fes_pl = fib_path_list_copy_and_path_remove(src->fes_pl,
80                                                          pl_flags,
81                                                          rpaths);
82     }
83
84     /*
85      * remove the path-extension for the path
86      */
87     vec_foreach(rpath, rpaths)
88     {
89         fib_path_ext_list_remove(&src->fes_path_exts, FIB_PATH_EXT_ADJ, rpath);
90     };
91     /*
92      * resolve the remaining extensions
93      */
94     fib_path_ext_list_resolve(&src->fes_path_exts, src->fes_pl);
95 }
96
97 static void
98 fib_entry_src_adj_path_swap (fib_entry_src_t *src,
99                              const fib_entry_t *entry,
100                              fib_path_list_flags_t pl_flags,
101                              const fib_route_path_t *paths)
102 {
103     const fib_route_path_t *rpath;
104
105     /*
106      * flush all the old extensions before we create a brand new path-list
107      */
108     fib_path_ext_list_flush(&src->fes_path_exts);
109
110     src->fes_pl = fib_path_list_create(pl_flags, paths);
111
112     /*
113      * and new extensions
114      */
115     vec_foreach(rpath, paths)
116     {
117         fib_path_ext_list_push_back(&src->fes_path_exts,
118                                     src->fes_pl,
119                                     FIB_PATH_EXT_ADJ,
120                                     rpath);
121     }
122 }
123
124 static void
125 fib_entry_src_adj_remove (fib_entry_src_t *src)
126 {
127     src->fes_pl = FIB_NODE_INDEX_INVALID;
128 }
129
130 /*
131  * Add a path-extension indicating whether this path is resolved,
132  * because it passed the refinement check
133  */
134 static void
135 fib_enty_src_adj_update_path_ext (fib_entry_src_t *src,
136                                   fib_node_index_t path_index,
137                                   fib_path_ext_adj_flags_t flags)
138 {
139     fib_path_ext_t *path_ext;
140
141     path_ext = fib_path_ext_list_find_by_path_index(&src->fes_path_exts,
142                                                     path_index);
143
144     if (NULL != path_ext)
145     {
146         path_ext->fpe_adj_flags = flags;
147     }
148     else
149     {
150         ASSERT(!"no path extension");
151     }
152 }
153
154 typedef struct fib_entry_src_path_list_walk_cxt_t_
155 {
156     fib_entry_src_t *src;
157     u32 cover_itf;
158     fib_path_ext_adj_flags_t flags;
159 } fib_entry_src_path_list_walk_cxt_t;
160
161 static fib_path_list_walk_rc_t
162 fib_entry_src_adj_path_list_walk (fib_node_index_t pl_index,
163                                   fib_node_index_t path_index,
164                                   void *arg)
165 {
166     fib_entry_src_path_list_walk_cxt_t *ctx;
167     u32 adj_itf;
168
169     ctx = arg;
170     adj_itf = fib_path_get_resolving_interface(path_index);
171
172     if (ctx->cover_itf == adj_itf)
173     {
174         fib_enty_src_adj_update_path_ext(ctx->src, path_index,
175                                          FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER);
176         ctx->flags |= FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER;
177     }
178     else
179     {
180         /*
181          * if the interface the adj is on is unnumbered to the
182          * cover's, then allow that too.
183          */
184         vnet_sw_interface_t *swif;
185
186         swif = vnet_get_sw_interface (vnet_get_main(), adj_itf);
187
188         if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED &&
189             ctx->cover_itf == swif->unnumbered_sw_if_index)
190         {
191             fib_enty_src_adj_update_path_ext(ctx->src, path_index,
192                                              FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER);
193             ctx->flags |= FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER;
194         }
195         else
196         {
197             fib_enty_src_adj_update_path_ext(ctx->src, path_index,
198                                              FIB_PATH_EXT_ADJ_FLAG_NONE);
199         }
200     }
201     return (FIB_PATH_LIST_WALK_CONTINUE);
202 }
203
204 static int
205 fib_entry_src_adj_activate (fib_entry_src_t *src,
206                             const fib_entry_t *fib_entry)
207 {
208     fib_entry_t *cover;
209
210     /*
211      * find the covering prefix. become a dependent thereof.
212      * there should always be a cover, though it may be the default route.
213      */
214     src->u.adj.fesa_cover = fib_table_get_less_specific(fib_entry->fe_fib_index,
215                                                         &fib_entry->fe_prefix);
216
217     ASSERT(FIB_NODE_INDEX_INVALID != src->u.adj.fesa_cover);
218     ASSERT(fib_entry_get_index(fib_entry) != src->u.adj.fesa_cover);
219
220     cover = fib_entry_get(src->u.adj.fesa_cover);
221
222     ASSERT(cover != fib_entry);
223
224     src->u.adj.fesa_sibling =
225         fib_entry_cover_track(cover,
226                               fib_entry_get_index(fib_entry));
227
228     /*
229      * if the cover is attached on the same interface as this adj source then
230      * install the FIB entry via the adj. otherwise install a drop.
231      * This prevents ARP/ND entries that on interface X that do not belong
232      * on X's subnet from being added to the FIB. To do so would allow
233      * nefarious gratuitous ARP requests from attracting traffic to the sender.
234      *
235      * and yes, I really do mean attached and not connected.
236      * this abomination;
237      *   ip route add 10.0.0.0/24 Eth0
238      * is attached. and we want adj-fibs to install on Eth0.
239      */
240     if (FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags_i(cover))
241     {
242         fib_entry_src_path_list_walk_cxt_t ctx = {
243             .cover_itf = fib_entry_get_resolving_interface(src->u.adj.fesa_cover),
244             .flags = FIB_PATH_EXT_ADJ_FLAG_NONE,
245             .src = src,
246         };
247
248         fib_path_list_walk(src->fes_pl,
249                            fib_entry_src_adj_path_list_walk,
250                            &ctx);
251
252         /*
253          * active the entry is one of the paths refines the cover.
254          */
255         return (FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER & ctx.flags);
256     }
257     return (0);
258 }
259
260 /*
261  * Source re-activate.
262  * Called when the source path lit has changed and the source is still
263  * the best source
264  */
265 static int
266 fib_entry_src_adj_reactivate (fib_entry_src_t *src,
267                               const fib_entry_t *fib_entry)
268 {
269     fib_entry_src_path_list_walk_cxt_t ctx = {
270         .cover_itf = fib_entry_get_resolving_interface(src->u.adj.fesa_cover),
271         .flags = FIB_PATH_EXT_ADJ_FLAG_NONE,
272         .src = src,
273     };
274
275     fib_path_list_walk(src->fes_pl,
276                        fib_entry_src_adj_path_list_walk,
277                        &ctx);
278
279     return (FIB_PATH_EXT_ADJ_FLAG_REFINES_COVER & ctx.flags);
280 }
281
282 /*
283  * Source Deactivate.
284  * Called when the source is no longer best source on the entry
285  */
286 static void
287 fib_entry_src_adj_deactivate (fib_entry_src_t *src,
288                               const fib_entry_t *fib_entry)
289 {
290     fib_entry_t *cover;
291
292     /*
293      * remove the dependency on the covering entry
294      */
295     if (FIB_NODE_INDEX_INVALID == src->u.adj.fesa_cover)
296     {
297         /*
298          * this is the case if the entry is in the non-forwarding trie
299          */
300         return;
301     }
302
303     cover = fib_entry_get(src->u.adj.fesa_cover);
304     fib_entry_cover_untrack(cover, src->u.adj.fesa_sibling);
305
306     /*
307      * tell the cover this entry no longer needs exporting
308      */
309     fib_attached_export_covered_removed(cover, fib_entry_get_index(fib_entry));
310
311     src->u.adj.fesa_cover = FIB_NODE_INDEX_INVALID;
312 }
313
314 static u8*
315 fib_entry_src_adj_format (fib_entry_src_t *src,
316                          u8* s)
317 {
318     return (format(s, " cover:%d", src->u.adj.fesa_cover));
319 }
320
321 static void
322 fib_entry_src_adj_installed (fib_entry_src_t *src,
323                              const fib_entry_t *fib_entry)
324 {
325     /*
326      * The adj source now rules! poke our cover to get exported
327      */
328     fib_entry_t *cover;
329
330     ASSERT(FIB_NODE_INDEX_INVALID != src->u.adj.fesa_cover);
331     cover = fib_entry_get(src->u.adj.fesa_cover);
332
333     fib_attached_export_covered_added(cover,
334                                       fib_entry_get_index(fib_entry));
335 }
336
337 static fib_entry_src_cover_res_t
338 fib_entry_src_adj_cover_change (fib_entry_src_t *src,
339                                 const fib_entry_t *fib_entry)
340 {
341     fib_entry_src_cover_res_t res = {
342         .install = !0,
343         .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
344     };
345
346     fib_entry_src_adj_deactivate(src, fib_entry);
347
348     res.install = fib_entry_src_adj_activate(src, fib_entry);
349
350     if (res.install) {
351         /*
352          * ADJ fib can install
353          */
354         res.bw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE;
355     }
356
357     FIB_ENTRY_DBG(fib_entry, "adj-src-cover-changed");
358     return (res);
359 }
360
361 /*
362  * fib_entry_src_adj_cover_update
363  */
364 static fib_entry_src_cover_res_t
365 fib_entry_src_adj_cover_update (fib_entry_src_t *src,
366                                 const fib_entry_t *fib_entry)
367 {
368     /*
369      * the cover has updated, i.e. its forwarding or flags
370      * have changed. don't deactivate/activate here, since this
371      * prefix is updated during the covers walk.
372      */
373     fib_entry_src_cover_res_t res = {
374         .install = !0,
375         .bw_reason = FIB_NODE_BW_REASON_FLAG_NONE,
376     };
377     fib_entry_t *cover;
378
379     ASSERT(FIB_NODE_INDEX_INVALID != src->u.adj.fesa_cover);
380
381     cover = fib_entry_get(src->u.adj.fesa_cover);
382
383     res.install = (FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags_i(cover));
384
385     FIB_ENTRY_DBG(fib_entry, "adj-src-cover-updated");
386
387     return (res);
388 }
389
390 const static fib_entry_src_vft_t adj_src_vft = {
391     .fesv_init = fib_entry_src_adj_init,
392     .fesv_path_swap = fib_entry_src_adj_path_swap,
393     .fesv_path_add = fib_entry_src_adj_path_add,
394     .fesv_path_remove = fib_entry_src_adj_path_remove,
395     .fesv_remove = fib_entry_src_adj_remove,
396     .fesv_activate = fib_entry_src_adj_activate,
397     .fesv_deactivate = fib_entry_src_adj_deactivate,
398     .fesv_reactivate = fib_entry_src_adj_reactivate,
399     .fesv_format = fib_entry_src_adj_format,
400     .fesv_installed = fib_entry_src_adj_installed,
401     .fesv_cover_change = fib_entry_src_adj_cover_change,
402     .fesv_cover_update = fib_entry_src_adj_cover_update,
403 };
404
405 void
406 fib_entry_src_adj_register (void)
407 {
408     fib_entry_src_register(FIB_SOURCE_ADJ, &adj_src_vft);
409 }