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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include <vnet/fib/fib_entry.h>
17 #include <vnet/fib/fib_table.h>
19 #include "fib_attached_export.h"
20 #include "fib_entry_cover.h"
21 #include "fib_entry_src.h"
24 * A description of the need to import routes from the export table
26 typedef struct fib_ae_import_t_
29 * The entry in the epxort table that this importer
30 * is importing covereds from
32 fib_node_index_t faei_export_entry;
35 * The attached entry in the import table
37 fib_node_index_t faei_import_entry;
39 * the sibling index on the cover
41 u32 faei_export_sibling;
44 * The index of the exporter tracker. Not set if the
45 * export entry is not valid for export
47 fib_node_index_t faei_exporter;
50 * A vector/list of imported entry indicies
52 fib_node_index_t *faei_importeds;
55 * The FIB index and prefix we are tracking
57 fib_node_index_t faei_export_fib;
58 fib_prefix_t faei_prefix;
61 * The FIB index we are importing into
63 fib_node_index_t faei_import_fib;
67 * A description of the need to export routes to one or more export tables
69 typedef struct fib_ae_export_t_ {
71 * The vector/list of import tracker indicies
73 fib_node_index_t *faee_importers;
76 * THe connected entry this export is acting on behalf of
78 fib_node_index_t faee_ei;
81 * Reference counting locks
87 * memory pools for the importers and exportes
89 static fib_ae_import_t *fib_ae_import_pool;
90 static fib_ae_export_t *fib_ae_export_pool;
92 static fib_ae_export_t *
93 fib_entry_ae_add_or_lock (fib_node_index_t connected)
95 fib_ae_export_t *export;
98 entry = fib_entry_get(connected);
100 if (FIB_NODE_INDEX_INVALID == entry->fe_export)
102 pool_get(fib_ae_export_pool, export);
103 memset(export, 0, sizeof(*export));
105 entry->fe_export = (export - fib_ae_export_pool);
106 export->faee_ei = connected;
110 export = pool_elt_at_index(fib_ae_export_pool, entry->fe_export);
113 export->faee_locks++;
119 fib_entry_import_remove (fib_ae_import_t *import,
120 fib_node_index_t entry_index)
126 * find the index in the vector of the entry we are removing
128 index = vec_search(import->faei_importeds, entry_index);
130 if (index < vec_len(import->faei_importeds))
133 * this is an entry that was previsouly imported
135 fib_entry_get_prefix(entry_index, &prefix);
137 fib_table_entry_special_remove(import->faei_import_fib,
141 fib_entry_unlock(entry_index);
142 vec_del1(import->faei_importeds, index);
147 fib_entry_import_add (fib_ae_import_t *import,
148 fib_node_index_t entry_index)
150 fib_node_index_t *existing;
154 * ensure we only add the exported entry once, since
155 * sourcing prefixes in the table is reference counted
157 vec_foreach(existing, import->faei_importeds)
159 if (*existing == entry_index)
166 * this is the first time this export entry has been imported
167 * Add it to the import FIB and to the list of importeds
169 fib_entry_get_prefix(entry_index, &prefix);
172 * don't import entries that have the same prefix the import entry
174 if (0 != fib_prefix_cmp(&prefix,
175 &import->faei_prefix))
179 dpo = fib_entry_contribute_ip_forwarding(entry_index);
181 if (dpo_id_is_valid(dpo))
183 fib_table_entry_special_dpo_add(import->faei_import_fib,
186 FIB_ENTRY_FLAG_EXCLUSIVE,
187 load_balance_get_bucket(dpo->dpoi_index, 0));
189 fib_entry_lock(entry_index);
190 vec_add1(import->faei_importeds, entry_index);
194 * the entry currently has no valid forwarding. when it
195 * does it will export itself
201 * Call back when walking a connected prefix's covered prefixes for import
204 fib_entry_covered_walk_import (fib_entry_t *cover,
205 fib_node_index_t covered,
208 fib_ae_import_t *import = ctx;
210 fib_entry_import_add(import, covered);
216 * fib_entry_ae_import_add
218 * Add an importer to a connected entry
221 fib_ae_export_import_add (fib_ae_export_t *export,
222 fib_ae_import_t *import)
226 import->faei_exporter = (export - fib_ae_export_pool);
227 entry = fib_entry_get(export->faee_ei);
229 fib_entry_cover_walk(entry,
230 fib_entry_covered_walk_import,
235 fib_attached_export_import (fib_entry_t *fib_entry,
236 fib_node_index_t export_fib)
238 fib_ae_import_t *import;
240 pool_get(fib_ae_import_pool, import);
242 import->faei_import_fib = fib_entry->fe_fib_index;
243 import->faei_export_fib = export_fib;
244 import->faei_prefix = fib_entry->fe_prefix;
245 import->faei_import_entry = fib_entry_get_index(fib_entry);
246 import->faei_export_sibling = ~0;
249 * do an exact match in the export table
251 import->faei_export_entry =
252 fib_table_lookup_exact_match(import->faei_export_fib,
253 &import->faei_prefix);
255 if (FIB_NODE_INDEX_INVALID == import->faei_export_entry)
258 * no exact matching entry in the export table. can't be good.
259 * track the next best thing
261 import->faei_export_entry =
262 fib_table_lookup(import->faei_export_fib,
263 &import->faei_prefix);
264 import->faei_exporter = FIB_NODE_INDEX_INVALID;
269 * found the entry in the export table. import the
270 * the prefixes that it covers.
271 * only if the prefix found in the export FIB really is
272 * attached do we want to import its covered
274 if (FIB_ENTRY_FLAG_ATTACHED &
275 fib_entry_get_flags_i(fib_entry_get(import->faei_export_entry)))
277 fib_ae_export_t *export;
279 export = fib_entry_ae_add_or_lock(import->faei_export_entry);
280 vec_add1(export->faee_importers, (import - fib_ae_import_pool));
281 fib_ae_export_import_add(export, import);
286 * track the entry in the export table so we can update appropriately
289 import->faei_export_sibling =
290 fib_entry_cover_track(fib_entry_get(import->faei_export_entry),
291 fib_entry_get_index(fib_entry));
293 fib_entry->fe_import = (import - fib_ae_import_pool);
297 * \brief All the imported entries need to be pruged
300 fib_attached_export_purge (fib_entry_t *fib_entry)
302 if (FIB_NODE_INDEX_INVALID != fib_entry->fe_import)
304 fib_node_index_t *import_index;
305 fib_entry_t *export_entry;
306 fib_ae_import_t *import;
307 fib_ae_export_t *export;
309 import = pool_elt_at_index(fib_ae_import_pool,
310 fib_entry->fe_import);
313 * remove each imported entry
315 vec_foreach(import_index, import->faei_importeds)
319 fib_entry_get_prefix(*import_index, &prefix);
321 fib_table_entry_delete(import->faei_import_fib,
324 fib_entry_unlock(*import_index);
326 vec_free(import->faei_importeds);
329 * stop tracking the export entry
331 if (~0 != import->faei_export_sibling)
333 fib_entry_cover_untrack(fib_entry_get(import->faei_export_entry),
334 import->faei_export_sibling);
336 import->faei_export_sibling = ~0;
339 * remove this import tracker from the export's list,
340 * if it is attached to one. It won't be in the case the tracked
341 * export entry is not an attached exact match.
343 if (FIB_NODE_INDEX_INVALID != import->faei_exporter)
345 export_entry = fib_entry_get(import->faei_export_entry);
346 ASSERT(FIB_NODE_INDEX_INVALID != export_entry->fe_export);
347 export = pool_elt_at_index(fib_ae_export_pool, export_entry->fe_export);
349 u32 index = vec_search(export->faee_importers,
350 (import - fib_ae_import_pool));
352 ASSERT(index < vec_len(export->faee_importers));
353 vec_del1(export->faee_importers, index);
356 * free the exporter if there are no longer importers
358 if (0 == --export->faee_locks)
360 pool_put(fib_ae_export_pool, export);
361 export_entry->fe_export = FIB_NODE_INDEX_INVALID;
366 * free the import tracker
368 pool_put(fib_ae_import_pool, import);
369 fib_entry->fe_import = FIB_NODE_INDEX_INVALID;
374 fib_attached_export_covered_added (fib_entry_t *cover,
375 fib_node_index_t covered)
377 if (FIB_NODE_INDEX_INVALID != cover->fe_export)
380 * the covering prefix is exporting to other tables
382 fib_node_index_t *import_index;
383 fib_ae_import_t *import;
384 fib_ae_export_t *export;
386 export = pool_elt_at_index(fib_ae_export_pool, cover->fe_export);
389 * export the covered entry to each of the importers
391 vec_foreach(import_index, export->faee_importers)
393 import = pool_elt_at_index(fib_ae_import_pool, *import_index);
395 fib_entry_import_add(import, covered);
401 fib_attached_export_covered_removed (fib_entry_t *cover,
402 fib_node_index_t covered)
404 if (FIB_NODE_INDEX_INVALID != cover->fe_export)
407 * the covering prefix is exporting to other tables
409 fib_node_index_t *import_index;
410 fib_ae_import_t *import;
411 fib_ae_export_t *export;
413 export = pool_elt_at_index(fib_ae_export_pool, cover->fe_export);
416 * remove the covered entry from each of the importers
418 vec_foreach(import_index, export->faee_importers)
420 import = pool_elt_at_index(fib_ae_import_pool, *import_index);
422 fib_entry_import_remove(import, covered);
428 fib_attached_export_cover_modified_i (fib_entry_t *fib_entry)
430 if (FIB_NODE_INDEX_INVALID != fib_entry->fe_import)
432 fib_ae_import_t *import;
436 * safe the temporaries we need from the existing import
437 * since it will be toast after the purge.
439 import = pool_elt_at_index(fib_ae_import_pool, fib_entry->fe_import);
440 export_fib = import->faei_export_fib;
443 * keep it simple. purge anything that was previously imported.
444 * then re-evaluate the need to import.
446 fib_attached_export_purge(fib_entry);
447 fib_attached_export_import(fib_entry, export_fib);
452 * \brief If this entry is tracking a cover (in another table)
453 * then that cover has changed. re-evaluate import.
456 fib_attached_export_cover_change (fib_entry_t *fib_entry)
458 fib_attached_export_cover_modified_i(fib_entry);
462 * \brief If this entry is tracking a cover (in another table)
463 * then that cover has been updated. re-evaluate import.
466 fib_attached_export_cover_update (fib_entry_t *fib_entry)
468 fib_attached_export_cover_modified_i(fib_entry);
472 fib_ae_import_format (fib_node_index_t import_index,
475 if (FIB_NODE_INDEX_INVALID != import_index)
477 fib_node_index_t *index;
478 fib_ae_import_t *import;
480 import = pool_elt_at_index(fib_ae_import_pool, import_index);
482 s = format(s, "\n Attached-Import:%d:[", (import - fib_ae_import_pool));
483 s = format(s, "export-prefix:%U ", format_fib_prefix, &import->faei_prefix);
484 s = format(s, "export-entry:%d ", import->faei_export_entry);
485 s = format(s, "export-sibling:%d ", import->faei_export_sibling);
486 s = format(s, "exporter:%d ", import->faei_exporter);
487 s = format(s, "export-fib:%d ", import->faei_export_fib);
489 s = format(s, "import-entry:%d ", import->faei_import_entry);
490 s = format(s, "import-fib:%d ", import->faei_import_fib);
492 s = format(s, "importeds:[");
493 vec_foreach(index, import->faei_importeds)
495 s = format(s, "%d, ", *index);
504 fib_ae_export_format (fib_node_index_t export_index, u8*s)
506 if (FIB_NODE_INDEX_INVALID != export_index)
508 fib_node_index_t *index;
509 fib_ae_export_t *export;
511 export = pool_elt_at_index(fib_ae_export_pool, export_index);
513 s = format(s, "\n Attached-Export:%d:[", (export - fib_ae_export_pool));
514 s = format(s, "export-entry:%d ", export->faee_ei);
516 s = format(s, "importers:[");
517 vec_foreach(index, export->faee_importers)
519 s = format(s, "%d, ", *index);