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